diff --git "a/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272(\344\270\213)/index.html" "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272(\344\270\213)/index.html" new file mode 100644 index 000000000..5e31c3f25 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272(\344\270\213)/index.html" @@ -0,0 +1,193 @@ +_3主3从的`Redis集群`搭建(下) | Research • 呓语 + + + + + + + + + + + + +

_3主3从的`Redis集群`搭建(下)

_3主3从的Redis集群搭建(下)

进入主机6381

+

redis-cli -p 6381

+
+
+ +
+ +

查看集群信息

+

cluster info

+
+
+ +
+ +

查看主机和从机之间的主从关系

+
+

cluster nodes

+
+

image-20220509101455220.assets\image-20220509101455220.png)

+
+ +
+ + +
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA(%E4%B8%8B)/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\344\271\213\345\223\210\345\270\214\346\247\275\347\256\227\346\263\225/index.html" "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\344\271\213\345\223\210\345\270\214\346\247\275\347\256\227\346\263\225/index.html" new file mode 100644 index 000000000..5af9fef08 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\344\271\213\345\223\210\345\270\214\346\247\275\347\256\227\346\263\225/index.html" @@ -0,0 +1,186 @@ +_3主3从的`Redis集群`搭建之哈希槽算法 | Research • 呓语 + + + + + + + + + + + + +

_3主3从的`Redis集群`搭建之哈希槽算法

_3主3从的Redis集群搭建之哈希槽算法

目的

解决一致性哈希算法数据倾斜问题

+

实质

是一个数组,数组[0,2^14-1]形成hash slot空间

+

作用

解决均匀分配问题,在数据和节点之间加入一层(哈希槽slot)用于管理数据和节点之间的关系,现在相当于节点里放槽,槽里放数据

+
+ +
+ +

方便数据移动

+

哈希解决的映射问题,使用key的哈希值来计算所在的槽,便于数据分配

+

多少个hash槽

一个集群只能有16384个槽,编号0-16383(0-2^14-1)

+

这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。

+

接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384

+

以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

+

举个栗子

Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上

+

首先有几个redis就把0-16383分成几个

+
+ +
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%E4%B9%8B%E5%93%88%E5%B8%8C%E6%A7%BD%E7%AE%97%E6%B3%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\357\274\210\344\270\212\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\357\274\210\344\270\212\357\274\211/index.html" new file mode 100644 index 000000000..f99547e89 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-_3\344\270\2733\344\273\216\347\232\204Redis\351\233\206\347\276\244\346\220\255\345\273\272\357\274\210\344\270\212\357\274\211/index.html" @@ -0,0 +1,216 @@ +_3主3从的`Redis集群`搭建(上) | Research • 呓语 + + + + + + + + + + + + +

_3主3从的`Redis集群`搭建(上)

_3主3从的Redis集群搭建(上)

    +
  • 关闭防火墙,启动docker
  • +
  • 新建6个docker容器docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
      +
    • docker run 创建并运行docker容器实例
    • +
    • —name redis-node-6 容器名字
    • +
    • —net host 使用宿主机的IP和端口,默认
    • +
    • —privileged=true 获取宿主机root用户权限
    • +
    • -v /data/redis/share/redis-node-6:/data 容器卷,宿主机地址:docker内部地址
    • +
    • redis:6.0.8 redis镜像和版本号
    • +
    • —cluster-enabled yes 开启redis集群
    • +
    • —appendonly yes 开启持久化
    • +
    • —port 6386 redis端口号
    • +
    +
  • +
+
1
2
3
4
5
6
docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
+

运行成功,使用docker ps查看

+
    +
  • 进入容器redis-node-1并为6台机器构建集群关系

    +
      +
    • 进入一台redis进行配置docker exec -it redis-node-1 bash

      +
    • +
    • #进入后执行
      +redis-cli --cluster create 8.142.144.75:6381 8.142.144.75:6382 8.142.144.75:6383 8.142.144.75:6384 8.142.144.75:6385 8.142.144.75:6386 --cluster-replicas 1
      +
      + --cluster create    构建集群
      + --cluster-replicas 1    集群关联一比一的关系
      +
      +--cluster-replicas 1 表示为每个master创建一个slave节点
      +# 注意:上面的ip为真实IP
      +
      +
    • +
    +

    有下面的绿色ok字样显示运行成功

    +
  • +
+
+ +
+ +
+

如果运行不成功,一直显示Waiting for the cluster to join..一直………………………………….,则是端口没有全部开放,防火墙也要开放端口,以阿里云为例

+
+

就是需要在安全组上面配置6381~6386的6个端口,还需要配置16381~16386的6个端口,共12个端口都要开放,不然会一直提示等待

+
    +
  • 一切OK的话,3主3从搭建搞定
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%EF%BC%88%E4%B8%8A%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/2022/08/26/docker/2022-08-25-_dockerfile/index.html b/2022/08/26/docker/2022-08-25-_dockerfile/index.html new file mode 100644 index 000000000..4a20f8ab8 --- /dev/null +++ b/2022/08/26/docker/2022-08-25-_dockerfile/index.html @@ -0,0 +1,181 @@ +_dockerfile | Research • 呓语 + + + + + + + + + + + + +

_dockerfile

_dockerfile

以dockerfile的方法来进行对centos的具有vim,ifconfig和jdk8的镜像

创建myfile文件夹

创建Dockerfile文件

+

注意:jdk8需要和Dockerfile放到同一个文件夹

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
FROM centos:7												
MAINTAINER zzyy<zzyybs@126.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
+

创建好Dockerfile后,运行docker build -t 新镜像名称:Tag .

注意:Tag后面有个空格,有个点 + +

虚悬镜像

+

仓库名和标签名全部为的镜像

+
+

碰到它还是进行删除的好

+

使用docker image ls -f dangling=true查找虚悬镜像

+

使用docker image prune删除镜像

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_dockerfile/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-_mysql\344\270\273\344\273\216\345\244\215\345\210\266docker\347\211\210/index.html" "b/2022/08/26/docker/2022-08-25-_mysql\344\270\273\344\273\216\345\244\215\345\210\266docker\347\211\210/index.html" new file mode 100644 index 000000000..b35ace87d --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-_mysql\344\270\273\344\273\216\345\244\215\345\210\266docker\347\211\210/index.html" @@ -0,0 +1,201 @@ +_mysql主从复制docker版 | Research • 呓语 + + + + + + + + + + + + +

_mysql主从复制docker版

_mysql主从复制docker版

安装mysql主从复制(一主一从)

新建主服务器容器实例3307

+
1
docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log/:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
+

进入/mydata/mysql-master/conf目录下新建my.cnf把下面内容粘贴到my.cnf

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
+

修改完配置后重启master容器

+

master容器实例内创建数据同步用户

+
1
2
3
4
# 建立一个用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 对新建的用户进行授权
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
+
+ +
+ + +

新建从服务器实例3308

+
1
docker run -p 3308:3306 --name mysql-slave -v /mydata/mysql-slave/log/:/var/log/mysql -v /mydata/mysql-slave/data:/var/lib/mysql -v /mydata/mysql-slave/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
+

进入/mydata/mysql-slave/conf目录下新建my.cnf

+
1
2
3
4
5
6
7
8
9
10
11
12
13
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
+

重启从机实例docker restart mysql-slave

+

在主数据库中查看主从同步状态show master status;

+

进入mysql-slave从机容器

+

在从数据库中配置主从复制change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;

+
1
2
3
4
5
6
7
8
# 说明:
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
+

在从数据库中查看主从同步状态show slave status \G;

+

在从数据库中开启主从同步start slave

+

查看从数据库状态发现已经同步

+
+ +
+ + +

主从复制测试

+

主机创建数据库,创建表,插入数据,搜索表的数据

+

从机直接搜索标的数据

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6docker%E7%89%88/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-_\344\270\273\344\273\216\345\256\271\351\224\231\345\210\207\346\215\242\350\277\201\347\247\273/index.html" "b/2022/08/26/docker/2022-08-25-_\344\270\273\344\273\216\345\256\271\351\224\231\345\210\207\346\215\242\350\277\201\347\247\273/index.html" new file mode 100644 index 000000000..680218188 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-_\344\270\273\344\273\216\345\256\271\351\224\231\345\210\207\346\215\242\350\277\201\347\247\273/index.html" @@ -0,0 +1,204 @@ +_主从容错切换迁移 | Research • 呓语 + + + + + + + + + + + + +

_主从容错切换迁移

_主从容错切换迁移

进入redis集群

+

注意:进入集群环境后,不能使用单机版的redis-cli -p 6381

+
+

因为这样会在增加数据时有error报错出现

+
+ +
+ + +

使用set k1 v1错误是因为1号主机里面的编号是0到5460,超过了这个范围就会报错

+
+

正确进入的方法redis-cli -p 6381 -c

+

-c 的作用是优化路由

+
+
+ +
+ + +注:FLUSHALL:作用是清除之前添加的记录 + +

集群检查

+

redis-cli —cluster check 8.142.144.75:6381

+
+注:可以进入任意一台主机 + + +
+ +
+ + +

主从容错切换迁移

+

主机宕机,从机自动切换成主机

+
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-_%E4%B8%BB%E4%BB%8E%E5%AE%B9%E9%94%99%E5%88%87%E6%8D%A2%E8%BF%81%E7%A7%BB/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\270\200\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\270\200\357\274\211/index.html" new file mode 100644 index 000000000..b24bc53d8 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\270\200\357\274\211/index.html" @@ -0,0 +1,185 @@ +docker 帮助启动类命令(一) | Research • 呓语 + + + + + + + + + + + + +

docker 帮助启动类命令(一)

docker 帮助启动类命令(一)

启动docker

+
+

systemctl start docker

+
+

停止docker

+
+

systemctl stop docker

+
+

查看docker状态

+
+

systemctl status docker

+
+

重启 docker,没有任何提示说明启动成功

+
+

systemctl restart docker

+
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-docker%20%E5%B8%AE%E5%8A%A9%E5%90%AF%E5%8A%A8%E7%B1%BB%E5%91%BD%E4%BB%A4%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\272\214\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\272\214\357\274\211/index.html" new file mode 100644 index 000000000..8fb55546f --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-docker \345\270\256\345\212\251\345\220\257\345\212\250\347\261\273\345\221\275\344\273\244\357\274\210\344\272\214\357\274\211/index.html" @@ -0,0 +1,183 @@ +docker 帮助启动类命令(二) | Research • 呓语 + + + + + + + + + + + + +

docker 帮助启动类命令(二)

docker 帮助启动类命令(二)

docker 开机启动

+
+

systemctl enable docker

+
+

查看 docker 概要信息

+
+

docker info

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.7.1-docker)
scan: Docker Scan (Docker Inc., v0.12.0)

Server:
Containers: 6
Running: 0
Paused: 0
Stopped: 6
Images: 5
Server Version: 20.10.12
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc version: v1.0.2-0-g52b36a2
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 3.10.0-1160.45.1.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 1.795GiB
Name: iZ8vbfaek3x3ogtpxnpnwfZ
ID: NQOP:KCP6:LS6G:K52A:XOQX:E7FG:FEHL:K3QX:NSLP:VY5S:TFX5:UR42
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://qp747t9w.mirror.aliyuncs.com/
Live Restore Enabled: false

+

查看 docker 总体帮助文档

+
+

docker —help

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker --help

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST
env var and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit

Management Commands:
app* Docker App (Docker Inc., v0.9.1-beta3)


查看 docker 命令帮助文档
> docker 具体命令 --help

```shell
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps --help

Usage: docker ps [OPTIONS]

List containers

Options:
-a, --all Show all containers (default shows just running)
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int Show n last created containers (includes all states) (default -1)
-l, --latest Show the latest created container (includes all states)
--no-trunc Don't truncate output
-q, --quiet Only display container IDs
-s, --size Display total file sizes
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-docker%20%E5%B8%AE%E5%8A%A9%E5%90%AF%E5%8A%A8%E7%B1%BB%E5%91%BD%E4%BB%A4%EF%BC%88%E4%BA%8C%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\270\200\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\270\200\357\274\211/index.html" new file mode 100644 index 000000000..8017c585b --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\270\200\357\274\211/index.html" @@ -0,0 +1,198 @@ +docker 镜像(一) | Research • 呓语 + + + + + + + + + + + + +

docker 镜像(一)

镜像(一)

查询本地主机上的镜像

+

docker images
OPTIONS说明:

+
    +
    • +
    • a 列出本地所有的镜像(含历史镜像)
    • +
    +
  • +
    • +
    • q 只显示镜像ID
    • +
    +
  • +
+
+

举个栗子

1
2
3
4
5
6
7
8
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
tomcat latest fb5657adc892 4 months ago 680MB
hello-world latest feb5d9fea6a5 7 months ago 13.3kB
centos latest 5d0da3dc9764 7 months ago 231MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+
1
2
3
4
5
6
7
8
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
tomcat latest fb5657adc892 4 months ago 680MB
hello-world latest feb5d9fea6a5 7 months ago 13.3kB
centos latest 5d0da3dc9764 7 months ago 231MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+
1
2
3
4
5
6
7
8
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images -q
b8e65a4d736d
fb5657adc892
feb5d9fea6a5
5d0da3dc9764
9b9cb95443b5
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#

+

查询镜像仓库是否有该镜像

+

docker search 镜像名称

+
+

举个栗子

STARS 点赞数
OFFICIAL 官方认证

+
1
2
3
4
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker search hello-world
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
hello-world Hello World! (an example of minimal Dockeriz… 1718 [OK]
kitematic/hello-world-nginx A light-weight nginx container that demonstr… 151
+

显示前n条镜像

+

docker search —limit n 镜像名称

+
+
1
2
3
4
5
6
7
8
9
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker search --limit 5 redis
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redis Redis is an open source key-value store that… 10851 [OK]
bitnami/redis Bitnami Redis Docker Image 214 [OK]
bitnami/redis-sentinel Bitnami Docker Image for Redis Sentinel 36 [OK]
circleci/redis CircleCI images for Redis 12 [OK]
bitnami/redis-exporter 6
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+

下载安装镜像到本地

+

docker pull 镜像名称:标签版本号

+
+

没有tag就是最新版

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker pull redis:6.0.8
6.0.8: Pulling from library/redis
bb79b6b2107f: Pull complete
1ed3521a5dcb: Pull complete
5999b99cee8f: Pull complete
3f806f5245c9: Pull complete
f8a4497572b2: Pull complete
eafe3b6b8d06: Pull complete
Digest: sha256:21db12e5ab3cc343e9376d655e8eabbdbe5516801373e95a8a9e66010c5b8819
Status: Downloaded newer image for redis:6.0.8
docker.io/library/redis:6.0.8
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-docker%20%E9%95%9C%E5%83%8F%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\272\214\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\272\214\357\274\211/index.html" new file mode 100644 index 000000000..6b101a0cf --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-docker \351\225\234\345\203\217\357\274\210\344\272\214\357\274\211/index.html" @@ -0,0 +1,188 @@ +docker 镜像(二) | Research • 呓语 + + + + + + + + + + + + +

docker 镜像(二)

镜像(二)

查看 镜像/容器/数据 卷所占的空间

+

docker system df

+
+
1
2
3
4
5
6
7
8
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 3 1.173GB 921.1MB (78%)
Containers 6 0 4.517MB 4.517MB (100%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+

删除镜像

+

docker rmi 镜像ID

+
+

```shell

+

如果提示报错

Error response from daemon: conflict: unable to delete feb5d9fea6a5 (must be forced) - image is being used by stopped container 13111f725991

+

说明之前运行过这个镜像,生成了容器,需要先删除容器,再删除镜像

+

使用 -f 删除一个

+

docker rmi -f 镜像id

+
+

使用 -f 删除多个

+

xxxxxxxxxx # 没有任何提示说明启动成功[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# systemctl restart docker[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#shell

+
+

使用 -f 删除全部

+

docker rmi -f $(docker images -qa)

+
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-docker%20%E9%95%9C%E5%83%8F%EF%BC%88%E4%BA%8C%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-redis3\344\270\2733\344\273\216\346\211\251\345\256\271/index.html" "b/2022/08/26/docker/2022-08-25-redis3\344\270\2733\344\273\216\346\211\251\345\256\271/index.html" new file mode 100644 index 000000000..d10f0bbe0 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-redis3\344\270\2733\344\273\216\346\211\251\345\256\271/index.html" @@ -0,0 +1,220 @@ +redis的3主3从扩容 | Research • 呓语 + + + + + + + + + + + + +

redis的3主3从扩容

redis的3主3从扩容

首先添加两个redis

1
2
3
4
# 创建redis-node-7
docler run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
# 创建redis-node-8
docler run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
+注:在阿里云的安全组和防火墙上添加6387,16387 6388,16388四个端口 + +

配置步骤:

执行docker exec -it redis-node-1 bash进入redis-node-1里面
执行redis-cli --cluster add-node 8.142.144.75:6387 8.142.144.75:6381
+ +
+ + + +

6387 新加入的节点

+

6381 相当于6387的领路人

+
使用redis-cli --cluster check 8.142.144.75:6381检查
+ +
+ +
重新分配槽号
+

redis-cli —cluster reshard IP地址:端口号

+
+
+ +
+ +注:上图的1指的是:对主机数平分16384个节点,16384/主机数(包含想要添加的主机) + +注:上图的2指的是:新加入的6387节点的ID + +
+ +
+ +all:表示全部进行重新分配 + +

在重新加载过程会碰到Do you want to proceed with the proposed reshard plan (yes/no)?一句话,选择yes就可以

+
+ +
+ +
检查集群情况
+ +
+ +
为主节点6387分配从节点6388
+

redis-cli —cluster add-node ip:新slave端口 ip:新master端口 —cluster-slave —cluster-master-id 新主机节点ID

+
+
+ +
+ +
检查集群情况
+ +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-redis3%E4%B8%BB3%E4%BB%8E%E6%89%A9%E5%AE%B9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-redis\347\232\2044\344\270\2734\344\273\216\347\274\251\345\256\271/index.html" "b/2022/08/26/docker/2022-08-25-redis\347\232\2044\344\270\2734\344\273\216\347\274\251\345\256\271/index.html" new file mode 100644 index 000000000..194905425 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-redis\347\232\2044\344\270\2734\344\273\216\347\274\251\345\256\271/index.html" @@ -0,0 +1,213 @@ +redis的4主4从缩容 | Research • 呓语 + + + + + + + + + + + + +

redis的4主4从缩容

redis的4主4从缩容

目的:6387和6388下线
检查集群情况获得6388的节点ID
+

redis-cli —cluster check 8.142.144.75:6382

+
+
+ +
+ +
从集群中将4号从节点6388删除
+

redis-cli —cluster del-node ip:从机端口 从机6388节点ID

+
+
+ +
+ +
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
+ +

6388删除成功

+
将6387的槽号清空,重新分配

本例将清出来的槽号都给6381

+

使用redis-cli --cluster reshard ip:6381进行节点的重组

+
+ +
+ +注: + +

上图中1输入的4096是6387主机所拥有的槽点数量,把他们全部拿出来分掉

+

上图的2输入的ID是接收6387主机所放出的槽点数的主机id

+

上图中3输入的ID是放出槽点数的6387主机的id

+

上图中4输入的done指的是已经输入完所有的节点

+
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
+ +
删除6387节点的主机
+

redis-cli —cluster del-node ip:端口 6387节点ID

+
+
+ +
+ +
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-redis%E7%9A%844%E4%B8%BB4%E4%BB%8E%E7%BC%A9%E5%AE%B9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232mysql/index.html" "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232mysql/index.html" new file mode 100644 index 000000000..96cd8752e --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232mysql/index.html" @@ -0,0 +1,194 @@ +使用docker安装常用软件:mysql | Research • 呓语 + + + + + + + + + + + + +

使用docker安装常用软件:mysql

使用docker安装常用软件:mysql

以mysql 5.7为例

使用docker pull mysql:5.7拉取mysql 5.7镜像

+

使用镜像创建容器

简单版

使用docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7运行镜像创建容器

+
+

因为linux系统自己装了mysql,避免端口冲突,先运行ps -ef|grep mysql查询

+
+

使用docker ps查询容器编号

+

使用docker exec -it 容器编号 bash进入mysql容器

+

使用mysql -uroot -p,输入密码,登录mysql

+
验证

show databases

+
1
2
3
4
5
6
7
8
9
10
mysql> show databases
-> ;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
+
中文乱码问题
1
2
3
4
5
INSERT INTo t1 VALUES(3, "张三");
---
INSERT INTo t1 VALUES(3, "张三")
> 1366 - Incorrect string value: '\xE5\xBC\xA0\xE4\xB8\x89' for column 'name' at row 1
> 时间: 0.038s
+因为docker默认编码字符集隐患 + +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
mysql>
+

解决中文乱码问题

在宿主机的/ggls/mysql/conf目录下vim my.cnf文件,通过容器卷同步给容器实例

+
1
2
3
4
5
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
+改完后重启mysql实例 + +
服务器输入SHOW VARIABLES LIKE 'character%';验证
docker安装好并run出容器后,先修改字符集编码在创建mysql库 + +
删库备份问题
只要本机上面的容器卷存在,容器卷位置没有改变的情况下,就算容器被删除,重新打开后,创建的数据库,表都还存在 + + +

工作使用版启动容器方法

+
1
2
3
4
5
6
7
docker run -d -p 3306:3306 --privileged=true
-v /ggls/mysql/log:/var/log/mysql
-v /ggls/mysql/data:/var/lib/mysql
-v /ggls/mysql/conf:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456
--name mysql
mysql:5.7
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Amysql/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232redis/index.html" "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232redis/index.html" new file mode 100644 index 000000000..09cca8d98 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232redis/index.html" @@ -0,0 +1,175 @@ +使用docker安装常用软件:redis | Research • 呓语 + + + + + + + + + + + + +

使用docker安装常用软件:redis

使用docker安装常用软件:redis

使用docker pull redis:6.0.8拉取redis:6.0.8镜像

+

创建容器

+
+

容器卷要加入--privileged=true

+
+

在宿主机下新建目录mkdir -p /app/redis

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Aredis/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232tomcat/index.html" "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232tomcat/index.html" new file mode 100644 index 000000000..55e0c066a --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\344\275\277\347\224\250docker\345\256\211\350\243\205\345\270\270\347\224\250\350\275\257\344\273\266\357\274\232tomcat/index.html" @@ -0,0 +1,197 @@ +使用docker安装常用软件:tomcat | Research • 呓语 + + + + + + + + + + + + +

使用docker安装常用软件:tomcat

使用docker安装常用软件:tomcat

安装流程

首先把tomcat在镜像源中pull下来,使用docker images 查看镜像

+

使用docker run -d -p 8080:8080 tomcat:9.0新建容器运行tomcat

+
+

运行后使用本地PC使用阿里云的ip和端口访问docker上面的tomcat

+
+
+ +
+ + + +

这是什么原因呢

使用docker ps查询到容器编号,docker exec -it 容器编号 bash 打开容器

+
1
2
3
4
5
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c52ab6b8b8df b8e65a4d736d "catalina.sh run" 7 minutes ago Up 7 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp inspiring_bohr
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker exec -it c52ab6b8b8df bash
root@c52ab6b8b8df:/usr/local/tomcat#
+

使用ls-l查看文件列表

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
root@c52ab6b8b8df:/usr/local/tomcat# ls -l
total 156
-rw-r--r-- 1 root root 18970 Dec 2 14:30 BUILDING.txt
-rw-r--r-- 1 root root 6210 Dec 2 14:30 CONTRIBUTING.md
-rw-r--r-- 1 root root 57092 Dec 2 14:30 LICENSE
-rw-r--r-- 1 root root 2333 Dec 2 14:30 NOTICE
-rw-r--r-- 1 root root 3378 Dec 2 14:30 README.md
-rw-r--r-- 1 root root 6898 Dec 2 14:30 RELEASE-NOTES
-rw-r--r-- 1 root root 16507 Dec 2 14:30 RUNNING.txt
drwxr-xr-x 2 root root 4096 Dec 22 17:16 bin
drwxr-xr-x 1 root root 4096 Apr 29 01:48 conf
drwxr-xr-x 2 root root 4096 Dec 22 17:16 lib
drwxrwxrwx 1 root root 4096 Apr 29 01:48 logs
drwxr-xr-x 2 root root 4096 Dec 22 17:16 native-jni-lib
drwxrwxrwx 2 root root 4096 Dec 22 17:16 temp
drwxr-xr-x 2 root root 4096 Dec 22 17:16 webapps
drwxr-xr-x 7 root root 4096 Dec 2 14:30 webapps.dist
drwxrwxrwx 2 root root 4096 Dec 2 14:30 work
root@c52ab6b8b8df:/usr/local/tomcat#
+

从列表可以看到有两个文件夹webappswebapps.dist,数据全部在webapps.dist里面,需要将webapps删除,把webapps.dist重命名成webapps即可访问

+

使用rm -rf webapps删除webapps文件夹

+

使用mv webapps.dist webapps重命名

+

再次使用本地访问

+
+ +
+ + +

使用免修改版的tomcat

+

docker pull billygoo/tomcat8-jdk8

+

docker run -d -p 8080:8080 —name tomcat8 billygoo/tomcat8-jdk8

+
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Atomcat/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\346\225\260\346\215\256\345\215\267/index.html" "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\346\225\260\346\215\256\345\215\267/index.html" new file mode 100644 index 000000000..3bc59a08c --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\346\225\260\346\215\256\345\215\267/index.html" @@ -0,0 +1,197 @@ +容器数据卷 | Research • 呓语 + + + + + + + + + + + + +

容器数据卷

容器数据卷

运行带有容器数据卷的容器实例

1
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
+

举个栗子

+

宿主vs容器之间映射添加容器卷

+
+
    +
  • 使用docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名 添加
  • +
+
1
docker run -it --privileged=true -v /tmp/host_data:/tmp/docker_data --name=ui ubuntu
+
    +
  • 查看数据卷是否挂载成功
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
`在容器内部创建一个dockerin.txt文件
root@48955acecd79:/tmp/docker_data# touch dockerin.txt
root@48955acecd79:/tmp/docker_data# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 28 09:21 ./
drwxrwxrwt 1 root root 4096 Apr 28 09:18 ../
-rw-r--r-- 1 root root 0 Apr 28 09:21 dockerin.txt
`在宿主机目录下查看该文件
root@48955acecd79:/tmp/docker_data# [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# cd /tmp/host_data/
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# ll
total 0
-rw-r--r-- 1 root root 0 Apr 28 17:21 dockerin.txt
`在宿主机创建一个文件
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# touch host.txt

`在容器查看文件
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# docker exec -it 48955acecd79 bash
root@48955acecd79:/# cd /tmp/docker_data/

+ 容器和宿主机之间数据共享

[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m="vim cmd add ok" -a="ggls" 356e32244966 ggls/ubuntu:1.5sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# shell

+ 主机修改,docker同步获得

+ docker容器stop,主机修改,docker容器重启数据同步

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f562278524cdacdee90a8c77d

+ 默认是可读可写的

```shell
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
+
    +
  • 修改成容器只读
  • +
+
1
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
+
+

卷的继承和共享

+
+
    +
  • 容器1完成和宿主机的映射
      +
    • 容器2继承容器1,则容器2操作后同步到容器1和宿主机
    • +
    • 宿主机操作同步到容器1,容器2
    • +
    • 容器1操作同步到宿主机,容器2
    • +
    +
  • +
+
1
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\200\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\200\357\274\211/index.html" new file mode 100644 index 000000000..62ee36f87 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\200\357\274\211/index.html" @@ -0,0 +1,199 @@ +容器(一) | Research • 呓语 + + + + + + + + + + + + +

容器(一)

容器(一)

新建和启动容器

OPTIONS说明:

    +
  • — name = “容器新名称” 为容器制定一个名称
  • +
  • -d 后台运行容器并返回容器id, 即启动守护式容器(后台运行)
  • +
  • -i 以交互模式运行容器,通常与 -t 同时使用
  • +
  • -t 为容器重新分配一个伪输入终端,通常与 -i 连用,也就是启动交互式容器
  • +
  • -P 随机端口映射
  • +
  • -p 指定端口映射
  • +
+

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker run -it ubuntu:15.10 /bin/bash
root@4fb757f69adb:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:26 pts/0 00:00:00 /bin/bash
root 11 1 0 03:26 pts/0 00:00:00 ps -ef
root@4fb757f69adb:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@4fb757f69adb:/# exit
exit
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

docker run -it ubuntu:15.10 /bin/bash
/bin/bash 希望有交互式shell 就用/bin/bash

+

查询正在运行的容器

+

docker ps [OPTIONS]

+
+
1
2
3
4
5
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cdee90a8c77d ubuntu "bash" 3 minutes ago Exited (0) 3 minutes ago ubuntu
0dcaa91afc0e ubuntu "/bin/bush" 5 minutes ago Created myubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

OPTIONS:

+
    +
  • -a 展示所有容器,包含历史用过容器
  • +
  • -d 只展示容器id
  • +
  • -l 显示最近创建的容器
  • +
  • -n 展示最近创建的前n个容器
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    List containers
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -n 1
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -an 1
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -an 2
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    0dcaa91afc0e ubuntu "/bin/bush" 19 minutes ago Created myubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

    +
  • +
+

退出容器

    +
  • exit
  • +
+

run进入容器,exit退出容器, 容器停止

+
    +
  • ctrl + p + q
  • +
+

run进入容器,exit退出容器, 容器不停止

1
2
3
4
5
6
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker run -it ubuntu bash
root@562278524cda:/# [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 16 seconds ago Up 15 seconds loving_dewdney

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\211\357\274\211\357\274\210\351\207\215\350\246\201\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\211\357\274\211\357\274\210\351\207\215\350\246\201\357\274\211/index.html" new file mode 100644 index 000000000..4b3476211 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\270\211\357\274\211\357\274\210\351\207\215\350\246\201\357\274\211/index.html" @@ -0,0 +1,214 @@ +容器(三) | Research • 呓语 + + + + + + + + + + + + +

容器(三)

容器(三)

创建后台守护式容器

(问题):使用docker run -d ubuntu命令启动后台模式的容器ubuntu,然后用docker ps 查询提示没有找到运行的容器

+
+

Docker容器后台运行就必须有一个前台进程,不然容器没事做,会自杀

+
+

解决方法:将运行的程序以前台进程的方式运行
常见方式:命令行模式

+

查看容器日志

+

docker logs 容器id

+
+

查看容器的进程

+

docker top 容器id

+
+

查看容器内部细节

+

docker inspect 容器id

+
+

重新进入

    +
  • 进入正在运行的容器并以命令行交互

    +
    +

    docker exec -it 容器id bashShell

    +
    +
  • +
  • 重新进入

    +
    +

    docker attach 容器id

    +
    +
  • +
+

(区别)
attach直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止
exec是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止

+
1
2
3
4
5
6
7
8
9
10
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAME
S562278524cda   ubuntu    "bash"    20 minutes ago   Up 20 minutes             loving_dewdn
eycdee90a8c77d   ubuntu    "bash"    45 minutes ago   Up 15 minutes             ubuntu

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f562278524cdacdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS   PORTS     NAMES

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#​shell
+

从容器内拷贝文件到主机

+

docker cp 容器id:容器地址 主机地址

+
+
1
2
3
4
5
6
7
8
9
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker cp 26191ecfb227:/tmp/a.txt /opt/ab.txt
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# cd /opt/
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 8
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]#

+

导入和导出容器

    +
  • export 导出容器的内容留作为一个tar归档文件[对应import命令]

    +
    +

    docker export 容器id > 自定义文件名.tar

    +
    +
  • +
  • import从tar包中的内容创建一个新的文件系统再导入为镜像[export]

    +
    +

    cat 文件名.tar | docker import - 自定义/镜像名:3.5(3.5是自定义)

    +
    +
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
26191ecfb227 ubuntu "bash" 7 minutes ago Up 7 minutes quirky_jemison
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker export 26191ecfb227 > abcd.tar
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 73408
-rw-r--r-- 1 root root 75158016 Apr 27 15:21 abcd.tar
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]#

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 73408
-rw-r--r-- 1 root root 75158016 Apr 27 15:21 abcd.tar
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# cat abcd.tar | docker import - mytest/ubuntu:3.5
sha256:a92a27affdde8ad7f07bef2fdc0f04b8e3aeacb9d6919a77da2921d552ab940b
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytest/ubuntu 3.5 a92a27affdde 11 seconds ago 72.8MB
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
ubuntu latest ba6acccedd29 6 months ago 72.8MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker run -it mytest/ubuntu:3.5 bash
root@356e32244966:/#
root@356e32244966:/# cd /tmp/
root@356e32244966:/tmp# ll
total 8
drwxrwxrwt 2 root root 4096 Apr 27 07:13 ./
drwxr-xr-x 1 root root 4096 Apr 27 07:32 ../
-rw-r--r-- 1 root root 0 Apr 27 07:13 a.txt
root@356e32244966:/tmp#

文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%B8%89%EF%BC%89%EF%BC%88%E9%87%8D%E8%A6%81%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\272\214\357\274\211/index.html" "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\272\214\357\274\211/index.html" new file mode 100644 index 000000000..d1541455b --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\345\256\271\345\231\250\357\274\210\344\272\214\357\274\211/index.html" @@ -0,0 +1,190 @@ +容器(二) | Research • 呓语 + + + + + + + + + + + + +

容器(二)

容器(二)

启动已经停止运行的容器

+

docker start 容器id/容器名

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 4 minutes ago Up 4 minutes loving_dewdney
9a1a43aee837 ubuntu "bush" 4 minutes ago Created admiring_wiles
cdee90a8c77d ubuntu "bash" 29 minutes ago Exited (0) 29 minutes ago ubuntu
0dcaa91afc0e ubuntu "/bin/bush" 31 minutes ago Created myubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 4 minutes ago Up 4 minutes loving_dewdney
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker start cdee90a8c77d
cdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 5 minutes ago Up 5 minutes loving_dewdney
cdee90a8c77d ubuntu "bash" 30 minutes ago Up 3 seconds ubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

重启容器

+

docker restart 容器id/容器名

+
+

停止容器

+

docker stop 容器id/容器名

+
+

强制停止容器

+

docker kill 容器id/容器名

+
+

删除已经停止的容器

+

docker rm 容器id

+
+

一次性删除多个容器

    +
  • docker rm -f $(docker ps -a -q)
  • +
  • docker ps -a -q | xargs docker rm
  • +
+

注:xargs是linux系统的可变参数,把分隔符前面的结果传给xargs里面,然后执行分隔符后面的命令

1
2
3
4
5
6
7
8
9
10
11
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 20 minutes ago Up 20 minutes loving_dewdney
cdee90a8c77d ubuntu "bash" 45 minutes ago Up 15 minutes ubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f
562278524cda
cdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%BA%8C%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\347\247\201\346\234\211\345\272\223/index.html" "b/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\347\247\201\346\234\211\345\272\223/index.html" new file mode 100644 index 000000000..cfa205507 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\347\247\201\346\234\211\345\272\223/index.html" @@ -0,0 +1,221 @@ +本地镜像发布到私有库 | Research • 呓语 + + + + + + + + + + + + +

本地镜像发布到私有库

本地镜像发布到私有库

+

步骤

+
+
    +
  • 下载Docker Registry
  • +
+
1
docker pull registry
+
    +
  • 运行私有库 Registry,相当于本地有Docker Registry
  • +
+
1
docker run -d -p 5000:5000 -v/ggls/myregistry/:/tmp/registry --privileged=true registry
+
    +
  • 新启动ubuntu容器,新增ifconfig命令

    +
      +
    • ​ 进入容器中输入apt-get update命令
    • +
    • ​ 输入apt-get install net-tools命令
    • +
    • xxxxxxxxxx [root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES356e32244966 mytest/ubuntu:3.5 “bash” 2 hours ago Up 2 hours elated_aryabhata[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m=”vim cmd add ok” -a=”ggls” 356e32244966 ggls/ubuntu:1.5sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEggls/ubuntu 1.5 87e99e19eeef 7 seconds ago 176MBmytest/ubuntu 3.5 a92a27affdde 2 hours ago 72.8MBtomcat 9.0 b8e65a4d736d 4 months ago 680MBubuntu latest ba6acccedd29 6 months ago 72.8MBredis 6.0.8 16ecd2772934 18 months ago 104MB[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# shell
    • +
    +
  • +
  • 容器外部执行docker commit -m="ifconfig cmd add" -a="ggls" ffcc5edf5071 ubuntu:1.6命令

    +
  • +
  • curl验证私服库上有什么镜像

    +
  • +
+
1
curl -XGET http://8.142.144.75:5000/v2/_catalog
+
    +
  • 将新镜像修改为符合私服库格式的镜像
  • +
+
1
2
3
docker tag 镜像:Tag Host:Port/Repository:Tag
#
docker tag ubuntu:1.6 8.142.144.75:5000/ubuntu:1.3
+
    +
  • 修改配置文件使之支持http

    +
    +

    docker 默认不允许http方式推送镜像,通过此配置取消这个限制,若不生效,重启docker

    +
    +
      +
    • 使用命令vim /etc/docker/daemon.json打开配置文件
    • +
    • 在阿里云加速后面新增一个json
    • +
    +
    1
    2
    3
    4
    {
    "registry-mirrors": ["https://qp747t9w.mirror.aliyuncs.com"],
    "insecure-registries": ["8.142.144.75:5000"]
    }
    +
      +
    • 重启docker,重启docker私服仓库
    • +
    +
  • +
  • push推送到私服库

    +
  • +
+
1
docker push 符合私服库格式的镜像名称:tag
+
    +
  • curl验证私服库上有什么镜像
  • +
  • pull到本地并运行
  • +
+
1
docker pull 8.142.144.75:5000/ubuntu:1.6
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%E5%8F%91%E5%B8%83%E5%88%B0%E7%A7%81%E6%9C%89%E5%BA%93/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\351\230\277\351\207\214\344\272\221/index.html" "b/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\351\230\277\351\207\214\344\272\221/index.html" new file mode 100644 index 000000000..de10f34c8 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\346\234\254\345\234\260\351\225\234\345\203\217\345\217\221\345\270\203\345\210\260\351\230\277\351\207\214\344\272\221/index.html" @@ -0,0 +1,195 @@ +本地镜像发布到阿里云 | Research • 呓语 + + + + + + + + + + + + +

本地镜像发布到阿里云

本地镜像发布到阿里云


+

使用docker进行对docker镜像功能的新增后,需要发布到阿里云上对镜像进行同步,下次pull镜像就不要pull缩减版的镜像,直接pull更新后的镜像,方便后续使用

+

执行顺序

    +
  • 阿里云开发者平台
  • +
  • 点击镜像容器服务
  • +
  • 创建镜像仓库
      +
    • 创建命名空间
    • +
    • 创建镜像仓库
    • +
    +
  • +
+

然后在基本信息上面就可以看到仓库指南

+
+

根据指南进行操作

+
+ +
+ +
+
+ +
+ +
+ +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%E5%8F%91%E5%B8%83%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/docker/2022-08-25-\351\225\234\345\203\217/index.html" "b/2022/08/26/docker/2022-08-25-\351\225\234\345\203\217/index.html" new file mode 100644 index 000000000..a26c339a1 --- /dev/null +++ "b/2022/08/26/docker/2022-08-25-\351\225\234\345\203\217/index.html" @@ -0,0 +1,191 @@ +镜像 | Research • 呓语 + + + + + + + + + + + + +

镜像

镜像

背景

docker镜像是最小的,被精简过的Linux系统,是不带vim命令的

+
+

使用命令 ‘vim a.txt’ 进行新建编辑a.txt文件,就会提示找不到命令

+
+

给镜像容器新增vim命令

    +
  1. 更新镜像

    +
    +

    apt-get update

    +
    +
  2. +
  3. 下载vim功能

    +
    +

    apt-get -y install vim

    +
    +
  4. +
  5. 提交副本使成为一个新镜像

    +
    +

    docker commit -m=”提交的描述信息” -a=”作者” 容器id 要创建的目标镜像名:[标签名]

    +
    +
  6. +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
356e32244966 mytest/ubuntu:3.5 "bash" 2 hours ago Up 2 hours elated_aryabhata
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m="vim cmd add ok" -a="ggls" 356e32244966 ggls/ubuntu:1.5
sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ggls/ubuntu 1.5 87e99e19eeef 7 seconds ago 176MB
mytest/ubuntu 3.5 a92a27affdde 2 hours ago 72.8MB
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
ubuntu latest ba6acccedd29 6 months ago 72.8MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/docker/2022-08-25-%E9%95%9C%E5%83%8F/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/error/2022-11-08-\344\275\277\347\224\250pip install\346\212\245\351\224\231\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" "b/2022/08/26/error/2022-11-08-\344\275\277\347\224\250pip install\346\212\245\351\224\231\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" new file mode 100644 index 000000000..7397dd46e --- /dev/null +++ "b/2022/08/26/error/2022-11-08-\344\275\277\347\224\250pip install\346\212\245\351\224\231\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" @@ -0,0 +1,179 @@ +使用pip install报错的解决办法 | Research • 呓语 + + + + + + + + + + + + +

使用pip install报错的解决办法

报错提示

今天使用PyCharm下载一个模块pip.exe install locust,有错误提示

+
1
2
3
4
5
6
7
8
9
10
11
https://visualstudio.microsoft.com/visual-cpp-build-tools/
[end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.
// 报错位置
ERROR: Failed building wheel for psutil

ERROR: Could not build wheels for psutil, which is required to install pyproject.toml-based projects
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
+

原因

+

缺少对应的whl文件

+
+

解决办法

碰到了这个错误ERROR: Failed building wheel for psutil,就需要下载psutil.whl

+

下载网站点击进入网站

+

下载psutil-5.9.0-cp38-cp38-win_amd64.whl文件

+

然后使用(pip install 文件的绝对路径)进行安装,然后使用pip.exe install locust正常安装

+
1
2
3
4
5

pip.exe install D:\Appium\psutil-5.9.0-cp38-cp38-win_amd64.whl

pip.exe install locust

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/error/2022-11-08-%E4%BD%BF%E7%94%A8pip%20install%E6%8A%A5%E9%94%99%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/jmeter/2022-10-30-\347\254\254\344\270\200\346\254\241\344\275\277\347\224\250jmeter\345\216\213\346\265\213/index.html" "b/2022/08/26/jmeter/2022-10-30-\347\254\254\344\270\200\346\254\241\344\275\277\347\224\250jmeter\345\216\213\346\265\213/index.html" new file mode 100644 index 000000000..6e557b047 --- /dev/null +++ "b/2022/08/26/jmeter/2022-10-30-\347\254\254\344\270\200\346\254\241\344\275\277\347\224\250jmeter\345\216\213\346\265\213/index.html" @@ -0,0 +1,225 @@ +使用jmeter录制压测 | Research • 呓语 + + + + + + + + + + + + +

使用jmeter录制压测

业务

    +
  • 压测对象:http://news.baidu.com
  • +
  • 压测页面:首页、国际频道、财经频道
  • +
  • 步骤
      +
    • 访问首页
    • +
    • 单击“国际”(频道)
    • +
    • 单击“财经”(频道)
    • +
    +
  • +
  • 操作手段:录制回放
  • +
+

操作步骤

    +
  • 添加录制器“HTTP(S) Test Script Recorder”

    +
      +
    • 右键Test Plan,点击add
    • +
    • 点击Non-Test Elements
    • +
    • 点击HTTP(S) Test Script Recorder
    • +
    +
  • +
  • 添加线程组“Thread Group”

    +
  • +
  • 添加录制控制器“Recording Controller”,

    +
      +
    • 右键线程组,点击and
    • +
    • 点击Logic Controller
    • +
    • 点击Recording Controller
    • +
    +
  • +
  • 录制脚本的配置(Test Plan Creation)

    +
      +
    • Port=8088
    • +
    • Target Controller = TestPlan > Tread Group > Recording Controller
    • +
    • 其他的配置保持默认
    • +
    +
  • +
  • 录制脚本的配置(Requests Filtering 请求过滤器)

    +
      +
    • URl Patterns to Include上添加正则.*\.(baidu\.com).*;表示只抓取百度URL的内容,不抓取其他网站的
    • +
    • URl Patterns to Exclude上添加正则.*\.(js|css|PNG|jpg|jpeg|ico|png|gif).*;去掉一些静态请求
    • +
    • 目的是:避免录制过多没必要的请求
    • +
    +
  • +
  • 单击保存按钮,将Jmeter脚本存储

    +
  • +
  • +
  • 打开浏览器,设置代理,将浏览器的代理服务地址指向http://localhost:8088,然后就可以进行访问录制了
  • +
  • +
  • 访问百度新闻的首页、国际、财经页面
  • +
  • +
  • 查看jmeter,录制结果在Recording Controller下面看到,然后停止录制
  • +
+

校验

录制结束后,要对录制的代码进行校验

+
    +
  • 添加查看结果树组件
  • +
+

运行录制的代码,在查看结果树上查看运行的结果

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/jmeter/2022-10-30-%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%BF%E7%94%A8jmeter%E5%8E%8B%E6%B5%8B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/other/2020-08-26-Yaml\344\275\277\347\224\250/index.html" "b/2022/08/26/other/2020-08-26-Yaml\344\275\277\347\224\250/index.html" new file mode 100644 index 000000000..c07ab181a --- /dev/null +++ "b/2022/08/26/other/2020-08-26-Yaml\344\275\277\347\224\250/index.html" @@ -0,0 +1,187 @@ +Yaml的使用 | Research • 呓语 + + + + + + + + + + + + +

Yaml的使用

编写字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#字符串
#单行
username: admin
username1: "周杰\n伦" #双引号不转义
username2: '周杰\n伦' ##单引号转义
#多行
william:



william2: |




william3: >



+

回显的结果是:

+
1
2
3
4
5
6
{ username: 'admin',
username1: '周杰\n伦',
username2: '周杰\\n伦',
william: '一 二 三',
william2: '一\n二\n三\n',
william3: '一 二 三\n' }
+
强制转换
1
2
3
forceStr: !!str 123
forceBoll: !!str true
forceInt: !!int "123"
+

回显的结果是:

+
1
2
3
forceStr: '123',
forceBoll: 'true',
forceInt: 123 }
+
编写数组
1
2
3
4
5
6
#数组
myFavourite:
- backaetball
- football

myFavourite2: ["bass","bahddd"]
+

回显的结果是:

+
1
2
myFavourite: [ 'backaetball', 'football' ],
myFavourite2: [ 'bass', 'bahddd' ],
+
编写对象
1
2
3
4
5
6
7
8
#对象
autotest:
username: root
password: root
age: 18
male: true

autotest2: [{username: admin, password: root, age: 22, male: false}]
+

回显的结果是:

+
1
2
autotest: { username: 'root', password: 'root', age: 18, male: true },
autotest2: [ { username: 'admin', password: 'root', age: 22, male: false } ],
+
编写复合结构的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#复合结构
companies:
-
id: 1
name: zhangsan
value: 10e+11

-
id: 2
name: lisi
value: 10e+12


websites:
baidu: www.baidu.com
google: www.google.com
+

回显的结果是:

+
1
2
3
4
companies: 
[ { id: 1, name: 'zhangsan', value: 1000000000000 },
{ id: 2, name: 'lisi', value: 10000000000000 } ],
websites: { baidu: 'www.baidu.com', google: 'www.google.com' } }
+
引用
1
2
3
4
5
6
7
8
#引用
father: &father_lastName
lastName:

son:
<<: *father_lastName
firstName:
age: 18
+

回显的结果是:

+
1
2
father: { lastName: '周' },
son: { lastName: '周', firstName: '董', age: 18 } }
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/other/2020-08-26-Yaml%E4%BD%BF%E7%94%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/26/other/2022-10-22-\346\200\247\350\203\275\346\265\213\350\257\225\344\270\273\350\246\201\345\205\263\346\263\250\347\202\271/index.html" "b/2022/08/26/other/2022-10-22-\346\200\247\350\203\275\346\265\213\350\257\225\344\270\273\350\246\201\345\205\263\346\263\250\347\202\271/index.html" new file mode 100644 index 000000000..0bacf9d17 --- /dev/null +++ "b/2022/08/26/other/2022-10-22-\346\200\247\350\203\275\346\265\213\350\257\225\344\270\273\350\246\201\345\205\263\346\263\250\347\202\271/index.html" @@ -0,0 +1,182 @@ +性能测试主要关注点 | Research • 呓语 + + + + + + + + + + + + +

性能测试主要关注点

性能关注点

接口响应时间

+

吞吐量

+

TPS: 事务处理能力,每秒处理事务数(打开页面、登录、选择商品、加入购物车、下单、付款)

+

注意:“日活” 每日活跃用户数,是运营数据,与性能无关

+

八二原则

+
+

计算QPS/TPS

+
+

相信80%会集中在20%时间内,24小时的流量集中在白天8小时内,同时在午高峰达到高峰

+

举个栗子

根据相应耗时计算公式预估所需并发,一次请求100ms

+

根据 QPS = Vue * Rt

+

1000000 80% / 8 3600 * 20% = 277 QPS

+

需要27个并发

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/26/other/2022-10-22-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%B8%BB%E8%A6%81%E5%85%B3%E6%B3%A8%E7%82%B9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/30/shell/2022-08-29-shell\350\204\232\346\234\254\345\210\235\346\216\242/index.html" "b/2022/08/30/shell/2022-08-29-shell\350\204\232\346\234\254\345\210\235\346\216\242/index.html" new file mode 100644 index 000000000..def9f8c7a --- /dev/null +++ "b/2022/08/30/shell/2022-08-29-shell\350\204\232\346\234\254\345\210\235\346\216\242/index.html" @@ -0,0 +1,177 @@ +Shell脚本初探 | Research • 呓语 + + + + + + + + + + + + +

Shell脚本初探

编写shell脚本时,必须以 #! /bin/bash 开头

在linux创建helloworld.sh文件,在文件内输入:

+
1
2
3
#!/bin/bash
#################
echo "hello World"
+

然后保存该文件

+

运行.sh文件时,有两种方法可以运行

+
第一种是给该文件添加可执行权限
1
chmod +x ./helloworld.sh
+

运行文件:./ 不能省略

+
1
./helloworld.sh
+
第二种是使用bash或sh 文件路径运行该文件
1
2
3
bash helloworld.sh
#
sh helloworld.sh
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/30/shell/2022-08-29-shell%E8%84%9A%E6%9C%AC%E5%88%9D%E6%8E%A2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/30/shell/2022-08-30-shell\345\217\230\351\207\217/index.html" "b/2022/08/30/shell/2022-08-30-shell\345\217\230\351\207\217/index.html" new file mode 100644 index 000000000..bbdb7f26a --- /dev/null +++ "b/2022/08/30/shell/2022-08-30-shell\345\217\230\351\207\217/index.html" @@ -0,0 +1,194 @@ +Shell变量 | Research • 呓语 + + + + + + + + + + + + +

Shell变量

shell变量分为系统变量和自定义变量,变量默认字符串类型

系统变量

$HOME 获取当前用户的家目录

+

$PWD 获取当前目录的路径

+

$SHELL 获取shell的执行引擎

+

$USER 获取当前用户的名称

+
自定义变量

在linux系统中定义变量A=1,等号两边不能有空格,使用echo $A显示A的值

+

使用unset A命令,撤销变量

+

定义只读变量readonly b=3,使用echo $b显示b的值,不能unset

+

export命令进行设置全局变量,可以让其他shell命令进行使用

+
特殊变量:$n

定义

+

n表示数字,范围是0~9,$0表示脚本名称,$1~9表示1~9个参数,10以上的参数要用花括号包裹,如${10}

+

运行apple.sh文件时可以传递参数

+

举个栗子

+
1
2
3
4
5
6
7
8
#!/bin/bash
#
echo "filename:" $0
echo "filename_1:" $1
echo "filename_2:" $2
echo "filename_3:" $3
echo "filename_4:" $4
echo "filename_5:" $5
+

运行后传递参数bash apple.sh 001 002 test "test sss" "hsgd_dee"

+
特殊变量:$

定义

+

获取所有输入参数的个数,常用于循环

+

举个栗子

+
1
2
3
4
5
6
7
8
#!/bin/bash
#
echo "filename:" $0
echo "filename_1:" $1
echo "filename_2:" $2
echo "filename_3:" $3
#
echo $#
+
特殊变量:$#,$*

定义

+

$*代表命令行中所有参数,把参数作为一个整体

+

$@代表命令行中所有参数,把参数区分对待

+
特殊变量:$?

定义

+

最后一次命令的返回状态,如果返回变量的值为0,则表示最后一次命令执行正确,如果变量的值非0,则证明上一条变量返回不正确

+

举个栗子

+
1
2
3
4
5
6
7
[root@b09ed0cc2c9d opt]# $?
bash: 0: command not found
[root@b09ed0cc2c9d opt]# echo $?
127
[root@b09ed0cc2c9d opt]# echo $?
0
[root@b09ed0cc2c9d opt]#
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/30/shell/2022-08-30-shell%E5%8F%98%E9%87%8F/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/30/shell/2022-08-30-shell\350\204\232\346\234\254\345\205\245\351\227\250/index.html" "b/2022/08/30/shell/2022-08-30-shell\350\204\232\346\234\254\345\205\245\351\227\250/index.html" new file mode 100644 index 000000000..ffd1a082e --- /dev/null +++ "b/2022/08/30/shell/2022-08-30-shell\350\204\232\346\234\254\345\205\245\351\227\250/index.html" @@ -0,0 +1,179 @@ +Shell脚本入门 | Research • 呓语 + + + + + + + + + + + + +

Shell脚本入门

创建txt文件并向txt文件追加数据

首先创建test_shell.sh文件

+
1
touch test_shell.sh
+

test_shell.sh文件输入shell脚本

+
    +
  • 使用shell创建banzhang.txt文件

    +
  • +
  • 在文件中追加数据echo "aabbccdd" >> banzhang.txt

    +
  • +
+
1
2
3
4
5
6
7
#!/bin/bash
# 指定目录
cd /opt/
# 创建文件
touch banzhang.txt
# 向文件追加数据
echo "touch banzhang" >> banzhang.txt
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/30/shell/2022-08-30-shell%E8%84%9A%E6%9C%AC%E5%85%A5%E9%97%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/python/2022-09-01-pyyaml\350\216\267\345\217\226yaml\346\225\260\346\215\256/index.html" "b/2022/08/31/python/2022-09-01-pyyaml\350\216\267\345\217\226yaml\346\225\260\346\215\256/index.html" new file mode 100644 index 000000000..bfbb62231 --- /dev/null +++ "b/2022/08/31/python/2022-09-01-pyyaml\350\216\267\345\217\226yaml\346\225\260\346\215\256/index.html" @@ -0,0 +1,193 @@ +如何使用pyyaml获取yaml里面的数据 | Research • 呓语 + + + + + + + + + + + + +

如何使用pyyaml获取yaml里面的数据

准备数据

在config目录下创建environment.yaml文件

+
1
2
username: 周杰伦
password: 123456
+
使用pyyaml获取yaml中的数据
解析yaml文件

首先创建yaml_config文件,为了方便自动化后面的引用,需要创建一个类,在__init__里面打开yaml文件,使用yaml.load(文件名称, Loader=yaml.FullLoader )方法获取数据

+

打印出字典格式的数据{'username': '周杰伦', 'password': 123456}

+
1
2
3
4
5
6
7
8
9
import yaml
from common.tools import get_project_path, sep


class GetConf:
def __init__(self):
with open(../config.environment.yaml), "r", encoding="utf-8")\
as env_file:
self.env = yaml.load(env_file, Loader=yaml.FullLoader)
+

现在使用的是相对路径,后期如果换系统,或者更换文件位置,就需要自己获得文件路径,下面对代码进行优化

+
优化项:获得项目名称的url地址

创建get_project_path方法,获取项目根目录的绝对路径

+

首先定义一个变量,变量的值是项目的名称project_name = "trading_system_autotest"

+

获取当前文件的所在目录的绝对路径,需要使用python的os模块file_path=os.path.dirname(__file__)

+

在绝对路径中找到项目名称的下标位置file_path.find(project_name)

+

找到项目所在目录的绝对路径下标+项目名称的长度=项目根目录的绝对路径的下标file_path.find(project_name)+len(project_name)

+

然后对所在目录的绝对路径file_path进行切片获得项目根目录的绝对路径

+

file_path[: file_path.find(project_name)+len(project_name)]

+
1
2
3
4
5
6
7
8
9
10
11
12
13
def get_project_path():
"""
获取项目根目录的绝对路径
:return:
"""
project_name = "trading_system_autotest"
# 获取当前文件的所在目录的绝对路径
file_path = os.path.dirname(__file__)
# # 在绝对路径中找到项目名称的下标位置
# print(file_path.find(project_name))
# 找到项目所在目录的绝对路径+项目名称的长度=项目的绝对路径
# print(len(project_name))
return file_path[: file_path.find(project_name)+len(project_name)]
+
优化项:获得拼接后的目录和文件

创建sep(path, add_sep_before=False, add_sep_after=False)方法,获得文件和目录的拼接

+

变量

+

path变量需要传输一个列表,列表里面是文件所在目录和文件名称,如[文件所在目录,文件名称]

+

首先使用os.sep.join对列表的字段进行拼接all_path = os.sep.join(path)

+

add_sep_before进行判断,如果是True,就在前面添加拼接符all_path = os.sep + all_path

+

add_sep_after进行判断,如果是True,就在后面添加拼接符all_path = all_path + os.sep

+

windows格式拼接符有可能错误,就要对拼接符转换格式all_path = all_path.replace('\\', '/'),就算没有这个代码,也可以运行出来,只是调试该代码看起来不好看

+

然后返回all_path

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def sep(path, add_sep_before=False, add_sep_after=False):
"""
:param path: is list format:[Current directory , Current file]
:param add_sep_before: Add before directory "/"
:param add_sep_after: Add after directory "/"
:return: Current directory/Current file
"""
all_path = os.sep.join(path)
# 在前面添加\
if add_sep_before:
all_path = os.sep + all_path
# 在后面添加\
if add_sep_after:
all_path = all_path + os.sep
# 转换格式 把\转换为/
all_path = all_path.replace('\\', '/')
return all_path
+
优化后的代码
1
2
3
4
5
6
7
8
9
class GetConf:
def __init__(self):
with open(get_project_path()+sep(["config", "environment.yaml"], add_sep_before=True), "r", encoding="utf-8")\
as env_file:
self.env = yaml.load(env_file, Loader=yaml.FullLoader)
print(self.env)

def get_username_password(self):
return self.env["username"], self.env["password"]
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/python/2022-09-01-pyyaml%E8%8E%B7%E5%8F%96yaml%E6%95%B0%E6%8D%AE/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-08-31-shell\345\207\275\346\225\260/index.html" "b/2022/08/31/shell/2022-08-31-shell\345\207\275\346\225\260/index.html" new file mode 100644 index 000000000..f46da8b45 --- /dev/null +++ "b/2022/08/31/shell/2022-08-31-shell\345\207\275\346\225\260/index.html" @@ -0,0 +1,180 @@ +Shell函数 | Research • 呓语 + + + + + + + + + + + + +

Shell函数

系统函数
basename基本语法
1
basename [string/ pathname][文件后缀] 
+

basename命令会删掉所有的前缀,只留一个文件名

+

选项:

+

如果指定后缀,basename会将pathname或string中的文件后缀去掉

+
举个栗子

截取该/opt/banzhang.txt路径的文件名称

+
1
2
3
4
5
[root@b09ed0cc2c9d opt]# basename /opt/banzhang.txt
banzhang.txt
[root@b09ed0cc2c9d opt]# basename /opt/banzhang.txt .txt
banzhang
[root@b09ed0cc2c9d opt]#
+
dirname基本语法
1
dirname 文件绝对路径
+

从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录部分)

+
举个栗子
1
2
3
[root@b09ed0cc2c9d opt]# dirname /opt/banzhang.txt
/opt
[root@b09ed0cc2c9d opt]#
+
自定义函数
基本语法
1
2
3
4
5
6
7
[function] funname[()]
{
Action;
[retion int;]
}

funname
+
举个栗子
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash

function sum()
{
s=0;
s=$[$1+$2]
echo $s
}

read -p "input your paratemer1:" p1
read -p "input your oaeayemer2:" p2

sum $p1 $p2
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-08-31-shell%E5%87%BD%E6%95%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-08-31-shell\345\267\245\345\205\267\357\274\210\344\270\200\357\274\211/index.html" "b/2022/08/31/shell/2022-08-31-shell\345\267\245\345\205\267\357\274\210\344\270\200\357\274\211/index.html" new file mode 100644 index 000000000..589e2c335 --- /dev/null +++ "b/2022/08/31/shell/2022-08-31-shell\345\267\245\345\205\267\357\274\210\344\270\200\357\274\211/index.html" @@ -0,0 +1,264 @@ +Shell工具(一) | Research • 呓语 + + + + + + + + + + + + +

Shell工具(一)

Cut工具
+

用于剪切数据

+
+
基本用法

cut[选项参数] filename

+

说明:默认分隔符是制表符

+
+ + + + + + + + + + + + + + + + + +
选项参数功能
-f列号,提取第几列
-d分隔符,按照指定分隔符分割列
+
+
举个栗子

准备数据

+
1
2
3
4
5
6
7
8
[root@b09ed0cc2c9d local]# touch cut.txt
[root@b09ed0cc2c9d local]# vim cut.txt

dong shen
guan zhen
wo wo
lai lai
le le
+

切割第一列数据

+
1
2
3
4
5
6
[root@b09ed0cc2c9d local]# cut -d " " -f 1 cut.txt
dong
guan
wo
lai
le
+

切割第二,三列

+
1
2
3
4
5
6
[root@b09ed0cc2c9d local]# cut -d " " -f 2,3 cut.txt
shen
zhen
wo
lai
le
+

在cut.txt文件切割出guan

+
1
2
3
4
5
6
7
8
9
10
11
12
[root@b09ed0cc2c9d local]# cat cut.txt
dong shen
guan zhen
wo wo
lai lai
le le
[root@b09ed0cc2c9d local]#
[root@b09ed0cc2c9d local]# cat cut.txt | grep guan
guan zhen
[root@b09ed0cc2c9d local]# cat cut.txt | grep guan | cut -d " " -f 1
guan
[root@b09ed0cc2c9d local]#
+

选取系统PATH变量值,第二个“:”之后的所有路径

+
1
2
3
4
[root@b09ed0cc2c9d local]# echo $PATH
/usr/local/java/jdk1.8.0_181/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
[root@b09ed0cc2c9d local]# echo $PATH | cut -d : -f 3- # 不加-表示第三列,加上-表示第三列之后
/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
+

切割ifconfig后打印的IP地址

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@b09ed0cc2c9d local]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0
inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link>
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 8 bytes 656 (656.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 8 bytes 656 (656.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
inet6 ::1 prefixlen 128 scopeid 0x10<host>
loop txqueuelen 1000 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

[root@b09ed0cc2c9d local]# ifconfig eth0 | grep "inet " | cut -d "t" -f 2 | cut -d " " -f 2
172.17.0.2
[root@b09ed0cc2c9d local]#
+
sed工具
+

一种流编辑器,一次处理一行内容

+
+
基本用法

sed [选项参数] command filename

+

选项参数说明

+
+ + + + + + + + + + + + + +
选项参数功能
-a直接在指定列模式上进行sed的动作编辑
+
+

命令功能描述

+
+ + + + + + + + + + + + + + + + + + + + + +
命令功能描述
a新增,a的后面可以接字串,在下一行出现
d删除
s查找并替换
+
+
举个栗子

数据准备

+
1
2
3
4
5
6
7
8
9
[root@b09ed0cc2c9d opt]# touch sed.txt
[root@b09ed0cc2c9d opt]# vim sed.txt

dong shen
guan zhen
wo wo
lai lai

le le
+

将mei nv 这个单词插入到 sed.txt 第二行下,打印

+
1
2
3
4
5
6
7
8
9
[root@b09ed0cc2c9d opt]# sed "2a mei nv" sed.txt
dong shen
guan zhen
mei nv
wo wo
lai lai

le le
[root@b09ed0cc2c9d opt]#
+

删除sed.txt文件所有包含 wo 的行

+
1
2
3
4
5
6
7
[root@b09ed0cc2c9d opt]# sed "/wo/d" sed.txt
dong shen
guan zhen
lai lai

le le
[root@b09ed0cc2c9d opt]#
+

将sed.txt文件中 wo 替换为 ni

+
1
2
3
4
5
6
7
8
[root@b09ed0cc2c9d opt]# sed "s/wo/ni/g" sed.txt
dong shen
guan zhen
ni ni
lai lai

le le
[root@b09ed0cc2c9d opt]#
+注意:g表示global,全部替换 + +

将sed.txt文件中的第二行删除并将wo替换成ni

+
1
2
3
4
5
6
7
[root@b09ed0cc2c9d opt]# sed -e "2d" -e "s/wo/ni/g" sed.txt
dong shen
ni ni
lai lai

le le
[root@b09ed0cc2c9d opt]#
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-08-31-shell%E5%B7%A5%E5%85%B7%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-08-31-shell\346\235\241\344\273\266\345\210\244\346\226\255/index.html" "b/2022/08/31/shell/2022-08-31-shell\346\235\241\344\273\266\345\210\244\346\226\255/index.html" new file mode 100644 index 000000000..55a8fb6ba --- /dev/null +++ "b/2022/08/31/shell/2022-08-31-shell\346\235\241\344\273\266\345\210\244\346\226\255/index.html" @@ -0,0 +1,182 @@ +Shell条件判断 | Research • 呓语 + + + + + + + + + + + + +

Shell条件判断

基本语法

[ condition ] (注意,condition 前后要有空格

+

注意:条件非空即为 true,[ atguigu ]返回 true, [] 返回 false.

+
常用条件判断
两个整数之间进行比较
1
2
3
4
5
6
7
= 字符串比较
-lt 小于
-le 小于等于
-eq 等于
-gt 大于
-ge 大于等于
-ne 不等于
+

举个栗子

+
1
2
[23 -lt 80]
echo $? # 判断上一步操作是不是正确
+
按照文件权限进行判断
1
2
3
-r 读
-w 写
-x 执行
+

举个栗子

+
1
2
[ -w 1.sh ]
echo $?
+
文件类型判断
1
2
3
-f 文件存在且是一个常规文件
-e 文件存在
-d 文件存在且是一个目录
+

举个栗子

+
1
2
[ -e 2.sh ]
echo $?
+
多条件判断

$$$$ 与 ,前对,才执行后

+

||

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-08-31-shell%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-08-31-shell\346\265\201\347\250\213\346\216\247\345\210\266/index.html" "b/2022/08/31/shell/2022-08-31-shell\346\265\201\347\250\213\346\216\247\345\210\266/index.html" new file mode 100644 index 000000000..950c27609 --- /dev/null +++ "b/2022/08/31/shell/2022-08-31-shell\346\265\201\347\250\213\346\216\247\345\210\266/index.html" @@ -0,0 +1,198 @@ +Shell流程控制 | Research • 呓语 + + + + + + + + + + + + +

Shell流程控制

if判断
基本语法
    +
  • [ 条件判断式 ],中括号和条件判断式之间必须有空格

    +
  • +
  • if后要有空格

    +
  • +
+
1
2
3
4
5
6
7
8
if [ 条件判断式 ]:then
程序
fi
#或者
if[ 条件判断式 ]
then
程序
fi
+
举个栗子

输入一个数字,如果是1,则输出 banzhang zhen shuai,如果是2,则输出 cls zhen mei ,如果是其他,则什么都不输出

+
1
2
3
4
5
6
7
8
#!/bin/bash
if [ $1 -eq 1 ]
then
echo "banzhang zhen shuai"
elif [ $1 -eq 2 ]
then
echo "cls zhen mei"
fi
+
case 语句
基本语法
    +
  • case行尾必须是单词 “in”,每一个模式匹配必须以右括号 “)” 结束
  • +
  • 双分号 “;;” 表示命令序列结束,相当于java的break
  • +
  • 最后的 “*)” 表示默认模式,相当于java的default
  • +
+
1
2
3
4
5
6
7
8
9
10
case $变量名 in  
"值 1")
如果变量的值等于1,执行程序1
;;
"值 2")
如果变量的值等于2,执行程序2
;;
*)
如果变量的值不是以上的值,则执行此程序
esac
+
举个栗子

输入一个数字,如果是 1,则输出 banzhang,如果是 2,则输出 cls,如果是其他,输出 renyao

+
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
case $1 in
"1")
echo "banzhang"
;;

"2")
echo "cls"
;;

*)
echo "renyou"
esac
+
For循环
基本语法1
1
2
3
4
for(( 初始值;循环控制添加;变量变化 ))
do
程序
done
+
举个栗子1

输出从1加到100的值

+
1
2
3
4
5
6
7
8
#!/bin/bash

s=0
for ((i=1;i<=100;i++))
do
s=$[$s+$i]
done
echo "cong1jiadao100:$s"
+
基本语法2
1
2
3
4
for 变量 in 值1 值2 值3...
do
程序
done
+
举个栗子2

打印所有输入参数

+
1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

for i in "$*"
do
echo "banzhang xihuan $i"
done
#-----------------------------------
for j in "$@"
do
echo "banzhang xihuan $j"
done
+
while 循环
基本语法
1
2
3
4
while[ 条件判断式 ]
do
程序
done
+
举个栗子

输出从1加到100的值

+
1
2
3
4
5
6
7
8
9
10
#!/bin/bash

i=1
while [ $i -le 100 ]
do
s=$[$s + $i]
i=$[$i + 1]
done

echo $s
+
read 读取控制台输入
基本语法
1
2
3
4
5
6
read(选项)(参数)
选项:
-p:指定读取值时的提示符
-t:指定读取值时的等待的时间(秒)
参数:
变量:指定读取值的变量名
+
举个栗子

提示7秒内,读取控制台输入的名称

+
1
2
3
4
5
#!/bin/bash

read -t 7 -p "input your name" NAME

echo $NAME
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-08-31-shell%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-08-31-shell\350\277\220\347\256\227\347\254\246/index.html" "b/2022/08/31/shell/2022-08-31-shell\350\277\220\347\256\227\347\254\246/index.html" new file mode 100644 index 000000000..46a02ac10 --- /dev/null +++ "b/2022/08/31/shell/2022-08-31-shell\350\277\220\347\256\227\347\254\246/index.html" @@ -0,0 +1,180 @@ +Shell运算符 | Research • 呓语 + + + + + + + + + + + + +

Shell运算符

基本语法
    +
  1. $((运算式)) 或 $[运算式]
  2. +
  3. expr + - * /
  4. +
+注意,运算符号间要有空格 + +
举个加法栗子
1
2
expr 3 + 2
5
+
举栗子[(2+3)*4]

需要使用键盘左上角的`,把需要提前运算的包起来

+
1
expr `expr 2 + 3` \* 4
+

或者

+
1
2
s=$[(2+3)*4]
echo $s
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-08-31-shell%E8%BF%90%E7%AE%97%E7%AC%A6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/08/31/shell/2022-09-01-shell\345\267\245\345\205\267\357\274\210\344\272\214\357\274\211/index.html" "b/2022/08/31/shell/2022-09-01-shell\345\267\245\345\205\267\357\274\210\344\272\214\357\274\211/index.html" new file mode 100644 index 000000000..4930c1a5a --- /dev/null +++ "b/2022/08/31/shell/2022-09-01-shell\345\267\245\345\205\267\357\274\210\344\272\214\357\274\211/index.html" @@ -0,0 +1,272 @@ +Shell工具(二) | Research • 呓语 + + + + + + + + + + + + +

Shell工具(二)

awk工具
+

强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

+
+

awk [选项参数] ‘pattern1{action1}’ filename

+
    +
  • pattern:表示awk在数据中查找的内容
  • +
  • action:找到匹配内容时执行命令
  • +
+
+ + + + + + + + + + + + + + + + + +
选项参数功能
-F指定输入文件分隔符
-v赋值一个用户定义变量
+
+
举个栗子

数据准备的是/etc/passwd

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@b09ed0cc2c9d opt]# cat passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
+

搜素passwd文件以root关键字开头的所有航,并输出该行的第7列

+
1
2
3
[root@b09ed0cc2c9d opt]# awk -F : '/^root/{print $7}' passwd
/bin/bash
[root@b09ed0cc2c9d opt]#
+

搜素passwd文件以root关键字开头的所有航,并输出该行的第1列和第7列,输出时以逗号分隔

+
1
2
[root@b09ed0cc2c9d opt]# awk -F : '/^root/{print $1","$7}' passwd
root,/bin/bash
+

只显示/etc/passwd的第一列和第7列,以逗号分隔,且在所有航前面添加列名 user,shell在最后一行添加 ddd, /bin/zuishuai

+
1
[root@b09ed0cc2c9d opt]# awk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "ddd,bin/zuishuai"}' passwd
+注意:BEGIN 在所有数据读取行之前执行; END 在所有数据执行之后执行 + +

将passwd 文件中的用户id增加数值1并输出

+
1
[root@b09ed0cc2c9d opt]# awk -F : -v i=1 '{print $3+i}' passwd
+
内置变量
+ + + + + + + + + + + + + + + + + + + + + +
变量说明
filename文件名
nr已读的记录数
nf浏览记录的域的个数
+
+
举个栗子

数据准备

+
1
2
3
4
5
6
7
[root@b09ed0cc2c9d opt]# cat sed.txt
dong shen
guan zhen
wo wo
lai lai

le le
+

统计passwd文件名,每行的行号,每列的列数

+
1
[root@b09ed0cc2c9d opt]# awk -F : '{print FILENAME "," NR "," NF}' passwd
+

打印空行所在的行号

+
1
awk '/^$/ {print NR}' sed.txt
+
sort工具
+

文件排序

+
+

sort(选项)(参数)

+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
选项说明
-n按照数值大小排序
-r以相反的顺序排序
-t设置排序使用的分隔字符
-k指定需要排序的列
+
+

参数是指定待排序文件列表

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/08/31/shell/2022-09-01-shell%E5%B7%A5%E5%85%B7%EF%BC%88%E4%BA%8C%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/02/other/2022-09-02-\344\275\277\347\224\250postman\345\246\202\344\275\225\345\201\232\346\216\245\345\217\243\346\265\213\350\257\225/index.html" "b/2022/09/02/other/2022-09-02-\344\275\277\347\224\250postman\345\246\202\344\275\225\345\201\232\346\216\245\345\217\243\346\265\213\350\257\225/index.html" new file mode 100644 index 000000000..d0bb7f4e7 --- /dev/null +++ "b/2022/09/02/other/2022-09-02-\344\275\277\347\224\250postman\345\246\202\344\275\225\345\201\232\346\216\245\345\217\243\346\265\213\350\257\225/index.html" @@ -0,0 +1,245 @@ +使用Postman如何做接口测试 | Research • 呓语 + + + + + + + + + + + + +

使用Postman如何做接口测试

Postman安装

+

Postman下载:https://www.postman.com/downloads/

+
+

image
下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

+

postman主要功能说明

postman主要模块功能介绍

image
点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
image
image
image
image
创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
image
image

+

发送http请求和分析响应数据

+

在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
请求的方法:get或post
请求的URL:协议+域名/IP+端口+资源路径

+
+

不带参数的请求:
image
发送需要认证的get接口:
image

+

------------恢复内容开始------------

## Postman安装

+
+

Postman下载:https://www.postman.com/downloads/

+
+

image
下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

+

postman主要功能说明

1、postman主要模块功能介绍

image
点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
image
image
image
image
创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
image
image

+

发送http请求和分析响应数据

+

在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
请求的方法:get或post
请求的URL:协议+域名/IP+端口+资源路径

+
+

get请求

不带参数的请求:
image
发送需要认证的get接口:
image

+

post请求

选择请求格式为post
传参:

+
    +
  • Body中raw:支持任意格式的数据编辑,选json(也可xml或html传参)
  • +
  • Body中Form-data:以表单的方式进行数据编辑
  • +
  • Body中x-www-form-urlencoded:与form-data类似,也是以表单的方式进行数据编辑,但是表单中的每一条数据只能是键值对.
  • +
  • Body中Binary:用来上传文件.并且由于没有键值,因此一次只能上传一个文件.
  • +
+

Pre-request Scrip

image

+

Tests

image

+

postman保存测试用例

image

+

postman批量运行

image
image

+

选择文件进行参数化

json文件

image

+

txt文件

image
使用参数时,变量名称要与文件里的变量名保持一致

+

postman环境管理

image
image
引用环境信息:

+

postman全局变量

image
也可以用javascript写变量:
image
引用全局变量信息:
image
image
Cookie用途:一个请求需要用到用户的登录状态(sessionid或token),一般 登录状态会记录在cookie ,postman会自动记录登录状态写入cookies.所以执行非登录接口的请求前,需要先执行登录接口请求。
image

+

关联

------------恢复内容结束------------

+

------------恢复内容开始------------

## Postman安装

+
+

Postman下载:https://www.postman.com/downloads/

+
+

image
下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

+

postman主要功能说明

1、postman主要模块功能介绍

image
点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
image
image
image
image
创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
image
image

+

发送http请求和分析响应数据

+

在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
请求的方法:get或post
请求的URL:协议+域名/IP+端口+资源路径

+
+

get请求

不带参数的请求:
image
发送需要认证的get接口:
image

+

post请求

选择请求格式为post
传参:

+
    +
  • Body中raw:支持任意格式的数据编辑,选json(也可xml或html传参)
  • +
  • Body中Form-data:以表单的方式进行数据编辑
  • +
  • Body中x-www-form-urlencoded:与form-data类似,也是以表单的方式进行数据编辑,但是表单中的每一条数据只能是键值对.
  • +
  • Body中Binary:用来上传文件.并且由于没有键值,因此一次只能上传一个文件.
  • +
+

Pre-request Scrip

image

+

Tests

image

+

postman保存测试用例

image

+

postman批量运行

image
image

+

选择文件进行参数化

json文件

image

+

txt文件

image
使用参数时,变量名称要与文件里的变量名保持一致

+

postman环境管理

image
image
引用环境信息:

+

postman全局变量

image
也可以用javascript写变量:
image
引用全局变量信息:
image
image
Cookie用途:一个请求需要用到用户的登录状态(sessionid或token),一般 登录状态会记录在cookie ,postman会自动记录登录状态写入cookies.所以执行非登录接口的请求前,需要先执行登录接口请求。
image

+

关联

断言

Postman通过tests插入断言
image

+

关联

+

把上一个接口的返回数据作为下一个参数的输入参数使用

+
+
    +
  • 先发送一个接口,查看返回值
  • +
  • 在上一个接口的tests里面添加js脚本
      +
    • 获取上一个接口返回值并赋值给变量
    • +
    • 定义全局变量,并获取要作为下一个接口输入的数据字段
    • +
    +
  • +
  • 引用全局变量
  • +
+

生成并导出接口脚本

导出接口测试脚本

image

+

导出测试集

image
image

+

导入测试集

image

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/02/other/2022-09-02-%E4%BD%BF%E7%94%A8postman%E5%A6%82%E4%BD%95%E5%81%9A%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/02/python/2022-09-02-\350\247\243\346\236\220Excel\347\224\250\344\272\216\346\225\260\346\215\256\351\251\261\345\212\250/index.html" "b/2022/09/02/python/2022-09-02-\350\247\243\346\236\220Excel\347\224\250\344\272\216\346\225\260\346\215\256\351\251\261\345\212\250/index.html" new file mode 100644 index 000000000..f6a9549a1 --- /dev/null +++ "b/2022/09/02/python/2022-09-02-\350\247\243\346\236\220Excel\347\224\250\344\272\216\346\225\260\346\215\256\351\251\261\345\212\250/index.html" @@ -0,0 +1,193 @@ +解析Excel用于数据驱动 | Research • 呓语 + + + + + + + + + + + + +

解析Excel用于数据驱动

新建Excel

+

创建Excel数据表:learn.xlsx

+
+
+ +
+ +

解析excel

+

使用python的openpyxl模块来解析Excel

+

1、读取Excel文件

openpyxl.load_workbook(‘文件路径’)

1
excel = openpyxl.load_workbook('learn.xlsx')

+

2、获取sheet页里面的数据

1
2
3
4
5
6
# 获取当前活动的表单
sheet = excel.active
# 获取指定的表单
for sheets in excel.sheetnames: #获取所有表单的名称
print(sheets)
sheet = excel[sheets] #获取指定表单
+

3、获取单元格里面的内容

1
2
3
for values in sheet.values:
if type(value[0]) == int: #从第二行开始
print(values)
+

运行代码:

+
+
+ +
+ +

把Excel表里面的数据以字典格式展示:

+
1
2
3
4
data = {}
data["name"] = values[0]
data["value"] = values[1]
print(data)
+

运行代码:

+
+ +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/02/python/2022-09-02-%E8%A7%A3%E6%9E%90Excel%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/02/python/2022-09-21-python\350\247\243\346\236\220ini\346\226\207\344\273\266/index.html" "b/2022/09/02/python/2022-09-21-python\350\247\243\346\236\220ini\346\226\207\344\273\266/index.html" new file mode 100644 index 000000000..fd0851537 --- /dev/null +++ "b/2022/09/02/python/2022-09-21-python\350\247\243\346\236\220ini\346\226\207\344\273\266/index.html" @@ -0,0 +1,221 @@ +解析ini文件用于数据驱动 | Research • 呓语 + + + + + + + + + + + + +

解析ini文件用于数据驱动

背景

    +
  • PO设计模式是selenum自动化测试中比较好的设计模式
  • +
  • 在项目的开发过程中,UI界面上的元素不确定,会经常变化
  • +
+

过程解析

    +
  • 在PyCharm创建ini文件
  • +
  • 创建一个可以解析ini文件的python模块(parse_ini)
  • +
  • 其他模块引用parse_ini文件里面的方法把ini文件解析出来
  • +
+

创建ini文件

image

+

创建parse_ini模块

import configparser
+
+class Parse_Ini(object):
+
+    def __init__(self):
+        self.file = r"D:\dingdang_project\test\config.ini"
+        self.parse = configparser.ConfigParser()
+        self.parse.read(self.file, encoding="utf-8")
+
+    def get_sections(self):
+        """
+        :return: 由sections组成的列表
+        """
+        return self.parse.sections()
+
+    def get_options(self, sections):
+        """
+        :return: 返回指定 section 中可用选项的列表。
+        """
+        return self.parse.options(sections)
+
+    def get_sections_options(self, sections, options):
+        """
+        :param sections: 元素名称
+        :param options: 元素地址
+        :return: 指定sections下的options
+        """
+        try:
+            option = self.parse.get(sections, options)
+            if ("-->" in option):
+                option = tuple(option.split("-->"))
+                return option
+        except configparser.NoOptionError as e:
+            return 'error: No option "{}" in section: "{}"'.format(options, sections)
+
+
+if __name__ == "__init__":
+    pass
+

举个栗子:

栗子1

image

+
运行结果:

image

+
栗子2

image

+
运行结果:

image

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/02/python/2022-09-21-python%E8%A7%A3%E6%9E%90ini%E6%96%87%E4%BB%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/05/other/\350\207\252\345\212\250\345\214\226\345\237\272\347\241\200\344\271\213Xpath\345\256\232\344\275\215/index.html" "b/2022/09/05/other/\350\207\252\345\212\250\345\214\226\345\237\272\347\241\200\344\271\213Xpath\345\256\232\344\275\215/index.html" new file mode 100644 index 000000000..81f8b88b4 --- /dev/null +++ "b/2022/09/05/other/\350\207\252\345\212\250\345\214\226\345\237\272\347\241\200\344\271\213Xpath\345\256\232\344\275\215/index.html" @@ -0,0 +1,237 @@ +自动化基础之Xpath定位 | Research • 呓语 + + + + + + + + + + + + +

自动化基础之Xpath定位

常用函数定位
+ + + + + + + + + + + + + + + + + +
定位函数position
//*contains(text(),’文字’)/li[position()=3]找到第三个 li
//*contains(text(),’文字’)/li[position()<=2]找到前两个 li
+
+
Xpath函数进行定位
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
定位方式描述实例
contains匹配在元素文本中查找包含 ‘文字’ 的元素//*contains(text(),’文字’)
starts-with匹配所有id开头为 ‘s’ 的元素//*[starts-with(@id,’s’)]
ends-with匹配所有id结尾头为 ‘s’ 的元素//*[ends-with(@id,”s”)]
following-sibling匹配和 ‘ul’ 元素同级别的下一个元素//div/following-sibling::ul
preceding-sibling匹配当前节点之前的所有同级节点
ancestor匹配当前节点的所有父级,祖父级还有更高级//div/ancestor::li[@role=”menuitem”]
parent匹配当前节点的父节点,相当于 ..//div/parent::button
+
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/05/other/%E8%87%AA%E5%8A%A8%E5%8C%96%E5%9F%BA%E7%A1%80%E4%B9%8BXpath%E5%AE%9A%E4%BD%8D/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/21/java/2022-09-21-\344\275\277\347\224\250Java\350\247\243\346\236\220Properties\346\226\207\344\273\266/index.html" "b/2022/09/21/java/2022-09-21-\344\275\277\347\224\250Java\350\247\243\346\236\220Properties\346\226\207\344\273\266/index.html" new file mode 100644 index 000000000..98342f241 --- /dev/null +++ "b/2022/09/21/java/2022-09-21-\344\275\277\347\224\250Java\350\247\243\346\236\220Properties\346\226\207\344\273\266/index.html" @@ -0,0 +1,204 @@ +使用Java解析Properties文件 | Research • 呓语 + + + + + + + + + + + + + +

使用Java解析Properties文件

主要函数

+ + + + + + + + + + + + + + + + + + + + + + + + + +
文件后缀函数方法
.Propertiesload加载文件
setProperty设置
getProperty获取
+
+

编写逻辑

创建加载文件的方法

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 加载文件
* @return Properties 对象
* @throws IOException I/O输入异常
*/
private Properties readProperties() throws IOException{
// 实例化,创建 Properties 对象
Properties properties = new Properties();
try {
// 创建文件输入对象 FileInputStream("testpro.properties")
InputStream inputStream = new FileInputStream(filepath);
// 把文件输入对象放入缓存输入对象 new BufferedInputStream 里面
BufferedInputStream in = new BufferedInputStream(inputStream);
// 加载文件 in = ParseProperties.class.getResourceAsStream("testpro.properties"),自动获取 resources 文件夹下路径
properties.load(in);
}catch (IOException e){
e.printStackTrace();
}
return properties;
}
+

获取key后面的数据

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 获取数据
* @param key 数据名称
* @return 数据等号右边的值
* @throws Exception 异常
*/
public String getPro(String key) throws Exception {
// 判断文件里面有没有这个 Key
if (prop.containsKey(key)) {
// 获得key后面的value值
return prop.getProperty(key);
}else {
System.out.println("你获取的key值不对");
return "";
}
}
+

获取定位类型或者定位表达式

+
1
2
3
4
5
6
7
8
9
/**
* 返回定位类型或者定位表达式
* @param key 数据名称
* @param num 输入0/1
* @return num=0时,返回定位类型,num=1时,返回定位表达式
*/
public String get_pro_element(String key, int num){
return (num!=0 & num!=1) ? "num:参数输入错误" : prop.getProperty(key).split("->")[num];
}
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/21/java/2022-09-21-%E4%BD%BF%E7%94%A8Java%E8%A7%A3%E6%9E%90Properties%E6%96%87%E4%BB%B6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/21/java/2022-12-06-\346\226\271\346\263\225\345\222\214\345\207\275\346\225\260/index.html" "b/2022/09/21/java/2022-12-06-\346\226\271\346\263\225\345\222\214\345\207\275\346\225\260/index.html" new file mode 100644 index 000000000..1148bd55a --- /dev/null +++ "b/2022/09/21/java/2022-12-06-\346\226\271\346\263\225\345\222\214\345\207\275\346\225\260/index.html" @@ -0,0 +1,229 @@ +java基础之方法和函数 | Research • 呓语 + + + + + + + + + + + + +

java基础之方法和函数

方法和函数

+ + + + + + + + + + + + + + + + + + + + + + + +
定义方式作用调用方式
函数public static void 函数名(){}封装指定功能的代码块函数名()
方法public [static] void 方法名(){}类的行为,对象可以执行的一些功能对象名.方法名
+
+

定义函数

+

使用static修饰的内容成为静态的内容

+
+
1
2
public static void function1(){
}
+

调用函数

1
function1()
+

定义方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void class className1{

String name;
//静态变量
static String age;

//静态方法
public static function1(){
}

//类方法
//非静态方法可以调用静态变量和非静态变量、静态方法和非静态方法
public function2(){
}
}
+

调用方法

    +
  • 调用静态方法,不需要实例化
  • +
+
1
className1.function1()
+
    +
  • 调用方法
  • +
+
1
className1的对象,需要实例化
+

静态方法注意事项:

    +
  • 静态方法无法直接引用非静态的变量
  • +
  • 静态方法不能直接调用非静态的方法
  • +
+

代码块

    +
  • 定义在方法内部,和局部变量处于平行的位置
  • +
  • 生命周期随着方法的调用而加载,随着方法的结束而消亡
  • +
  • 可以在局部代码块中定义一些使用范围和时间都很短的变量,用完就消失啦
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public void class className1{

String name;
static String age;

//类方法
//非静态方法可以调用静态变量和非静态变量、静态方法和非静态方法
public void function2(){

//定义代码块
{
int i = 100;
System.out.println("方法中的变量i=" + i);
}

}
}
+

构造代码块

    +
  • 构造代码快写在和构造方法平行的位置
  • +
  • 只要创建对象,构造代码块就会执行,不论是采用有参的还是无参数的构造方法
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void class{
//有参构造
class(String name){
}
//无参构造
class(){
}
//构造代码块
{
int i=100;
System.out.println("构造代码块i=" + i);
}

}
+

静态代码块

    +
  • 被static修饰的代码块称为静态代码块
  • +
  • 随着类的加载而加载
  • +
  • 静态代码块只执行一次,在程序中可以完成加载驱动等只执行一次的操作
  • +
+
1
2
3
4
5
public void className1{
static{
System.out.println("我是静态代码块i=" + i);
}
}
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/21/java/2022-12-06-%E6%96%B9%E6%B3%95%E5%92%8C%E5%87%BD%E6%95%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/09/26/error/2022-09-26-git\346\217\220\347\244\272Timed_out\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" "b/2022/09/26/error/2022-09-26-git\346\217\220\347\244\272Timed_out\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" new file mode 100644 index 000000000..714495d96 --- /dev/null +++ "b/2022/09/26/error/2022-09-26-git\346\217\220\347\244\272Timed_out\347\232\204\350\247\243\345\206\263\345\212\236\346\263\225/index.html" @@ -0,0 +1,176 @@ +git提示Timed out的解决办法 | Research • 呓语 + + + + + + + + + + + + +

git提示Timed out的解决办法

报错代码

运行git代码会提示Timed out错误

+
1
使用git,会发生报错:Failed to connect to github.com port 443 after 21098 ms: Timed out
+

解决办法

设置代理

+
1
git config --global https.proxy
+

取消代理

+
1
git config --global --unset https.proxy
+

然后输入git 命令使用

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/09/26/error/2022-09-26-git%E6%8F%90%E7%A4%BATimed_out%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/20/project/2022-10-20-\344\275\277\347\224\250ubuntu\345\256\271\345\231\250\345\256\211\350\243\205code-server/index.html" "b/2022/10/20/project/2022-10-20-\344\275\277\347\224\250ubuntu\345\256\271\345\231\250\345\256\211\350\243\205code-server/index.html" new file mode 100644 index 000000000..be7c5ba7f --- /dev/null +++ "b/2022/10/20/project/2022-10-20-\344\275\277\347\224\250ubuntu\345\256\271\345\231\250\345\256\211\350\243\205code-server/index.html" @@ -0,0 +1,194 @@ +使用docker的ubuntu容器安装code-server | Research • 呓语 + + + + + + + + + + + + +

使用docker的ubuntu容器安装code-server

搭建code-server

拉取Ubuntu 镜像

1
2
3
4
# 拉取镜像
docker pull aliyun
# 进入镜像
docker run --name [自定义名称] -u root --privileged=true -p 3300:8881 -v /opt/testubuntu/:/opt/main_file -it [镜像id]
+

安装code-server

github上下载安装包,解压后剪切到/home目录

+

运行code-server

1
2
3
4
# 找到bin目录下的code-server*
cd /home/code-server/bin
# 输入运行命令
export PASSWORD="123456" && ./code-server --host 0.0.0.0 --port 8881
+

然后在浏览器输入http://ip:3000查看搭建情况

+

但是这样搭建有问题

+
+

使用上面方法部署的code-server,因为是http的,导致一些功能不好用,比如写md文档无法预览

+
+

下面就是配置使用https运行

+

配置HTTPS

+

使用openssl为IP签发证书

+
+

安装openssl

一般的linux系统已经内置openssl,可以输入openssl进行查看,没有的话就需要安装

+

创建证书请求文件

新建openssl.cnf,并编辑如下内容

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[req_distinguished_name]
countryName = Country Name (2 letter code)
countryName_default = CH
stateOrProvinceName = State or Province Name (full name)
stateOrProvinceName_default = ZJ
localityName = Locality Name (eg, city)
localityName_default = HangZhou
organizationalUnitName = Organizational Unit Name (eg, section)
organizationalUnitName_default = THS
commonName = Internet Widgits Ltd
commonName_max = 64

[ v3_req ]
# Extensions to add to a certificate request
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]

# 改成自己的域名
# DNS.1 = your_domain_name.com

# 改成自己的ip
IP.1 = 8.142.144.75
IP.2 = 0.0.0.0
+

生成私钥

san_domain_com 为最终生成的文件名,一般以服务器命名,可改。

+
1
openssl genrsa -out san_domain_com.key 2048
+

生成CSR文件

1
openssl req -new -out san_domain_com.csr -key san_domain_com.key -config openssl.cnf
+

执行后,系统提示输入组织等信息,按[]内容提示输入如即可。

+

需要测试CSR文件是否生成成功

1
> openssl req -text -noout -in san_domain_com.csr

有下面的信息,说明生成成功

+
1
2
3
4
5
6
7
8
Certificate Request:
Data:
Version: 0 (0x0)
Subject: C=US, ST=MN, L=Minneapolis, OU=Domain Control Validated, CN=zz
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
//...
+

自签名并生成证书

1
openssl x509 -req -days 3650 -in san_domain_com.csr -signkey san_domain_com.key -out san_domain_com.crt -extensions v3_req -extfile openssl.cnf
+

在当前目录会生成三个文件

1
2
3
4
5
san_domain_com.crt

san_domain_com.csr

san_domain_com.key

+

在用户电脑安装证书

.crt证书发给用户,用户双击进行安装,然后重启浏览器

+

code server启动

在code-server的bin目录下运行如下命令,设置端口号为8881,指定对应生成的crt和key密钥文件,即可正常访问https域名

1
2
3
4
# 给ssh创建密码
export PASSWORD="123456"
# 启动ssh
nohup ./code-server --port 8881 --host 0.0.0.0 --cert ../san_domain_com.crt --cert-key ../san_domain_com.key > vscode.log 2>&1 &

然后通过浏览器访问https://ip:3000

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/20/project/2022-10-20-%E4%BD%BF%E7%94%A8ubuntu%E5%AE%B9%E5%99%A8%E5%AE%89%E8%A3%85code-server/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/20/project/2022-11-24-\346\220\255\345\273\272\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" "b/2022/10/20/project/2022-11-24-\346\220\255\345\273\272\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" new file mode 100644 index 000000000..1ee096475 --- /dev/null +++ "b/2022/10/20/project/2022-11-24-\346\220\255\345\273\272\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" @@ -0,0 +1,468 @@ +性能监控平台 | Research • 呓语 + + + + + + + + + + + + +

性能监控平台

搭建容器

+

拉取CentOS7镜像,下载安装Grafana和Influxdb

+
+

+        # 拉取阿里云的centos7镜像
+        git pull registry.cn-zhangjiakou.aliyuncs.com/ggls/centos:7.1
+        # 运行镜像生成容器
+        docker run -itd --name centos7-influx 
+        -p 8083:8083 -p 8086:8086 
+        -p 2003:2003 -p 3000:3000 
+        -v /opt/centos7_influx:/opt 
+        --privileged=true 
+        registry.cn-zhangjiakou.aliyuncs.com/ggls/centos:7.1 /usr/sbin/init
+        # 进入容器
+        docker exec -it centos7-influx bash
+    
+

端口说明:

+
    +
  • 8083:InfluxDB的UI界面展示的端口
  • +
  • 8086:Grafana用来从数据库取数据的端口
  • +
  • 2003:Jmeter往数据库发数据的端口
  • +
  • 3000:本地访问服务器内部docker容器的端口
  • +
+

安装Influxdb

    +
  1. 下载influxDB
  2. +
+

新版本可以点击influxDB官网进行下载

+ + # 下载安装包 + wget https://dl.influxdata.com/influxdb/releases/influxdb-1.6.3.x86_64.rpm + # 安装运行 + yum localinstall influxdb-1.6.3.x86_64.rpm + +
    +
  1. influxDB配置
  2. +
+

安装运行后,然后对influxDB进行配置,主要是配置Jmeter连接的数据库和端口号

+ + vim /etc/influxdb/influxdb.conf + +

找到graphite并且修改它的库与端口

1
2
3
4
5
6
enabled = true
database = "jmeter"
retention-policy = ""
bind-address = ":2003"
protocol = "tcp"
consistency-level = "one"

+
    +
  1. 找到[http],将前面的#号去掉
  2. +
+
+ +
+ +
    +
  1. 配置成功,启动influxDB
  2. +
+
    +
  • 启动命令: systemctl start influxdb.service
  • +
  • 查看状态命令: systemctl status influxdb.service
  • +
+
+ +
+ +

安装Grafana

新版本下载位置:Grafana官网下载:https://grafana.com/grafana/download

+
1
2
3
wget https://dl.grafana.com/oss/release/grafana-6.5.2-1.x86_64.rpm

sudo yum localinstall grafana-6.5.2-1.x86_64.rpm
+

然后启动

启动命令: systemctl start grafana-server.service

+

查看状态命令: systemctl status grafana-server.service

+

然后在浏览器访问登录http://ip:3000

+

配置Jmeter

一、添加监听器:Backend Listener

    +
  • 右键点击Thread Group
  • +
  • 点击Add -> Listener -> Backend Listener
  • +
+

二、配置监听器:Backend Listener

Backend Listener implementation 默认选择GraphiteBackendListenerClient

+
    +
  • graphiteHost:InfluxDB安装的服务器的ip
  • +
  • graphitePort:端口;默认就是2003,除非你自己安装InfluxDB时设置了其他端口是哦(可见上面安装InfluxDB后关于graphite的配置)
  • +
  • rootMetricsPrefix:指标的根前缀;将测试结果存入数据库时,不同指标会生成不同表,但这些表都最好要有一个共同的前缀,这个就是了;后面会讲到不同的指标的含义(重点哦)
  • +
  • summaryOnly:当你线程组有多个请求又想知道每个请求的结果数据时,最好填false,因为true只会返回所有请求的集合数据报告,不会输出每条请求的数据报告
  • +
  • samplersList:取样器列表;想收集哪些请求就填哪些,最好用正则去匹配,减轻工作量
  • +
  • useRegexpForSamplersList:是否使用正则;如果true则使用,samplersList里可以匹配正则表达式
  • +
  • percentiles:百分比;即类似聚合报告里90% Line,95% Line,99% Line的数据;倘若想要99.9时,需要写成【99_9】,用下划线代替点
  • +
+

三:运行Jmeter脚本,查看数据库

数据库里面有两个库,jmeter库就是jmeter运行生成表的数据库

+

可以看到生成了三类前缀的表,分别是: jmeter.all 、 jmeter.[请求名称];最后还有 jmeter.test 开头的表,这个后面会单独拿出来说

+

前缀的含义

+
    +
  • jmeter.all :代表了所有请求;当summaryOnly=true时,就只有samplerName=all的表了
  • +
  • jmeter.[请求名称]:代表了HTTP请求,即samplerName=[请求名称]
  • +
+

Thread/Virtual Users metrics - 线程/虚拟用户指标
跟线程组设置相关的

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
指标全称含义
jmeter.test.minATMin active threads最小活跃线程数
jmeter.test.maxATMax active threads最大活跃线程数
jmeter.test.meanATMean active threads平均活跃线程数
jmeter.test.startedTStarted threads启动线程数
jmeter.test.endedTFinished threads结束线程数
+
+

Response times metrics - 响应时间指标

+

划重点:每个sampler(请求)都包含了所有响应时间指标,每个sampler(请求)的每个指标都会有单独的一个表存储结果数据

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
指标含义
.ok.countsampler的成功响应数
.h.count服务器每秒命中次数(每秒点击数,即TPS)
.ok.minsampler响应成功的最短响应时间
.ok.maxsampler响应成功的最长响应时间
.ok.avgsampler响应成功的平均响应时间
.ok.pctsampler响应成功的所占百分比
.ko.countsampler的失败响应数
.ko.minsampler响应失败的最短响应时间
.ko.maxsampler响应失败的最长响应时间
.ko.avgsampler响应失败的平均响应时间
.ko.pctsampler响应失败的所占百分比
.a.countsampler响应数(ok.count+ko.count)
.sb.bytes已发送字节
.rb.bytes已接收字节
.a.minsampler响应的最短响应时间(ok.count和ko.count的最小值)
.a.maxsampler响应的最长响应时间(ok.count和ko.count的最大值)
.a.avgsampler响应的平均响应时间(ok.count和ko.count的平均值)
.a.pctsampler响应的百分比(根据成功和失败的总数来计算)
+
+

四、配置Grafana

步骤:

+
    +
  • 配置数据源

    +
  • +
  • 创建数据面板

    +
  • +
+
+ +
+ +

配置数据源

点击首页的Create your first data source,然后进行配置

+
+ +
+ +

点击选择influxDB

+
+ +
+ +
+ +
+ +

配置数据面板

+ +
+ +

选择Add Query,然后进行配置

+
+ +
+ +

当我们只想看数据而不想看数据趋势图的话,可以改变它的类型;

+

在同一个界面,点击左侧列表选中第二个icon,然后选择Singlestat即可

+
+ +
+ +

基本的配置完成,Jmeter使用GraphiteBackendListenerClient来采集数据的,因为请求多起来的时候会有非常多的表,维护成本也会增加;后面将会介绍如何通过InfluxDBBackendListenerClient来采集数据

+

给Jmeter的Backend Listener配置为InfluxDBBackendListenerClient

+

首先来看看每个配置项的含义

+
    +
  1. influxdbUrl:安装influxdb的路径;主要格式:http://主机地址:8086/write?db=数据库名
  2. +
  3. application:应用名称;在 events 表中对应的字段是 application
  4. +
  5. measurement:表名;数据存储到哪个表,默认是jmeter,不用改即可
  6. +
  7. summaryOnly:同GraphiteBackendListenerClient
  8. +
  9. samplersRegex:同GraphiteBackendListenerClient
  10. +
  11. percentiles:同GraphiteBackendListenerClient
  12. +
  13. testTitle:测试名称;在 events 表中对应的字段是 text ,JMeter在测试的开始和结束时自动生成注释,该注释的值以’start’和’end’结尾
  14. +
  15. eventTags:Grafana允许为每个注释显示标签;在 events 表中对应的字段是 tags
  16. +
+

inDB数据库
使用InfluxDBBackendListenerClient好处就是,再多的请求也只会生成两张表:

+

events :主要拿存事件的

+

jmeter :存测试结果数据的,Grafana也是从这个表获取数据再展示

+

配置数据面板

+

首先,进入官方模板库: https://grafana.com/dashboards ,然后跟着图片导入模板并初始化即可

+
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +

然后jmeter再次执行一下测试计划

+
+ +
+ +

模板自带了三个下拉筛选框

+
    +
  1. data_source:数据源,在Grafana配置了多少个就显示多少个

    +
  2. +
  3. application:在Jmeter配置好的application,如果每次测试计划执行时的application都不一样,你就可以通过这个筛选出对应测试时机的结果数据了

    +
  4. +
  5. transaction:在Jmeter配置好的sampleList,譬如我只发了get、post请求,这里就只会给你选get、post;可以滑到页面下面看到针对某个请求的数据展示

    +
  6. +
+

卸载Grafana

停止Grafana服务。

1
systemctl stop grafana-server.service

1
systemctl disable grafana-server.service

查看要卸载的包的名称
1
yum list installed

输入命令行卸载Grafana
1
yum remove grafana.x86_64

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/20/project/2022-11-24-%E6%90%AD%E5%BB%BA%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B9%B3%E5%8F%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/21/springboot/2022-10-21-\345\274\200\345\217\221\346\227\266\351\201\207\345\210\260\347\253\257\345\217\243\345\206\262\347\252\201\350\247\243\345\206\263\345\212\236\346\263\225/index.html" "b/2022/10/21/springboot/2022-10-21-\345\274\200\345\217\221\346\227\266\351\201\207\345\210\260\347\253\257\345\217\243\345\206\262\347\252\201\350\247\243\345\206\263\345\212\236\346\263\225/index.html" new file mode 100644 index 000000000..cf76c9b9e --- /dev/null +++ "b/2022/10/21/springboot/2022-10-21-\345\274\200\345\217\221\346\227\266\351\201\207\345\210\260\347\253\257\345\217\243\345\206\262\347\252\201\350\247\243\345\206\263\345\212\236\346\263\225/index.html" @@ -0,0 +1,172 @@ +开发时遇到端口冲突解决办法 | Research • 呓语 + + + + + + + + + + + + +

开发时遇到端口冲突解决办法

解决办法

resources下面新建文件application.properties,名称不能变,只能是这个,运行时系统会自动获取这个端口数据

+

在里面输入代码数据

+
1
server.port=${port:8888}
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/21/springboot/2022-10-21-%E5%BC%80%E5%8F%91%E6%97%B6%E9%81%87%E5%88%B0%E7%AB%AF%E5%8F%A3%E5%86%B2%E7%AA%81%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/21/springboot/2022-10-21-\346\216\245\345\217\243\345\274\200\345\217\221\347\216\257\345\242\203\351\203\250\347\275\262/index.html" "b/2022/10/21/springboot/2022-10-21-\346\216\245\345\217\243\345\274\200\345\217\221\347\216\257\345\242\203\351\203\250\347\275\262/index.html" new file mode 100644 index 000000000..fa7f1686c --- /dev/null +++ "b/2022/10/21/springboot/2022-10-21-\346\216\245\345\217\243\345\274\200\345\217\221\347\216\257\345\242\203\351\203\250\347\275\262/index.html" @@ -0,0 +1,176 @@ +接口开发环境部署 | Research • 呓语 + + + + + + + + + + + + +

接口开发环境部署

开发环境

    +
  • IDEA
  • +
  • Maven
  • +
  • Spring Boot
  • +
  • JDK_86001
  • +
+

在idea安装SpringBoot插件

在maven下安装插件,需要在pox.xml文件输入下面的数据,然后更新文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<springboot.version>2.5.6</springboot.version>
<swagger.version>2.9.2</swagger.version>
</properties>

<dependencies>
<!-- springboot 2.5.6 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>${springboot.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>${springboot.version}</version>
</dependency>
</dependencies>


上面的${springboot.version}是在上面里面定义的版本信息,如果多个插件的版本一致就可以在属性上进行定义,然后使用变量进行引用

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/21/springboot/2022-10-21-%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/21/springboot/2022-10-21-\350\277\224\345\233\236cookie\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" "b/2022/10/21/springboot/2022-10-21-\350\277\224\345\233\236cookie\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" new file mode 100644 index 000000000..ee7541907 --- /dev/null +++ "b/2022/10/21/springboot/2022-10-21-\350\277\224\345\233\236cookie\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" @@ -0,0 +1,187 @@ +返回cookie的Get接口开发 | Research • 呓语 + + + + + + + + + + + + +

返回cookie的Get接口开发

位置布局

1
2
3
4
5
6
7
- java
- com.course.server
- intertype
MyGetMethod
Application
- resources
- application.properties
+

Application 类

创建Application.java类,用来运行接口,类名只能是Application,不能自定义

+
1
2
3
4
5
6
7
8
@SpringBootApplication
@Controller("com.course.server.intertype")
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
+
    +
  • @SpringBootApplication 作用是给当前类标明是运行的主类,相当于被SpringBoot托管了
  • +
  • @Controller("com.course.server.intertype") 钩子标识符,扫描包下面的类,被Springboot托管
  • +
+

编写Get接口

创建MyGetMethod

+

类名上有修饰符@RestController@Api(value = "/")

+
    +
  • @RestController 标识该类会被扫描到,然后被SpringBoot托管
  • +
  • @Api(value = "/") 可加可不加
  • +
  • @RequestMapping(value = "访问路径", method = 访问方法) 定义接口的访问路径及访问方法
  • +
  • @ApiOperation(value = "接口信息", httpMethod = "接口的请求方法") 展示接口的基本信息和它的请求方法,可加可不加
  • +
+

下面是代码信息,之后的所有GET接口都在该类里面写接口方法

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
@Api(value = "/", tags = {SwaggerConfig.TagGet} )
public class MyGetMethod {

@RequestMapping(value = "/getCookies", method = RequestMethod.GET)
@ApiOperation(value = "通过这个方法可以获得cookies", httpMethod = "GET")
public String getCookies(HttpServletResponse response){

// HttpServerletRequest 装请求信息类
// HttpServerletResponse 装响应信息类

Cookie cookie = new Cookie("login", "True");

response.addCookie(cookie);

return "恭喜获得cookies信息成功";
}
}
+

上面就是返回cookie的get接口开发,接下来就是 需要携带cookies信息才能访问的get请求

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/21/springboot/2022-10-21-%E8%BF%94%E5%9B%9Ecookie%E7%9A%84Get%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201cookie\350\256\277\351\227\256\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" "b/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201cookie\350\256\277\351\227\256\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" new file mode 100644 index 000000000..972f496a4 --- /dev/null +++ "b/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201cookie\350\256\277\351\227\256\347\232\204Get\346\216\245\345\217\243\345\274\200\345\217\221/index.html" @@ -0,0 +1,170 @@ +需要cookie访问的Get接口开发 | Research • 呓语 + + + + + + + + + + + + +

需要cookie访问的Get接口开发

编写需要cookie才能访问的接口

这个接口还是在MyGetMethod类里面编写方法

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 要求客户端携带cookie访问
* 这是一个需要携带cookies信息才能访问的get请求
*/
@RequestMapping(value = "/get/with/cookies", method = RequestMethod.GET)
@ApiOperation(value = "要求客户端携带cookie访问", httpMethod = "GET")
public String getWithCookies(HttpServletRequest request){
Cookie[] cookies = request.getCookies();
if(Objects.isNull(cookies)){
return "你必须携带cookies信息来";
}
for(Cookie cookie : cookies){
if(cookie.getName().equals("login") && cookie.getValue().equals("True")){
return "恭喜你,访问成功!,这是一个需要携带cookies信息才能访问的get请求";
}
}
return "你必须携带cookies信息来";
}
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/21/springboot/2022-10-21-%E9%9C%80%E8%A6%81cookie%E8%AE%BF%E9%97%AE%E7%9A%84Get%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201\345\217\202\346\225\260\346\211\215\350\203\275\350\256\277\351\227\256\347\232\204get\350\257\267\346\261\202/index.html" "b/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201\345\217\202\346\225\260\346\211\215\350\203\275\350\256\277\351\227\256\347\232\204get\350\257\267\346\261\202/index.html" new file mode 100644 index 000000000..3b55980a4 --- /dev/null +++ "b/2022/10/21/springboot/2022-10-21-\351\234\200\350\246\201\345\217\202\346\225\260\346\211\215\350\203\275\350\256\277\351\227\256\347\232\204get\350\257\267\346\261\202/index.html" @@ -0,0 +1,175 @@ +需要参数才能访问的get请求 | Research • 呓语 + + + + + + + + + + + + +

需要参数才能访问的get请求

编写需要参数才能访问的get请求

使用参数就要用到@RequestParam 参数类型 参数变量,可以有多个参数

+

这个接口还是在MyGetMethod类里面编写方法,有两种方法

+

第一种url:key=value&&key=value

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 开发一个需要参数才能访问的get请求
* 模拟获取商品列表
*/
@RequestMapping(value = "/get/with/param", method = RequestMethod.GET)
@ApiOperation(value = "需要参数才能访问的get请求的第一种实现方法", httpMethod = "GET")
public Map<String, Integer> getList(@RequestParam Integer start,
@RequestParam Integer end){

Map<String, Integer> myList = new HashMap<>();

myList.put("鞋",400);
myList.put("电脑",5000);
myList.put("手机",3500);

return myList;

}
+

方法二url: ip:port/get/with/param/10/20

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/**
* 第二种需要携带参数访问的get请求
*/

@RequestMapping(value = "/get/with/param/{start}/{end}", method = RequestMethod.GET)
@ApiOperation(value = "需要参数才能访问的get请求的第二种实现方法", httpMethod = "GET")
public Map<String,Integer> myGetList(@PathVariable Integer start,
@PathVariable Integer end){

Map<String, Integer> myList = new HashMap<>();

myList.put("鞋",400);
myList.put("电脑",5000);
myList.put("手机",3500);

return myList;
}
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/21/springboot/2022-10-21-%E9%9C%80%E8%A6%81%E5%8F%82%E6%95%B0%E6%89%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E7%9A%84get%E8%AF%B7%E6%B1%82/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/22/other/2022-10-22-SQL\350\257\255\350\250\200\347\232\204\345\237\272\346\234\254\346\223\215\344\275\234/index.html" "b/2022/10/22/other/2022-10-22-SQL\350\257\255\350\250\200\347\232\204\345\237\272\346\234\254\346\223\215\344\275\234/index.html" new file mode 100644 index 000000000..56aa6825c --- /dev/null +++ "b/2022/10/22/other/2022-10-22-SQL\350\257\255\350\250\200\347\232\204\345\237\272\346\234\254\346\223\215\344\275\234/index.html" @@ -0,0 +1,301 @@ +测试必会的sql基本操作 | Research • 呓语 + + + + + + + + + + + + +

测试必会的sql基本操作

1、创建数据库
1
2
create database 数据库名;
create database 数据库名 character set 字符集;
+
2、查看全部的数据库
1
show databases;   
+

3、查看某个数据库的定义的信息:

+
1
show create database 数据库名;         
+
4、删除数据库
1
drop database 数据库名称;
+

5、切换数据库:

+
1
use 数据库名;
+

6、查看正在使用的数据库:

+
1
select database();          
+

7、查看数据库中的所有表:

+
1
show tables;
+

8、查看表结构:

+
1
desc 表名;    
+

9、修改表删除列.

+
1
alter table 表名 drop 列名;            
+

10、修改表名

+
1
rename table 表名 to 新表名;              
+

11、修改表的字符集

+
1
alter table 表名 character set 字符集;
+

12、数据类型与约束

+
    +
  • int :整数 有符号和无符号,长度不受限制
  • +
  • varchar:字符串 中文/数字/字母都是一字字符,受长度限制
  • +
  • decimal :小数 decimal(5,2)总长度5位,整数3位,小数2位
  • +
  • 主键 id :int unsigned primary key auto_increment
  • +
  • 非空 :not null
  • +
  • 唯一 :unique
  • +
  • 默认 :default
  • +
+

SQL中表的操作

1、创建表

1
create table 表名(字段名 类型 约束,.....)
+

2、删除表

1
2
drop table 表名
drop table if exists 表名
+

3、表数据操作

3.1、添加数据
1
2
insert into 表名 values(值1,值2...)给表中所有字段插入数据
insert into 表名(字段2,字段1values(值2,值1
+
3.2、修改数据
1
2
update 表名 set 字段1=1,字段2=2 where 条件
isdelete 逻辑删除
+
3.3、删除数据
1
delete from 表名 where 条件
+
3.4、查询数据
    +
  • 3.4.1、查询表中所有信息
    1
    select * from 表名 where 条件
    +
  • +
  • 3.4.2、查询表中指定字段
    1
    select 字段1,字段2,字段3...from 表名 where 条件
    +
  • +
  • 3.4.3、给字段取别名
    1
    select 字段1as) 别名,字段2 别名 from 表名 where 条件
    +
  • +
  • 3.4.4、去重
    1
    select distinct 字段 from 表名 where 条件
    +
  • +
  • 3.4.5、比较运算符
    1
    select * from 表名 where age>20
    +
  • +
  • 3.4.6、逻辑运算符
      +
    • and 满足所有条件

      +
    • +
    • or 满足其中任意一个条件

      +
    • +
    • not 不满足条件

      +
    • +
    +
  • +
  • 3.4.7、模糊查询
      +
    • like
    • +
    • % 0到任意多个字符
    • +
    • _表示任意一个字符
    • +
    +
  • +
  • 3.4.8、范围查询
      +
    • in 在一个非连续的范围内
    • +
    • between and 在一个连续的范围内 闭区间 小的数据在前
    • +
    +
  • +
  • 3.4.9、空查询
      +
    • is null
    • +
    • ‘’空字符串
    • +
    +
  • +
+
3.5、多表查询
    +
  • 3.5.1、排序

    +
    1
    2
    select * from 表名 where 条件 order by1asc|desc,列2 asc|desc
    select * from student where 条件 order by convert(字段 using gbk)asc|desc 纯中文转换后排序
    +
  • +
  • 3.5.2、聚合函数

    +
    1
    2
    3
    4
    5
    6
    count: 总数 select count(*/字段)from 表名 where 条件 
    max: 最大值 select max(age) from 表名 where 条件
    min: 最小值 select min(age) from 表名 where 条件
    avg: 平均值 select avg(grade) from 表名 where 条件
    sum: 求和 select sum(grade) from 表名 where 条件
    select avg(age)as 平均年龄,max(age)最大年龄,min(age)最小年龄 from 表名 where 条件
    +
  • +
  • 3.5.3、分组

    +
    1
    select * from 表名 group by 字段,字段2 having 条件
    +
  • +
  • 3.5.4、分页

    +
    1
    2
    select * from 表名 limit 05 从第一行数据开始,显示5
    select * from 表名 limit (n-1*m,m n代表第几页,m代表每页显示多少条数据
    +
  • +
  • 3.5.5、等值连接

    +
    1
    2
    3
    4
    方式一 :
    select * from1,表2,表3 where1.=2.and2.=3.where 条件
    方式二 内连接 取交集:
    select * from1 inner join2 on1.=2.inner join3 on2.=3.where 条件
    +
  • +
  • 3.5.6、左连接

    +
    +

    左边的表全显示,右边表能匹配的上的数据连接显示,匹配不上(没有的)以null补充

    +
    +
    1
    select * from1 left join2 on1.=2.left join3 on2.=3.where 条件
    +
  • +
  • 3.5.7、右连接

    +
    +

    右边的表全显示,左边表能匹配上的数据连接显示,匹配不上(没有的)以null补充

    +
    +
    1
    select * from1 right join2 on1.=2.right join3 on2.=3.where 条件
    +
  • +
  • 3.5.8、自关联

    +
    1
    select * from 表 别名1 inner join 表 别名2 on 别名1.aid=别名2.pid
    +
  • +
  • 3.5.9、子查询
      +
    • 标量子查询
    • +
    +
    +

    子查询结果输出的是一行一列

    +
    +
    1
    select * from student where age>(select avg(age) from student)
    +
      +
    • 列子查询
    • +
    +
    +

    子查询的结果输出的是一列多行

    +
    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    in:  
    select * from student where age in
    (select age from student where age=18)

    any/some: >:大于最小的; <: 小于最大的
    select * from student where age>/< any
    (select age from student where age between 18 and 22)

    all: >:大于最大的; <: 小于最小的
    select * from student where age>/<all
    (select age from student where age between 18 and 22
    +
      +
    • 行子查询
    • +
    +
    +

    子查询的结果输出的是一行多列

    +
    +
    1
    select * from student where(name,sex)=select name,sex from student where sex='男' order by age desc limit 1
    +
      +
    • 表子查询
    • +
    +
    +

    子查询的输出结果是一个表

    +
    +
    1
    select * from scores inner joinselect cno from courses where cname in('数据库',‘系统测试’) as c on scores.cno=c.cno
    +
  • +
+
3.6、数据分表
1
2
3
4
5
insert into goods_cate(cate_name) select distinct cate from goods;

create table goods_cate (id int unsigned primary key auto_incremen,cate varchar(10)) select distinct cate from goods;

update goods inner join goods_cate on goods_cate.cate=goods.cate set goods.cate=goods_cate.id
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/22/other/2022-10-22-SQL%E8%AF%AD%E8%A8%80%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\217\226\347\224\250\346\210\267\345\210\227\350\241\250\347\232\204post\350\257\267\346\261\202/index.html" "b/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\217\226\347\224\250\346\210\267\345\210\227\350\241\250\347\232\204post\350\257\267\346\261\202/index.html" new file mode 100644 index 000000000..b55253158 --- /dev/null +++ "b/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\217\226\347\224\250\346\210\267\345\210\227\350\241\250\347\232\204post\350\257\267\346\261\202/index.html" @@ -0,0 +1,172 @@ +开发获取用户列表的Post接口 | Research • 呓语 + + + + + + + + + + + + +

开发获取用户列表的Post接口

开发获取用户列表的post请求

开发添加人员信息时需要的字段数据

首先,写一个User类,这将是添加时的字段数据

+
1
2
3
4
5
6
7
8
@Data
public class User {
private String userName;
private String password;
private String name;
private String age;
private String sex;
}
+

然后开始写怎么获取用户列表,相当于添加用户

@RequestBody User u请求post接口时,在Body填写上传的数据

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RequestMapping(value = "/getUserList", method = RequestMethod.POST)
@ApiOperation(value = "获取用户列表", httpMethod = "POST")
public String getUserList(HttpServletRequest request,
@RequestBody User u){
User user;
// 获取cookies
Cookie[] cookies= request.getCookies();
// 验证cookies是否合法
for(Cookie c:cookies){
if (c.getName().equals("login")
&& c.getValue().equals("true")
&& u.getUserName().equals("zhangsan")
&& u.getPassword().equals("123456")){
user = new User();
user.setName("lisi");
user.setAge("18");
user.setSex("man");
return user.toString();
}
}
return "参数不合法";
}
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/22/springboot/2022-10-22-%E5%BC%80%E5%8F%91%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%88%97%E8%A1%A8%E7%9A%84post%E8%AF%B7%E6%B1%82/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\276\227cookie\347\232\204Post\347\231\273\345\275\225\346\216\245\345\217\243/index.html" "b/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\276\227cookie\347\232\204Post\347\231\273\345\275\225\346\216\245\345\217\243/index.html" new file mode 100644 index 000000000..f895628fd --- /dev/null +++ "b/2022/10/22/springboot/2022-10-22-\345\274\200\345\217\221\350\216\267\345\276\227cookie\347\232\204Post\347\231\273\345\275\225\346\216\245\345\217\243/index.html" @@ -0,0 +1,172 @@ +开发获得cookie的Post登录接口 | Research • 呓语 + + + + + + + + + + + + +

开发获得cookie的Post登录接口

开发获得cookie的Post登录接口

@RequestMapping(value = "/v1")的作用是把这个value和方法上的登录地址进行拼接,比如:/v1/login

+

@RestController标识该接口可以被托管

+

方法参数@RequestParam(value = "userName", required = true) String userName,代码中的required = true起到必填的作用

+

举个栗子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RestController
@Api(value = "/", tags = {SwaggerConfig.TagPost})
@RequestMapping(value = "/v1")
public class MyPostMethod {

//这个变量用来装cookie信息的
private static Cookie cookie;

//用户登录成功获取到cookies,然后访问其他接口获取到列表
@RequestMapping(value = "/login",method = RequestMethod.POST)
@ApiOperation(value = "登录接口,成功后获取到cookies信息",httpMethod = "POST")
public String login(HttpServletResponse response,
@RequestParam(value = "userName", required = true) String userName,
@RequestParam(value = "password", required = true) String password){
if (userName.equals("zhangsan") && password.equals("123456")){
cookie = new Cookie("login","true");
response.addCookie(cookie);
return "恭喜你登录成功!";
}
return "用户名或密码错误!";

}
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/10/22/springboot/2022-10-22-%E5%BC%80%E5%8F%91%E8%8E%B7%E5%BE%97cookie%E7%9A%84Post%E7%99%BB%E5%BD%95%E6%8E%A5%E5%8F%A3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/16/jmeter/2022-11-16-Jmeter\344\271\213\346\226\255\350\250\200/index.html" "b/2022/11/16/jmeter/2022-11-16-Jmeter\344\271\213\346\226\255\350\250\200/index.html" new file mode 100644 index 000000000..d063a5bc6 --- /dev/null +++ "b/2022/11/16/jmeter/2022-11-16-Jmeter\344\271\213\346\226\255\350\250\200/index.html" @@ -0,0 +1,217 @@ +Jmeter之断言和聚合报告 | Research • 呓语 + + + + + + + + + + + + +

Jmeter之断言和聚合报告

怎么对请求进行响应断言

    +
  • 右键 HTTP Request

    +
  • +
  • 点击add --> Assertions --> Response Assertion

    +
  • +
+

断言组件就添加成功

+

配置响应断言

Field to Test 下面就是断言的各种方法

+
    +
  • Text Response 文本断言
  • +
+
+

Patterns to Test输入title之间包含的文字,及配置成功

+
+
    +
  • Response Code 响应码断言
  • +
+
+

Patterns to Test输入响应码,比如 200

+
+
    +
  • Response Message
  • +
  • Request Headers
  • +
  • URL Sampled
  • +
  • Document(text)
  • +
  • Request Data
  • +
+

然后运行但并发压测,验证断言添加是否正确,在View Results Tree中查看结果

+

怎么使用聚合报告

    +
  • 右键 Thread Group

    +
  • +
  • 点击 Add --> Listener --> Aggregate Report

    +
  • +
+

聚合报告就添加了

+

性能指标解读

    +
  • Average: 单个请求的平均响应时间
  • +
  • Median: 中位数,也就是50%用户的响应时间
  • +
  • 90%Line: 90%用户的响应时间
  • +
  • 95%Line: 95%用户的响应时间
  • +
  • 99%Line: 99%用户的响应时间
  • +
  • Min: 最小的请求响应时间
  • +
  • Max: 最大的请求响应时间
  • +
  • Error%: 错误率
  • +
  • Throughput: 吞吐量
  • +
  • Received KB/sec: 每秒从服务器接收到的数据量
  • +
  • Sent KB/sec: 每秒从客户端发送的请求的数量
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/16/jmeter/2022-11-16-Jmeter%E4%B9%8B%E6%96%AD%E8%A8%80/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/17/jmeter/2022-11-17-jmeter\346\200\216\344\271\210\350\204\261\347\246\273UI\350\277\233\350\241\214\345\216\213\346\265\213/index.html" "b/2022/11/17/jmeter/2022-11-17-jmeter\346\200\216\344\271\210\350\204\261\347\246\273UI\350\277\233\350\241\214\345\216\213\346\265\213/index.html" new file mode 100644 index 000000000..27595ac7c --- /dev/null +++ "b/2022/11/17/jmeter/2022-11-17-jmeter\346\200\216\344\271\210\350\204\261\347\246\273UI\350\277\233\350\241\214\345\216\213\346\265\213/index.html" @@ -0,0 +1,174 @@ +Jmeter之静默压测 | Research • 呓语 + + + + + + + + + + + + +

Jmeter之静默压测

静默压测

+

jmeter -n -t $jmx_file -l $jtl_file

+
+

如: jmeter -n -t HTTP代理服务器luzhi.jmx -l result.jtl

+

jmx: Jmeter压测程序脚本文件
jtl: Jmeter压测请求响应数据的原始文件,查看结果树和聚合报告可以导入该文件查看

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/17/jmeter/2022-11-17-jmeter%E6%80%8E%E4%B9%88%E8%84%B1%E7%A6%BBUI%E8%BF%9B%E8%A1%8C%E5%8E%8B%E6%B5%8B/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/18/jmeter/2022-11-18-Jmeter\344\271\213json\346\225\260\346\215\256\346\217\220\345\217\226\345\222\214\345\217\202\346\225\260\344\274\240\351\200\222/index.html" "b/2022/11/18/jmeter/2022-11-18-Jmeter\344\271\213json\346\225\260\346\215\256\346\217\220\345\217\226\345\222\214\345\217\202\346\225\260\344\274\240\351\200\222/index.html" new file mode 100644 index 000000000..518f77a0d --- /dev/null +++ "b/2022/11/18/jmeter/2022-11-18-Jmeter\344\271\213json\346\225\260\346\215\256\346\217\220\345\217\226\345\222\214\345\217\202\346\225\260\344\274\240\351\200\222/index.html" @@ -0,0 +1,190 @@ +Jmeter之json数据提取和参数传递 | Research • 呓语 + + + + + + + + + + + + +

Jmeter之json数据提取和参数传递

安装组件JSON Extractor

    +
  • 右键Http Request
  • +
  • 点击Add -> Post Processors -> JSON Extractor
  • +
+

组件安装成功

+

组件配置

    +
  • Names of created variables : 参数变量名称,提取出来的json使用这个变量
  • +
  • Json Path expressions : JSON提取的正则 比如:$.access_token这个是提取response里面的token
  • +
  • Match NO.(0 for Random):这个是写提取出json的第几条, 比如使用正则能匹配多条,使用这个输入数字就可以匹配对应的
  • +
+
引用json变量
    +
  • Jmeter中引用变量的方法${变量名}
  • +
+

调试脚本 Debug Sampler

+

帮助检查变量值,调试脚本

+
+
    +
  • 右键Thread Group
  • +
  • 点击Add -> Sampler -> Debug Sampler
  • +
+

注意:把Debug放到所有请求的最底下,运行的后可以查看变量参数,方便调试

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/18/jmeter/2022-11-18-Jmeter%E4%B9%8Bjson%E6%95%B0%E6%8D%AE%E6%8F%90%E5%8F%96%E5%92%8C%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/18/jmeter/2022-11-18-jmeter\344\271\213\345\205\250\345\261\200\345\217\202\346\225\260\350\256\276\347\275\256\345\222\214csv\346\225\260\346\215\256\345\257\274\345\205\245/index.html" "b/2022/11/18/jmeter/2022-11-18-jmeter\344\271\213\345\205\250\345\261\200\345\217\202\346\225\260\350\256\276\347\275\256\345\222\214csv\346\225\260\346\215\256\345\257\274\345\205\245/index.html" new file mode 100644 index 000000000..d41fda0e9 --- /dev/null +++ "b/2022/11/18/jmeter/2022-11-18-jmeter\344\271\213\345\205\250\345\261\200\345\217\202\346\225\260\350\256\276\347\275\256\345\222\214csv\346\225\260\346\215\256\345\257\274\345\205\245/index.html" @@ -0,0 +1,204 @@ +Jmeter之全局参数设置和csv数据导入 | Research • 呓语 + + + + + + + + + + + + +

Jmeter之全局参数设置和csv数据导入

全局参数设置

添加组件
    +
  • 右键Thread Group
  • +
  • 点击Add -> Config Element -> User Defined Variables
  • +
+
添加对应的变量
    +
  • hostname:localhost
  • +
  • port:9090
  • +
  • protocol:http
  • +
+

然后再请求参数中使用对应的参数变量名

+
    +
  • ${hostname}
  • +
  • ${port}
  • +
  • ${protocol}
  • +
+

csv数据导入

创建csv文件
    +
  • 使用Excel创建csv文件
  • +
  • csv数据之间使用英文逗号来分割
  • +
  • 保存成.csv文件
  • +
+
添加csv导入组件
    +
  • 右键Thread Group
  • +
  • 点击Add -> Config Element -> CSV Data Set Config
  • +
+
配置
    +
  • Filename:文件位置
  • +
  • File encoding:编码格式
  • +
  • Variable Names(comma-delimited):数据参数 如:no,username,password
  • +
  • lgnore first lline (only user if Variable Names is not empty):是否忽略第一行(表头)
  • +
  • Delimiter(use "\t" for tab):分隔符
  • +
  • Allow quoted data?:是否允许双引号括住数据
  • +
  • Recycle on EOF?:到了文件结尾是否循环
  • +
  • Stop thread on EOF?:到了文件结尾是否停止
  • +
  • Sharinng mode:共享模式
  • +
+注意:把请求的参数修改为:`${变量}`
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/18/jmeter/2022-11-18-jmeter%E4%B9%8B%E5%85%A8%E5%B1%80%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%E5%92%8Ccsv%E6%95%B0%E6%8D%AE%E5%AF%BC%E5%85%A5/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/19/jmeter/2022-11-14-jmeter\350\207\252\345\212\250\345\214\226\345\216\213\345\212\233\346\265\213\350\257\225/index.html" "b/2022/11/19/jmeter/2022-11-14-jmeter\350\207\252\345\212\250\345\214\226\345\216\213\345\212\233\346\265\213\350\257\225/index.html" new file mode 100644 index 000000000..fdefce949 --- /dev/null +++ "b/2022/11/19/jmeter/2022-11-14-jmeter\350\207\252\345\212\250\345\214\226\345\216\213\345\212\233\346\265\213\350\257\225/index.html" @@ -0,0 +1,174 @@ +jmeter自动化压力测试 | Research • 呓语 + + + + + + + + + + + + +

jmeter自动化压力测试

思路

    +
  • jmeter脚本实现压测逻辑
  • +
  • Shell控制逻辑
  • +
  • 使用jmeter进行静默压测
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/19/jmeter/2022-11-14-jmeter%E8%87%AA%E5%8A%A8%E5%8C%96%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
目录
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/20/jmeter/2022-11-20-jmeter\345\257\271\346\225\260\346\215\256\345\272\223\346\225\260\346\215\256\350\277\233\350\241\214\345\242\236\345\210\240\346\224\271\346\237\245/index.html" "b/2022/11/20/jmeter/2022-11-20-jmeter\345\257\271\346\225\260\346\215\256\345\272\223\346\225\260\346\215\256\350\277\233\350\241\214\345\242\236\345\210\240\346\224\271\346\237\245/index.html" new file mode 100644 index 000000000..0523d9afe --- /dev/null +++ "b/2022/11/20/jmeter/2022-11-20-jmeter\345\257\271\346\225\260\346\215\256\345\272\223\346\225\260\346\215\256\350\277\233\350\241\214\345\242\236\345\210\240\346\224\271\346\237\245/index.html" @@ -0,0 +1,205 @@ +jmeter对数据库进行增删改查 | Research • 呓语 + + + + + + + + + + + + +

jmeter对数据库进行增删改查

环境

    +
  • jmeter版本(5.1.1)
  • +
  • mysql-connector-java-8.0.15.jar
  • +
+

mysql.jar放在jmeter的lib目录下

+

配置

连接配置组件

    +
  • 右键Thread Group
  • +
  • 点击Add -> Config Element -> JDBC Connection Configuration
  • +
+

参数配置

    +
  • ==Varianle Name for created pool==:db_connnection_pool # 连接池名称
  • +
  • ==Validation Query==:select 1
  • +
  • ==Database URL==:jdbc:mysql://8.142.144.75:3306/jmeter_class?alloMultiQueries = true&useSSL=false
  • +
  • ==JDBC Driver class==:选择com.mysql.jbc.Driver
  • +
  • 输入username
  • +
  • 输入password
  • +
+

Jmeter数据库JDBC请求

    +
  • 右键Thread Group
  • +
  • 点击Add -> Sampler -> JDBC Request
  • +
+
配置介绍

Variable Name Bound to Pool: 配置参数区
SQL Query:sql语句区
其他:变量配置区

+
举个栗子:通过Insert语句,向数据库添加测试数据
    +
  • JDBC Connection Configuration: db_connnection_pool #输入连接池名称
  • +
  • Query Type:选择Prepared Updata Statement
  • +
  • Quert:输入sql语句
  • +
+
1
INSERT INTO jmeter_class.user (`username`,`password`) VALUES(?,?)
+
    +
  • Paeameter values:testuser,aaaaaa
  • +
  • Paeameter types:varchar,varchar
  • +
  • Query timeout(s):6
  • +
  • 添加查看结果树
  • +
  • 运行
  • +
+

运行结果ResponseBody:

1
1 updates.

这就配置成功

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/20/jmeter/2022-11-20-jmeter%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%BA%93%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/2022/11/28/moko/2022-11-28-moko/index.html b/2022/11/28/moko/2022-11-28-moko/index.html new file mode 100644 index 000000000..408118227 --- /dev/null +++ b/2022/11/28/moko/2022-11-28-moko/index.html @@ -0,0 +1,173 @@ +使用moko编写测试接口(无) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写测试接口(无)

测试

测试

测试moko


+

测试

+

🐱

+

❄️

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-moko/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231Get\345\222\214Post\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\214\357\274\211/index.html" "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231Get\345\222\214Post\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\214\357\274\211/index.html" new file mode 100644 index 000000000..6c7214768 --- /dev/null +++ "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231Get\345\222\214Post\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\214\357\274\211/index.html" @@ -0,0 +1,173 @@ +使用moko编写Get和Post测试接口(二) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写Get和Post测试接口(二)

上一节已经写了规则,这次直接来编写Get和Post请求

+

模拟一个没有参数的get请求

1
2
3
4
5
6
7
8
9
10
{
"description": "模拟一个没有参数的get请求",
"request": {
"uri": "/getdemo",
"method": "get"
},
"response": {
"text": "这是一个没有参数的get请求"
}
}

模拟一个带参数的请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"description": "模拟一个带参数的请求",
"request": {
"uri": "getwithparam",
"method": "get",
"queries": {
"name": "胡汉三",
"age": "18"
}
},
"response": {
"text": "我胡汉三又回来了!!!!!"
}
}

+

模拟一个Post请求

1
2
3
4
5
6
7
8
9
10
{
"description": "模拟一个Post请求",
"request": {
"uri": "/postdemo",
"method": "post"
},
"response": {
"text": "这是我的第一个mosk的post请求"
}
}

+

这是一个带参数的post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"description": "这是一个带参数的post请求",
"request": {
"uri": "/postwithparam",
"method": "post",
"forms": {
"name": "胡汉三",
"sex": "男人"
}
},
"response": {
"text": "我胡汉三带着参数来了!!!!"
}
}

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99Get%E5%92%8CPost%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%BA%8C%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\345\214\205\345\220\253cookie\344\277\241\346\201\257\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\211\357\274\211/index.html" "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\345\214\205\345\220\253cookie\344\277\241\346\201\257\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\211\357\274\211/index.html" new file mode 100644 index 000000000..50a4c58ed --- /dev/null +++ "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\345\214\205\345\220\253cookie\344\277\241\346\201\257\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\211\357\274\211/index.html" @@ -0,0 +1,173 @@ +使用moko编写包含cookie信息的测试接口(二) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写包含cookie信息的测试接口(二)

上一节已经写了规则,这次直接来编写Get和Post请求

+

这是一个会返回cookie的get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"description": "这是一个会返回cookie的get请求",
"request": {
"uri": "/getCookies",
"method": "get"
},
"response": {
"cookies": {
"login": "true"
},
"text": "恭喜你获得cookies信息成功",
"status": 200,
"msg": "成功"
}
}
+

这是一个携带cookies信息的get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"description": "这是一个带cookies信息的get请求",
"request": {
"uri": "/get/with/cookies",
"method": "get",
"cookies": {
"login": "true"
}
},
"response": {
"text": "这是一个需要携带cookies信息才能访问的get请求"
}
}
+

这是一个携带cookies信息的post请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
"description": "这是一个带cookies信息的post请求",
"request": {
"uri": "/post/with/cookies",
"method": "post",
"cookies": {
"login": "true"
},
"json": {
"name": "huhansan",
"age": "18"
}
},
"response": {
"status": 200,
"json": {
"huhansan": "success",
"status": "1"
}
}
}
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E5%8C%85%E5%90%ABcookie%E4%BF%A1%E6%81%AF%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%B8%89%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\200\357\274\211/index.html" "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\200\357\274\211/index.html" new file mode 100644 index 000000000..32216bcd7 --- /dev/null +++ "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\270\200\357\274\211/index.html" @@ -0,0 +1,194 @@ +使用moko编写测试接口(一) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写测试接口(一)

编写规则

    +
  • []包裹着以{}包起来的接口脚本

    +
  • +
  • description:接口简介

    +
  • +
  • request:使用{}包含接口的请求信息

    +
      +
    • uri:接口的地址名称
    • +
    • method:请求方法
    • +
    • queries:get请求参数
    • +
    • forms:post请求参数
    • +
    • headers:请求头信息
    • +
    +
  • +
  • response:返回的数据,使用{}

    +
      +
    • text:返回的文字数据
    • +
    • cookies:返回的cookie信息
    • +
    • status:返回的响应码
    • +
    +
  • +
+

举个栗子demo

+
1
2
3
4
5
6
7
8
9
10
11
[
{
"description": "这是我们的第一个mock栗子",
"request": {
"uri": "/demo"
},
"response": {
"text": "第一个mock响应demo"
}
}
]
+

get请求demo

1
2
3
4
5
6
7
8
9
10
11
12
[
{
"description": "接口的get请求",
"request": {
"uri": "/#/test/xml",
"method": "get"
},
"response": {
"text": "get请求接口"
}
}
]

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%B8%80%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\224\357\274\211/index.html" "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\224\357\274\211/index.html" new file mode 100644 index 000000000..96feed673 --- /dev/null +++ "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\344\272\224\357\274\211/index.html" @@ -0,0 +1,170 @@ +使用moko编写测试接口(五) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写测试接口(五)

下载jar包

点击moke选择版本进行下载,我下载的的是moco-runner-0.11.0-standalone.jar

+

使用命令启动测试脚本

1
java -jar jar包的存放路径 http -p 端口 -c json文件路径
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%BA%94%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\351\207\215\345\256\232\345\220\221\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\345\233\233\357\274\211/index.html" "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\351\207\215\345\256\232\345\220\221\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\345\233\233\357\274\211/index.html" new file mode 100644 index 000000000..b7d44ad56 --- /dev/null +++ "b/2022/11/28/moko/2022-11-28-\344\275\277\347\224\250moko\347\274\226\345\206\231\351\207\215\345\256\232\345\220\221\347\232\204\346\265\213\350\257\225\346\216\245\345\217\243\357\274\210\345\233\233\357\274\211/index.html" @@ -0,0 +1,174 @@ +使用moko编写重定向测试接口(四) | Research • 呓语 + + + + + + + + + + + + +

使用moko编写重定向测试接口(四)

上一节已经写了规则,这次直接来编写Get和Post请求

+

重定向的测试接口

    +
  • 使用了redirectTo:目标地址
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
[
{
"description": "重定向到百度",
"request": {
"uri": "/redirect"
},
"redirectTo": "http://www.baidu.com"
},
{
"description": "重定向到自己的网页上",
"request": {
"uri": "/redirect/topath"
},
"redirectTo": "/redirect/new"
},
{
"description": "这是被重定到的请求",
"request": {
"uri": "/redirect/new"
},
"response": {
"text": "重定向成功了"
}
}
]
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E9%87%8D%E5%AE%9A%E5%90%91%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E5%9B%9B%EF%BC%89/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-Constant Timer\345\256\232\346\227\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-Constant Timer\345\256\232\346\227\266\345\231\250/index.html" new file mode 100644 index 000000000..ced24cc2b --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-Constant Timer\345\256\232\346\227\266\345\231\250/index.html" @@ -0,0 +1,172 @@ +Constant Timer定时器 | Research • 呓语 + + + + + + + + + + + + +

Constant Timer定时器

作用

就是loadrunner上面的思考时间,就是模拟真实用户操作过程的等待时间

+

生效范围

定时器的父节点和子节点,如果想让一个请求强制停止一段时间,就把定时器放在这个请求的下面

+

单位是以ms为单位,1s=1000ms

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Constant%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-Loop Controller\346\216\247\345\210\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-Loop Controller\346\216\247\345\210\266\345\231\250/index.html" new file mode 100644 index 000000000..7d9b6eb97 --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-Loop Controller\346\216\247\345\210\266\345\231\250/index.html" @@ -0,0 +1,174 @@ +循环控制器Loop Controller | Research • 呓语 + + + + + + + + + + + + +

循环控制器Loop Controller

作用

指定子节点运行的次数,使用变量或数值进行控制

+
    +
  • Infinite:表示一直循环
  • +
  • 如果同时设置线程组循环次数和循环控制器的循环次数,那控制器子节点运行的次数为两个数值相乘的结果
  • +
+

添加

文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Loop%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/2022/11/29/jmeter/2022-11-29-Modeule Controller/index.html b/2022/11/29/jmeter/2022-11-29-Modeule Controller/index.html new file mode 100644 index 000000000..b9bd75cb9 --- /dev/null +++ b/2022/11/29/jmeter/2022-11-29-Modeule Controller/index.html @@ -0,0 +1,169 @@ +Modeule Controller和Include Controller | Research • 呓语 + + + + + + + + + + + + +

Modeule Controller和Include Controller

Modeule Controller介绍

文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Modeule%20Controller/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-Random Controller\346\216\247\345\210\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-Random Controller\346\216\247\345\210\266\345\231\250/index.html" new file mode 100644 index 000000000..139433c81 --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-Random Controller\346\216\247\345\210\266\345\231\250/index.html" @@ -0,0 +1,176 @@ +随机控制器Random Controller和Random Order Controller | Research • 呓语 + + + + + + + + + + + + +

随机控制器Random Controller和Random Order Controller

作用

    +
  • Random Controller:控制器子节点随机运行一个请求
      +
    • lgnore sub-controller blocks:忽略子控制器块
    • +
    +
  • +
  • Random Order Controller:控制器子节点随机运行全部请求
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Random%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
目录
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-Simple Controller\346\216\247\345\210\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-Simple Controller\346\216\247\345\210\266\345\231\250/index.html" new file mode 100644 index 000000000..996c2b9a1 --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-Simple Controller\346\216\247\345\210\266\345\231\250/index.html" @@ -0,0 +1,170 @@ +逻辑控制器Simple Controller | Research • 呓语 + + + + + + + + + + + + +

逻辑控制器Simple Controller

作用

把多个请求放入Simple Controller,可以多个请求进行同时操作

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Simple%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
目录
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-Transcation Controller\346\216\247\345\210\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-Transcation Controller\346\216\247\345\210\266\345\231\250/index.html" new file mode 100644 index 000000000..b9876a6f8 --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-Transcation Controller\346\216\247\345\210\266\345\231\250/index.html" @@ -0,0 +1,191 @@ +事务控制器Transcation Controller | Research • 呓语 + + + + + + + + + + + + +

事务控制器Transcation Controller

作用

一个事务会包含并请求,然后查看一个事务的QPS等性能指标

+

指标

QPS:每秒处理完请求的次数,具体指1s内发出请求到服务器处理完成并返回结果的次数

+

TPS:每秒处理完的事务次数,一般TPS是对整个系统来讲的,一个应用系统1s能完成多少事务处理,一个事务在分布式处理中,可能对应多个请求,对于衡量单个接口服务的处理能力,一般使用QPS

+

参数

    +
  • Generate Parent sample:生成父样例,就是控制器里面的请求不展示
  • +
+

没有选中Generate Parent sample,运行后的结果是

+
+ +
+
+ +
+选中后`Generate Parent sample`,运行后的结果是 +
+ +
+
+ +
+ + +
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-Transcation%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/29/jmeter/2022-11-29-if Controller\346\216\247\345\210\266\345\231\250/index.html" "b/2022/11/29/jmeter/2022-11-29-if Controller\346\216\247\345\210\266\345\231\250/index.html" new file mode 100644 index 000000000..d21047405 --- /dev/null +++ "b/2022/11/29/jmeter/2022-11-29-if Controller\346\216\247\345\210\266\345\231\250/index.html" @@ -0,0 +1,169 @@ +逻辑控制器If Controller | Research • 呓语 + + + + + + + + + + + + +

逻辑控制器If Controller

逻辑控制器If Controller

文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/29/jmeter/2022-11-29-if%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/2022-11-30-Constant Throughput Timer\345\256\232\346\227\266\345\231\250/index.html" "b/2022/11/30/jmeter/2022-11-30-Constant Throughput Timer\345\256\232\346\227\266\345\231\250/index.html" new file mode 100644 index 000000000..ac9807f6a --- /dev/null +++ "b/2022/11/30/jmeter/2022-11-30-Constant Throughput Timer\345\256\232\346\227\266\345\231\250/index.html" @@ -0,0 +1,181 @@ +Constant Throughput Timer定时器 | Research • 呓语 + + + + + + + + + + + + +

Constant Throughput Timer定时器

作用

限制整个运行过程中的生成的吞吐量不要超过某一个值,防止压死系统

+

参数

    +
  • Target throughput(in samples per minute):目标吞吐量,指的是每分钟发送的请求数,对应测试要求的20 QPS,这里应该输入1200
  • +
  • Calculate Throughput based on:有5个选项
      +
    • This Thread only:控制每个线程的吞吐量,这个模式的作用是:总的吞吐量=Target throughput * 线程的数量
    • +
    • All active threads:设置的Target throughput将分配在每个活跃线程上,每个活跃线程在上一次运行结束后等待合理时间后再次运行。活跃线程指的是同一时刻同时运行的线程
    • +
    • All active threads in current thread group:设置的`Target throughput将分配在当前线程祖的每一个活跃线程上,当测试计划只有一个线程组,这个模式作用和All active threads一样
    • +
    • All active threads(shared):与All active threads选项基本一致,唯一区别是,每一个活跃线程都会在所有活跃线程上一次运行结束后等待合理时间再次运行
    • +
    • All active threads in current thread group(shared):与All active threads in current thread group选项基本一致,唯一区别是,每个活跃线程都会在所有活跃线程的上一次运行结束等待合理的时间后再次运行
    • +
    +
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/2022-11-30-Constant%20Throughput%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/2022-11-30-Gaussian Random Timer\345\256\232\346\227\266\345\231\250/index.html" "b/2022/11/30/jmeter/2022-11-30-Gaussian Random Timer\345\256\232\346\227\266\345\231\250/index.html" new file mode 100644 index 000000000..125808680 --- /dev/null +++ "b/2022/11/30/jmeter/2022-11-30-Gaussian Random Timer\345\256\232\346\227\266\345\231\250/index.html" @@ -0,0 +1,175 @@ +Gaussian Random Timer定时器 | Research • 呓语 + + + + + + + + + + + + +

Gaussian Random Timer定时器

作用

生成随机等待时间

+

参数

    +
  • Deviation(in milliseconds):高斯定时器参数,随机的
  • +
  • Constant Delay Offset(in milliseconds):固定等待时长
  • +
+

生成的时长是Deviation + Constant Delay Offset

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/2022-11-30-Gaussian%20Random%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/2022-11-30-\345\220\216\347\275\256\345\244\204\347\220\206\345\231\250\344\271\213\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\244\204\347\220\206\345\231\250/index.html" "b/2022/11/30/jmeter/2022-11-30-\345\220\216\347\275\256\345\244\204\347\220\206\345\231\250\344\271\213\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\244\204\347\220\206\345\231\250/index.html" new file mode 100644 index 000000000..cef302b23 --- /dev/null +++ "b/2022/11/30/jmeter/2022-11-30-\345\220\216\347\275\256\345\244\204\347\220\206\345\231\250\344\271\213\346\255\243\345\210\231\350\241\250\350\276\276\345\274\217\345\244\204\347\220\206\345\231\250/index.html" @@ -0,0 +1,178 @@ +Regular Expression Extractor正则表达式处理器 | Research • 呓语 + + + + + + + + + + + + +

Regular Expression Extractor正则表达式处理器

正则表达式规则

    +
  • ():括起来的部分是要提取的
  • +
  • .:匹配任何字符串
  • +
  • +:一次或多次
  • +
  • ?:在找到第一个匹配项后停止
  • +
+

模板

2$等,表示解析到的第几个值给title,$1$表示第一个

+

匹配数字

0代表随机,1代表全部取值,通常使用0

+

缺省值

若参数没有取到值,那默认给一个值让他取

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/2022-11-30-%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%E4%B9%8B%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%A4%84%E7%90%86%E5%99%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/2022-12-1-Groovy\347\274\226\345\206\231\346\226\271\346\263\225/index.html" "b/2022/11/30/jmeter/2022-12-1-Groovy\347\274\226\345\206\231\346\226\271\346\263\225/index.html" new file mode 100644 index 000000000..9201d9d62 --- /dev/null +++ "b/2022/11/30/jmeter/2022-12-1-Groovy\347\274\226\345\206\231\346\226\271\346\263\225/index.html" @@ -0,0 +1,189 @@ +Groovy编写方法 | Research • 呓语 + + + + + + + + + + + + +

Groovy编写方法

关键字:

    +
  • log:写入信息到jmeterlog文件,使用方法:log.info(*Thisisloginfo
  • +
  • ctx:该变量引用了当前线程的上下文,使用方法可参考:org.apache.imeter.threads.JMeterContext。
  • +
  • vars-(JMeterVariables):操作imeter变量,这个变量实际引用了JMeter线程中的局部变量容器(本质上是Map),它是测试用例与BeanShell交互的桥梁,
    常用方法:
      +
    • a)vars.get(Stringkey):从imeter中获得变量值
    • +
    • b)vars.put(Stringkey,Stringvalue):数据存到imeter变量中
      更多方法可参考:org.apache.imeter.threads.JMeterVariables
    • +
    +
  • +
  • props-(JMeterProperties-classjava.util.Properties):操作imeter属性,该变量引用了JMeter的配置信息,可以获取Jmeter的属性,它的使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。
    对应于iava.util.Properties。
      +
    • a)props.get(“START.HMS”); 注:START.HMS为属性名,在文件imeter.properties中定义
    • +
    • b)props.put(“PROP1”,”1234”);
    • +
    +
  • +
  • prey-(SampleResult):获取前面的sample返回的信息,
    常用方法:
      +
    • a)getResponseDataAsString():获取响应信息
    • +
    • b)getResponseCode():获取响应code
      更多方法可参考:org.apache.imeter.samplers.SampleResult
    • +
    +
  • +
  • sampler-(Sampler):gives access to the current sampler
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/2022-12-1-Groovy%E7%BC%96%E5%86%99%E6%96%B9%E6%B3%95/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Arrivals Thread Group\347\232\204\344\275\277\347\224\250/index.html" "b/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Arrivals Thread Group\347\232\204\344\275\277\347\224\250/index.html" new file mode 100644 index 000000000..3c7810c6f --- /dev/null +++ "b/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Arrivals Thread Group\347\232\204\344\275\277\347\224\250/index.html" @@ -0,0 +1,184 @@ +Arrivals Thread Group的使用 | Research • 呓语 + + + + + + + + + + + + +

Arrivals Thread Group的使用

前提

    +
  • 安装插件,下载Custom Thread Groupsan插件

    +
  • +
  • 添加Arrivals Thread Group

    +
  • +
+

配置

    +
  • Target Rate (arrivals/sec) : 相当于QPS, 输入10就是10QPS
  • +
  • Ramp Up Time (sec) : 在多少秒内达到最大的QPS,4代表在4秒内获得最大的QPS
  • +
  • Ramp-Up Steps Count : 代表并发数,4代表实现4次的并发
  • +
  • Hold Target Rate Time (sec) : 对系统压多长时间就输入多长时间 ,10代表压上10s
  • +
  • Concurrency Limit : 最大启动多少线程,100代表最多启动100线程
  • +
+
+ +
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Arrivals%20Thread%20Group%E7%9A%84%E4%BD%BF%E7%94%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Ultimate Thread Group\347\232\204\344\275\277\347\224\250/index.html" "b/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Ultimate Thread Group\347\232\204\344\275\277\347\224\250/index.html" new file mode 100644 index 000000000..d9b53ca38 --- /dev/null +++ "b/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Ultimate Thread Group\347\232\204\344\275\277\347\224\250/index.html" @@ -0,0 +1,185 @@ +Ultimate Thread Group的使用 | Research • 呓语 + + + + + + + + + + + + +

Ultimate Thread Group的使用

前提

    +
  • 安装插件,下载Custom Thread Groupsan插件

    +
  • +
  • 添加Ultimate Thread Group

    +
  • +
+

配置

    +
  • Start Threads Count : 线程数
  • +
  • Initial Delay,sec : 线程延迟启动,0指的是立即启动;5代表五秒后启动
  • +
  • Startup Time,sec : 线程及时启动,0代表立即启动,5代表五秒之内启动完成
  • +
  • Hold Load For,sec : 启动后运行的时间,120代表运行120秒
  • +
  • Shutdown Time : 代表运行结束后停止的时间,0代表运行结束后立即停止,5代表运行结束后五秒内停止
  • +
+
+ +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/11/30/jmeter/jmeter_plugins/2022-12-07-Ultimate%20Thread%20Group%E7%9A%84%E4%BD%BF%E7%94%A8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/12/01/project/2022-12-1-\346\220\255\345\273\272\347\241\254\344\273\266\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" "b/2022/12/01/project/2022-12-1-\346\220\255\345\273\272\347\241\254\344\273\266\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" new file mode 100644 index 000000000..8a68f46b5 --- /dev/null +++ "b/2022/12/01/project/2022-12-1-\346\220\255\345\273\272\347\241\254\344\273\266\346\200\247\350\203\275\347\233\221\346\216\247\345\271\263\345\217\260/index.html" @@ -0,0 +1,195 @@ +硬件性能监控平台 | Research • 呓语 + + + + + + + + + + + + +

硬件性能监控平台

拉取prometheus镜像

1
docker pull prom/prometheus
+

创建prometheus容器并启动

1
docker run -itd --name=docker_prometheus --restart=always -p 3090:9090 -v /opt/prometheus:/ prom/prometheus
+

验证

+

通过浏览器访问http://ip:3090进行访问

+

方法一:服务器上直接安装node_export

首先,用浏览器访问:node_export 下载,然后上传到被监控的服务器并解压
进入解压文件夹,直接启动./node_exporter

+

方法二:拉取docker node_export镜像

1
docker pull prom/node-exporter
+

创建node_export容器并启动

1
2
3
4
5
6
7
docker run -itd --name=node-exporter \
--restart=always \
-p 9100:9100 \
-v "/proc:/host/proc:ro" \
-v "/sys:/host/sys:ro" \
-v "/:/rootfs:ro" \
prom/node-exporter
+

验证

+

在浏览器访问http://ip:9100/metrics进行访问

+

配置prometheus + node_export

node_export的作用收集硬件数据

+

使用vim修改yum文件容器内:/etc/prometheus/prometheus.yml

+
1
2
3
4
5
6
7
8
9
10
11
12
scrape_configs:
- job_name: prometheus
static_configs:
- targets: ['localhost:9090']
labels:
instance: prometheus

- job_name: linux
static_configs:
- targets: ['被监控的服务器ip:9100']
labels:
instance: localhost
+

重启prometheus容器

1
docker restart docker_prometheus
+

配置Grafana

使用Grafana下载版本

+

配置数据源

    +
  • 数据源:选择prometheus

    +
  • +
  • URL输入http://prometheus机器ip:3090

    +
  • +
  • 点击Save & Test保存

    +
  • +
+

添加仪表盘

使用官方仪表盘进行下载仪表盘
导入仪表盘
import via grafana.com输入框输入模板ID12884

+

ID:12633也可以使用。

+

点击 load,然后底部选择刚弄的数据源,点击import

+

注意:
点击json下载12884的json文件

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/12/01/project/2022-12-1-%E6%90%AD%E5%BB%BA%E7%A1%AC%E4%BB%B6%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B9%B3%E5%8F%B0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/12/07/java/2022-12-07-\345\214\205\350\243\205\347\261\273/index.html" "b/2022/12/07/java/2022-12-07-\345\214\205\350\243\205\347\261\273/index.html" new file mode 100644 index 000000000..2ec5c081e --- /dev/null +++ "b/2022/12/07/java/2022-12-07-\345\214\205\350\243\205\347\261\273/index.html" @@ -0,0 +1,265 @@ +包装类 | Research • 呓语 + + + + + + + + + + + + +

包装类

    +
  • 基本数据类型对应的包装类
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
基本数据类型包装类大小(字节)
byteByte1—(-128~127)
shortShort2—(-32768~32767)
intInteger4
longLong8
floatFloat4
doubleDouble8
charCharacter2
booleanBoolean1
+
+

包装类方法

    +
  • Integer的作用主要是对int、Integer、String几种类型的数据进行转换,还能获取一些常量
  • +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法描述
compareTo()用于将对象与方法的参数进行比较(相同类型)
decode()将方法的参数转为包装类对象
equals()判断对象是否与参数相等
Integer.parseInt(“字符串’)将字符串转为Int类型
Integer.toString(int数据)将Int类型转为字符串
+
+

compareTo()方法

    +
  • 如果指定的数与参数相等返回 0。
  • +
  • 如果指定的数小于参数返回 -1。
  • +
  • 如果指定的数大于参数返回 1。
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/12/07/java/2022-12-07-%E5%8C%85%E8%A3%85%E7%B1%BB/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/12/07/java/2022-12-07-\345\255\227\347\254\246\344\270\262/index.html" "b/2022/12/07/java/2022-12-07-\345\255\227\347\254\246\344\270\262/index.html" new file mode 100644 index 000000000..3003cb66a --- /dev/null +++ "b/2022/12/07/java/2022-12-07-\345\255\227\347\254\246\344\270\262/index.html" @@ -0,0 +1,215 @@ +字符串 | Research • 呓语 + + + + + + + + + + + + +

字符串

字符串的方法

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
方法描述
str.concat()将参数拼接到字符串上
trim()去除字符串两端的字符串,不能去除中间
replace(oldChar, newChar)将字符串的old参数替换为new参数
length()返回此字符串的长度
isEmpty()判断字符串是否为空
+
+

concat()方法

    +
  • 返回字符串类型
  • +
  • 字符串在后面拼接

    +
    1
    2
    3
    String str = "床前明月光";
    String str1 = str.concat("疑是地上霜。");
    System.out.println(str1);
    +

    trim()方法

    1
    2
    3
    String str = "    床  前明   月光   ";
    String str1 = str.trim();
    System.out.println(str1);
    +

    replace(oldChar, newChar)方法

    1
    2
    3
    String str = "床前明月光";
    String str1 = str.replace("床", "llll");
    System.out.println(str1);
    +

    length()方法

  • +
  • 返回int类型

    +
    1
    2
    3
    String str = "床前明月光";
    int str1 = str.length();
    System.out.println(str1);
    +

    isEmpty()方法

  • +
  • 返回布尔类型

    +
    1
    2
    3
    String str = "床前明月光";
    boolean str1 = str.isEmpty();
    System.out.println(str1);
    +
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/12/07/java/2022-12-07-%E5%AD%97%E7%AC%A6%E4%B8%B2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/12/07/java/2022-12-07-\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243/index.html" "b/2022/12/07/java/2022-12-07-\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243/index.html" new file mode 100644 index 000000000..d68d9cecd --- /dev/null +++ "b/2022/12/07/java/2022-12-07-\346\212\275\350\261\241\347\261\273\344\270\216\346\216\245\345\217\243/index.html" @@ -0,0 +1,183 @@ +抽象类与接口 | Research • 呓语 + + + + + + + + + + + + +

抽象类与接口

抽象类

使用abstract修饰一个类,把这个类变成抽象类,抽象类不能直接创建对象,需要其他类进行继承该抽象类

+
    +
  • 抽象方法不能有方法体
  • +
  • 抽象方法必须使用abstract进行修饰,不能有方法体
  • +
  • 子类必须实现父抽象类的方法

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public abstract class Ahsse {
    String name;
    int age;

    //普通方法
    public String aaa(){
    return name;
    };
    // 抽象方法
    public abstract String bbb();
    }

    class sss extends Ahsse{

    @Override
    public String bbb() {
    System.out.println("实现抽象类的抽象方法");
    return "ces ";
    }
    }
    +

    接口

    使用interface定义接口,相当于class

    +
  • +
  • 接口可以多继承

    +
  • +
  • 变量全部默认使用public static final修饰,使用之前必须赋值
  • +
  • 类里面全部是抽象方法(默认使用public abstract修饰,没有方法体)需要被实现类进行实现
  • +
  • 接口可以被多实现—implements
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/12/07/java/2022-12-07-%E6%8A%BD%E8%B1%A1%E7%B1%BB%E4%B8%8E%E6%8E%A5%E5%8F%A3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2022/12/07/java/2022-12-07-\347\273\247\346\211\277\343\200\201\351\207\215\345\206\231\344\270\216\351\207\215\350\275\275/index.html" "b/2022/12/07/java/2022-12-07-\347\273\247\346\211\277\343\200\201\351\207\215\345\206\231\344\270\216\351\207\215\350\275\275/index.html" new file mode 100644 index 000000000..136a246f4 --- /dev/null +++ "b/2022/12/07/java/2022-12-07-\347\273\247\346\211\277\343\200\201\351\207\215\345\206\231\344\270\216\351\207\215\350\275\275/index.html" @@ -0,0 +1,208 @@ +继承、重写与重载 | Research • 呓语 + + + + + + + + + + + + +

继承、重写与重载

继承

继承是相对于类来说,通过关键字extends来实现

+
    +
  • 可以获取父类的属性和方法
  • +
  • 提高代码的复用性
  • +
  • 父类修改了内容,子类也会修改

    +

    调用

    父类的属性和方法

    +
  • +
  • this表示当前对象的引用

    +
  • +
  • super表示父类对象的引用
  • +
  • 调用构造方法
      +
    • this(参数列表)表示调用当前类中的构造方法
    • +
    • super(参数列表)表示调用父类的构造方法,必须放在方法中的第一行
    • +
    +
  • +
  • 调用属性
      +
    • this.属性表示调用当前对象的属性
    • +
    • super.属性表示调用父类的属性,可以拿到被重写之前的数据
    • +
    +
  • +
  • 调用方法

    +
      +
    • this.方法表示调用当前对象的方法
    • +
    • super.方法表示调用父类的方法,可以拿到被重写之前的方法,不用放在代码的第一行

      重写

      重写是子类可以重写父类的方法,使用override标识
    • +
    +
  • +
  • 方法名和参数不变,只修改方法体

    +
  • +
  • 访问权限不能比父类的范围更小
  • +
  • 私有的方法能被子类继承,但不能使用和重写
  • +
  • 静态的方法能被子类继承,能使用但不能被重写

    +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class testeass {

    public void aa(String name, int age){
    System.out.println(name + age);
    }
    }

    class testaaa extends testeass{

    @Override
    public void aa(String name, int age) {
    System.out.println("这是重写方法,方法名、参数和返回数据都不变,只能修改方法体");
    System.out.println(name + age);
    }
    }
    +

    重载

    重载是同一个类下对方法进行重载

    +
  • +
  • 方法名相同,参数不相同 (参数个数不同/参数类型不同/参数排列顺序不同)

    +
  • +
  • 返回类型不限制
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class jichu {

    // 原方法
    public void hello(String name, int aa){
    System.out.println("拼接起来的值是:"+ name + aa );
    }

    // 重载后的方法
    public void hello(int aa, String name){
    System.out.println("aaaaaaa:" + aa);
    }
    }
    +
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2022/12/07/java/2022-12-07-%E7%BB%A7%E6%89%BF%E3%80%81%E9%87%8D%E5%86%99%E4%B8%8E%E9%87%8D%E8%BD%BD/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/2023/09/11/English/english-1/index.html b/2023/09/11/English/english-1/index.html new file mode 100644 index 000000000..a034eb7fb --- /dev/null +++ b/2023/09/11/English/english-1/index.html @@ -0,0 +1,169 @@ +2023立的flag | Research • 呓语 + + + + + + + + + + + + +

2023立的flag

文章作者: Gglss
文章链接: https://gglss.gitee.io/2023/09/11/English/english-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/2023/09/11/\347\233\256\346\240\207&\344\274\230\345\214\226/2023\347\233\256\346\240\207/index.html" "b/2023/09/11/\347\233\256\346\240\207&\344\274\230\345\214\226/2023\347\233\256\346\240\207/index.html" new file mode 100644 index 000000000..ea54ea675 --- /dev/null +++ "b/2023/09/11/\347\233\256\346\240\207&\344\274\230\345\214\226/2023\347\233\256\346\240\207/index.html" @@ -0,0 +1,177 @@ +2023立的flag | Research • 呓语 + + + + + + + + + + + + +

2023立的flag

目前所拥有的进度

    +
  • 考研恋练有词必背词全部背锅一边

    +
  • +
  • 自动化测试已部署

    +
  • +
  • +
  • +
+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2023/09/11/%E7%9B%AE%E6%A0%87&%E4%BC%98%E5%8C%96/2023%E7%9B%AE%E6%A0%87/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
公告
This is my Blog
最新文章
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
包装类
包装类
字符串
字符串
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/2023/10/07/hello-world/index.html b/2023/10/07/hello-world/index.html new file mode 100644 index 000000000..c96853dd2 --- /dev/null +++ b/2023/10/07/hello-world/index.html @@ -0,0 +1,177 @@ +Hello World | Research • 呓语 + + + + + + + + + + + +

Hello World

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

+

Quick Start

Create a new post

1
$ hexo new "My New Post"
+

More info: Writing

+

Run server

1
$ hexo server
+

More info: Server

+

Generate static files

1
$ hexo generate
+

More info: Generating

+

Deploy to remote sites

1
$ hexo deploy
+

More info: Deployment

+
文章作者: Gglss
文章链接: https://gglss.gitee.io/2023/10/07/hello-world/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Research • 呓语
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/about/index.html b/about/index.html new file mode 100644 index 000000000..adb3c1564 --- /dev/null +++ b/about/index.html @@ -0,0 +1,193 @@ +关于 | Research • 呓语 + + + + + + + + + + + +

浅言

喜欢学习技术的测试工程师.

这个博客主要记录学习的技术,一方面是帮助别人学习,另一方面也是留给自己方便回顾和查找。
+

联系我的方式

    +
  1. 邮箱:2302209664@qq.com 或直接用这个QQ号联系我,请注明来意
  2. +
  3. GitHub账号:https://github.com/gglss 项目都在里面
  4. +
+

近况与学习计划

    +
  1. 学Java,学Go
  2. +
  3. 编写python自动化测试框架
  4. +
+

接下来文章的方向

    +
  1. Python
  2. +
  3. go
  4. +
  5. Java源码
  6. +
  7. 测试分享
  8. +
+

目标

    +
  1. 学习更好的技术
  2. +
+
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/08/index.html b/archives/2022/08/index.html new file mode 100644 index 000000000..bf1a7ad2b --- /dev/null +++ b/archives/2022/08/index.html @@ -0,0 +1,171 @@ +八月 2022 | Research • 呓语 + + + + + + + +
文章总览 - 36
2022
如何使用pyyaml获取yaml里面的数据
如何使用pyyaml获取yaml里面的数据
Shell函数
Shell函数
Shell工具(一)
Shell工具(一)
Shell条件判断
Shell条件判断
Shell流程控制
Shell流程控制
Shell运算符
Shell运算符
Shell工具(二)
Shell工具(二)
Shell脚本初探
Shell脚本初探
Shell变量
Shell变量
Shell脚本入门
Shell脚本入门
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/08/page/2/index.html b/archives/2022/08/page/2/index.html new file mode 100644 index 000000000..7cbe31755 --- /dev/null +++ b/archives/2022/08/page/2/index.html @@ -0,0 +1,171 @@ +八月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/08/page/3/index.html b/archives/2022/08/page/3/index.html new file mode 100644 index 000000000..9262518bd --- /dev/null +++ b/archives/2022/08/page/3/index.html @@ -0,0 +1,171 @@ +八月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/08/page/4/index.html b/archives/2022/08/page/4/index.html new file mode 100644 index 000000000..141d9783c --- /dev/null +++ b/archives/2022/08/page/4/index.html @@ -0,0 +1,171 @@ +八月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/09/index.html b/archives/2022/09/index.html new file mode 100644 index 000000000..31fdea5a0 --- /dev/null +++ b/archives/2022/09/index.html @@ -0,0 +1,171 @@ +九月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/10/index.html b/archives/2022/10/index.html new file mode 100644 index 000000000..7b6add34a --- /dev/null +++ b/archives/2022/10/index.html @@ -0,0 +1,171 @@ +十月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/11/index.html b/archives/2022/11/index.html new file mode 100644 index 000000000..4865810fc --- /dev/null +++ b/archives/2022/11/index.html @@ -0,0 +1,171 @@ +十一月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/11/page/2/index.html b/archives/2022/11/page/2/index.html new file mode 100644 index 000000000..4c792e856 --- /dev/null +++ b/archives/2022/11/page/2/index.html @@ -0,0 +1,171 @@ +十一月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/11/page/3/index.html b/archives/2022/11/page/3/index.html new file mode 100644 index 000000000..121d88191 --- /dev/null +++ b/archives/2022/11/page/3/index.html @@ -0,0 +1,171 @@ +十一月 2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/12/index.html b/archives/2022/12/index.html new file mode 100644 index 000000000..84f75809c --- /dev/null +++ b/archives/2022/12/index.html @@ -0,0 +1,171 @@ +十二月 2022 | Research • 呓语 + + + + + + + +
文章总览 - 5
2022
包装类
包装类
字符串
字符串
抽象类与接口
抽象类与接口
继承、重写与重载
继承、重写与重载
硬件性能监控平台
硬件性能监控平台
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/index.html b/archives/2022/index.html new file mode 100644 index 000000000..7111343fe --- /dev/null +++ b/archives/2022/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/2/index.html b/archives/2022/page/2/index.html new file mode 100644 index 000000000..220028178 --- /dev/null +++ b/archives/2022/page/2/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/3/index.html b/archives/2022/page/3/index.html new file mode 100644 index 000000000..5df2d9301 --- /dev/null +++ b/archives/2022/page/3/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/4/index.html b/archives/2022/page/4/index.html new file mode 100644 index 000000000..be37e94b3 --- /dev/null +++ b/archives/2022/page/4/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/5/index.html b/archives/2022/page/5/index.html new file mode 100644 index 000000000..98d30e467 --- /dev/null +++ b/archives/2022/page/5/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/6/index.html b/archives/2022/page/6/index.html new file mode 100644 index 000000000..f667be372 --- /dev/null +++ b/archives/2022/page/6/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/7/index.html b/archives/2022/page/7/index.html new file mode 100644 index 000000000..3b7f8bca4 --- /dev/null +++ b/archives/2022/page/7/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/8/index.html b/archives/2022/page/8/index.html new file mode 100644 index 000000000..e2d9b228f --- /dev/null +++ b/archives/2022/page/8/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2022/page/9/index.html b/archives/2022/page/9/index.html new file mode 100644 index 000000000..6f6438327 --- /dev/null +++ b/archives/2022/page/9/index.html @@ -0,0 +1,171 @@ +2022 | Research • 呓语 + + + + + + + +
文章总览 - 83
2022
使用jmeter录制压测
使用jmeter录制压测
Yaml的使用
Yaml的使用
性能测试主要关注点
性能测试主要关注点
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2023/09/index.html b/archives/2023/09/index.html new file mode 100644 index 000000000..7004a0f12 --- /dev/null +++ b/archives/2023/09/index.html @@ -0,0 +1,171 @@ +九月 2023 | Research • 呓语 + + + + + + + +
文章总览 - 2
2023
2023立的flag
2023立的flag
2023立的flag
2023立的flag
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2023/10/index.html b/archives/2023/10/index.html new file mode 100644 index 000000000..4dcdffa8f --- /dev/null +++ b/archives/2023/10/index.html @@ -0,0 +1,171 @@ +十月 2023 | Research • 呓语 + + + + + + + +
文章总览 - 1
2023
Hello World
Hello World
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 000000000..d8c3693c7 --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,171 @@ +2023 | Research • 呓语 + + + + + + + +
文章总览 - 3
2023
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 000000000..ec77bd77f --- /dev/null +++ b/archives/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
文章总览 - 86
2023
Hello World
Hello World
2023立的flag
2023立的flag
2023立的flag
2023立的flag
2022
包装类
包装类
字符串
字符串
抽象类与接口
抽象类与接口
继承、重写与重载
继承、重写与重载
硬件性能监控平台
硬件性能监控平台
Constant Throughput Timer定时器
Constant Throughput Timer定时器
Gaussian Random Timer定时器
Gaussian Random Timer定时器
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 000000000..3595645ab --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 000000000..b59dbc2a0 --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 000000000..4064c7907 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/5/index.html b/archives/page/5/index.html new file mode 100644 index 000000000..9c03f5d13 --- /dev/null +++ b/archives/page/5/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/6/index.html b/archives/page/6/index.html new file mode 100644 index 000000000..7dae2f0f8 --- /dev/null +++ b/archives/page/6/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
文章总览 - 86
2022
如何使用pyyaml获取yaml里面的数据
如何使用pyyaml获取yaml里面的数据
Shell函数
Shell函数
Shell工具(一)
Shell工具(一)
Shell条件判断
Shell条件判断
Shell流程控制
Shell流程控制
Shell运算符
Shell运算符
Shell工具(二)
Shell工具(二)
Shell脚本初探
Shell脚本初探
Shell变量
Shell变量
Shell脚本入门
Shell脚本入门
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/7/index.html b/archives/page/7/index.html new file mode 100644 index 000000000..62a9d5634 --- /dev/null +++ b/archives/page/7/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/8/index.html b/archives/page/8/index.html new file mode 100644 index 000000000..8c23ce21b --- /dev/null +++ b/archives/page/8/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/archives/page/9/index.html b/archives/page/9/index.html new file mode 100644 index 000000000..3d3233a76 --- /dev/null +++ b/archives/page/9/index.html @@ -0,0 +1,171 @@ +归档 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 000000000..7745013b4 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,173 @@ +分类 | Research • 呓语 + + + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\345\255\246\344\271\240\346\227\245\345\270\270/index.html" "b/categories/\345\255\246\344\271\240\346\227\245\345\270\270/index.html" new file mode 100644 index 000000000..0f0bf07da --- /dev/null +++ "b/categories/\345\255\246\344\271\240\346\227\245\345\270\270/index.html" @@ -0,0 +1,171 @@ +分类: 学习日常 | Research • 呓语 + + + + + + + +
分类 - 学习日常
2023
2023立的flag
2023立的flag
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" new file mode 100644 index 000000000..4ad540558 --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/index.html" @@ -0,0 +1,171 @@ +分类: 工具教程 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/2/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/2/index.html" new file mode 100644 index 000000000..e998af497 --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/2/index.html" @@ -0,0 +1,171 @@ +分类: 工具教程 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/3/index.html" "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/3/index.html" new file mode 100644 index 000000000..7fe19043b --- /dev/null +++ "b/categories/\345\267\245\345\205\267\346\225\231\347\250\213/page/3/index.html" @@ -0,0 +1,171 @@ +分类: 工具教程 | Research • 呓语 + + + + + + + +
分类 - 工具教程
2022
使用jmeter录制压测
使用jmeter录制压测
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\224\237\346\264\273\346\227\245\345\270\270/index.html" "b/categories/\347\224\237\346\264\273\346\227\245\345\270\270/index.html" new file mode 100644 index 000000000..573338c27 --- /dev/null +++ "b/categories/\347\224\237\346\264\273\346\227\245\345\270\270/index.html" @@ -0,0 +1,171 @@ +分类: 生活日常 | Research • 呓语 + + + + + + + +
分类 - 生活日常
2023
2023立的flag
2023立的flag
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/index.html" new file mode 100644 index 000000000..f969b7b3d --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/2/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/2/index.html" new file mode 100644 index 000000000..54d95981e --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/2/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/3/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/3/index.html" new file mode 100644 index 000000000..afcadcac9 --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/3/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/4/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/4/index.html" new file mode 100644 index 000000000..94ae5336b --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/4/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/5/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/5/index.html" new file mode 100644 index 000000000..c9acdf9d3 --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/5/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/6/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/6/index.html" new file mode 100644 index 000000000..77e105c49 --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/6/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git "a/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/7/index.html" "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/7/index.html" new file mode 100644 index 000000000..677f0f3d1 --- /dev/null +++ "b/categories/\347\273\217\351\252\214\345\210\206\344\272\253/page/7/index.html" @@ -0,0 +1,171 @@ +分类: 经验分享 | Research • 呓语 + + + + + + + +
分类 - 经验分享
2022
Yaml的使用
Yaml的使用
性能测试主要关注点
性能测试主要关注点
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/css/index.css b/css/index.css new file mode 100644 index 000000000..408307b08 --- /dev/null +++ b/css/index.css @@ -0,0 +1,6172 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html { + line-height: 1.15; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +main { + display: block +} + +h1 { + font-size: 2em; + margin: .67em 0 +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible +} + +pre { + font-family: monospace, monospace; + font-size: 1em +} + +a { + background-color: transparent +} + +abbr[title] { + border-bottom: none; + text-decoration: underline; + text-decoration: underline dotted +} + +b, +strong { + font-weight: bolder +} + +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em +} + +small { + font-size: 80% +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sub { + bottom: -.25em +} + +sup { + top: -.5em +} + +img { + border-style: none +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0 +} + +button, +input { + overflow: visible +} + +button, +select { + text-transform: none +} + +[type=button], +[type=reset], +[type=submit], +button { + -webkit-appearance: button +} + +[type=button]::-moz-focus-inner, +[type=reset]::-moz-focus-inner, +[type=submit]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0 +} + +[type=button]:-moz-focusring, +[type=reset]:-moz-focusring, +[type=submit]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText +} + +fieldset { + padding: .35em .75em .625em +} + +legend { + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal +} + +progress { + vertical-align: baseline +} + +textarea { + overflow: auto +} + +[type=checkbox], +[type=radio] { + box-sizing: border-box; + padding: 0 +} + +[type=number]::-webkit-inner-spin-button, +[type=number]::-webkit-outer-spin-button { + height: auto +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px +} + +[type=search]::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit +} + +details { + display: block +} + +summary { + display: list-item +} + +template { + display: none +} + +[hidden] { + display: none +} +.limit-one-line, +#article-container .flink .flink-item-name, +#article-container .flink .flink-item-desc, +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span, +.site-data > a .headline, +#nav #blog-info, +.layout .prev_info, +.layout .next_info, +#sidebar #sidebar-menus .menus_items .site-page { + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} +.limit-more-line, +.article-sort-item-title, +#recent-posts > .recent-post-item >.recent-post-info > .article-title, +#recent-posts > .recent-post-item >.recent-post-info > .content, +#aside-content .aside-list > .aside-list-item .content > .name, +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment, +#post-info .post-title, +.relatedPosts > .relatedPosts-list .content .title, +#article-container figure.gallery-group p, +#article-container figure.gallery-group .gallery-group-name { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; +} +.fontawesomeIcon, +.custom-hr:before, +span.categoryBar-list-count::before, +#article-container.post-content h1:before, +#article-container.post-content h2:before, +#article-container.post-content h3:before, +#article-container.post-content h4:before, +#article-container.post-content h5:before, +#article-container.post-content h6:before, +#article-container.post-content hr:before, +#post .post-copyright:before, +#post .post-outdate-notice:before, +.note:not(.no-icon)::before, +.search-dialog hr:before { + display: inline-block; + font-weight: 600; + font-family: 'Font Awesome 6 Free'; + text-rendering: auto; + -webkit-font-smoothing: antialiased; +} +.cardHover, +.layout > div:first-child:not(.recent-posts), +#recent-posts > .recent-post-item, +#aside-content .card-widget { + border-radius: 8px; + background: var(--card-bg); + -webkit-box-shadow: var(--card-box-shadow); + box-shadow: var(--card-box-shadow); + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.cardHover:hover, +.layout > div:first-child:not(.recent-posts):hover, +#recent-posts > .recent-post-item:hover, +#aside-content .card-widget:hover { + -webkit-box-shadow: var(--card-hover-box-shadow); + box-shadow: var(--card-hover-box-shadow); +} +.imgHover, +.article-sort-item-img :first-child, +#recent-posts > .recent-post-item .post_cover .post-bg, +#aside-content .aside-list > .aside-list-item .thumbnail :first-child { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.6s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.6s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.6s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.6s; + transition: filter 375ms ease-in 0.2s, transform 0.6s; + object-fit: cover; +} +.imgHover:hover, +.article-sort-item-img :first-child:hover, +#recent-posts > .recent-post-item .post_cover .post-bg:hover, +#aside-content .aside-list > .aside-list-item .thumbnail :first-child:hover { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover:hover .cover, +.layout .prev-post:hover .cover, +.layout .next-post:hover .cover, +.relatedPosts > .relatedPosts-list > div:hover .cover { + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover .cover, +.layout .prev-post .cover, +.layout .next-post .cover, +.relatedPosts > .relatedPosts-list > div .cover { + position: absolute; + width: 100%; + height: 100%; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transition: all 0.6s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.6s, filter 375ms ease-in 0.2s; + -o-transition: all 0.6s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.6s, filter 375ms ease-in 0.2s; + transition: all 0.6s, filter 375ms ease-in 0.2s; + object-fit: cover; +} +.list-beauty, +.category-lists ul { + list-style: none; +} +.list-beauty li, +.category-lists ul li { + position: relative; + padding: 0.12em 0.4em 0.12em 1.4em; +} +.list-beauty li:hover:before, +.category-lists ul li:hover:before { + border-color: var(--pseudo-hover); +} +.list-beauty li:before, +.category-lists ul li:before { + position: absolute; + top: 0.67em; + left: 0; + width: 0.43em; + height: 0.43em; + border: 0.215em solid #49b1f5; + border-radius: 0.43em; + background: transparent; + content: ''; + cursor: pointer; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +.custom-hr, +#article-container.post-content hr, +.search-dialog hr { + position: relative; + margin: 40px auto; + border: 2px dashed var(--hr-border); + width: calc(100% - 4px); +} +.custom-hr:hover:before, +#article-container.post-content hr:hover:before, +.search-dialog hr:hover:before { + left: calc(95% - 20px); +} +.custom-hr:before, +#article-container.post-content hr:before, +.search-dialog hr:before { + position: absolute; + top: -10px; + left: 5%; + z-index: 1; + color: var(--hr-before-color); + content: '\f0c4'; + font-size: 20px; + line-height: 1; + -webkit-transition: all 1s ease-in-out; + -moz-transition: all 1s ease-in-out; + -o-transition: all 1s ease-in-out; + -ms-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; +} +#content-inner, +#footer { + -webkit-animation: bottom-top 1s; + -moz-animation: bottom-top 1s; + -o-animation: bottom-top 1s; + -ms-animation: bottom-top 1s; + animation: bottom-top 1s; +} +#page-header { + -webkit-animation: header-effect 1s; + -moz-animation: header-effect 1s; + -o-animation: header-effect 1s; + -ms-animation: header-effect 1s; + animation: header-effect 1s; +} +#site-title, +#site-subtitle { + -webkit-animation: titleScale 1s; + -moz-animation: titleScale 1s; + -o-animation: titleScale 1s; + -ms-animation: titleScale 1s; + animation: titleScale 1s; +} +#nav.show { + -webkit-animation: headerNoOpacity 1s; + -moz-animation: headerNoOpacity 1s; + -o-animation: headerNoOpacity 1s; + -ms-animation: headerNoOpacity 1s; + animation: headerNoOpacity 1s; +} +canvas:not(#ribbon-canvas), +#web_bg { + -webkit-animation: to_show 4s; + -moz-animation: to_show 4s; + -o-animation: to_show 4s; + -ms-animation: to_show 4s; + animation: to_show 4s; +} +#ribbon-canvas { + -webkit-animation: ribbon_to_show 4s; + -moz-animation: ribbon_to_show 4s; + -o-animation: ribbon_to_show 4s; + -ms-animation: ribbon_to_show 4s; + animation: ribbon_to_show 4s; +} +#sidebar-menus.open > :nth-child(1) { + -webkit-animation: sidebarItem 0.2s; + -moz-animation: sidebarItem 0.2s; + -o-animation: sidebarItem 0.2s; + -ms-animation: sidebarItem 0.2s; + animation: sidebarItem 0.2s; +} +#sidebar-menus.open > :nth-child(2) { + -webkit-animation: sidebarItem 0.4s; + -moz-animation: sidebarItem 0.4s; + -o-animation: sidebarItem 0.4s; + -ms-animation: sidebarItem 0.4s; + animation: sidebarItem 0.4s; +} +#sidebar-menus.open > :nth-child(3) { + -webkit-animation: sidebarItem 0.6s; + -moz-animation: sidebarItem 0.6s; + -o-animation: sidebarItem 0.6s; + -ms-animation: sidebarItem 0.6s; + animation: sidebarItem 0.6s; +} +#sidebar-menus.open > :nth-child(4) { + -webkit-animation: sidebarItem 0.8s; + -moz-animation: sidebarItem 0.8s; + -o-animation: sidebarItem 0.8s; + -ms-animation: sidebarItem 0.8s; + animation: sidebarItem 0.8s; +} +.scroll-down-effects { + -webkit-animation: scroll-down-effect 1.5s infinite; + -moz-animation: scroll-down-effect 1.5s infinite; + -o-animation: scroll-down-effect 1.5s infinite; + -ms-animation: scroll-down-effect 1.5s infinite; + animation: scroll-down-effect 1.5s infinite; +} +.reward-main { + -webkit-animation: donate_effcet 0.3s 0.1s ease both; + -moz-animation: donate_effcet 0.3s 0.1s ease both; + -o-animation: donate_effcet 0.3s 0.1s ease both; + -ms-animation: donate_effcet 0.3s 0.1s ease both; + animation: donate_effcet 0.3s 0.1s ease both; +} +@-moz-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-webkit-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-o-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-moz-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-moz-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-webkit-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-o-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-moz-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-moz-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-o-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-webkit-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-o-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +:root { + --global-font-size: 14px; + --global-bg: #fff; + --font-color: #4c4948; + --hr-border: #a4d8fa; + --hr-before-color: #80c8f8; + --search-bg: #f6f8fa; + --search-input-color: #4c4948; + --search-a-color: #4c4948; + --preloader-bg: #37474f; + --preloader-color: #fff; + --tab-border-color: #f0f0f0; + --tab-botton-bg: #f0f0f0; + --tab-botton-color: #1f2d3d; + --tab-button-hover-bg: #dcdcdc; + --tab-button-active-bg: #fff; + --card-bg: #fff; + --sidebar-bg: #f6f8fa; + --btn-hover-color: #ff7242; + --btn-color: #fff; + --btn-bg: #49b1f5; + --text-bg-hover: rgba(73,177,245,0.7); + --light-grey: #eee; + --dark-grey: #cacaca; + --white: #fff; + --text-highlight-color: #1f2d3d; + --blockquote-color: #6a737d; + --blockquote-bg: rgba(73,177,245,0.1); + --reward-pop: #f5f5f5; + --toc-link-color: #666261; + --card-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.05); + --card-hover-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.09); + --pseudo-hover: #ff7242; + --headline-presudo: #a0a0a0; + --scrollbar-color: #49b1f5; + --default-bg-color: #49b1f5; + --zoom-bg: #fff; + --mark-bg: rgba(0,0,0,0.3); +} +body { + position: relative; + min-height: 100%; + background: var(--global-bg); + color: var(--font-color); + font-size: var(--global-font-size); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif; + line-height: 2; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +*::-webkit-scrollbar { + width: 5px; + height: 5px; +} +*::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); +} +*::-webkit-scrollbar-track { + background-color: transparent; +} +* { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color) transparent; +} +input::placeholder { + color: var(--font-color); +} +#web_bg { + position: fixed; + z-index: -999; + width: 100%; + height: 100%; + background: -webkit-linear-gradient(270deg,#fff1eb,#ace0f9); + background: -moz-linear-gradient(270deg,#fff1eb,#ace0f9); + background: -o-linear-gradient(270deg,#fff1eb,#ace0f9); + background: -ms-linear-gradient(270deg,#fff1eb,#ace0f9); + background: linear-gradient(180deg,#fff1eb,#ace0f9); + background-attachment: local; + background-position: center; + background-size: cover; + background-repeat: no-repeat; +} +h1, +h2, +h3, +h4, +h5, +h6 { + position: relative; + margin: 20px 0 14px; + color: var(--text-highlight-color); + font-weight: bold; +} +h1 code, +h2 code, +h3 code, +h4 code, +h5 code, +h6 code { + font-size: inherit !important; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +.table-wrap { + overflow-x: scroll; + margin: 0 0 20px; +} +table { + display: table; + width: 100%; + border-spacing: 0; + border-collapse: collapse; + empty-cells: show; +} +table thead { + background: rgba(153,169,191,0.1); +} +table th, +table td { + padding: 6px 12px; + border: 1px solid var(--light-grey); + vertical-align: middle; +} +*::selection { + background: #00c4b6; + color: #f7f7f7; +} +button { + padding: 0; + outline: 0; + border: none; + background: none; + cursor: pointer; + touch-action: manipulation; +} +a { + color: #99a9bf; + text-decoration: none; + word-wrap: break-word; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -o-transition: all 0.2s; + -ms-transition: all 0.2s; + transition: all 0.2s; + overflow-wrap: break-word; +} +a:hover { + color: #49b1f5; +} +.is-center { + text-align: center; +} +.pull-left { + float: left; +} +.pull-right { + float: right; +} +img[src=''], +img:not([src]) { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.img-alt { + margin: -10px 0 10px; + color: #858585; +} +.img-alt:hover { + text-decoration: none !important; +} +blockquote { + margin: 0 0 20px; + padding: 12px 15px; + border-left: 3px solid #49b1f5; + background-color: var(--blockquote-bg); + color: var(--blockquote-color); +} +blockquote footer cite:before { + padding: 0 5px; + content: '—'; +} +blockquote > :last-child { + margin-bottom: 0 !important; +} +:root { + --hl-color: #90a4ae; + --hl-bg: #f6f8fa; + --hltools-bg: #e6ebf1; + --hltools-color: #90a4ae; + --hlnumber-bg: #f6f8fa; + --hlnumber-color: rgba(144,164,174,0.5); + --hlscrollbar-bg: #dce4eb; + --hlexpand-bg: linear-gradient(180deg, rgba(246,248,250,0.6), rgba(246,248,250,0.9)); +} +figure.highlight table { + scrollbar-color: var(--hlscrollbar-bg) transparent; +} +figure.highlight table::-webkit-scrollbar-thumb { + background: var(--hlscrollbar-bg); +} +figure.highlight pre .deletion { + color: #bf42bf; +} +figure.highlight pre .addition { + color: #105ede; +} +figure.highlight pre .meta { + color: #7c4dff; +} +figure.highlight pre .comment { + color: rgba(149,165,166,0.8); +} +figure.highlight pre .variable, +figure.highlight pre .attribute, +figure.highlight pre .regexp, +figure.highlight pre .ruby .constant, +figure.highlight pre .xml .tag .title, +figure.highlight pre .xml .pi, +figure.highlight pre .xml .doctype, +figure.highlight pre .html .doctype, +figure.highlight pre .css .id, +figure.highlight pre .tag .name, +figure.highlight pre .css .class, +figure.highlight pre .css .pseudo { + color: #e53935; +} +figure.highlight pre .tag { + color: #39adb5; +} +figure.highlight pre .number, +figure.highlight pre .preprocessor, +figure.highlight pre .literal, +figure.highlight pre .params, +figure.highlight pre .constant, +figure.highlight pre .command { + color: #f76d47; +} +figure.highlight pre .built_in { + color: #ffb62c; +} +figure.highlight pre .ruby .class .title, +figure.highlight pre .css .rules .attribute, +figure.highlight pre .string, +figure.highlight pre .value, +figure.highlight pre .inheritance, +figure.highlight pre .header, +figure.highlight pre .ruby .symbol, +figure.highlight pre .xml .cdata, +figure.highlight pre .special, +figure.highlight pre .number, +figure.highlight pre .formula { + color: #91b859; +} +figure.highlight pre .keyword, +figure.highlight pre .title, +figure.highlight pre .css .hexcolor { + color: #39adb5; +} +figure.highlight pre .function, +figure.highlight pre .python .decorator, +figure.highlight pre .python .title, +figure.highlight pre .ruby .function .title, +figure.highlight pre .ruby .title .keyword, +figure.highlight pre .perl .sub, +figure.highlight pre .javascript .title, +figure.highlight pre .coffeescript .title { + color: #6182b8; +} +figure.highlight pre .tag .attr, +figure.highlight pre .javascript .function { + color: #7c4dff; +} +#article-container figure.highlight .line.marked { + background-color: rgba(128,203,196,0.251); +} +#article-container figure.highlight table { + display: block; + overflow: auto; + border: none; +} +#article-container figure.highlight table td { + padding: 0; + border: none; +} +#article-container figure.highlight .gutter pre { + padding-right: 10px; + padding-left: 10px; + background-color: var(--hlnumber-bg); + color: var(--hlnumber-color); + text-align: right; +} +#article-container figure.highlight .code pre { + padding-right: 10px; + padding-left: 10px; + width: 100%; +} +#article-container pre, +#article-container figure.highlight { + overflow: auto; + margin: 0 0 20px; + padding: 0; + background: var(--hl-bg); + color: var(--hl-color); + line-height: 1.6; +} +#article-container pre, +#article-container code { + font-size: var(--global-font-size); + font-family: consolas, Menlo, 'PingFang SC', 'Microsoft YaHei', sans-serif !important; +} +#article-container code { + padding: 2px 4px; + background: rgba(27,31,35,0.05); + color: #f47466; +} +#article-container pre { + padding: 10px 20px; +} +#article-container pre code { + padding: 0; + background: none; + color: var(--hl-color); + text-shadow: none; +} +#article-container figure.highlight { + position: relative; +} +#article-container figure.highlight pre { + margin: 0; + padding: 8px 0; + border: none; +} +#article-container figure.highlight figcaption, +#article-container figure.highlight .caption { + padding: 6px 0 2px 14px; + font-size: var(--global-font-size); + line-height: 1em; +} +#article-container figure.highlight figcaption a, +#article-container figure.highlight .caption a { + float: right; + padding-right: 10px; + color: var(--hl-color); +} +#article-container figure.highlight figcaption a:hover, +#article-container figure.highlight .caption a:hover { + border-bottom-color: var(--hl-color); +} +#article-container figure.highlight.copy-true { + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; +} +#article-container figure.highlight.copy-true > table, +#article-container figure.highlight.copy-true > pre { + display: block !important; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container .highlight-tools { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + min-height: 24px; + height: 2.15em; + background: var(--hltools-bg); + color: var(--hltools-color); + font-size: var(--global-font-size); +} +#article-container .highlight-tools.closed ~ * { + display: none; +} +#article-container .highlight-tools .expand { + position: absolute; + padding: 0.57em 0.7em; + cursor: pointer; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#article-container .highlight-tools .expand + .code-lang { + left: 1.7em; +} +#article-container .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(-90deg) !important; + -moz-transform: rotate(-90deg) !important; + -o-transform: rotate(-90deg) !important; + -ms-transform: rotate(-90deg) !important; + transform: rotate(-90deg) !important; +} +#article-container .highlight-tools .code-lang { + position: absolute; + left: 14px; + text-transform: uppercase; + font-weight: bold; + font-size: 1.15em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .highlight-tools .copy-notice { + position: absolute; + right: 2.4em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s; + -moz-transition: opacity 0.4s; + -o-transition: opacity 0.4s; + -ms-transition: opacity 0.4s; + transition: opacity 0.4s; +} +#article-container .highlight-tools .copy-button { + position: absolute; + right: 14px; + cursor: pointer; + -webkit-transition: color 0.2s; + -moz-transition: color 0.2s; + -o-transition: color 0.2s; + -ms-transition: color 0.2s; + transition: color 0.2s; +} +#article-container .highlight-tools .copy-button:hover { + color: #49b1f5; +} +#article-container .gutter { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .gist table { + width: auto; +} +#article-container .gist table td { + border: none; +} +#article-container figure.highlight { + margin: 0 0 24px; + border-radius: 7px; + -webkit-box-shadow: 0 5px 10px 0 rgba(144,164,174,0.4); + box-shadow: 0 5px 10px 0 rgba(144,164,174,0.4); + -webkit-transform: translateZ(0); +} +#article-container figure.highlight .highlight-tools:after { + position: absolute; + left: 14px; + width: 12px; + height: 12px; + border-radius: 50%; + background: #fc625d; + -webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + content: ' '; +} +#article-container figure.highlight .highlight-tools .expand { + right: 0; +} +#article-container figure.highlight .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(90deg) !important; + -moz-transform: rotate(90deg) !important; + -o-transform: rotate(90deg) !important; + -ms-transform: rotate(90deg) !important; + transform: rotate(90deg) !important; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-notice { + right: 3.45em; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-button { + right: 2.1em; +} +#article-container figure.highlight .highlight-tools .code-lang { + left: 75px; +} +@-moz-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +.article-sort { + margin-left: 10px; + padding-left: 20px; + border-left: 2px solid #aadafa; +} +.article-sort-title { + position: relative; + margin-left: 10px; + padding-bottom: 20px; + padding-left: 20px; + font-size: 1.72em; +} +.article-sort-title:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-title:before { + position: absolute; + top: calc(((100% - 36px) / 2)); + left: -9px; + z-index: 1; + width: 10px; + height: 10px; + border: 5px solid #49b1f5; + border-radius: 10px; + background: var(--card-bg); + content: ''; + line-height: 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-title:after { + position: absolute; + bottom: 0; + left: 0; + z-index: 0; + width: 2px; + height: 1.5em; + background: #aadafa; + content: ''; +} +.article-sort-item { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + margin: 0 0 20px 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-item:before { + position: absolute; + left: calc(-20px - 17px); + width: 6px; + height: 6px; + border: 3px solid #49b1f5; + border-radius: 6px; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item.no-article-cover { + height: 80px; +} +.article-sort-item.no-article-cover .article-sort-item-info { + padding: 0; +} +.article-sort-item.year { + font-size: 1.43em; +} +.article-sort-item.year:hover:before { + border-color: #49b1f5; +} +.article-sort-item.year:before { + border-color: var(--pseudo-hover); +} +.article-sort-item-time { + color: #858585; + font-size: 95%; +} +.article-sort-item-time time { + padding-left: 6px; + cursor: default; +} +.article-sort-item-title { + color: var(--font-color); + font-size: 1.1em; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-line-clamp: 2; +} +.article-sort-item-title:hover { + color: #49b1f5; + -webkit-transform: translateX(10px); + -moz-transform: translateX(10px); + -o-transform: translateX(10px); + -ms-transform: translateX(10px); + transform: translateX(10px); +} +.article-sort-item-img { + overflow: hidden; + width: 80px; + height: 80px; +} +.article-sort-item-info { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 0 16px; +} +.category-lists .category-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .category-lists .category-title { + font-size: 2em; + } +} +.category-lists .category-list { + margin-bottom: 0; +} +.category-lists .category-list a { + color: var(--font-color); +} +.category-lists .category-list a:hover { + color: #49b1f5; +} +.category-lists .category-list .category-list-count { + margin-left: 8px; + color: #858585; +} +.category-lists .category-list .category-list-count:before { + content: '('; +} +.category-lists .category-list .category-list-count:after { + content: ')'; +} +.category-lists ul { + padding: 0 0 0 20px; +} +.category-lists ul ul { + padding-left: 4px; +} +.category-lists ul li { + position: relative; + margin: 6px 0; + padding: 0.12em 0.4em 0.12em 1.4em; +} +#body-wrap { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + min-height: 100vh; +} +.layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + margin: 0 auto; + padding: 40px 15px; + max-width: 1200px; + width: 100%; +} +@media screen and (max-width: 900px) { + .layout { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} +@media screen and (max-width: 768px) { + .layout { + padding: 20px 5px; + } +} +@media screen and (min-width: 2000px) { + .layout { + max-width: 70%; + } +} +.layout > div:first-child:not(.recent-posts) { + -webkit-align-self: flex-start; + align-self: flex-start; + -ms-flex-item-align: start; + padding: 50px 40px; +} +@media screen and (max-width: 768px) { + .layout > div:first-child:not(.recent-posts) { + padding: 36px 14px; + } +} +.layout > div:first-child { + width: 74%; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +@media screen and (max-width: 900px) { + .layout > div:first-child { + width: 100% !important; + } +} +@media screen and (min-width: 900px) { + .layout > div:first-child { + -webkit-box-ordinal-group: 2; + -moz-box-ordinal-group: 2; + -o-box-ordinal-group: 2; + -ms-flex-order: 2; + -webkit-order: 2; + order: 2; + } +} +.layout.hide-aside { + max-width: 1000px; +} +@media screen and (min-width: 2000px) { + .layout.hide-aside { + max-width: 1300px; + } +} +.layout.hide-aside > div { + width: 100% !important; +} +.apple #page-header.full_page { + background-attachment: scroll !important; +} +.apple .recent-post-item, +.apple .avatar-img, +.apple .flink-item-icon { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); +} +#article-container .flink { + margin-bottom: 20px; +} +#article-container .flink .flink-list { + overflow: auto; + padding: 10px 10px 0; + text-align: center; +} +#article-container .flink .flink-list > .flink-list-item { + position: relative; + float: left; + overflow: hidden; + margin: 15px 7px; + width: calc(100% / 3 - 15px); + height: 90px; + border-radius: 8px; + line-height: 17px; + -webkit-transform: translateZ(0); +} +@media screen and (max-width: 1024px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(50% - 15px) !important; + } +} +@media screen and (max-width: 600px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(100% - 15px) !important; + } +} +#article-container .flink .flink-list > .flink-list-item:hover .flink-item-icon { + margin-left: -10px; + width: 0; +} +#article-container .flink .flink-list > .flink-list-item:before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + background: var(--text-bg-hover); + content: ''; + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + -ms-transition: -ms-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + -webkit-transform: scale(0); + -moz-transform: scale(0); + -o-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); +} +#article-container .flink .flink-list > .flink-list-item:hover:before, +#article-container .flink .flink-list > .flink-list-item:focus:before, +#article-container .flink .flink-list > .flink-list-item:active:before { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); +} +#article-container .flink .flink-list > .flink-list-item a { + color: var(--font-color); + text-decoration: none; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon { + float: left; + overflow: hidden; + margin: 15px 10px; + width: 60px; + height: 60px; + border-radius: 35px; + -webkit-transition: width 0.3s ease-out; + -moz-transition: width 0.3s ease-out; + -o-transition: width 0.3s ease-out; + -ms-transition: width 0.3s ease-out; + transition: width 0.3s ease-out; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +#article-container .flink .flink-list > .flink-list-item a .img-alt { + display: none; +} +#article-container .flink .flink-item-name { + padding: 16px 10px 0 0; + height: 40px; + font-weight: bold; + font-size: 1.43em; +} +#article-container .flink .flink-item-desc { + padding: 16px 10px 16px 0; + height: 50px; + font-size: 0.93em; +} +#article-container .flink .flink-name { + margin-bottom: 5px; + font-weight: bold; + font-size: 1.5em; +} +#recent-posts > .recent-post-item:not(:first-child) { + margin-top: 20px; +} +#recent-posts > .recent-post-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + height: 16.8em; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + height: auto; + } +} +#recent-posts > .recent-post-item:hover img.post-bg { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +#recent-posts > .recent-post-item.ads-wrap { + display: block !important; + height: auto !important; +} +#recent-posts > .recent-post-item .post_cover { + overflow: hidden; + width: 42%; + height: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover { + width: 100%; + height: 230px; + } +} +#recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -o-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 0; + -moz-box-ordinal-group: 0; + -o-box-ordinal-group: 0; + -ms-flex-order: 0; + -webkit-order: 0; + order: 0; + } +} +#recent-posts > .recent-post-item >.recent-post-info { + padding: 0 40px; + width: 58%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info { + padding: 20px 20px 30px; + width: 100%; + } +} +#recent-posts > .recent-post-item >.recent-post-info.no-cover { + width: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info.no-cover { + padding: 30px 20px; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title { + color: var(--text-highlight-color); + font-size: 1.55em; + line-height: 1.4; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + -webkit-line-clamp: 2; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info > .article-title { + font-size: 1.43em; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title:hover { + color: #49b1f5; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap { + margin: 6px 0; + color: #858585; + font-size: 0.9em; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap > .post-meta-date { + cursor: default; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .sticky { + color: #ff7242; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap i { + margin: 0 4px 0 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .fa-spinner { + margin: 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-label { + padding-right: 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-separator { + margin: 0 6px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-link { + margin: 0 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a { + color: #858585; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a:hover { + color: #49b1f5; + text-decoration: underline; +} +#recent-posts > .recent-post-item >.recent-post-info > .content { + -webkit-line-clamp: 2; +} +.tag-cloud-list a { + display: inline-block; + padding: 0 8px; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.tag-cloud-list a:hover { + color: #49b1f5 !important; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +@media screen and (max-width: 768px) { + .tag-cloud-list a { + zoom: 0.85; + } +} +.tag-cloud-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .tag-cloud-title { + font-size: 2em; + } +} +h1.page-title + .tag-cloud-list { + text-align: left; +} +#aside-content { + width: 26%; +} +@media screen and (min-width: 900px) { + #aside-content { + padding-right: 15px; + } +} +@media screen and (max-width: 900px) { + #aside-content { + width: 100%; + } +} +#aside-content > .card-widget:first-child { + margin-top: 0; +} +@media screen and (max-width: 900px) { + #aside-content > .card-widget:first-child { + margin-top: 20px; + } +} +#aside-content .card-widget { + position: relative; + overflow: hidden; + margin-top: 20px; + padding: 20px 24px; +} +#aside-content .card-info .author-info__name { + font-weight: 500; + font-size: 1.57em; +} +#aside-content .card-info .author-info__description { + margin-top: -0.42em; +} +#aside-content .card-info .card-info-data { + margin: 14px 0 4px; +} +#aside-content .card-info .card-info-social-icons { + margin: 6px 0 -6px; +} +#aside-content .card-info .card-info-social-icons .social-icon { + margin: 0 10px; + color: var(--font-color); + font-size: 1.4em; +} +#aside-content .card-info .card-info-social-icons i { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#aside-content .card-info .card-info-social-icons i:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +#aside-content .card-info #card-info-btn { + display: block; + margin-top: 14px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + line-height: 2.4; +} +#aside-content .card-info #card-info-btn:hover { + background-color: var(--btn-hover-color); +} +#aside-content .card-info #card-info-btn span { + padding-left: 10px; +} +#aside-content .item-headline { + padding-bottom: 6px; + font-size: 1.2em; +} +#aside-content .item-headline span { + margin-left: 6px; +} +@media screen and (min-width: 900px) { + #aside-content .sticky_layout { + position: sticky; + position: -webkit-sticky; + top: 20px; + -webkit-transition: top 0.3s; + -moz-transition: top 0.3s; + -o-transition: top 0.3s; + -ms-transition: top 0.3s; + transition: top 0.3s; + } +} +#aside-content .card-tag-cloud a { + display: inline-block; + padding: 0 4px; +} +#aside-content .card-tag-cloud a:hover { + color: #49b1f5 !important; +} +#aside-content .aside-list > span { + display: block; + margin-bottom: 10px; + text-align: center; +} +#aside-content .aside-list > .aside-list-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 6px 0; +} +#aside-content .aside-list > .aside-list-item:first-child { + padding-top: 0; +} +#aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed #f5f5f5; +} +#aside-content .aside-list > .aside-list-item:last-child { + padding-bottom: 0; +} +#aside-content .aside-list > .aside-list-item .thumbnail { + overflow: hidden; + width: 4.2em; + height: 4.2em; +} +#aside-content .aside-list > .aside-list-item .content { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-left: 10px; + word-break: break-all; +} +#aside-content .aside-list > .aside-list-item .content > .name { + -webkit-line-clamp: 1; +} +#aside-content .aside-list > .aside-list-item .content > time, +#aside-content .aside-list > .aside-list-item .content > .name { + display: block; + color: #858585; + font-size: 85%; +} +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment { + color: var(--font-color); + font-size: 95%; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#aside-content .aside-list > .aside-list-item .content > .title:hover, +#aside-content .aside-list > .aside-list-item .content > .comment:hover { + color: #49b1f5; +} +#aside-content .aside-list > .aside-list-item.no-cover { + min-height: 4.4em; +} +#aside-content .card-archives ul.card-archive-list, +#aside-content .card-categories ul.card-category-list { + margin: 0; + padding: 0; + list-style: none; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 3px 10px; + color: var(--font-color); + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a:hover, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a:hover { + padding: 3px 17px; + background-color: var(--text-bg-hover); +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span:first-child, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} +#aside-content .card-categories .card-category-list.child { + padding: 0 0 0 16px; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-name { + width: 70% !important; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-count { + width: calc(100% - 70% - 20px); + text-align: right; +} +#aside-content .card-categories .card-category-list > .parent i { + float: right; + margin-right: -0.5em; + padding: 0.5em; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); +} +#aside-content .card-categories .card-category-list > .parent i.expand { + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); +} +#aside-content .card-webinfo .webinfo .webinfo-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 2px 10px 0; +} +#aside-content .card-webinfo .webinfo .webinfo-item div:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-right: 20px; +} +@media screen and (min-width: 901px) { + #aside-content #card-toc { + right: 0 !important; + } +} +@media screen and (max-width: 900px) { + #aside-content #card-toc { + position: fixed; + right: -100%; + bottom: 30px; + z-index: 100; + max-width: 380px; + max-height: calc(100% - 60px); + width: calc(100% - 80px); + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: initial; + -moz-transition: initial; + -o-transition: initial; + -ms-transition: initial; + transition: initial; + -webkit-transform-origin: right bottom; + -moz-transform-origin: right bottom; + -o-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + } +} +#aside-content #card-toc .toc-percentage { + float: right; + margin-top: -9px; + color: #a9a9a9; + font-style: italic; + font-size: 140%; +} +#aside-content #card-toc .toc-content { + overflow-y: scroll; + overflow-y: overlay; + margin: 0 -24px; + max-height: calc(100vh - 120px); +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content { + max-height: calc(100vh - 140px); + } +} +#aside-content #card-toc .toc-content > * { + margin: 0 20px !important; +} +#aside-content #card-toc .toc-content > * > .toc-item > .toc-child { + margin-left: 10px; + padding-left: 10px; + border-left: 1px solid var(--dark-grey); +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: none; +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: block !important; + } +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-item.active .toc-child { + display: block; +} +#aside-content #card-toc .toc-content ol, +#aside-content #card-toc .toc-content li { + list-style: none; +} +#aside-content #card-toc .toc-content > ol { + padding: 0 !important; +} +#aside-content #card-toc .toc-content ol { + margin: 0; + padding-left: 18px; +} +#aside-content #card-toc .toc-content .toc-link { + display: block; + margin: 4px 0; + padding: 1px 6px; + color: var(--toc-link-color); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#aside-content #card-toc .toc-content .toc-link:hover { + color: #49b1f5; +} +#aside-content #card-toc .toc-content .toc-link.active { + background: #00c4b6; + color: #fff; +} +#aside-content .sticky_layout:only-child > :first-child { + margin-top: 0; +} +#aside-content .card-more-btn { + float: right; + color: inherit; +} +#aside-content .card-more-btn:hover { + -webkit-animation: more-btn-move 1s infinite; + -moz-animation: more-btn-move 1s infinite; + -o-animation: more-btn-move 1s infinite; + -ms-animation: more-btn-move 1s infinite; + animation: more-btn-move 1s infinite; +} +#aside-content .card-announcement .item-headline i { + color: #f00; +} +.avatar-img { + overflow: hidden; + margin: 0 auto; + width: 110px; + height: 110px; + border-radius: 70px; +} +.avatar-img img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +.avatar-img img:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +.site-data { + display: table; + width: 100%; + table-layout: fixed; +} +.site-data > a { + display: table-cell; +} +.site-data > a div { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.site-data > a:hover div { + color: #49b1f5 !important; +} +.site-data > a .headline { + color: var(--font-color); +} +.site-data > a .length-num { + margin-top: -0.32em; + color: var(--text-highlight-color); + font-size: 1.4em; +} +@media screen and (min-width: 900px) { + html.hide-aside .layout { + -webkit-box-pack: center; + -moz-box-pack: center; + -o-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } + html.hide-aside .layout > .aside-content { + display: none; + } + html.hide-aside .layout > div:first-child { + width: 80%; + } +} +.page .sticky_layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} +@-moz-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-webkit-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-o-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-moz-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +#categoryBar { + width: 100% !important; +} +ul.categoryBar-list { + margin: 5px 5px 0 5px !important; + padding: 0 !important; +} +li.categoryBar-list-item { + font-weight: bold; + display: inline-block; + height: 180px !important; + margin: 5px 0.5% 0 0.5% !important; + background-image: -webkit-linear-gradient(rgba(0,0,0,0.4) 25%, rgba(16,16,16,0) 100%); + background-image: -moz-linear-gradient(rgba(0,0,0,0.4) 25%, rgba(16,16,16,0) 100%); + background-image: -o-linear-gradient(rgba(0,0,0,0.4) 25%, rgba(16,16,16,0) 100%); + background-image: -ms-linear-gradient(rgba(0,0,0,0.4) 25%, rgba(16,16,16,0) 100%); + background-image: linear-gradient(rgba(0,0,0,0.4) 25%, rgba(16,16,16,0) 100%); + border-radius: 10px; + padding: 25px 0 25px 25px !important; + -webkit-box-shadow: rgba(50,50,50,0.3) 50px 50px 50px 50px inset; + box-shadow: rgba(50,50,50,0.3) 50px 50px 50px 50px inset; + overflow: hidden; + background-size: 100% !important; + background-position: center !important; +} +li.categoryBar-list-item:hover { + background-size: 110% !important; + -webkit-box-shadow: inset 500px 50px 50px 50px rgba(50,50,50,0.6); + box-shadow: inset 500px 50px 50px 50px rgba(50,50,50,0.6); +} +li.categoryBar-list-item:hover span.categoryBar-list-count::after { + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; + -webkit-transform: translate(-100%, 0); + -moz-transform: translate(-100%, 0); + -o-transform: translate(-100%, 0); + -ms-transform: translate(-100%, 0); + transform: translate(-100%, 0); +} +a.categoryBar-list-link { + color: #fff !important; + font-size: 20px !important; +} +a.categoryBar-list-link::before { + content: '|' !important; + color: #fff !important; + font-size: 20px !important; +} +a.categoryBar-list-link:after { + content: ''; + position: relative; + width: 0; + bottom: 0; + display: block; + height: 3px; + border-radius: 3px; + background-color: #fff; +} +a.categoryBar-list-link:hover:after { + width: 90%; + left: 1%; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +span.categoryBar-list-count { + display: block !important; + color: #fff !important; + font-size: 20px !important; +} +span.categoryBar-list-count::before { + content: '\f02d' !important; + padding-right: 15px !important; +} +span.categoryBar-list-count::after { + padding: 5px; + display: block !important; + color: #fff !important; + font-size: 20px !important; + position: relative; + right: -100%; +} +li.categoryBar-list-item:nth-child(1) { + background: url('https://npm.elemecdn.com/akilar-candyassets/image/cover1.webp'); +} +li.categoryBar-list-item:nth-child(2) { + background: #abcdef; +} +li.categoryBar-list-item:nth-child(3) { + background: rgba(45,67,89,0.7); +} +li.categoryBar-list-item:nth-child(4) { + background: -webkit-linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%); + background: -moz-linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%); + background: -o-linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%); + background: -ms-linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%); + background: linear-gradient(rgba(0, 0, 0, 0.4) 25%, rgba(200,16 , 16, 0) 100%); +} +li.categoryBar-list-item:nth-child(5) { + background: url('https://npm.elemecdn.com/akilar-candyassets/image/cover5.webp'); +} +li.categoryBar-list-item:nth-child(6) { + background: url('https://npm.elemecdn.com/akilar-candyassets/image/cover6.webp'); +} +li.categoryBar-list-item:nth-child(1)>span::after { + content: '经验分享' !important; +} +li.categoryBar-list-item:nth-child(2)>span::after { + content: '生活日常' !important; +} +li.categoryBar-list-item:nth-child(3)>span::after { + content: '工具教程' !important; +} +li.categoryBar-list-item { + width: 32.3% !important; +} +@media screen and (max-width: 650px) { + li.categoryBar-list-item { + width: 48% !important; + height: 150px !important; + margin: 5px 1% 0 1% !important; + } +} +.categoryBar-list { + max-height: 380px; + overflow: auto; +} +.categoryBar-list::-webkit-scrollbar { + width: 0 !important; +} +@media screen and (max-width: 650px) { + .categoryBar-list { + max-height: 320px; + } +} +#post-comment .comment-head { + margin-bottom: 20px; +} +#post-comment .comment-head .comment-headline { + display: inline-block; + vertical-align: middle; + font-weight: 700; + font-size: 1.43em; +} +#post-comment .comment-head #comment-switch { + display: inline-block; + float: right; + margin: 2px auto 0; + padding: 4px 16px; + width: max-content; + border-radius: 8px; + background: #f6f8fa; +} +#post-comment .comment-head #comment-switch .first-comment { + color: #49b1f5; +} +#post-comment .comment-head #comment-switch .second-comment { + color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn { + position: relative; + display: inline-block; + margin: -4px 8px 0; + width: 42px; + height: 22px; + border-radius: 34px; + background-color: #49b1f5; + vertical-align: middle; + cursor: pointer; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn:before { + position: absolute; + bottom: 4px; + left: 4px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #fff; + content: ''; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn.move { + background-color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn.move:before { + -webkit-transform: translateX(20px); + -moz-transform: translateX(20px); + -o-transform: translateX(20px); + -ms-transform: translateX(20px); + transform: translateX(20px); +} +#post-comment .comment-wrap > div:nth-child(2) { + display: none; +} +#footer { + position: relative; + background-color: #49b1f5; + background-attachment: scroll; + background-position: bottom; + background-size: cover; +} +#footer-wrap { + position: relative; + padding: 40px 20px; + color: var(--light-grey); + text-align: center; +} +#footer-wrap a { + color: var(--light-grey); +} +#footer-wrap a:hover { + text-decoration: underline; +} +#footer-wrap .footer-separator { + margin: 0 4px; +} +#footer-wrap .icp-icon { + padding: 0 4px; + max-height: 1.4em; + width: auto; + vertical-align: text-bottom; +} +#footer-wrap { + position: relative; + padding: 40px 20px; + color: var(--light-grey); + text-align: center; +} +#footer-wrap a { + color: var(--light-grey); +} +#footer-wrap a:hover { + text-decoration: underline; +} +#footer-wrap .footer-separator { + margin: 0 4px; +} +#footer-wrap .icp-icon { + padding: 0 4px; + max-height: 1.4em; + width: auto; + vertical-align: text-bottom; +} +#page-header { + position: relative; + width: 100%; + background-color: #49b1f5; + background-position: center center; + background-size: cover; + background-repeat: no-repeat; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#page-header:not(.not-top-img):before { + position: absolute; + width: 100%; + height: 100%; + background-color: var(--mark-bg); + content: ''; +} +#page-header.full_page { + height: 100vh; + background-attachment: fixed; +} +#page-header.full_page #site-info { + position: absolute; + top: 43%; + padding: 0 10px; + width: 100%; +} +#page-header #site-title, +#page-header #site-subtitle, +#page-header #scroll-down .scroll-down-effects { + text-align: center; + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + line-height: 1.5; +} +#page-header #site-title { + margin: 0; + color: var(--white); + font-size: 1.85em; +} +@media screen and (min-width: 768px) { + #page-header #site-title { + font-size: 2.85em; + } +} +#page-header #site-subtitle { + color: var(--light-grey); + font-size: 1.15em; +} +@media screen and (min-width: 768px) { + #page-header #site-subtitle { + font-size: 1.72em; + } +} +#page-header #site_social_icons { + display: none; + margin: 0 auto; + width: 300px; + text-align: center; +} +@media screen and (max-width: 768px) { + #page-header #site_social_icons { + display: block; + } +} +#page-header #site_social_icons .social-icon { + margin: 0 10px; + color: var(--light-grey); + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-size: 1.43em; +} +#page-header #scroll-down { + position: absolute; + bottom: 0; + width: 100%; + cursor: pointer; +} +#page-header #scroll-down .scroll-down-effects { + position: relative; + width: 100%; + color: var(--light-grey); + font-size: 30px; +} +#page-header.not-home-page { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.not-home-page { + height: 280px; + } +} +#page-header #page-site-info { + position: absolute; + top: 200px; + padding: 0 10px; + width: 100%; +} +@media screen and (max-width: 768px) { + #page-header #page-site-info { + top: 140px; + } +} +#page-header.post-bg { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.post-bg { + height: 360px; + } +} +#page-header #post-info { + position: absolute; + bottom: 100px; + padding: 0 8%; + width: 100%; + text-align: center; +} +@media screen and (max-width: 900px) { + #page-header #post-info { + bottom: 30px; + text-align: left; + } +} +@media screen and (max-width: 768px) { + #page-header #post-info { + bottom: 22px; + padding: 0 22px; + } +} +#page-header.not-top-img { + margin-bottom: 10px; + height: 60px; + background: 0; +} +#page-header.not-top-img #nav { + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); +} +#page-header.not-top-img #nav a, +#page-header.not-top-img #nav .site-name { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav { + position: fixed; + top: -60px; + z-index: 91; + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -moz-transition: -moz-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -ms-transition: -ms-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out; +} +#page-header.nav-fixed #nav #blog-info { + color: var(--font-color); +} +#page-header.nav-fixed #nav #blog-info:hover { + color: #49b1f5; +} +#page-header.nav-fixed #nav #blog-info .site-name { + text-shadow: none; +} +#page-header.nav-fixed #nav a, +#page-header.nav-fixed #nav #toggle-menu { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav a:hover, +#page-header.nav-fixed #nav #toggle-menu:hover { + color: #49b1f5; +} +#page-header.nav-fixed.fixed #nav { + top: 0; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#page-header.nav-visible:not(.fixed) #nav { + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; + -webkit-transform: translate3d(0, 100%, 0); + -moz-transform: translate3d(0, 100%, 0); + -o-transform: translate3d(0, 100%, 0); + -ms-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +#page-header.nav-visible:not(.fixed) + .layout > .aside-content > .sticky_layout { + top: 70px; + -webkit-transition: top 0.5s; + -moz-transition: top 0.5s; + -o-transition: top 0.5s; + -ms-transition: top 0.5s; + transition: top 0.5s; +} +#page-header.fixed #nav { + position: fixed; +} +#page-header.fixed + .layout > .aside-content > .sticky_layout { + top: 70px; + -webkit-transition: top 0.5s; + -moz-transition: top 0.5s; + -o-transition: top 0.5s; + -ms-transition: top 0.5s; + transition: top 0.5s; +} +#page-header.fixed + .layout #card-toc .toc-content { + max-height: calc(100vh - 170px); +} +#page h1.page-title { + margin: 8px 0 20px; +} +#post > #post-info { + margin-bottom: 30px; +} +#post > #post-info .post-title { + padding-bottom: 4px; + border-bottom: 1px solid var(--light-grey); + color: var(--text-highlight-color); +} +#post > #post-info .post-title .post-edit-link { + float: right; +} +#post > #post-info #post-meta, +#post > #post-info #post-meta a { + color: #78818a; +} +#post-info .post-title { + margin-bottom: 8px; + color: var(--white); + font-weight: normal; + font-size: 2.5em; + line-height: 1.5; + -webkit-line-clamp: 3; +} +@media screen and (max-width: 768px) { + #post-info .post-title { + font-size: 2.1em; + } +} +#post-info .post-title .post-edit-link { + padding-left: 10px; +} +#post-info #post-meta { + color: var(--light-grey); + font-size: 95%; +} +@media screen and (min-width: 768px) { + #post-info #post-meta > .meta-secondline > span:first-child { + display: none; + } +} +@media screen and (max-width: 768px) { + #post-info #post-meta { + font-size: 90%; + } + #post-info #post-meta > .meta-firstline, + #post-info #post-meta > .meta-secondline { + display: inline; + } +} +#post-info #post-meta .post-meta-separator { + margin: 0 5px; +} +#post-info #post-meta .post-meta-icon { + margin-right: 4px; +} +#post-info #post-meta .post-meta-label { + margin-right: 4px; +} +#post-info #post-meta a { + color: var(--light-grey); + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +#post-info #post-meta a:hover { + color: #49b1f5; + text-decoration: underline; +} +#nav { + position: absolute; + top: 0; + z-index: 90; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 0 36px; + width: 100%; + height: 60px; + font-size: 1.3em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +@media screen and (max-width: 768px) { + #nav { + padding: 0 16px; + } +} +#nav.show { + opacity: 1; + -ms-filter: none; + filter: none; +} +#nav #blog-info { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + color: var(--light-grey); +} +#nav #blog-info .site-icon { + margin-right: 6px; + height: 36px; + vertical-align: middle; +} +#nav #toggle-menu { + display: none; + padding: 2px 0 0 6px; + vertical-align: top; +} +#nav #toggle-menu:hover { + color: var(--white); +} +#nav a { + color: var(--light-grey); +} +#nav a:hover { + color: var(--white); +} +#nav .site-name { + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-weight: bold; +} +#nav .menus_items { + display: inline; +} +#nav .menus_items .menus_item { + position: relative; + display: inline-block; + padding: 0 0 0 14px; +} +#nav .menus_items .menus_item:hover .menus_item_child { + display: block; +} +#nav .menus_items .menus_item:hover > a > i:last-child { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +#nav .menus_items .menus_item > a > i:last-child { + padding: 4px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#nav .menus_items .menus_item .menus_item_child { + position: absolute; + right: 0; + display: none; + margin-top: 8px; + padding: 0; + width: max-content; + border-radius: 5px; + background-color: var(--sidebar-bg); + -webkit-box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + -webkit-animation: sub_menus 0.3s 0.1s ease both; + -moz-animation: sub_menus 0.3s 0.1s ease both; + -o-animation: sub_menus 0.3s 0.1s ease both; + -ms-animation: sub_menus 0.3s 0.1s ease both; + animation: sub_menus 0.3s 0.1s ease both; +} +#nav .menus_items .menus_item .menus_item_child:before { + position: absolute; + top: -8px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +#nav .menus_items .menus_item .menus_item_child li { + list-style: none; +} +#nav .menus_items .menus_item .menus_item_child li:hover { + background: var(--text-bg-hover); +} +#nav .menus_items .menus_item .menus_item_child li:first-child { + border-top-left-radius: 5px; + border-top-right-radius: 5px; +} +#nav .menus_items .menus_item .menus_item_child li:last-child { + border-bottom-right-radius: 5px; + border-bottom-left-radius: 5px; +} +#nav .menus_items .menus_item .menus_item_child li a { + display: inline-block; + padding: 8px 16px; + width: 100%; + color: var(--font-color) !important; + text-shadow: none !important; +} +#nav.hide-menu #toggle-menu { + display: inline-block !important; +} +#nav.hide-menu #toggle-menu .site-page { + font-size: inherit; +} +#nav.hide-menu .menus_items { + display: none; +} +#nav.hide-menu #search-button span { + display: none; +} +#nav #search-button { + display: inline; + padding: 0 0 0 14px; +} +#nav .site-page { + position: relative; + padding-bottom: 6px; + text-shadow: 1px 1px 2px rgba(0,0,0,0.3); + font-size: 0.78em; + cursor: pointer; +} +#nav .site-page:not(.child):after { + position: absolute; + bottom: 0; + left: 0; + z-index: -1; + width: 0; + height: 3px; + background-color: #80c8f8; + content: ''; + -webkit-transition: all 0.3s ease-in-out; + -moz-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + -ms-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; +} +#nav .site-page:not(.child):hover:after { + width: 100%; +} +:root { + --pagenumber-color: #fff; + --pagenumber-current-color: rgba(153,54,44,0.8); + --pagenumber-current-shadow-color: #572020; + --pagenumber-hover-color: rgba(153,54,44,0.8); + --pagenumber-background-color: rgba(80,80,80,0.85); +} +[data-theme="dark"] { + --pagenumber-color: #fff; + --pagenumber-current-color: #1e7ee2; + --pagenumber-current-shadow-color: #104477; + --pagenumber-hover-color: #1e7ee2; + --pagenumber-background-color: rgba(50,50,50,0.85); +} +#pagination { + font-family: 'UnidreamLED', 'TaikoMagic'; +} +#pagination .pagination { + margin-top: 20px; + text-align: center; + position: relative; +} +#pagination .pagination a { + color: var(--pagenumber-color); +} +#pagination .pagination::after { + content: ''; + position: absolute; + width: 100%; + height: 35px; + left: 0; + bottom: 0; + z-index: -1; + background-image: -webkit-linear-gradient(left, rgba(0,0,0,0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0,0,0,0) 100%); + background-image: -moz-linear-gradient(left, rgba(0,0,0,0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0,0,0,0) 100%); + background-image: -o-linear-gradient(left, rgba(0,0,0,0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0,0,0,0) 100%); + background-image: -ms-linear-gradient(left, rgba(0,0,0,0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0,0,0,0) 100%); + background-image: linear-gradient(to right, rgba(0,0,0,0) 0%, var(--pagenumber-background-color) 40%, var(--pagenumber-background-color) 50%, var(--pagenumber-background-color) 60%, rgba(0,0,0,0) 100%); +} +#pagination .page-number { + position: relative; +} +#pagination .page-number.current { + background: var(--pagenumber-current-color); + color: var(--pagenumber-color); + padding: 9px 3px 0px 3px; + height: 40px; +} +#pagination .page-number.current:before { + content: ''; + position: absolute; + top: -10px; + left: -10px; + width: 30px; + border: 10px solid transparent; + border-bottom: 7px solid var(--pagenumber-current-shadow-color); + z-index: -1; +} +#pagination .page-number.current:before:hover::after { + display: none; +} +.layout .pagination { + z-index: 20; +} +.layout .pagination > * { + display: inline-block; + margin: 0 6px; + min-width: 30px; + width: auto; + height: 35px; + line-height: 30px; + padding: 4px 3px 0px 3px; +} +.layout .pagination > *:not(.space):hover { + background: var(--pagenumber-hover-color); + color: var(--pagenumber-color); +} +.layout .pagination-info { + position: absolute; + top: 50%; + padding: 20px 40px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +.layout .prev_info, +.layout .next_info { + color: var(--white); + font-weight: 500; +} +.layout .next-post .pagination-info { + text-align: right; +} +.layout .pull-full { + width: 100% !important; +} +.layout .prev-post .label, +.layout .next-post .label { + color: var(--light-grey); + text-transform: uppercase; + font-size: 90%; +} +.layout .prev-post, +.layout .next-post { + width: 50%; +} +@media screen and (max-width: 768px) { + .layout .prev-post, + .layout .next-post { + width: 100%; + } +} +.layout .prev-post a, +.layout .next-post a { + position: relative; + display: block; + overflow: hidden; + height: 150px; +} +.layout.pagination-post { + overflow: hidden; + margin-top: 40px; + width: 100%; + background: #000; +} +#article-container { + word-wrap: break-word; + overflow-wrap: break-word; +} +#article-container a { + color: #49b1f5; +} +#article-container a:hover { + text-decoration: underline; +} +#article-container img { + display: block; + margin: 0 auto 20px; + max-width: 100%; + -webkit-transition: filter 375ms ease-in 0.2s; + -moz-transition: filter 375ms ease-in 0.2s; + -o-transition: filter 375ms ease-in 0.2s; + -ms-transition: filter 375ms ease-in 0.2s; + transition: filter 375ms ease-in 0.2s; +} +#article-container p { + margin: 0 0 16px; +} +#article-container iframe { + margin: 0 0 20px; +} +#article-container kbd { + margin: 0 3px; + padding: 3px 5px; + border: 1px solid #b4b4b4; + border-radius: 3px; + background-color: #f8f8f8; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + color: #34495e; + white-space: nowrap; + font-weight: 600; + font-size: 0.9em; + font-family: Monaco, 'Ubuntu Mono', monospace; + line-height: 1em; +} +#article-container ol ol, +#article-container ul ol, +#article-container ol ul, +#article-container ul ul { + padding-left: 20px; +} +#article-container ol li, +#article-container ul li { + margin: 4px 0; +} +#article-container ol p, +#article-container ul p { + margin: 0 0 8px; +} +#article-container > :last-child { + margin-bottom: 0 !important; +} +#article-container hr { + margin: 20px 0; +} +#article-container.post-content h1, +#article-container.post-content h2, +#article-container.post-content h3, +#article-container.post-content h4, +#article-container.post-content h5, +#article-container.post-content h6 { + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +#article-container.post-content h1:before, +#article-container.post-content h2:before, +#article-container.post-content h3:before, +#article-container.post-content h4:before, +#article-container.post-content h5:before, +#article-container.post-content h6:before { + position: absolute; + top: calc(50% - 7px); + color: #f47466; + content: '\f0c1'; + line-height: 1; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +#article-container.post-content h1:hover:before, +#article-container.post-content h2:hover:before, +#article-container.post-content h3:hover:before, +#article-container.post-content h4:hover:before, +#article-container.post-content h5:hover:before, +#article-container.post-content h6:hover:before { + color: #49b1f5; +} +#article-container.post-content h1 { + padding-left: 32px; +} +#article-container.post-content h1:before { + margin-left: -26px; + font-size: 20px; +} +#article-container.post-content h1:hover { + padding-left: 38px; +} +#article-container.post-content h2 { + padding-left: 30px; +} +#article-container.post-content h2:before { + margin-left: -24px; + font-size: 18px; +} +#article-container.post-content h2:hover { + padding-left: 36px; +} +#article-container.post-content h3 { + padding-left: 28px; +} +#article-container.post-content h3:before { + margin-left: -22px; + font-size: 16px; +} +#article-container.post-content h3:hover { + padding-left: 34px; +} +#article-container.post-content h4 { + padding-left: 26px; +} +#article-container.post-content h4:before { + margin-left: -20px; + font-size: 14px; +} +#article-container.post-content h4:hover { + padding-left: 32px; +} +#article-container.post-content h5 { + padding-left: 24px; +} +#article-container.post-content h5:before { + margin-left: -18px; + font-size: 12px; +} +#article-container.post-content h5:hover { + padding-left: 30px; +} +#article-container.post-content h6 { + padding-left: 24px; +} +#article-container.post-content h6:before { + margin-left: -18px; + font-size: 12px; +} +#article-container.post-content h6:hover { + padding-left: 30px; +} +#article-container.post-content ol p, +#article-container.post-content ul p { + margin: 0 0 8px; +} +#article-container.post-content li::marker { + color: #49b1f5; + font-weight: 600; + font-size: 1.05em; +} +#article-container.post-content li:hover::marker { + color: var(--pseudo-hover); +} +#article-container.post-content ul > li { + list-style-type: circle; +} +#post .tag_share:after { + display: block; + clear: both; + content: ''; +} +#post .tag_share .post-meta__tag-list { + display: inline-block; +} +#post .tag_share .post-meta__tags { + display: inline-block; + margin: 8px 8px 8px 0; + padding: 0 12px; + width: fit-content; + border: 1px solid #49b1f5; + border-radius: 12px; + color: #49b1f5; + font-size: 0.85em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#post .tag_share .post-meta__tags:hover { + background: #49b1f5; + color: var(--white); +} +#post .tag_share .post_share { + display: inline-block; + float: right; + margin: 8px 0 0; + width: fit-content; +} +#post .tag_share .post_share .social-share { + font-size: 0.85em; +} +#post .tag_share .post_share .social-share .social-share-icon { + margin: 0 4px; + width: 1.85em; + height: 1.85em; + font-size: 1.2em; + line-height: 1.85em; +} +#post .post-copyright { + position: relative; + margin: 40px 0 10px; + padding: 10px 16px; + border: 1px solid var(--light-grey); + -webkit-transition: box-shadow 0.3s ease-in-out; + -moz-transition: box-shadow 0.3s ease-in-out; + -o-transition: box-shadow 0.3s ease-in-out; + -ms-transition: box-shadow 0.3s ease-in-out; + transition: box-shadow 0.3s ease-in-out; +} +#post .post-copyright:before { + position: absolute; + top: 2px; + right: 12px; + color: #49b1f5; + content: '\f1f9'; + font-size: 1.3em; +} +#post .post-copyright:hover { + -webkit-box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); + box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); +} +#post .post-copyright .post-copyright-meta { + color: #49b1f5; + font-weight: bold; +} +#post .post-copyright .post-copyright-info { + padding-left: 6px; +} +#post .post-copyright .post-copyright-info a { + text-decoration: underline; + word-break: break-word; +} +#post .post-copyright .post-copyright-info a:hover { + text-decoration: none; +} +#post .post-outdate-notice { + position: relative; + margin: 0 0 20px; + padding: 0.5em 1.2em; + border-radius: 3px; + background-color: #ffe6e6; + color: #f66; + padding: 0.5em 1em 0.5em 2.6em; + border-left: 5px solid #ff8080; +} +#post .post-outdate-notice:before { + position: absolute; + top: 50%; + left: 0.9em; + color: #ff8080; + content: '\f071'; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} +#post .ads-wrap { + margin: 40px 0; +} +.relatedPosts { + margin-top: 40px; +} +.relatedPosts > .headline { + margin-bottom: 5px; + font-weight: 700; + font-size: 1.43em; +} +.relatedPosts > .relatedPosts-list > div { + position: relative; + display: inline-block; + overflow: hidden; + margin: 3px; + width: calc(33.333% - 6px); + height: 200px; + background: #000; + vertical-align: bottom; +} +@media screen and (max-width: 768px) { + .relatedPosts > .relatedPosts-list > div { + margin: 2px; + width: calc(50% - 4px); + height: 150px; + } +} +@media screen and (max-width: 600px) { + .relatedPosts > .relatedPosts-list > div { + width: calc(100% - 4px); + } +} +.relatedPosts > .relatedPosts-list .content { + position: absolute; + top: 50%; + padding: 0 20px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +.relatedPosts > .relatedPosts-list .content .date { + color: var(--light-grey); + font-size: 90%; +} +.relatedPosts > .relatedPosts-list .content .title { + color: var(--white); + -webkit-line-clamp: 2; +} +.post-reward { + position: relative; + margin-top: 80px; + width: 100%; + text-align: center; + pointer-events: none; +} +.post-reward > * { + pointer-events: auto; +} +.post-reward .reward-button { + display: inline-block; + padding: 4px 24px; + background: var(--btn-bg); + color: var(--btn-color); + cursor: pointer; +} +.post-reward:hover .reward-button { + background: var(--btn-hover-color); +} +.post-reward:hover > .reward-main { + display: block; +} +.post-reward .reward-main { + position: absolute; + bottom: 40px; + left: 0; + z-index: 100; + display: none; + padding: 0 0 15px; + width: 100%; +} +.post-reward .reward-main .reward-all { + display: inline-block; + margin: 0; + padding: 20px 10px; + border-radius: 4px; + background: var(--reward-pop); +} +.post-reward .reward-main .reward-all:before { + position: absolute; + bottom: -10px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +.post-reward .reward-main .reward-all:after { + position: absolute; + right: 0; + bottom: 2px; + left: 0; + margin: 0 auto; + width: 0; + height: 0; + border-top: 13px solid var(--reward-pop); + border-right: 13px solid transparent; + border-left: 13px solid transparent; + content: ''; +} +.post-reward .reward-main .reward-all .reward-item { + display: inline-block; + padding: 0 8px; + list-style-type: none; + vertical-align: top; +} +.post-reward .reward-main .reward-all .reward-item img { + width: 130px; + height: 130px; +} +.post-reward .reward-main .reward-all .reward-item .post-qr-code-desc { + width: 130px; + color: #858585; +} +#rightside { + position: fixed; + right: -48px; + bottom: 40px; + z-index: 100; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#rightside #rightside-config-hide { + height: 0; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: -webkit-transform 0.4s; + -moz-transition: -moz-transform 0.4s; + -o-transition: -o-transform 0.4s; + -ms-transition: -ms-transform 0.4s; + transition: transform 0.4s; + -webkit-transform: translate(45px, 0); + -moz-transform: translate(45px, 0); + -o-transform: translate(45px, 0); + -ms-transform: translate(45px, 0); + transform: translate(45px, 0); +} +#rightside #rightside-config-hide.show { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate(0, 0); + -moz-transform: translate(0, 0); + -o-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +#rightside #rightside-config-hide.status { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; +} +#rightside > div > button, +#rightside > div > a { + display: block; + margin-bottom: 5px; + width: 35px; + height: 35px; + border-radius: 5px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + font-size: 16px; + line-height: 35px; +} +#rightside > div > button:hover, +#rightside > div > a:hover { + background-color: var(--btn-hover-color); +} +#rightside #mobile-toc-button { + display: none; +} +@media screen and (max-width: 900px) { + #rightside #mobile-toc-button { + display: block; + } +} +@media screen and (max-width: 900px) { + #rightside #hide-aside-btn { + display: none; + } +} +#rightside #go-up .scroll-percent { + display: none; +} +#rightside #go-up.show-percent .scroll-percent { + display: block; +} +#rightside #go-up.show-percent .scroll-percent + i { + display: none; +} +#rightside #go-up:hover .scroll-percent { + display: none; +} +#rightside #go-up:hover .scroll-percent + i { + display: block; +} +#sidebar #menu-mask { + position: fixed; + z-index: 102; + display: none; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.8); +} +#sidebar #sidebar-menus { + position: fixed; + top: 0; + right: -300px; + z-index: 103; + overflow-x: hidden; + overflow-y: auto; + width: 300px; + height: 100%; + background: var(--sidebar-bg); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#sidebar #sidebar-menus.open { + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#sidebar #sidebar-menus > .avatar-img { + margin: 20px auto; +} +#sidebar #sidebar-menus .sidebar-site-data { + padding: 0 10px; +} +#sidebar #sidebar-menus hr { + margin: 20px auto; +} +#sidebar #sidebar-menus .menus_items { + padding: 0 10px 40px; +} +#sidebar #sidebar-menus .menus_items .site-page { + position: relative; + display: block; + padding: 6px 30px 6px 22px; + color: var(--font-color); + font-size: 1.15em; +} +#sidebar #sidebar-menus .menus_items .site-page:hover { + background: var(--text-bg-hover); +} +#sidebar #sidebar-menus .menus_items .site-page i:first-child { + width: 15%; + text-align: left; +} +#sidebar #sidebar-menus .menus_items .site-page.group > i:last-child { + position: absolute; + top: 0.78em; + right: 18px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide > i:last-child { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide + .menus_item_child { + display: none; +} +#sidebar #sidebar-menus .menus_items .menus_item_child { + margin: 0; + list-style: none; +} +#vcomment { + font-size: 1.1em; +} +#vcomment .vbtn { + border: none; + background: var(--btn-bg); + color: var(--btn-color); +} +#vcomment .vbtn:hover { + background: var(--btn-hover-color); +} +#vcomment .vimg { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#vcomment .vimg:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +#vcomment .vcards .vcard .vcontent.expand:before, +#vcomment .vcards .vcard .vcontent.expand:after { + z-index: 22; +} +#waline-wrap { + --waline-font-size: 1.1em; + --waline-theme-color: #49b1f5; + --waline-active-color: #ff7242; +} +#waline-wrap .wl-comment-actions > button:not(last-child) { + padding-right: 4px; +} +.fireworks { + position: fixed; + top: 0; + left: 0; + z-index: 9999; + pointer-events: none; +} +.medium-zoom-image--opened { + z-index: 99999 !important; + margin: 0 !important; +} +.medium-zoom-overlay { + z-index: 99999 !important; +} +.mermaid-wrap { + margin: 0 0 20px; + text-align: center; +} +.mermaid-wrap > svg { + height: 100%; +} +.utterances, +.fb-comments iframe { + width: 100% !important; +} +#gitalk-container .gt-meta { + margin: 0 0 0.8em; + padding: 6px 0 16px; +} +.katex-wrap { + overflow: auto; +} +.katex-wrap::-webkit-scrollbar { + display: none; +} +mjx-container { + overflow-x: auto; + overflow-y: hidden; + padding-bottom: 4px; + max-width: 100%; +} +mjx-container[display] { + display: block !important; + min-width: auto !important; +} +mjx-container:not([display]) { + display: inline-grid !important; +} +mjx-assistive-mml { + right: 0; + bottom: 0; +} +.aplayer { + color: #4c4948; +} +#article-container .aplayer { + margin: 0 0 20px; +} +#article-container .aplayer ol, +#article-container .aplayer ul { + margin: 0; + padding: 0; +} +#article-container .aplayer ol li, +#article-container .aplayer ul li { + margin: 0; + padding: 0 15px; +} +#article-container .aplayer ol li:before, +#article-container .aplayer ul li:before { + content: none; +} +.snackbar-css { + border-radius: 5px !important; +} +.abc-music-sheet { + margin: 0 0 20px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.3s; + -moz-transition: opacity 0.3s; + -o-transition: opacity 0.3s; + -ms-transition: opacity 0.3s; + transition: opacity 0.3s; +} +.abc-music-sheet.abcjs-container { + opacity: 1; + -ms-filter: none; + filter: none; +} +@media screen and (max-width: 768px) { + .fancybox__toolbar__column.is-middle { + display: none; + } +} +#article-container .btn-center { + margin: 0 0 20px; + text-align: center; +} +#article-container .btn-beautify { + display: inline-block; + margin: 0 4px 6px; + padding: 0 15px; + background-color: var(--btn-beautify-color, #777); + color: #fff; + line-height: 2; +} +#article-container .btn-beautify.blue { + --btn-beautify-color: #428bca; +} +#article-container .btn-beautify.pink { + --btn-beautify-color: #ff69b4; +} +#article-container .btn-beautify.red { + --btn-beautify-color: #f00; +} +#article-container .btn-beautify.purple { + --btn-beautify-color: #6f42c1; +} +#article-container .btn-beautify.orange { + --btn-beautify-color: #ff8c00; +} +#article-container .btn-beautify.green { + --btn-beautify-color: #5cb85c; +} +#article-container .btn-beautify:hover { + background-color: var(--btn-hover-color); +} +#article-container .btn-beautify i + span { + margin-left: 6px; +} +#article-container .btn-beautify:not(.block) + .btn-beautify:not(.block) { + margin: 0 4px 20px; +} +#article-container .btn-beautify.block { + display: block; + margin: 0 0 20px; + width: fit-content; + width: -moz-fit-content; +} +#article-container .btn-beautify.block.center { + margin: 0 auto 20px; +} +#article-container .btn-beautify.block.right { + margin: 0 0 20px auto; +} +#article-container .btn-beautify.larger { + padding: 6px 15px; +} +#article-container .btn-beautify:hover { + text-decoration: none; +} +#article-container .btn-beautify.outline { + border: 1px solid transparent; + border-color: var(--btn-beautify-color, #777); + background-color: transparent; + color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + background-color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + color: #fff !important; +} +#article-container figure.gallery-group { + position: relative; + float: left; + overflow: hidden; + margin: 6px 4px; + width: calc(50% - 8px); + height: 250px; + border-radius: 8px; + background: #000; + -webkit-transform: translate3d(0, 0, 0); +} +@media screen and (max-width: 600px) { + #article-container figure.gallery-group { + width: calc(100% - 8px); + } +} +#article-container figure.gallery-group:hover img { + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover .gallery-group-name::after { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover p { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group img { + position: relative; + margin: 0; + max-width: none; + width: calc(100% + 20px); + height: 250px; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transition: all 0.3s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.3s, filter 375ms ease-in 0.2s; + -o-transition: all 0.3s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.3s, filter 375ms ease-in 0.2s; + transition: all 0.3s, filter 375ms ease-in 0.2s; + -webkit-transform: translate3d(-10px, 0, 0); + -moz-transform: translate3d(-10px, 0, 0); + -o-transform: translate3d(-10px, 0, 0); + -ms-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + object-fit: cover; +} +#article-container figure.gallery-group figcaption { + position: absolute; + top: 0; + left: 0; + padding: 30px; + width: 100%; + height: 100%; + color: #fff; + text-transform: uppercase; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; +} +#article-container figure.gallery-group figcaption > a { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container figure.gallery-group p { + margin: 0; + padding: 8px 0 0; + letter-spacing: 1px; + font-size: 1.1em; + line-height: 1.5; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.35s, -webkit-transform 0.35s; + -moz-transition: opacity 0.35s, -moz-transform 0.35s; + -o-transition: opacity 0.35s, -o-transform 0.35s; + -ms-transition: opacity 0.35s, -ms-transform 0.35s; + transition: opacity 0.35s, transform 0.35s; + -webkit-transform: translate3d(100%, 0, 0); + -moz-transform: translate3d(100%, 0, 0); + -o-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + -webkit-line-clamp: 4; +} +#article-container figure.gallery-group .gallery-group-name { + position: relative; + margin: 0; + padding: 8px 0; + font-weight: bold; + font-size: 1.65em; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#article-container figure.gallery-group .gallery-group-name:after { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: #fff; + content: ''; + -webkit-transition: -webkit-transform 0.35s; + -moz-transition: -moz-transform 0.35s; + -o-transition: -o-transform 0.35s; + -ms-transition: -ms-transform 0.35s; + transition: transform 0.35s; + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#article-container .gallery-group-main { + overflow: auto; + padding: 0 0 16px; +} +#article-container .gallery { + margin: 0 0 16px; + text-align: center; +} +#article-container .gallery .fj-gallery { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container .gallery .fj-gallery .img-alt { + display: none; +} +#article-container .gallery .fj-gallery.lazyload + button { + display: inline-block; +} +#article-container .gallery .fj-gallery .gallery-data { + display: none; +} +#article-container .gallery button { + display: none; + margin-top: 25px; + padding: 10px; + width: 9em; + border-radius: 5px; + background: var(--btn-bg); + color: var(--btn-color); + font-weight: bold; + font-size: 1.1em; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#article-container .gallery button > * { + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#article-container .gallery button i { + width: 0; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container .gallery button:hover { + background: var(--btn-hover-color); +} +#article-container .gallery button:hover i { + margin-left: 2px; + width: 20px; + opacity: 1; + -ms-filter: none; + filter: none; +} +blockquote.pullquote { + position: relative; + max-width: 45%; + font-size: 110%; +} +blockquote.pullquote.left { + float: left; + margin: 1em 0.5em 0 0; +} +blockquote.pullquote.right { + float: right; + margin: 1em 0 0 0.5em; +} +.video-container { + position: relative; + overflow: hidden; + margin-bottom: 16px; + padding-top: 56.25%; + height: 0; +} +.video-container iframe { + position: absolute; + top: 0; + left: 0; + margin-top: 0; + width: 100%; + height: 100%; +} +.hide-inline > .hide-button, +.hide-block > .hide-button { + display: inline-block; + padding: 5px 18px; + background: #49b1f5; + color: var(--white); +} +.hide-inline > .hide-button:hover, +.hide-block > .hide-button:hover { + background-color: var(--btn-hover-color); +} +.hide-inline > .hide-button.open, +.hide-block > .hide-button.open { + display: none; +} +.hide-inline > .hide-button.open + div, +.hide-block > .hide-button.open + div { + display: block; +} +.hide-inline > .hide-button.open + span, +.hide-block > .hide-button.open + span { + display: inline; +} +.hide-inline > .hide-content, +.hide-block > .hide-content { + display: none; +} +.hide-inline > .hide-button { + margin: 0 6px; +} +.hide-inline > .hide-content { + margin: 0 6px; +} +.hide-block { + margin: 0 0 16px; +} +.toggle { + margin-bottom: 20px; + border: 1px solid #f0f0f0; +} +.toggle > .toggle-button { + padding: 6px 15px; + background: #f0f0f0; + color: #1f2d3d; + cursor: pointer; +} +.toggle > .toggle-content { + margin: 30px 24px; +} +#article-container .inline-img { + display: inline; + margin: 0 3px; + height: 1.1em; + vertical-align: text-bottom; +} +.hl-label { + padding: 2px 4px; + border-radius: 3px; + color: #fff; +} +.hl-label.default { + background-color: #777; +} +.hl-label.blue { + background-color: #428bca; +} +.hl-label.pink { + background-color: #ff69b4; +} +.hl-label.red { + background-color: #f00; +} +.hl-label.purple { + background-color: #6f42c1; +} +.hl-label.orange { + background-color: #ff8c00; +} +.hl-label.green { + background-color: #5cb85c; +} +.note { + position: relative; + margin: 0 0 20px; + padding: 15px; + border-radius: 3px; +} +.note.icon-padding { + padding-left: 3em; +} +.note > .note-icon { + position: absolute; + top: calc(50% - 0.5em); + left: 0.8em; + font-size: larger; +} +.note.blue:not(.disabled) { + border-left-color: #428bca !important; +} +.note.blue:not(.disabled).modern { + border-left-color: transparent !important; + color: #428bca; +} +.note.blue:not(.disabled):not(.simple) { + background: #e3eef7 !important; +} +.note.blue > .note-icon { + color: #428bca; +} +.note.pink:not(.disabled) { + border-left-color: #ff69b4 !important; +} +.note.pink:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff69b4; +} +.note.pink:not(.disabled):not(.simple) { + background: #ffe9f4 !important; +} +.note.pink > .note-icon { + color: #ff69b4; +} +.note.red:not(.disabled) { + border-left-color: #f00 !important; +} +.note.red:not(.disabled).modern { + border-left-color: transparent !important; + color: #f00; +} +.note.red:not(.disabled):not(.simple) { + background: #ffd9d9 !important; +} +.note.red > .note-icon { + color: #f00; +} +.note.purple:not(.disabled) { + border-left-color: #6f42c1 !important; +} +.note.purple:not(.disabled).modern { + border-left-color: transparent !important; + color: #6f42c1; +} +.note.purple:not(.disabled):not(.simple) { + background: #e9e3f6 !important; +} +.note.purple > .note-icon { + color: #6f42c1; +} +.note.orange:not(.disabled) { + border-left-color: #ff8c00 !important; +} +.note.orange:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff8c00; +} +.note.orange:not(.disabled):not(.simple) { + background: #ffeed9 !important; +} +.note.orange > .note-icon { + color: #ff8c00; +} +.note.green:not(.disabled) { + border-left-color: #5cb85c !important; +} +.note.green:not(.disabled).modern { + border-left-color: transparent !important; + color: #5cb85c; +} +.note.green:not(.disabled):not(.simple) { + background: #e7f4e7 !important; +} +.note.green > .note-icon { + color: #5cb85c; +} +.note.simple { + border: 1px solid #eee; + border-left-width: 5px; +} +.note.modern { + border: 1px solid transparent !important; + background-color: #f5f5f5; + color: #4c4948; +} +.note.flat { + border: initial; + border-left: 5px solid #eee; + background-color: #f9f9f9; + color: #4c4948; +} +.note h2, +.note h3, +.note h4, +.note h5, +.note h6 { + margin-top: 3px; + margin-bottom: 0; + padding-top: 0 !important; + border-bottom: initial; +} +.note p:first-child, +.note ul:first-child, +.note ol:first-child, +.note table:first-child, +.note pre:first-child, +.note blockquote:first-child, +.note img:first-child { + margin-top: 0 !important; +} +.note p:last-child, +.note ul:last-child, +.note ol:last-child, +.note table:last-child, +.note pre:last-child, +.note blockquote:last-child, +.note img:last-child { + margin-bottom: 0 !important; +} +.note:not(.no-icon) { + padding-left: 3em; +} +.note:not(.no-icon)::before { + position: absolute; + top: calc(50% - 0.95em); + left: 0.8em; + font-size: larger; +} +.note.default.flat { + background: #f7f7f7; +} +.note.default.modern { + border-color: #e1e1e1; + background: #f3f3f3; + color: #666; +} +.note.default.modern a:not(.btn) { + color: #666; +} +.note.default.modern a:not(.btn):hover { + color: #454545; +} +.note.default:not(.modern) { + border-left-color: #777; +} +.note.default:not(.modern) h2, +.note.default:not(.modern) h3, +.note.default:not(.modern) h4, +.note.default:not(.modern) h5, +.note.default:not(.modern) h6 { + color: #777; +} +.note.default:not(.no-icon)::before { + content: '\f0a9'; +} +.note.default:not(.no-icon):not(.modern)::before { + color: #777; +} +.note.primary.flat { + background: #f5f0fa; +} +.note.primary.modern { + border-color: #e1c2ff; + background: #f3daff; + color: #6f42c1; +} +.note.primary.modern a:not(.btn) { + color: #6f42c1; +} +.note.primary.modern a:not(.btn):hover { + color: #453298; +} +.note.primary:not(.modern) { + border-left-color: #6f42c1; +} +.note.primary:not(.modern) h2, +.note.primary:not(.modern) h3, +.note.primary:not(.modern) h4, +.note.primary:not(.modern) h5, +.note.primary:not(.modern) h6 { + color: #6f42c1; +} +.note.primary:not(.no-icon)::before { + content: '\f055'; +} +.note.primary:not(.no-icon):not(.modern)::before { + color: #6f42c1; +} +.note.info.flat { + background: #eef7fa; +} +.note.info.modern { + border-color: #b3e5ef; + background: #d9edf7; + color: #31708f; +} +.note.info.modern a:not(.btn) { + color: #31708f; +} +.note.info.modern a:not(.btn):hover { + color: #215761; +} +.note.info:not(.modern) { + border-left-color: #428bca; +} +.note.info:not(.modern) h2, +.note.info:not(.modern) h3, +.note.info:not(.modern) h4, +.note.info:not(.modern) h5, +.note.info:not(.modern) h6 { + color: #428bca; +} +.note.info:not(.no-icon)::before { + content: '\f05a'; +} +.note.info:not(.no-icon):not(.modern)::before { + color: #428bca; +} +.note.success.flat { + background: #eff8f0; +} +.note.success.modern { + border-color: #d0e6be; + background: #dff0d8; + color: #3c763d; +} +.note.success.modern a:not(.btn) { + color: #3c763d; +} +.note.success.modern a:not(.btn):hover { + color: #32562c; +} +.note.success:not(.modern) { + border-left-color: #5cb85c; +} +.note.success:not(.modern) h2, +.note.success:not(.modern) h3, +.note.success:not(.modern) h4, +.note.success:not(.modern) h5, +.note.success:not(.modern) h6 { + color: #5cb85c; +} +.note.success:not(.no-icon)::before { + content: '\f058'; +} +.note.success:not(.no-icon):not(.modern)::before { + color: #5cb85c; +} +.note.warning.flat { + background: #fdf8ea; +} +.note.warning.modern { + border-color: #fae4cd; + background: #fcf4e3; + color: #8a6d3b; +} +.note.warning.modern a:not(.btn) { + color: #8a6d3b; +} +.note.warning.modern a:not(.btn):hover { + color: #714f30; +} +.note.warning:not(.modern) { + border-left-color: #f0ad4e; +} +.note.warning:not(.modern) h2, +.note.warning:not(.modern) h3, +.note.warning:not(.modern) h4, +.note.warning:not(.modern) h5, +.note.warning:not(.modern) h6 { + color: #f0ad4e; +} +.note.warning:not(.no-icon)::before { + content: '\f06a'; +} +.note.warning:not(.no-icon):not(.modern)::before { + color: #f0ad4e; +} +.note.danger.flat { + background: #fcf1f2; +} +.note.danger.modern { + border-color: #ebcdd2; + background: #f2dfdf; + color: #a94442; +} +.note.danger.modern a:not(.btn) { + color: #a94442; +} +.note.danger.modern a:not(.btn):hover { + color: #84333f; +} +.note.danger:not(.modern) { + border-left-color: #d9534f; +} +.note.danger:not(.modern) h2, +.note.danger:not(.modern) h3, +.note.danger:not(.modern) h4, +.note.danger:not(.modern) h5, +.note.danger:not(.modern) h6 { + color: #d9534f; +} +.note.danger:not(.no-icon)::before { + content: '\f056'; +} +.note.danger:not(.no-icon):not(.modern)::before { + color: #d9534f; +} +#article-container .tabs { + position: relative; + margin: 0 0 20px; + border-right: 1px solid var(--tab-border-color); + border-bottom: 1px solid var(--tab-border-color); + border-left: 1px solid var(--tab-border-color); +} +#article-container .tabs > .nav-tabs { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -o-box-lines: multiple; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0; + padding: 0; + background: var(--tab-botton-bg); +} +#article-container .tabs > .nav-tabs > .tab { + margin: 0; + padding: 0; + list-style: none; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .nav-tabs > .tab { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + -ms-box-flex: 1; + box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + } +} +#article-container .tabs > .nav-tabs > .tab button { + display: block; + padding: 8px 18px; + width: 100%; + border-top: 2px solid var(--tab-border-color); + background: var(--tab-botton-bg); + color: var(--tab-botton-color); + line-height: 2; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#article-container .tabs > .nav-tabs > .tab button i { + width: 1.5em; +} +#article-container .tabs > .nav-tabs > .tab.active button { + border-top: 2px solid #49b1f5; + background: var(--tab-button-active-bg); + cursor: default; +} +#article-container .tabs > .nav-tabs > .tab:not(.active) button:hover { + border-top: 2px solid var(--tab-button-hover-bg); + background: var(--tab-button-hover-bg); +} +#article-container .tabs > .tab-contents .tab-item-content { + position: relative; + display: none; + padding: 36px 24px; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .tab-contents .tab-item-content { + padding: 24px 14px; + } +} +#article-container .tabs > .tab-contents .tab-item-content.active { + display: block; + -webkit-animation: tabshow 0.5s; + -moz-animation: tabshow 0.5s; + -o-animation: tabshow 0.5s; + -ms-animation: tabshow 0.5s; + animation: tabshow 0.5s; +} +#article-container .tabs .tab-to-top { + position: relative; + display: block; + margin: 0 0 0 auto; + color: #99a9bf; +} +@-moz-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +#article-container .timeline { + margin: 0 0 20px 10px; + padding: 14px 20px 5px; + border-left: 2px solid var(--timeline-color, #49b1f5); +} +#article-container .timeline.blue { + --timeline-color: #428bca; + --timeline-bg: rgba(66,139,202, 0.2); +} +#article-container .timeline.pink { + --timeline-color: #ff69b4; + --timeline-bg: rgba(255,105,180, 0.2); +} +#article-container .timeline.red { + --timeline-color: #f00; + --timeline-bg: rgba(255,0,0, 0.2); +} +#article-container .timeline.purple { + --timeline-color: #6f42c1; + --timeline-bg: rgba(111,66,193, 0.2); +} +#article-container .timeline.orange { + --timeline-color: #ff8c00; + --timeline-bg: rgba(255,140,0, 0.2); +} +#article-container .timeline.green { + --timeline-color: #5cb85c; + --timeline-bg: rgba(92,184,92, 0.2); +} +#article-container .timeline .timeline-item { + margin: 0 0 15px; +} +#article-container .timeline .timeline-item:hover .item-circle:before { + border-color: var(--timeline-color, #49b1f5); +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle > p { + font-weight: 600; + font-size: 1.2em; +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle:before { + left: -28px; + border: 4px solid var(--timeline-color, #49b1f5); +} +#article-container .timeline .timeline-item.headline:hover .item-circle:before { + border-color: var(--pseudo-hover); +} +#article-container .timeline .timeline-item .timeline-item-title { + position: relative; +} +#article-container .timeline .timeline-item .item-circle:before { + position: absolute; + top: 50%; + left: -27px; + width: 6px; + height: 6px; + border: 3px solid var(--pseudo-hover); + border-radius: 50%; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +#article-container .timeline .timeline-item .item-circle > p { + margin: 0 0 8px; + font-weight: 500; +} +#article-container .timeline .timeline-item .timeline-item-content { + position: relative; + padding: 12px 15px; + border-radius: 8px; + background: var(--timeline-bg, #e4f3fd); + font-size: 0.93em; +} +#article-container .timeline .timeline-item .timeline-item-content > :last-child { + margin-bottom: 0; +} +#article-container .timeline + .timeline { + margin-top: -20px; +} +[data-theme='dark'] { + --global-bg: #0d0d0d; + --font-color: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.4); + --hr-before-color: rgba(255,255,255,0.7); + --search-bg: #121212; + --search-input-color: rgba(255,255,255,0.7); + --search-a-color: rgba(255,255,255,0.7); + --preloader-bg: #0d0d0d; + --preloader-color: rgba(255,255,255,0.7); + --tab-border-color: #2c2c2c; + --tab-botton-bg: #2c2c2c; + --tab-botton-color: rgba(255,255,255,0.7); + --tab-button-hover-bg: #383838; + --tab-button-active-bg: #121212; + --card-bg: #121212; + --sidebar-bg: #121212; + --btn-hover-color: #787878; + --btn-color: rgba(255,255,255,0.7); + --btn-bg: #1f1f1f; + --text-bg-hover: #383838; + --light-grey: rgba(255,255,255,0.7); + --dark-grey: rgba(255,255,255,0.2); + --white: rgba(255,255,255,0.9); + --text-highlight-color: rgba(255,255,255,0.9); + --blockquote-color: rgba(255,255,255,0.7); + --blockquote-bg: #2c2c2c; + --reward-pop: #2c2c2c; + --toc-link-color: rgba(255,255,255,0.6); + --hl-color: rgba(255,255,255,0.7); + --hl-bg: #171717; + --hltools-bg: #1a1a1a; + --hltools-color: #90a4ae; + --hlnumber-bg: #171717; + --hlnumber-color: rgba(255,255,255,0.4); + --hlscrollbar-bg: #1f1f1f; + --hlexpand-bg: linear-gradient(180deg, rgba(23,23,23,0.6), rgba(23,23,23,0.9)); + --scrollbar-color: #1f1f1f; + --timeline-bg: #1f1f1f; + --zoom-bg: #121212; + --mark-bg: rgba(0,0,0,0.6); +} +[data-theme='dark'] #web_bg:before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.7); + content: ''; +} +[data-theme='dark'] #article-container code { + background: #2c2c2c; +} +[data-theme='dark'] #article-container pre > code { + background: #171717; +} +[data-theme='dark'] #article-container figure.highlight { + -webkit-box-shadow: none; + box-shadow: none; +} +[data-theme='dark'] #article-container .note code { + background: rgba(27,31,35,0.05); +} +[data-theme='dark'] #article-container .aplayer { + filter: brightness(0.8); +} +[data-theme='dark'] #article-container kbd { + border-color: #696969; + background-color: #525252; + color: #e2f1ff; +} +[data-theme='dark'] #page-header.nav-fixed > #nav, +[data-theme='dark'] #page-header.not-top-img > #nav { + background: rgba(18,18,18,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0); +} +[data-theme='dark'] #post-comment #comment-switch { + background: #2c2c2c !important; +} +[data-theme='dark'] #post-comment #comment-switch .switch-btn { + filter: brightness(0.8); +} +[data-theme='dark'] .note { + filter: brightness(0.8); +} +[data-theme='dark'] .hide-button, +[data-theme='dark'] .btn-beautify, +[data-theme='dark'] .hl-label, +[data-theme='dark'] .post-outdate-notice, +[data-theme='dark'] .error-img, +[data-theme='dark'] #article-container iframe, +[data-theme='dark'] .gist, +[data-theme='dark'] .ads-wrap { + filter: brightness(0.8); +} +[data-theme='dark'] img { + filter: brightness(0.8); +} +[data-theme='dark'] #aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed rgba(255,255,255,0.1); +} +[data-theme='dark'] #gitalk-container { + filter: brightness(0.8); +} +[data-theme='dark'] #gitalk-container svg { + fill: rgba(255,255,255,0.9) !important; +} +[data-theme='dark'] #disqusjs #dsqjs:hover, +[data-theme='dark'] #disqusjs #dsqjs:focus, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-tab-active, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-no-comment { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-order-label { + background-color: #1f1f1f; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body code, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body pre { + background: #2c2c2c; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body blockquote { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #artitalk_main #lazy { + background: #121212; +} +[data-theme='dark'] #operare_artitalk .c2 { + background: #121212; +} +@media screen and (max-width: 900px) { + [data-theme='dark'] #card-toc { + background: #1f1f1f; + } +} +.read-mode { + --font-color: #4c4948; + --readmode-light-color: #fff; + --white: #4c4948; + --light-grey: #4c4948; + --gray: #d6dbdf; + --hr-border: #d6dbdf; + --hr-before-color: #b9c2c9; + --highlight-bg: #f7f7f7; + --exit-btn-bg: #c0c0c0; + --exit-btn-color: #fff; + --exit-btn-hover: #8d8d8d; + --pseudo-hover: none; +} +[data-theme='dark'] .read-mode { + --font-color: rgba(255,255,255,0.7); + --readmode-light-color: #0d0d0d; + --white: rgba(255,255,255,0.9); + --light-grey: rgba(255,255,255,0.7); + --gray: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.5); + --hr-before-color: rgba(255,255,255,0.7); + --highlight-bg: #171717; + --exit-btn-bg: #1f1f1f; + --exit-btn-color: rgba(255,255,255,0.9); + --exit-btn-hover: #525252; +} +.read-mode { + background: var(--readmode-light-color); +} +.read-mode .exit-readmode { + position: fixed; + top: 30px; + right: 30px; + z-index: 100; + width: 40px; + height: 40px; + border-radius: 8px; + background: var(--exit-btn-bg); + color: var(--exit-btn-color); + font-size: 16px; + -webkit-transition: background 0.3s; + -moz-transition: background 0.3s; + -o-transition: background 0.3s; + -ms-transition: background 0.3s; + transition: background 0.3s; +} +@media screen and (max-width: 768px) { + .read-mode .exit-readmode { + top: initial; + bottom: 30px; + } +} +.read-mode .exit-readmode:hover { + background: var(--exit-btn-hover); +} +.read-mode #aside-content { + display: none; +} +.read-mode #page-header.post-bg { + background: none !important; +} +.read-mode #page-header.post-bg:before { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.read-mode #page-header.post-bg > #post-info { + text-align: center; +} +.read-mode #post { + margin: 0 auto; + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode #post:hover { + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode > canvas { + display: none !important; +} +.read-mode .highlight-tools, +.read-mode #footer, +.read-mode #post > *:not(#post-info):not(.post-content), +.read-mode #nav, +.read-mode .post-outdate-notice, +.read-mode #web_bg, +.read-mode #rightside, +.read-mode .not-top-img { + display: none !important; +} +.read-mode #article-container a { + color: #99a9bf; +} +.read-mode #article-container pre, +.read-mode #article-container .highlight:not(.js-file-line-container) { + background: var(--highlight-bg) !important; +} +.read-mode #article-container pre *, +.read-mode #article-container .highlight:not(.js-file-line-container) * { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight { + border-radius: 0 !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} +.read-mode #article-container figure.highlight > :not(.highlight-tools) { + display: block !important; +} +.read-mode #article-container figure.highlight .line:before { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight .hljs { + background: var(--highlight-bg) !important; +} +.read-mode #article-container h1, +.read-mode #article-container h2, +.read-mode #article-container h3, +.read-mode #article-container h4, +.read-mode #article-container h5, +.read-mode #article-container h6 { + padding: 0; +} +.read-mode #article-container h1:before, +.read-mode #article-container h2:before, +.read-mode #article-container h3:before, +.read-mode #article-container h4:before, +.read-mode #article-container h5:before, +.read-mode #article-container h6:before { + content: ''; +} +.read-mode #article-container h1:hover, +.read-mode #article-container h2:hover, +.read-mode #article-container h3:hover, +.read-mode #article-container h4:hover, +.read-mode #article-container h5:hover, +.read-mode #article-container h6:hover { + padding: 0; +} +.read-mode #article-container ul:hover:before, +.read-mode #article-container li:hover:before, +.read-mode #article-container ol:hover:before { + -webkit-transform: none !important; + -moz-transform: none !important; + -o-transform: none !important; + -ms-transform: none !important; + transform: none !important; +} +.read-mode #article-container ol:before, +.read-mode #article-container li:before { + background: transparent !important; + color: var(--font-color) !important; +} +.read-mode #article-container ul >li:before { + border-color: var(--gray) !important; +} +.read-mode #article-container .tabs { + border: 2px solid var(--tab-border-color); +} +.read-mode #article-container .tabs > .nav-tabs { + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab { + border-bottom: 0; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button { + border-top: none !important; + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button:hover { + background: none !important; +} +.read-mode #article-container .tabs > .nav-tabs > .tab.active button { + text-decoration: underline; +} +.read-mode #article-container .tabs > .tab-contents .tab-item-content.active { + -webkit-animation: none; + -moz-animation: none; + -o-animation: none; + -ms-animation: none; + animation: none; +} +.read-mode #article-container code { + color: var(--font-color); +} +.read-mode #article-container blockquote { + border-color: var(--gray); + background-color: var(--readmode-light-color); +} +.read-mode #article-container kbd { + border: 1px solid var(--gray); + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; + color: var(--font-color); +} +.read-mode #article-container .hide-toggle { + border: 1px solid var(--gray) !important; +} +.read-mode #article-container .hide-button, +.read-mode #article-container .btn-beautify, +.read-mode #article-container .hl-label { + border: 1px solid var(--gray) !important; + background: var(--readmode-light-color) !important; + color: var(--font-color) !important; +} +.read-mode #article-container .note { + border: 2px solid var(--gray); + border-left-color: var(--gray) !important; + filter: none; + background-color: var(--readmode-light-color) !important; + color: var(--font-color); +} +.read-mode #article-container .note:before, +.read-mode #article-container .note .note-icon { + color: var(--font-color); +} +.search-dialog { + position: fixed; + top: 10%; + left: 50%; + z-index: 1001; + display: none; + margin-left: -300px; + padding: 20px; + width: 600px; + border-radius: 8px; + background: var(--search-bg); + --search-height: 100vh; +} +@media screen and (max-width: 768px) { + .search-dialog { + top: 0; + left: 0; + margin: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +.search-dialog hr { + margin: 20px auto; +} +.search-dialog .search-nav { + margin: 0 0 14px; + color: #49b1f5; + font-size: 1.4em; + line-height: 1; +} +.search-dialog .search-nav .search-dialog-title { + margin-right: 10px; +} +.search-dialog .search-nav .search-close-button { + float: right; + color: #858585; + -webkit-transition: color 0.2s ease-in-out; + -moz-transition: color 0.2s ease-in-out; + -o-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; +} +.search-dialog .search-nav .search-close-button:hover { + color: #49b1f5; +} +.search-dialog hr { + margin: 20px auto; +} +#search-mask { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + display: none; + background: rgba(0,0,0,0.6); +} +#local-search .search-dialog .local-search-box { + margin: 0 auto; + max-width: 100%; + width: 100%; +} +#local-search .search-dialog .local-search-box input { + padding: 5px 14px; + width: 100%; + outline: none; + border: 2px solid #49b1f5; + border-radius: 40px; + background: var(--search-bg); + color: var(--search-input-color); + -webkit-appearance: none; +} +#local-search .search-dialog .search-wrap { + display: none; +} +#local-search .search-dialog .local-search-hit-item { + position: relative; + padding-left: 24px; + line-height: 1.7; +} +#local-search .search-dialog .local-search-hit-item:hover:before { + border-color: var(--pseudo-hover); +} +#local-search .search-dialog .local-search-hit-item:before { + position: absolute; + top: 0.45em; + left: 0; + width: 0.5em; + height: 0.5em; + border: 3px solid #49b1f5; + border-radius: 0.5em; + background: transparent; + content: ''; + line-height: 0.5em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#local-search .search-dialog .local-search-hit-item a { + display: block; + color: var(--search-a-color); +} +#local-search .search-dialog .local-search-hit-item a:hover { + color: #49b1f5; +} +#local-search .search-dialog .local-search-hit-item .search-result-title { + font-weight: 600; +} +#local-search .search-dialog .local-search-hit-item .search-result { + margin: 0 0 8px; + word-break: break-word; +} +#local-search .search-dialog .search-result-list { + overflow-y: overlay; + margin: 0 -20px; + padding: 0 22px; + max-height: calc(80vh - 200px); +} +@media screen and (max-width: 768px) { + #local-search .search-dialog .search-result-list { + max-height: calc(var(--search-height) - 220px) !important; + } +} +#local-search .search-dialog .no-result + #local-search-stats-wrap { + display: none; +} +.search-keyword { + background: transparent; + color: #f47466; + font-weight: bold; +} diff --git a/placeholder b/css/var.css similarity index 100% rename from placeholder rename to css/var.css diff --git a/img/404.jpg b/img/404.jpg new file mode 100644 index 000000000..4bab3c3f2 Binary files /dev/null and b/img/404.jpg differ diff --git a/img/favicon.png b/img/favicon.png new file mode 100644 index 000000000..862ebe858 Binary files /dev/null and b/img/favicon.png differ diff --git a/img/friend_404.gif b/img/friend_404.gif new file mode 100644 index 000000000..91dd56a28 Binary files /dev/null and b/img/friend_404.gif differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..e8239658c --- /dev/null +++ b/index.html @@ -0,0 +1,374 @@ +Research • 呓语 - Research + + + + + + + +
Hello World
2023立的flag
2023立的flag
包装类
字符串
抽象类与接口
继承、重写与重载
硬件性能监控平台
Constant Throughput Timer定时器
Gaussian Random Timer定时器
空降评论开/关评论弹幕复制本文地址
随便逛逛昼夜切换繁简转换阅读模式版权声明博客设置进入全屏
\ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 000000000..08bdc55d7 --- /dev/null +++ b/js/main.js @@ -0,0 +1,829 @@ +document.addEventListener('DOMContentLoaded', function () { + let headerContentWidth, $nav + let mobileSidebarOpen = false + + const adjustMenu = init => { + const getAllWidth = ele => { + let width = 0 + ele.length && Array.from(ele).forEach(i => { width += i.offsetWidth }) + return width + } + + if (init) { + const blogInfoWidth = getAllWidth(document.querySelector('#blog-info > a').children) + const menusWidth = getAllWidth(document.getElementById('menus').children) + headerContentWidth = blogInfoWidth + menusWidth + $nav = document.getElementById('nav') + } + + let hideMenuIndex = '' + if (window.innerWidth <= 768) hideMenuIndex = true + else hideMenuIndex = headerContentWidth > $nav.offsetWidth - 120 + + if (hideMenuIndex) { + $nav.classList.add('hide-menu') + } else { + $nav.classList.remove('hide-menu') + } + } + + // 初始化header + const initAdjust = () => { + adjustMenu(true) + $nav.classList.add('show') + } + + // sidebar menus + const sidebarFn = { + open: () => { + btf.sidebarPaddingR() + document.body.style.overflow = 'hidden' + btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s') + document.getElementById('sidebar-menus').classList.add('open') + mobileSidebarOpen = true + }, + close: () => { + const $body = document.body + $body.style.overflow = '' + $body.style.paddingRight = '' + btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s') + document.getElementById('sidebar-menus').classList.remove('open') + mobileSidebarOpen = false + } + } + + /** + * 首頁top_img底下的箭頭 + */ + const scrollDownInIndex = () => { + const $scrollDownEle = document.getElementById('scroll-down') + $scrollDownEle && $scrollDownEle.addEventListener('click', function () { + btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300) + }) + } + + /** + * 代碼 + * 只適用於Hexo默認的代碼渲染 + */ + const addHighlightTool = function () { + const highLight = GLOBAL_CONFIG.highlight + if (!highLight) return + + const { highlightCopy, highlightLang, highlightHeightLimit, plugin } = highLight + const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink + const isShowTool = highlightCopy || highlightLang || isHighlightShrink !== undefined + const $figureHighlight = plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') + + if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return + + const isPrismjs = plugin === 'prismjs' + const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' + const highlightShrinkEle = isHighlightShrink !== undefined ? `` : '' + const highlightCopyEle = highlightCopy ? '
' : '' + + const copy = (text, ctx) => { + if (document.queryCommandSupported && document.queryCommandSupported('copy')) { + document.execCommand('copy') + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.success) + } else { + const prevEle = ctx.previousElementSibling + prevEle.textContent = GLOBAL_CONFIG.copy.success + prevEle.style.opacity = 1 + setTimeout(() => { prevEle.style.opacity = 0 }, 700) + } + } else { + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport) + } else { + ctx.previousElementSibling.textContent = GLOBAL_CONFIG.copy.noSupport + } + } + } + + // click events + const highlightCopyFn = (ele) => { + const $buttonParent = ele.parentNode + $buttonParent.classList.add('copy-true') + const selection = window.getSelection() + const range = document.createRange() + const preCodeSelector = isPrismjs ? 'pre code' : 'table .code pre' + range.selectNodeContents($buttonParent.querySelectorAll(`${preCodeSelector}`)[0]) + selection.removeAllRanges() + selection.addRange(range) + const text = selection.toString() + copy(text, ele.lastChild) + selection.removeAllRanges() + $buttonParent.classList.remove('copy-true') + } + + const highlightShrinkFn = (ele) => { + const $nextEle = [...ele.parentNode.children].slice(1) + ele.firstChild.classList.toggle('closed') + if (btf.isHidden($nextEle[$nextEle.length - 1])) { + $nextEle.forEach(e => { e.style.display = 'block' }) + } else { + $nextEle.forEach(e => { e.style.display = 'none' }) + } + } + + const highlightToolsFn = function (e) { + const $target = e.target.classList + if ($target.contains('expand')) highlightShrinkFn(this) + else if ($target.contains('copy-button')) highlightCopyFn(this) + } + + const expandCode = function () { + this.classList.toggle('expand-done') + } + + function createEle (lang, item, service) { + const fragment = document.createDocumentFragment() + + if (isShowTool) { + const hlTools = document.createElement('div') + hlTools.className = `highlight-tools ${highlightShrinkClass}` + hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle + hlTools.addEventListener('click', highlightToolsFn) + fragment.appendChild(hlTools) + } + + if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) { + const ele = document.createElement('div') + ele.className = 'code-expand-btn' + ele.innerHTML = '' + ele.addEventListener('click', expandCode) + fragment.appendChild(ele) + } + + if (service === 'hl') { + item.insertBefore(fragment, item.firstChild) + } else { + item.parentNode.insertBefore(fragment, item) + } + } + + if (isPrismjs) { + $figureHighlight.forEach(item => { + if (highlightLang) { + const langName = item.getAttribute('data-language') || 'Code' + const highlightLangEle = `
${langName}
` + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle(highlightLangEle, item) + } else { + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle('', item) + } + }) + } else { + $figureHighlight.forEach(function (item) { + if (highlightLang) { + let langName = item.getAttribute('class').split(' ')[1] + if (langName === 'plain' || langName === undefined) langName = 'Code' + const highlightLangEle = `
${langName}
` + createEle(highlightLangEle, item, 'hl') + } else { + createEle('', item, 'hl') + } + }) + } + } + + /** + * PhotoFigcaption + */ + function addPhotoFigcaption () { + document.querySelectorAll('#article-container img').forEach(function (item) { + const parentEle = item.parentNode + const altValue = item.title || item.alt + if (altValue && !parentEle.parentNode.classList.contains('justified-gallery')) { + const ele = document.createElement('div') + ele.className = 'img-alt is-center' + ele.textContent = altValue + parentEle.insertBefore(ele, item.nextSibling) + } + }) + } + + /** + * Lightbox + */ + const runLightbox = () => { + btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)')) + } + + /** + * justified-gallery 圖庫排版 + */ + const runJustifiedGallery = function (ele) { + const htmlStr = arr => { + let str = '' + const replaceDq = str => str.replace(/"/g, '"') // replace double quotes to " + arr.forEach(i => { + const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : '' + const title = i.title ? `title="${replaceDq(i.title)}"` : '' + str += `` + }) + return str + } + + const lazyloadFn = (i, arr, limit) => { + const loadItem = limit + const arrLength = arr.length + if (arrLength > loadItem) i.insertAdjacentHTML('beforeend', htmlStr(arr.splice(0, loadItem))) + else { + i.insertAdjacentHTML('beforeend', htmlStr(arr)) + i.classList.remove('lazyload') + } + return arrLength > loadItem ? loadItem : arrLength + } + + const fetchUrl = async (url) => { + const response = await fetch(url) + return await response.json() + } + + const runJustifiedGallery = (item, arr) => { + if (!item.classList.contains('lazyload')) item.innerHTML = htmlStr(arr) + else { + const limit = item.getAttribute('data-limit') + lazyloadFn(item, arr, limit) + const clickBtnFn = () => { + const lastItemLength = lazyloadFn(item, arr, limit) + fjGallery(item, 'appendImages', item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)) + btf.loadLightbox(item.querySelectorAll('img')) + lastItemLength < limit && item.nextElementSibling.removeEventListener('click', clickBtnFn) + } + item.nextElementSibling.addEventListener('click', clickBtnFn) + } + btf.initJustifiedGallery(item) + btf.loadLightbox(item.querySelectorAll('img')) + } + + const addJustifiedGallery = () => { + ele.forEach(item => { + item.classList.contains('url') + ? fetchUrl(item.textContent).then(res => { runJustifiedGallery(item, res) }) + : runJustifiedGallery(item, JSON.parse(item.textContent)) + }) + } + + if (window.fjGallery) { + addJustifiedGallery() + return + } + + getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`) + getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(addJustifiedGallery) + } + + /** + * rightside scroll percent + */ + const rightsideScrollPercent = currentTop => { + const perNum = btf.getScrollPercent(currentTop, document.body) + const $goUp = document.getElementById('go-up') + if (perNum < 95) { + $goUp.classList.add('show-percent') + $goUp.querySelector('.scroll-percent').textContent = perNum + } else { + $goUp.classList.remove('show-percent') + } + } + + /** + * 滾動處理 + */ + const scrollFn = function () { + const $rightside = document.getElementById('rightside') + const innerHeight = window.innerHeight + 56 + let initTop = 0 + let isChatShow = true + const $header = document.getElementById('page-header') + const isChatBtn = typeof chatBtn !== 'undefined' + const isShowPercent = GLOBAL_CONFIG.percent.rightside + + // 當滾動條小于 56 的時候 + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 1; transform: translateX(-58px)' + return + } + + // find the scroll direction + const scrollDirection = currentTop => { + const result = currentTop > initTop // true is down & false is up + initTop = currentTop + return result + } + + const scrollTask = btf.throttle(() => { + const currentTop = window.scrollY || document.documentElement.scrollTop + const isDown = scrollDirection(currentTop) + if (currentTop > 56) { + $header.classList.add('is-top-bar') + if (isDown) { + if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible') + if (isChatBtn && isChatShow === true) { + window.chatBtn.hide() + isChatShow = false + } + } else { + if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible') + if (isChatBtn && isChatShow === false) { + window.chatBtn.show() + isChatShow = true + } + } + $header.classList.add('nav-fixed') + if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + } else { + if (currentTop === 0) { + // $header.classList.remove('nav-fixed', 'nav-visible') + $header.classList.remove('is-top-bar') + } + $rightside.style.cssText = "opacity: ''; transform: ''" + } + + isShowPercent && rightsideScrollPercent(currentTop) + + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + }, 200) + + window.scrollCollect = scrollTask + + window.addEventListener('scroll', scrollCollect) + } + + /** + * toc,anchor + */ + const scrollFnToDo = function () { + const isToc = GLOBAL_CONFIG_SITE.isToc + const isAnchor = GLOBAL_CONFIG.isAnchor + const $article = document.getElementById('article-container') + + if (!($article && (isToc || isAnchor))) return + + let $tocLink, $cardToc, autoScrollToc, $tocPercentage, isExpand + + if (isToc) { + const $cardTocLayout = document.getElementById('card-toc') + $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0] + $tocLink = $cardToc.querySelectorAll('.toc-link') + $tocPercentage = $cardTocLayout.querySelector('.toc-percentage') + isExpand = $cardToc.classList.contains('is-expand') + + window.mobileToc = { + open: () => { + $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px' + }, + + close: () => { + $cardTocLayout.style.animation = 'toc-close .2s' + setTimeout(() => { + $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''" + }, 100) + } + } + + // toc元素點擊 + $cardToc.addEventListener('click', e => { + e.preventDefault() + const target = e.target.classList + if (target.contains('toc-content')) return + const $target = target.contains('toc-link') + ? e.target + : e.target.parentElement + btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300) + if (window.innerWidth < 900) { + window.mobileToc.close() + } + }) + + autoScrollToc = item => { + const activePosition = item.getBoundingClientRect().top + const sidebarScrollTop = $cardToc.scrollTop + if (activePosition > (document.documentElement.clientHeight - 100)) { + $cardToc.scrollTop = sidebarScrollTop + 150 + } + if (activePosition < 100) { + $cardToc.scrollTop = sidebarScrollTop - 150 + } + } + } + + // find head position & add active class + const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6') + let detectItem = '' + const findHeadPosition = function (top) { + if (top === 0) { + return false + } + + let currentId = '' + let currentIndex = '' + + list.forEach(function (ele, index) { + if (top > btf.getEleTop(ele) - 80) { + const id = ele.id + currentId = id ? '#' + encodeURI(id) : '' + currentIndex = index + } + }) + + if (detectItem === currentIndex) return + + if (isAnchor) btf.updateAnchor(currentId) + + detectItem = currentIndex + + if (isToc) { + $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') }) + + if (currentId === '') { + return + } + + const currentActive = $tocLink[currentIndex] + currentActive.classList.add('active') + + setTimeout(() => { + autoScrollToc(currentActive) + }, 0) + + if (isExpand) return + let parent = currentActive.parentNode + + for (; !parent.matches('.toc'); parent = parent.parentNode) { + if (parent.matches('li')) parent.classList.add('active') + } + } + } + + // main of scroll + window.tocScrollFn = btf.throttle(() => { + const currentTop = window.scrollY || document.documentElement.scrollTop + if (isToc && GLOBAL_CONFIG.percent.toc) { + $tocPercentage.textContent = btf.getScrollPercent(currentTop, $article) + } + findHeadPosition(currentTop) + }, 100) + + window.addEventListener('scroll', tocScrollFn) + } + + const modeChangeFn = mode => { + if (!window.themeChange) { + return + } + + const turnMode = item => window.themeChange[item](mode) + + Object.keys(window.themeChange).forEach(item => { + if (['disqus', 'disqusjs'].includes(item)) { + setTimeout(() => turnMode(item), 300) + } else { + turnMode(item) + } + }) + } + + /** + * Rightside + */ + const rightSideFn = { + switchReadMode: () => { // read-mode + const $body = document.body + $body.classList.add('read-mode') + const newEle = document.createElement('button') + newEle.type = 'button' + newEle.className = 'fas fa-sign-out-alt exit-readmode' + $body.appendChild(newEle) + + const clickFn = () => { + $body.classList.remove('read-mode') + newEle.remove() + newEle.removeEventListener('click', clickFn) + } + + newEle.addEventListener('click', clickFn) + }, + switchDarkMode: () => { // Switch Between Light And Dark Mode + const willChangeMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'light' : 'dark' + if (willChangeMode === 'dark') { + activateDarkMode() + saveToLocal.set('theme', 'dark', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) + } else { + activateLightMode() + saveToLocal.set('theme', 'light', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) + } + modeChangeFn(willChangeMode) + }, + showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開 + const rightsideHideClassList = document.getElementById('rightside-config-hide').classList + rightsideHideClassList.toggle('show') + if (e.classList.contains('show')) { + rightsideHideClassList.add('status') + setTimeout(() => { + rightsideHideClassList.remove('status') + }, 300) + } + e.classList.toggle('show') + }, + scrollToTop: () => { // Back to top + btf.scrollToDest(0, 500) + }, + hideAsideBtn: () => { // Hide aside + const $htmlDom = document.documentElement.classList + const saveStatus = $htmlDom.contains('hide-aside') ? 'show' : 'hide' + saveToLocal.set('aside-status', saveStatus, 2) + $htmlDom.toggle('hide-aside') + }, + runMobileToc: () => { + if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open() + else window.mobileToc.close() + }, + toggleChatDisplay: () => { + window.chatBtnFn() + } + } + + document.getElementById('rightside').addEventListener('click', function (e) { + const $target = e.target.id ? e.target : e.target.parentNode + switch ($target.id) { + case 'go-up': + rightSideFn.scrollToTop() + break + case 'rightside_config': + rightSideFn.showOrHideBtn($target) + break + case 'mobile-toc-button': + rightSideFn.runMobileToc() + break + case 'readmode': + rightSideFn.switchReadMode() + break + case 'darkmode': + rightSideFn.switchDarkMode() + break + case 'hide-aside-btn': + rightSideFn.hideAsideBtn() + break + case 'chat-btn': + rightSideFn.toggleChatDisplay() + break + default: + break + } + }) + + /** + * menu + * 側邊欄sub-menu 展開/收縮 + */ + const clickFnOfSubMenu = () => { + document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) { + item.addEventListener('click', function () { + this.classList.toggle('hide') + }) + }) + } + + /** + * 複製時加上版權信息 + */ + const addCopyright = () => { + const copyright = GLOBAL_CONFIG.copyright + document.body.oncopy = (e) => { + e.preventDefault() + const copyFont = window.getSelection(0).toString() + let textFont = copyFont + if (copyFont.length > copyright.limitCount) { + textFont = `${copyFont}\n\n\n${copyright.languages.author}\n${copyright.languages.link}${window.location.href}\n${copyright.languages.source}\n${copyright.languages.info}` + } + if (e.clipboardData) { + return e.clipboardData.setData('text', textFont) + } else { + return window.clipboardData.setData('text', textFont) + } + } + } + + /** + * 網頁運行時間 + */ + const addRuntime = () => { + const $runtimeCount = document.getElementById('runtimeshow') + if ($runtimeCount) { + const publishDate = $runtimeCount.getAttribute('data-publishDate') + $runtimeCount.textContent = `${btf.diffDate(publishDate)} ${GLOBAL_CONFIG.runtime}` + } + } + + /** + * 最後一次更新時間 + */ + const addLastPushDate = () => { + const $lastPushDateItem = document.getElementById('last-push-date') + if ($lastPushDateItem) { + const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate') + $lastPushDateItem.textContent = btf.diffDate(lastPushDate, true) + } + } + + /** + * table overflow + */ + const addTableWrap = () => { + const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table') + if ($table.length) { + $table.forEach(item => { + btf.wrap(item, 'div', { class: 'table-wrap' }) + }) + } + } + + /** + * tag-hide + */ + const clickFnOfTagHide = function () { + const $hideInline = document.querySelectorAll('#article-container .hide-button') + if ($hideInline.length) { + $hideInline.forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + $this.classList.add('open') + const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery') + $fjGallery.length && btf.initJustifiedGallery($fjGallery) + }) + }) + } + } + + const tabsFn = { + clickFnOfTabs: function () { + document.querySelectorAll('#article-container .tab > button').forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + const $tabItem = $this.parentNode + + if (!$tabItem.classList.contains('active')) { + const $tabContent = $tabItem.parentNode.nextElementSibling + const $siblings = btf.siblings($tabItem, '.active')[0] + $siblings && $siblings.classList.remove('active') + $tabItem.classList.add('active') + const tabId = $this.getAttribute('data-href').replace('#', '') + const childList = [...$tabContent.children] + childList.forEach(item => { + if (item.id === tabId) item.classList.add('active') + else item.classList.remove('active') + }) + const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`) + if ($isTabJustifiedGallery.length > 0) { + btf.initJustifiedGallery($isTabJustifiedGallery) + } + } + }) + }) + }, + backToTop: () => { + document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) { + item.addEventListener('click', function () { + btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300) + }) + }) + } + } + + const toggleCardCategory = function () { + const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i') + if ($cardCategory.length) { + $cardCategory.forEach(function (item) { + item.addEventListener('click', function (e) { + e.preventDefault() + const $this = this + $this.classList.toggle('expand') + const $parentEle = $this.parentNode.nextElementSibling + if (btf.isHidden($parentEle)) { + $parentEle.style.display = 'block' + } else { + $parentEle.style.display = 'none' + } + }) + }) + } + } + + const switchComments = function () { + let switchDone = false + const $switchBtn = document.querySelector('#comment-switch > .switch-btn') + $switchBtn && $switchBtn.addEventListener('click', function () { + this.classList.toggle('move') + document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) { + if (btf.isHidden(item)) { + item.style.cssText = 'display: block;animation: tabshow .5s' + } else { + item.style.cssText = "display: none;animation: ''" + } + }) + + if (!switchDone && typeof loadOtherComment === 'function') { + switchDone = true + loadOtherComment() + } + }) + } + + const addPostOutdateNotice = function () { + const data = GLOBAL_CONFIG.noticeOutdate + const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate) + if (diffDay >= data.limitDay) { + const ele = document.createElement('div') + ele.className = 'post-outdate-notice' + ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext + const $targetEle = document.getElementById('article-container') + if (data.position === 'top') { + $targetEle.insertBefore(ele, $targetEle.firstChild) + } else { + $targetEle.appendChild(ele) + } + } + } + + const lazyloadImg = () => { + window.lazyLoadInstance = new LazyLoad({ + elements_selector: 'img', + threshold: 0, + data_src: 'lazy-src' + }) + } + + const relativeDate = function (selector) { + selector.forEach(item => { + const timeVal = item.getAttribute('datetime') + item.textContent = btf.diffDate(timeVal, true) + item.style.display = 'inline' + }) + } + + const unRefreshFn = function () { + window.addEventListener('resize', () => { + adjustMenu(false) + btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close() + }) + + document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() }) + + clickFnOfSubMenu() + GLOBAL_CONFIG.islazyload && lazyloadImg() + GLOBAL_CONFIG.copyright !== undefined && addCopyright() + + if (GLOBAL_CONFIG.autoDarkmode) { + window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { + if (saveToLocal.get('theme') !== undefined) return + e.matches ? modeChangeFn('dark') : modeChangeFn('light') + }) + } + } + + window.refreshFn = function () { + initAdjust() + + if (GLOBAL_CONFIG_SITE.isPost) { + GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice() + GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time')) + } else { + GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time')) + GLOBAL_CONFIG.runtime && addRuntime() + addLastPushDate() + toggleCardCategory() + } + + scrollFnToDo() + GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() + addHighlightTool() + GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() + scrollFn() + + const $jgEle = document.querySelectorAll('#article-container .fj-gallery') + $jgEle.length && runJustifiedGallery($jgEle) + + runLightbox() + addTableWrap() + clickFnOfTagHide() + tabsFn.clickFnOfTabs() + tabsFn.backToTop() + switchComments() + document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() }) + } + + refreshFn() + unRefreshFn() +}) diff --git a/js/search/algolia.js b/js/search/algolia.js new file mode 100644 index 000000000..9ac9f94ea --- /dev/null +++ b/js/search/algolia.js @@ -0,0 +1,177 @@ +window.addEventListener('load', () => { + const $searchMask = document.getElementById('search-mask') + const $searchDialog = document.querySelector('#algolia-search .search-dialog') + + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn($searchMask, 'to_show 0.5s') + btf.animateIn($searchDialog, 'titleScale 0.5s') + setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100) + + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + + fixSafariHeight() + window.addEventListener('resize', fixSafariHeight) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut($searchDialog, 'search_close .5s') + btf.animateOut($searchMask, 'to_hide 0.5s') + window.removeEventListener('resize', fixSafariHeight) + } + + // fix safari + const fixSafariHeight = () => { + if (window.innerWidth < 768) { + $searchDialog.style.setProperty('--search-height', window.innerHeight + 'px') + } + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchFnOnce = () => { + $searchMask.addEventListener('click', closeSearch) + document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch) + } + + const cutContent = content => { + if (content === '') return '' + + const firstOccur = content.indexOf('') + + let start = firstOccur - 30 + let end = firstOccur + 120 + let pre = '' + let post = '' + + if (start <= 0) { + start = 0 + end = 140 + } else { + pre = '...' + } + + if (end > content.length) { + end = content.length + } else { + post = '...' + } + + const matchContent = pre + content.substring(start, end) + post + return matchContent + } + + const algolia = GLOBAL_CONFIG.algolia + const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName + if (!isAlgoliaValid) { + return console.error('Algolia setting is invalid!') + } + + const search = instantsearch({ + indexName: algolia.indexName, + /* global algoliasearch */ + searchClient: algoliasearch(algolia.appId, algolia.apiKey), + searchFunction (helper) { + helper.state.query && helper.search() + } + }) + + const configure = instantsearch.widgets.configure({ + hitsPerPage: 5 + }) + + const searchBox = instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + showReset: false, + showSubmit: false, + placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder, + showLoadingIndicator: true + }) + + const hits = instantsearch.widgets.hits({ + container: '#algolia-hits', + templates: { + item (data) { + const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path) + const result = data._highlightResult + const content = result.contentStripTruncate + ? cutContent(result.contentStripTruncate.value) + : result.contentStrip + ? cutContent(result.contentStrip.value) + : result.content + ? cutContent(result.content.value) + : '' + return ` + + ${result.title.value || 'no-title'} +

${content}

+
` + }, + empty: function (data) { + return ( + '
' + + GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) + + '
' + ) + } + } + }) + + const stats = instantsearch.widgets.stats({ + container: '#algolia-info > .algolia-stats', + templates: { + text: function (data) { + const stats = GLOBAL_CONFIG.algolia.languages.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS) + return ( + `
${stats}` + ) + } + } + }) + + const powerBy = instantsearch.widgets.poweredBy({ + container: '#algolia-info > .algolia-poweredBy' + }) + + const pagination = instantsearch.widgets.pagination({ + container: '#algolia-pagination', + totalPages: 5, + templates: { + first: '', + last: '', + previous: '', + next: '' + } + }) + + search.addWidgets([configure, searchBox, hits, stats, powerBy, pagination]) // add the widgets to the instantsearch instance + + search.start() + + searchClickFn() + searchFnOnce() + + window.addEventListener('pjax:complete', () => { + !btf.isHidden($searchMask) && closeSearch() + searchClickFn() + }) + + window.pjax && search.on('render', () => { + window.pjax.refresh(document.getElementById('algolia-hits')) + }) +}) diff --git a/js/search/local-search.js b/js/search/local-search.js new file mode 100644 index 000000000..47cf84d23 --- /dev/null +++ b/js/search/local-search.js @@ -0,0 +1,360 @@ +/** + * Refer to hexo-generator-searchdb + * https://github.com/next-theme/hexo-generator-searchdb/blob/main/dist/search.js + * Modified by hexo-theme-butterfly + */ + +class LocalSearch { + constructor ({ + path = '', + unescape = false, + top_n_per_article = 1 + }) { + this.path = path + this.unescape = unescape + this.top_n_per_article = top_n_per_article + this.isfetched = false + this.datas = null + } + + getIndexByWord (words, text, caseSensitive = false) { + const index = [] + const included = new Set() + + if (!caseSensitive) { + text = text.toLowerCase() + } + words.forEach(word => { + if (this.unescape) { + const div = document.createElement('div') + div.innerText = word + word = div.innerHTML + } + const wordLen = word.length + if (wordLen === 0) return + let startPosition = 0 + let position = -1 + if (!caseSensitive) { + word = word.toLowerCase() + } + while ((position = text.indexOf(word, startPosition)) > -1) { + index.push({ position, word }) + included.add(word) + startPosition = position + wordLen + } + }) + // Sort index by position of keyword + index.sort((left, right) => { + if (left.position !== right.position) { + return left.position - right.position + } + return right.word.length - left.word.length + }) + return [index, included] + } + + // Merge hits into slices + mergeIntoSlice (start, end, index) { + let item = index[0] + let { position, word } = item + const hits = [] + const count = new Set() + while (position + word.length <= end && index.length !== 0) { + count.add(word) + hits.push({ + position, + length: word.length + }) + const wordEnd = position + word.length + + // Move to next position of hit + index.shift() + while (index.length !== 0) { + item = index[0] + position = item.position + word = item.word + if (wordEnd > position) { + index.shift() + } else { + break + } + } + } + return { + hits, + start, + end, + count: count.size + } + } + + // Highlight title and content + highlightKeyword (val, slice) { + let result = '' + let index = slice.start + for (const { position, length } of slice.hits) { + result += val.substring(index, position) + index = position + length + result += `${val.substr(position, length)}` + } + result += val.substring(index, slice.end) + return result + } + + getResultItems (keywords) { + const resultItems = [] + this.datas.forEach(({ title, content, url }) => { + // The number of different keywords included in the article. + const [indexOfTitle, keysOfTitle] = this.getIndexByWord(keywords, title) + const [indexOfContent, keysOfContent] = this.getIndexByWord(keywords, content) + const includedCount = new Set([...keysOfTitle, ...keysOfContent]).size + + // Show search results + const hitCount = indexOfTitle.length + indexOfContent.length + if (hitCount === 0) return + + const slicesOfTitle = [] + if (indexOfTitle.length !== 0) { + slicesOfTitle.push(this.mergeIntoSlice(0, title.length, indexOfTitle)) + } + + let slicesOfContent = [] + while (indexOfContent.length !== 0) { + const item = indexOfContent[0] + const { position } = item + // Cut out 120 characters. The maxlength of .search-input is 80. + const start = Math.max(0, position - 20) + const end = Math.min(content.length, position + 100) + slicesOfContent.push(this.mergeIntoSlice(start, end, indexOfContent)) + } + + // Sort slices in content by included keywords' count and hits' count + slicesOfContent.sort((left, right) => { + if (left.count !== right.count) { + return right.count - left.count + } else if (left.hits.length !== right.hits.length) { + return right.hits.length - left.hits.length + } + return left.start - right.start + }) + + // Select top N slices in content + const upperBound = parseInt(this.top_n_per_article, 10) + if (upperBound >= 0) { + slicesOfContent = slicesOfContent.slice(0, upperBound) + } + + let resultItem = '' + + url = new URL(url, location.origin) + url.searchParams.append('highlight', keywords.join(' ')) + + if (slicesOfTitle.length !== 0) { + resultItem += `
${this.highlightKeyword(title, slicesOfTitle[0])}` + } else { + resultItem += `' + resultItems.push({ + item: resultItem, + id: resultItems.length, + hitCount, + includedCount + }) + }) + return resultItems + } + + fetchData () { + const isXml = !this.path.endsWith('json') + fetch(this.path) + .then(response => response.text()) + .then(res => { + // Get the contents from search data + this.isfetched = true + this.datas = isXml + ? [...new DOMParser().parseFromString(res, 'text/xml').querySelectorAll('entry')].map(element => ({ + title: element.querySelector('title').textContent, + content: element.querySelector('content').textContent, + url: element.querySelector('url').textContent + })) + : JSON.parse(res) + // Only match articles with non-empty titles + this.datas = this.datas.filter(data => data.title).map(data => { + data.title = data.title.trim() + data.content = data.content ? data.content.trim().replace(/<[^>]+>/g, '') : '' + data.url = decodeURIComponent(data.url).replace(/\/{2,}/g, '/') + return data + }) + // Remove loading animation + window.dispatchEvent(new Event('search:loaded')) + }) + } + + // Highlight by wrapping node in mark elements with the given class name + highlightText (node, slice, className) { + const val = node.nodeValue + let index = slice.start + const children = [] + for (const { position, length } of slice.hits) { + const text = document.createTextNode(val.substring(index, position)) + index = position + length + const mark = document.createElement('mark') + mark.className = className + mark.appendChild(document.createTextNode(val.substr(position, length))) + children.push(text, mark) + } + node.nodeValue = val.substring(index, slice.end) + children.forEach(element => { + node.parentNode.insertBefore(element, node) + }) + } + + // Highlight the search words provided in the url in the text + highlightSearchWords (body) { + const params = new URL(location.href).searchParams.get('highlight') + const keywords = params ? params.split(' ') : [] + if (!keywords.length || !body) return + const walk = document.createTreeWalker(body, NodeFilter.SHOW_TEXT, null) + const allNodes = [] + while (walk.nextNode()) { + if (!walk.currentNode.parentNode.matches('button, select, textarea, .mermaid')) allNodes.push(walk.currentNode) + } + allNodes.forEach(node => { + const [indexOfNode] = this.getIndexByWord(keywords, node.nodeValue) + if (!indexOfNode.length) return + const slice = this.mergeIntoSlice(0, node.nodeValue.length, indexOfNode) + this.highlightText(node, slice, 'search-keyword') + }) + } +} + +window.addEventListener('load', () => { +// Search + const { path, top_n_per_article, unescape, languages } = GLOBAL_CONFIG.localSearch + const localSearch = new LocalSearch({ + path, + top_n_per_article, + unescape + }) + + const input = document.querySelector('#local-search-input input') + const statsItem = document.getElementById('local-search-stats-wrap') + const $loadingStatus = document.getElementById('loading-status') + + const inputEventFunction = () => { + if (!localSearch.isfetched) return + const searchText = input.value.trim().toLowerCase() + if (searchText !== '') $loadingStatus.innerHTML = '' + const keywords = searchText.split(/[-\s]+/) + const container = document.getElementById('local-search-results') + let resultItems = [] + if (searchText.length > 0) { + // Perform local searching + resultItems = localSearch.getResultItems(keywords) + } + if (keywords.length === 1 && keywords[0] === '') { + container.classList.add('no-result') + container.textContent = '' + } else if (resultItems.length === 0) { + container.textContent = '' + statsItem.innerHTML = `
${languages.hits_empty.replace(/\$\{query}/, searchText)}
` + } else { + resultItems.sort((left, right) => { + if (left.includedCount !== right.includedCount) { + return right.includedCount - left.includedCount + } else if (left.hitCount !== right.hitCount) { + return right.hitCount - left.hitCount + } + return right.id - left.id + }) + + const stats = languages.hits_stats.replace(/\$\{hits}/, resultItems.length) + + container.classList.remove('no-result') + container.innerHTML = `
${resultItems.map(result => result.item).join('')}
` + statsItem.innerHTML = `
${stats}
` + window.pjax && window.pjax.refresh(container) + } + + $loadingStatus.textContent = '' + } + + let loadFlag = false + const $searchMask = document.getElementById('search-mask') + const $searchDialog = document.querySelector('#local-search .search-dialog') + + // fix safari + const fixSafariHeight = () => { + if (window.innerWidth < 768) { + $searchDialog.style.setProperty('--search-height', window.innerHeight + 'px') + } + } + + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn($searchMask, 'to_show 0.5s') + btf.animateIn($searchDialog, 'titleScale 0.5s') + setTimeout(() => { input.focus() }, 300) + if (!loadFlag) { + !localSearch.isfetched && localSearch.fetchData() + input.addEventListener('input', inputEventFunction) + loadFlag = true + } + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + + fixSafariHeight() + window.addEventListener('resize', fixSafariHeight) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut($searchDialog, 'search_close .5s') + btf.animateOut($searchMask, 'to_hide 0.5s') + window.removeEventListener('resize', fixSafariHeight) + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchFnOnce = () => { + document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch) + $searchMask.addEventListener('click', closeSearch) + if (GLOBAL_CONFIG.localSearch.preload) { + localSearch.fetchData() + } + localSearch.highlightSearchWords(document.getElementById('article-container')) + } + + window.addEventListener('search:loaded', () => { + const $loadDataItem = document.getElementById('loading-database') + $loadDataItem.nextElementSibling.style.display = 'block' + $loadDataItem.remove() + }) + + searchClickFn() + searchFnOnce() + + // pjax + window.addEventListener('pjax:complete', () => { + !btf.isHidden($searchMask) && closeSearch() + localSearch.highlightSearchWords(document.getElementById('article-container')) + searchClickFn() + }) +}) diff --git a/js/tw_cn.js b/js/tw_cn.js new file mode 100644 index 000000000..c27db8f2d --- /dev/null +++ b/js/tw_cn.js @@ -0,0 +1,115 @@ +document.addEventListener('DOMContentLoaded', function () { + const { defaultEncoding, translateDelay, msgToTraditionalChinese, msgToSimplifiedChinese } = GLOBAL_CONFIG.translate + const snackbarData = GLOBAL_CONFIG.Snackbar + let currentEncoding = defaultEncoding + const targetEncodingCookie = 'translate-chn-cht' + let targetEncoding = + saveToLocal.get(targetEncodingCookie) === undefined + ? defaultEncoding + : Number(saveToLocal.get('translate-chn-cht')) + let translateButtonObject + const isSnackbar = snackbarData !== undefined + + function setLang () { + document.documentElement.lang = targetEncoding === 1 ? 'zh-TW' : 'zh-CN' + } + + function translateText (txt) { + if (txt === '' || txt == null) return '' + if (currentEncoding === 1 && targetEncoding === 2) return Simplized(txt) + else if (currentEncoding === 2 && targetEncoding === 1) { + return Traditionalized(txt) + } else return txt + } + function translateBody (fobj) { + let objs + if (typeof fobj === 'object') objs = fobj.childNodes + else objs = document.body.childNodes + for (let i = 0; i < objs.length; i++) { + const obj = objs.item(i) + if ( + '||BR|HR|'.indexOf('|' + obj.tagName + '|') > 0 || + obj === translateButtonObject + ) { + continue + } + if (obj.title !== '' && obj.title != null) { + obj.title = translateText(obj.title) + } + if (obj.alt !== '' && obj.alt != null) obj.alt = translateText(obj.alt) + if (obj.placeholder !== '' && obj.placeholder != null) { obj.placeholder = translateText(obj.placeholder) } + if ( + obj.tagName === 'INPUT' && + obj.value !== '' && + obj.type !== 'text' && + obj.type !== 'hidden' + ) { + obj.value = translateText(obj.value) + } + if (obj.nodeType === 3) obj.data = translateText(obj.data) + else translateBody(obj) + } + } + function translatePage () { + if (targetEncoding === 1) { + currentEncoding = 1 + targetEncoding = 2 + translateButtonObject.textContent = msgToTraditionalChinese + isSnackbar && btf.snackbarShow(snackbarData.cht_to_chs) + } else if (targetEncoding === 2) { + currentEncoding = 2 + targetEncoding = 1 + translateButtonObject.textContent = msgToSimplifiedChinese + isSnackbar && btf.snackbarShow(snackbarData.chs_to_cht) + } + saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + setLang() + translateBody() + } + + function JTPYStr () { + return '万与丑专业丛东丝丢两严丧个丬丰临为丽举么义乌乐乔习乡书买乱争于亏云亘亚产亩亲亵亸亿仅从仑仓仪们价众优伙会伛伞伟传伤伥伦伧伪伫体余佣佥侠侣侥侦侧侨侩侪侬俣俦俨俩俪俭债倾偬偻偾偿傥傧储傩儿兑兖党兰关兴兹养兽冁内冈册写军农冢冯冲决况冻净凄凉凌减凑凛几凤凫凭凯击凼凿刍划刘则刚创删别刬刭刽刿剀剂剐剑剥剧劝办务劢动励劲劳势勋勐勚匀匦匮区医华协单卖卢卤卧卫却卺厂厅历厉压厌厍厕厢厣厦厨厩厮县参叆叇双发变叙叠叶号叹叽吁后吓吕吗吣吨听启吴呒呓呕呖呗员呙呛呜咏咔咙咛咝咤咴咸哌响哑哒哓哔哕哗哙哜哝哟唛唝唠唡唢唣唤唿啧啬啭啮啰啴啸喷喽喾嗫呵嗳嘘嘤嘱噜噼嚣嚯团园囱围囵国图圆圣圹场坂坏块坚坛坜坝坞坟坠垄垅垆垒垦垧垩垫垭垯垱垲垴埘埙埚埝埯堑堕塆墙壮声壳壶壸处备复够头夸夹夺奁奂奋奖奥妆妇妈妩妪妫姗姜娄娅娆娇娈娱娲娴婳婴婵婶媪嫒嫔嫱嬷孙学孪宁宝实宠审宪宫宽宾寝对寻导寿将尔尘尧尴尸尽层屃屉届属屡屦屿岁岂岖岗岘岙岚岛岭岳岽岿峃峄峡峣峤峥峦崂崃崄崭嵘嵚嵛嵝嵴巅巩巯币帅师帏帐帘帜带帧帮帱帻帼幂幞干并广庄庆庐庑库应庙庞废庼廪开异弃张弥弪弯弹强归当录彟彦彻径徕御忆忏忧忾怀态怂怃怄怅怆怜总怼怿恋恳恶恸恹恺恻恼恽悦悫悬悭悯惊惧惨惩惫惬惭惮惯愍愠愤愦愿慑慭憷懑懒懔戆戋戏戗战戬户扎扑扦执扩扪扫扬扰抚抛抟抠抡抢护报担拟拢拣拥拦拧拨择挂挚挛挜挝挞挟挠挡挢挣挤挥挦捞损捡换捣据捻掳掴掷掸掺掼揸揽揿搀搁搂搅携摄摅摆摇摈摊撄撑撵撷撸撺擞攒敌敛数斋斓斗斩断无旧时旷旸昙昼昽显晋晒晓晔晕晖暂暧札术朴机杀杂权条来杨杩杰极构枞枢枣枥枧枨枪枫枭柜柠柽栀栅标栈栉栊栋栌栎栏树栖样栾桊桠桡桢档桤桥桦桧桨桩梦梼梾检棂椁椟椠椤椭楼榄榇榈榉槚槛槟槠横樯樱橥橱橹橼檐檩欢欤欧歼殁殇残殒殓殚殡殴毁毂毕毙毡毵氇气氢氩氲汇汉污汤汹沓沟没沣沤沥沦沧沨沩沪沵泞泪泶泷泸泺泻泼泽泾洁洒洼浃浅浆浇浈浉浊测浍济浏浐浑浒浓浔浕涂涌涛涝涞涟涠涡涢涣涤润涧涨涩淀渊渌渍渎渐渑渔渖渗温游湾湿溃溅溆溇滗滚滞滟滠满滢滤滥滦滨滩滪漤潆潇潋潍潜潴澜濑濒灏灭灯灵灾灿炀炉炖炜炝点炼炽烁烂烃烛烟烦烧烨烩烫烬热焕焖焘煅煳熘爱爷牍牦牵牺犊犟状犷犸犹狈狍狝狞独狭狮狯狰狱狲猃猎猕猡猪猫猬献獭玑玙玚玛玮环现玱玺珉珏珐珑珰珲琎琏琐琼瑶瑷璇璎瓒瓮瓯电画畅畲畴疖疗疟疠疡疬疮疯疱疴痈痉痒痖痨痪痫痴瘅瘆瘗瘘瘪瘫瘾瘿癞癣癫癯皑皱皲盏盐监盖盗盘眍眦眬着睁睐睑瞒瞩矫矶矾矿砀码砖砗砚砜砺砻砾础硁硅硕硖硗硙硚确硷碍碛碜碱碹磙礼祎祢祯祷祸禀禄禅离秃秆种积称秽秾稆税稣稳穑穷窃窍窑窜窝窥窦窭竖竞笃笋笔笕笺笼笾筑筚筛筜筝筹签简箓箦箧箨箩箪箫篑篓篮篱簖籁籴类籼粜粝粤粪粮糁糇紧絷纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵罂网罗罚罢罴羁羟羡翘翙翚耢耧耸耻聂聋职聍联聩聪肃肠肤肷肾肿胀胁胆胜胧胨胪胫胶脉脍脏脐脑脓脔脚脱脶脸腊腌腘腭腻腼腽腾膑臜舆舣舰舱舻艰艳艹艺节芈芗芜芦苁苇苈苋苌苍苎苏苘苹茎茏茑茔茕茧荆荐荙荚荛荜荞荟荠荡荣荤荥荦荧荨荩荪荫荬荭荮药莅莜莱莲莳莴莶获莸莹莺莼萚萝萤营萦萧萨葱蒇蒉蒋蒌蓝蓟蓠蓣蓥蓦蔷蔹蔺蔼蕲蕴薮藁藓虏虑虚虫虬虮虽虾虿蚀蚁蚂蚕蚝蚬蛊蛎蛏蛮蛰蛱蛲蛳蛴蜕蜗蜡蝇蝈蝉蝎蝼蝾螀螨蟏衅衔补衬衮袄袅袆袜袭袯装裆裈裢裣裤裥褛褴襁襕见观觃规觅视觇览觉觊觋觌觍觎觏觐觑觞触觯詟誉誊讠计订讣认讥讦讧讨让讪讫训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷豮贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赪赵赶趋趱趸跃跄跖跞践跶跷跸跹跻踊踌踪踬踯蹑蹒蹰蹿躏躜躯车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辞辩辫边辽达迁过迈运还这进远违连迟迩迳迹适选逊递逦逻遗遥邓邝邬邮邹邺邻郁郄郏郐郑郓郦郧郸酝酦酱酽酾酿释里鉅鉴銮錾钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铈铉铊铋铍铎铏铐铑铒铕铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗错锚锜锞锟锠锡锢锣锤锥锦锨锩锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镆镇镈镉镊镌镍镎镏镐镑镒镕镖镗镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镶长门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛队阳阴阵阶际陆陇陈陉陕陧陨险随隐隶隽难雏雠雳雾霁霉霭靓静靥鞑鞒鞯鞴韦韧韨韩韪韫韬韵页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧风飏飐飑飒飓飔飕飖飗飘飙飚飞飨餍饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧髅髋髌鬓魇魉鱼鱽鱾鱿鲀鲁鲂鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳛鳜鳝鳞鳟鳠鳡鳢鳣鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹯鹰鹱鹲鹳鹴鹾麦麸黄黉黡黩黪黾龙历志制一台皋准复猛钟注范签' + } + function FTPYStr () { + return '萬與醜專業叢東絲丟兩嚴喪個爿豐臨為麗舉麼義烏樂喬習鄉書買亂爭於虧雲亙亞產畝親褻嚲億僅從侖倉儀們價眾優夥會傴傘偉傳傷倀倫傖偽佇體餘傭僉俠侶僥偵側僑儈儕儂俁儔儼倆儷儉債傾傯僂僨償儻儐儲儺兒兌兗黨蘭關興茲養獸囅內岡冊寫軍農塚馮衝決況凍淨淒涼淩減湊凜幾鳳鳧憑凱擊氹鑿芻劃劉則剛創刪別剗剄劊劌剴劑剮劍剝劇勸辦務勱動勵勁勞勢勳猛勩勻匭匱區醫華協單賣盧鹵臥衛卻巹廠廳曆厲壓厭厙廁廂厴廈廚廄廝縣參靉靆雙發變敘疊葉號歎嘰籲後嚇呂嗎唚噸聽啟吳嘸囈嘔嚦唄員咼嗆嗚詠哢嚨嚀噝吒噅鹹呱響啞噠嘵嗶噦嘩噲嚌噥喲嘜嗊嘮啢嗩唕喚呼嘖嗇囀齧囉嘽嘯噴嘍嚳囁嗬噯噓嚶囑嚕劈囂謔團園囪圍圇國圖圓聖壙場阪壞塊堅壇壢壩塢墳墜壟壟壚壘墾坰堊墊埡墶壋塏堖塒塤堝墊垵塹墮壪牆壯聲殼壺壼處備複夠頭誇夾奪奩奐奮獎奧妝婦媽嫵嫗媯姍薑婁婭嬈嬌孌娛媧嫻嫿嬰嬋嬸媼嬡嬪嬙嬤孫學孿寧寶實寵審憲宮寬賓寢對尋導壽將爾塵堯尷屍盡層屭屜屆屬屢屨嶼歲豈嶇崗峴嶴嵐島嶺嶽崠巋嶨嶧峽嶢嶠崢巒嶗崍嶮嶄嶸嶔崳嶁脊巔鞏巰幣帥師幃帳簾幟帶幀幫幬幘幗冪襆幹並廣莊慶廬廡庫應廟龐廢廎廩開異棄張彌弳彎彈強歸當錄彠彥徹徑徠禦憶懺憂愾懷態慫憮慪悵愴憐總懟懌戀懇惡慟懨愷惻惱惲悅愨懸慳憫驚懼慘懲憊愜慚憚慣湣慍憤憒願懾憖怵懣懶懍戇戔戲戧戰戩戶紮撲扡執擴捫掃揚擾撫拋摶摳掄搶護報擔擬攏揀擁攔擰撥擇掛摯攣掗撾撻挾撓擋撟掙擠揮撏撈損撿換搗據撚擄摑擲撣摻摜摣攬撳攙擱摟攪攜攝攄擺搖擯攤攖撐攆擷擼攛擻攢敵斂數齋斕鬥斬斷無舊時曠暘曇晝曨顯晉曬曉曄暈暉暫曖劄術樸機殺雜權條來楊榪傑極構樅樞棗櫪梘棖槍楓梟櫃檸檉梔柵標棧櫛櫳棟櫨櫟欄樹棲樣欒棬椏橈楨檔榿橋樺檜槳樁夢檮棶檢欞槨櫝槧欏橢樓欖櫬櫚櫸檟檻檳櫧橫檣櫻櫫櫥櫓櫞簷檁歡歟歐殲歿殤殘殞殮殫殯毆毀轂畢斃氈毿氌氣氫氬氳彙漢汙湯洶遝溝沒灃漚瀝淪滄渢溈滬濔濘淚澩瀧瀘濼瀉潑澤涇潔灑窪浹淺漿澆湞溮濁測澮濟瀏滻渾滸濃潯濜塗湧濤澇淶漣潿渦溳渙滌潤澗漲澀澱淵淥漬瀆漸澠漁瀋滲溫遊灣濕潰濺漵漊潷滾滯灩灄滿瀅濾濫灤濱灘澦濫瀠瀟瀲濰潛瀦瀾瀨瀕灝滅燈靈災燦煬爐燉煒熗點煉熾爍爛烴燭煙煩燒燁燴燙燼熱煥燜燾煆糊溜愛爺牘犛牽犧犢強狀獷獁猶狽麅獮獰獨狹獅獪猙獄猻獫獵獼玀豬貓蝟獻獺璣璵瑒瑪瑋環現瑲璽瑉玨琺瓏璫琿璡璉瑣瓊瑤璦璿瓔瓚甕甌電畫暢佘疇癤療瘧癘瘍鬁瘡瘋皰屙癰痙癢瘂癆瘓癇癡癉瘮瘞瘺癟癱癮癭癩癬癲臒皚皺皸盞鹽監蓋盜盤瞘眥矓著睜睞瞼瞞矚矯磯礬礦碭碼磚硨硯碸礪礱礫礎硜矽碩硤磽磑礄確鹼礙磧磣堿镟滾禮禕禰禎禱禍稟祿禪離禿稈種積稱穢穠穭稅穌穩穡窮竊竅窯竄窩窺竇窶豎競篤筍筆筧箋籠籩築篳篩簹箏籌簽簡籙簀篋籜籮簞簫簣簍籃籬籪籟糴類秈糶糲粵糞糧糝餱緊縶糸糾紆紅紂纖紇約級紈纊紀紉緯紜紘純紕紗綱納紝縱綸紛紙紋紡紵紖紐紓線紺絏紱練組紳細織終縐絆紼絀紹繹經紿綁絨結絝繞絰絎繪給絢絳絡絕絞統綆綃絹繡綌綏絛繼綈績緒綾緓續綺緋綽緔緄繩維綿綬繃綢綯綹綣綜綻綰綠綴緇緙緗緘緬纜緹緲緝縕繢緦綞緞緶線緱縋緩締縷編緡緣縉縛縟縝縫縗縞纏縭縊縑繽縹縵縲纓縮繆繅纈繚繕繒韁繾繰繯繳纘罌網羅罰罷羆羈羥羨翹翽翬耮耬聳恥聶聾職聹聯聵聰肅腸膚膁腎腫脹脅膽勝朧腖臚脛膠脈膾髒臍腦膿臠腳脫腡臉臘醃膕齶膩靦膃騰臏臢輿艤艦艙艫艱豔艸藝節羋薌蕪蘆蓯葦藶莧萇蒼苧蘇檾蘋莖蘢蔦塋煢繭荊薦薘莢蕘蓽蕎薈薺蕩榮葷滎犖熒蕁藎蓀蔭蕒葒葤藥蒞蓧萊蓮蒔萵薟獲蕕瑩鶯蓴蘀蘿螢營縈蕭薩蔥蕆蕢蔣蔞藍薊蘺蕷鎣驀薔蘞藺藹蘄蘊藪槁蘚虜慮虛蟲虯蟣雖蝦蠆蝕蟻螞蠶蠔蜆蠱蠣蟶蠻蟄蛺蟯螄蠐蛻蝸蠟蠅蟈蟬蠍螻蠑螿蟎蠨釁銜補襯袞襖嫋褘襪襲襏裝襠褌褳襝褲襇褸襤繈襴見觀覎規覓視覘覽覺覬覡覿覥覦覯覲覷觴觸觶讋譽謄訁計訂訃認譏訐訌討讓訕訖訓議訊記訒講諱謳詎訝訥許訛論訩訟諷設訪訣證詁訶評詛識詗詐訴診詆謅詞詘詔詖譯詒誆誄試詿詩詰詼誠誅詵話誕詬詮詭詢詣諍該詳詫諢詡譸誡誣語誚誤誥誘誨誑說誦誒請諸諏諾讀諑誹課諉諛誰諗調諂諒諄誶談誼謀諶諜謊諫諧謔謁謂諤諭諼讒諮諳諺諦謎諞諝謨讜謖謝謠謗諡謙謐謹謾謫譾謬譚譖譙讕譜譎讞譴譫讖穀豶貝貞負貟貢財責賢敗賬貨質販貪貧貶購貯貫貳賤賁貰貼貴貺貸貿費賀貽賊贄賈賄貲賃賂贓資賅贐賕賑賚賒賦賭齎贖賞賜贔賙賡賠賧賴賵贅賻賺賽賾贗讚贇贈贍贏贛赬趙趕趨趲躉躍蹌蹠躒踐躂蹺蹕躚躋踴躊蹤躓躑躡蹣躕躥躪躦軀車軋軌軒軑軔轉軛輪軟轟軲軻轤軸軹軼軤軫轢軺輕軾載輊轎輈輇輅較輒輔輛輦輩輝輥輞輬輟輜輳輻輯轀輸轡轅轄輾轆轍轔辭辯辮邊遼達遷過邁運還這進遠違連遲邇逕跡適選遜遞邐邏遺遙鄧鄺鄔郵鄒鄴鄰鬱郤郟鄶鄭鄆酈鄖鄲醞醱醬釅釃釀釋裏钜鑒鑾鏨釓釔針釘釗釙釕釷釺釧釤鈒釩釣鍆釹鍚釵鈃鈣鈈鈦鈍鈔鍾鈉鋇鋼鈑鈐鑰欽鈞鎢鉤鈧鈁鈥鈄鈕鈀鈺錢鉦鉗鈷缽鈳鉕鈽鈸鉞鑽鉬鉭鉀鈿鈾鐵鉑鈴鑠鉛鉚鈰鉉鉈鉍鈹鐸鉶銬銠鉺銪鋏鋣鐃銍鐺銅鋁銱銦鎧鍘銖銑鋌銩銛鏵銓鉿銚鉻銘錚銫鉸銥鏟銃鐋銨銀銣鑄鐒鋪鋙錸鋱鏈鏗銷鎖鋰鋥鋤鍋鋯鋨鏽銼鋝鋒鋅鋶鐦鐧銳銻鋃鋟鋦錒錆鍺錯錨錡錁錕錩錫錮鑼錘錐錦鍁錈錇錟錠鍵鋸錳錙鍥鍈鍇鏘鍶鍔鍤鍬鍾鍛鎪鍠鍰鎄鍍鎂鏤鎡鏌鎮鎛鎘鑷鐫鎳鎿鎦鎬鎊鎰鎔鏢鏜鏍鏰鏞鏡鏑鏃鏇鏐鐔钁鐐鏷鑥鐓鑭鐠鑹鏹鐙鑊鐳鐶鐲鐮鐿鑔鑣鑞鑲長門閂閃閆閈閉問闖閏闈閑閎間閔閌悶閘鬧閨聞闥閩閭闓閥閣閡閫鬮閱閬闍閾閹閶鬩閿閽閻閼闡闌闃闠闊闋闔闐闒闕闞闤隊陽陰陣階際陸隴陳陘陝隉隕險隨隱隸雋難雛讎靂霧霽黴靄靚靜靨韃鞽韉韝韋韌韍韓韙韞韜韻頁頂頃頇項順須頊頑顧頓頎頒頌頏預顱領頗頸頡頰頲頜潁熲頦頤頻頮頹頷頴穎顆題顒顎顓顏額顳顢顛顙顥纇顫顬顰顴風颺颭颮颯颶颸颼颻飀飄飆飆飛饗饜飣饑飥餳飩餼飪飫飭飯飲餞飾飽飼飿飴餌饒餉餄餎餃餏餅餑餖餓餘餒餕餜餛餡館餷饋餶餿饞饁饃餺餾饈饉饅饊饌饢馬馭馱馴馳驅馹駁驢駔駛駟駙駒騶駐駝駑駕驛駘驍罵駰驕驊駱駭駢驫驪騁驗騂駸駿騏騎騍騅騌驌驂騙騭騤騷騖驁騮騫騸驃騾驄驏驟驥驦驤髏髖髕鬢魘魎魚魛魢魷魨魯魴魺鮁鮃鯰鱸鮋鮓鮒鮊鮑鱟鮍鮐鮭鮚鮳鮪鮞鮦鰂鮜鱠鱭鮫鮮鮺鯗鱘鯁鱺鰱鰹鯉鰣鰷鯀鯊鯇鮶鯽鯒鯖鯪鯕鯫鯡鯤鯧鯝鯢鯰鯛鯨鯵鯴鯔鱝鰈鰏鱨鯷鰮鰃鰓鱷鰍鰒鰉鰁鱂鯿鰠鼇鰭鰨鰥鰩鰟鰜鰳鰾鱈鱉鰻鰵鱅鰼鱖鱔鱗鱒鱯鱤鱧鱣鳥鳩雞鳶鳴鳲鷗鴉鶬鴇鴆鴣鶇鸕鴨鴞鴦鴒鴟鴝鴛鴬鴕鷥鷙鴯鴰鵂鴴鵃鴿鸞鴻鵐鵓鸝鵑鵠鵝鵒鷳鵜鵡鵲鶓鵪鶤鵯鵬鵮鶉鶊鵷鷫鶘鶡鶚鶻鶿鶥鶩鷊鷂鶲鶹鶺鷁鶼鶴鷖鸚鷓鷚鷯鷦鷲鷸鷺鸇鷹鸌鸏鸛鸘鹺麥麩黃黌黶黷黲黽龍歷誌製壹臺臯準復勐鐘註範籤' + } + function Traditionalized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && ss.indexOf(cc.charAt(i)) !== -1) { + str += tt.charAt(ss.indexOf(cc.charAt(i))) + } else str += cc.charAt(i) + } + return str + } + function Simplized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && tt.indexOf(cc.charAt(i)) !== -1) { + str += ss.charAt(tt.indexOf(cc.charAt(i))) + } else str += cc.charAt(i) + } + return str + } + + function translateInitialization () { + translateButtonObject = document.getElementById('translateLink') + if (translateButtonObject) { + if (currentEncoding !== targetEncoding) { + translateButtonObject.textContent = + targetEncoding === 1 + ? msgToSimplifiedChinese + : msgToTraditionalChinese + setLang() + setTimeout(translateBody, translateDelay) + } + translateButtonObject.addEventListener('click', translatePage, false) + } + } + translateInitialization() + document.addEventListener('pjax:complete', translateInitialization) +}) diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 000000000..adff39ca8 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,307 @@ +const btf = { + debounce: function (func, wait, immediate) { + let timeout + return function () { + const context = this + const args = arguments + const later = function () { + timeout = null + if (!immediate) func.apply(context, args) + } + const callNow = immediate && !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func.apply(context, args) + } + }, + + throttle: function (func, wait, options) { + let timeout, context, args + let previous = 0 + if (!options) options = {} + + const later = function () { + previous = options.leading === false ? 0 : new Date().getTime() + timeout = null + func.apply(context, args) + if (!timeout) context = args = null + } + + const throttled = function () { + const now = new Date().getTime() + if (!previous && options.leading === false) previous = now + const remaining = wait - (now - previous) + context = this + args = arguments + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + previous = now + func.apply(context, args) + if (!timeout) context = args = null + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining) + } + } + + return throttled + }, + + sidebarPaddingR: () => { + const innerWidth = window.innerWidth + const clientWidth = document.body.clientWidth + const paddingRight = innerWidth - clientWidth + if (innerWidth !== clientWidth) { + document.body.style.paddingRight = paddingRight + 'px' + } + }, + + snackbarShow: (text, showAction = false, duration = 2000) => { + const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar + const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark + Snackbar.show({ + text, + backgroundColor: bg, + showAction, + duration, + pos: position, + customClass: 'snackbar-css' + }) + }, + + diffDate: (d, more = false) => { + const dateNow = new Date() + const datePost = new Date(d) + const dateDiff = dateNow.getTime() - datePost.getTime() + const minute = 1000 * 60 + const hour = minute * 60 + const day = hour * 24 + const month = day * 30 + const { dateSuffix } = GLOBAL_CONFIG + + if (!more) return parseInt(dateDiff / day) + + const monthCount = dateDiff / month + const dayCount = dateDiff / day + const hourCount = dateDiff / hour + const minuteCount = dateDiff / minute + + if (monthCount > 12) return datePost.toISOString().slice(0, 10) + if (monthCount >= 1) return `${parseInt(monthCount)} ${dateSuffix.month}` + if (dayCount >= 1) return `${parseInt(dayCount)} ${dateSuffix.day}` + if (hourCount >= 1) return `${parseInt(hourCount)} ${dateSuffix.hour}` + if (minuteCount >= 1) return `${parseInt(minuteCount)} ${dateSuffix.min}` + return dateSuffix.just + }, + + loadComment: (dom, callback) => { + if ('IntersectionObserver' in window) { + const observerItem = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + callback() + observerItem.disconnect() + } + }, { threshold: [0] }) + observerItem.observe(dom) + } else { + callback() + } + }, + + scrollToDest: (pos, time = 500) => { + const currentPos = window.pageYOffset + const isNavFixed = document.getElementById('page-header').classList.contains('fixed') + if (currentPos > pos || isNavFixed) pos = pos - 70 + + if ('scrollBehavior' in document.documentElement.style) { + window.scrollTo({ + top: pos, + behavior: 'smooth' + }) + return + } + + let start = null + pos = +pos + window.requestAnimationFrame(function step (currentTime) { + start = !start ? currentTime : start + const progress = currentTime - start + if (currentPos < pos) { + window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) + } else { + window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) + } + if (progress < time) { + window.requestAnimationFrame(step) + } else { + window.scrollTo(0, pos) + } + }) + }, + + animateIn: (ele, text) => { + ele.style.display = 'block' + ele.style.animation = text + }, + + animateOut: (ele, text) => { + ele.addEventListener('animationend', function f () { + ele.style.display = '' + ele.style.animation = '' + ele.removeEventListener('animationend', f) + }) + ele.style.animation = text + }, + + getParents: (elem, selector) => { + for (; elem && elem !== document; elem = elem.parentNode) { + if (elem.matches(selector)) return elem + } + return null + }, + + siblings: (ele, selector) => { + return [...ele.parentNode.children].filter((child) => { + if (selector) { + return child !== ele && child.matches(selector) + } + return child !== ele + }) + }, + + /** + * @param {*} selector + * @param {*} eleType the type of create element + * @param {*} options object key: value + */ + wrap: (selector, eleType, options) => { + const createEle = document.createElement(eleType) + for (const [key, value] of Object.entries(options)) { + createEle.setAttribute(key, value) + } + selector.parentNode.insertBefore(createEle, selector) + createEle.appendChild(selector) + }, + + unwrap: el => { + const parent = el.parentNode + if (parent && parent !== document.body) { + parent.replaceChild(el, parent) + } + }, + + isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0, + + getEleTop: ele => { + let actualTop = ele.offsetTop + let current = ele.offsetParent + + while (current !== null) { + actualTop += current.offsetTop + current = current.offsetParent + } + + return actualTop + }, + + loadLightbox: ele => { + const service = GLOBAL_CONFIG.lightbox + + if (service === 'mediumZoom') { + mediumZoom(ele, { background: 'var(--zoom-bg)' }) + } + + if (service === 'fancybox') { + ele.forEach(i => { + if (i.parentNode.tagName !== 'A') { + const dataSrc = i.dataset.lazySrc || i.src + const dataCaption = i.title || i.alt || '' + btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc }) + } + }) + + if (!window.fancyboxRun) { + Fancybox.bind('[data-fancybox]', { + Hash: false, + Thumbs: { + showOnStart: false + }, + Images: { + Panzoom: { + maxScale: 4 + } + }, + Carousel: { + transition: 'slide' + }, + Toolbar: { + display: { + left: ['infobar'], + middle: [ + 'zoomIn', + 'zoomOut', + 'toggle1to1', + 'rotateCCW', + 'rotateCW', + 'flipX', + 'flipY' + ], + right: ['slideshow', 'thumbs', 'close'] + } + } + }) + window.fancyboxRun = true + } + } + }, + + initJustifiedGallery: function (selector) { + const runJustifiedGallery = i => { + if (!btf.isHidden(i)) { + fjGallery(i, { + itemSelector: '.fj-gallery-item', + rowHeight: i.getAttribute('data-rowHeight'), + gutter: 4, + onJustify: function () { + this.$container.style.opacity = '1' + } + }) + } + } + + if (Array.from(selector).length === 0) runJustifiedGallery(selector) + else selector.forEach(i => { runJustifiedGallery(i) }) + }, + + updateAnchor: (anchor) => { + if (anchor !== window.location.hash) { + if (!anchor) anchor = location.pathname + const title = GLOBAL_CONFIG_SITE.title + window.history.replaceState({ + url: location.href, + title + }, title, anchor) + } + }, + + getScrollPercent: (currentTop, ele) => { + const docHeight = ele.clientHeight + const winHeight = document.documentElement.clientHeight + const headerHeight = ele.offsetTop + const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) + const scrollPercent = (currentTop - headerHeight) / (contentMath) + const scrollPercentRounded = Math.round(scrollPercent * 100) + const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded + return percentage + }, + + addModeChange: (name, fn) => { + if (window.themeChange && window.themeChange[name]) return + window.themeChange = { + ...window.themeChange, + [name]: fn + } + } +} diff --git a/link/index.html b/link/index.html new file mode 100644 index 000000000..1577a7526 --- /dev/null +++ b/link/index.html @@ -0,0 +1,218 @@ +友情链接 | Research • 呓语 + + + + + + + + + +
\ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 000000000..14007ddab --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,257 @@ +Research • 呓语 - Research + + + + + + + +
Regular Expression Extractor正则表达式处理器
Groovy编写方法
Arrivals Thread Group的使用
Ultimate Thread Group的使用
Constant Timer定时器
循环控制器Loop Controller
Modeule Controller和Include Controller
随机控制器Random Controller和Random Order Controller
逻辑控制器Simple Controller
事务控制器Transcation Controller
\ No newline at end of file diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 000000000..b947a6842 --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,250 @@ +Research • 呓语 - Research + + + + + + + +
逻辑控制器If Controller
使用moko编写测试接口(无)
使用moko编写Get和Post测试接口(二)
使用moko编写包含cookie信息的测试接口(二)
使用moko编写测试接口(一)
使用moko编写测试接口(五)
使用moko编写重定向测试接口(四)
jmeter对数据库进行增删改查
jmeter自动化压力测试
Jmeter之json数据提取和参数传递
\ No newline at end of file diff --git a/page/4/index.html b/page/4/index.html new file mode 100644 index 000000000..3b0e6121a --- /dev/null +++ b/page/4/index.html @@ -0,0 +1,284 @@ +Research • 呓语 - Research + + + + + + + +
Jmeter之全局参数设置和csv数据导入
Jmeter之静默压测
Jmeter之断言和聚合报告
测试必会的sql基本操作
开发获取用户列表的Post接口
开发获得cookie的Post登录接口
开发时遇到端口冲突解决办法
接口开发环境部署
返回cookie的Get接口开发
需要cookie访问的Get接口开发
\ No newline at end of file diff --git a/page/5/index.html b/page/5/index.html new file mode 100644 index 000000000..151d148ab --- /dev/null +++ b/page/5/index.html @@ -0,0 +1,382 @@ +Research • 呓语 - Research + + + + + + + +
需要参数才能访问的get请求
使用docker的ubuntu容器安装code-server
性能监控平台
git提示Timed out的解决办法
使用Java解析Properties文件
java基础之方法和函数
自动化基础之Xpath定位
使用Postman如何做接口测试
解析Excel用于数据驱动
解析ini文件用于数据驱动
\ No newline at end of file diff --git a/page/6/index.html b/page/6/index.html new file mode 100644 index 000000000..2c6f032b4 --- /dev/null +++ b/page/6/index.html @@ -0,0 +1,313 @@ +Research • 呓语 - Research + + + + + + + +
如何使用pyyaml获取yaml里面的数据
Shell函数
Shell工具(一)
Shell条件判断
Shell流程控制
Shell运算符
Shell工具(二)
Shell脚本初探
Shell变量
Shell脚本入门
\ No newline at end of file diff --git a/page/7/index.html b/page/7/index.html new file mode 100644 index 000000000..716694989 --- /dev/null +++ b/page/7/index.html @@ -0,0 +1,304 @@ +Research • 呓语 - Research + + + + + + + +
_3主3从的`Redis集群`搭建(下)
_3主3从的`Redis集群`搭建之哈希槽算法
_3主3从的`Redis集群`搭建(上)
_dockerfile
_mysql主从复制docker版
_主从容错切换迁移
docker 帮助启动类命令(一)
docker 帮助启动类命令(二)
docker 镜像(一)
docker 镜像(二)
\ No newline at end of file diff --git a/page/8/index.html b/page/8/index.html new file mode 100644 index 000000000..29879adca --- /dev/null +++ b/page/8/index.html @@ -0,0 +1,283 @@ +Research • 呓语 - Research + + + + + + + +
redis的3主3从扩容
redis的4主4从缩容
使用docker安装常用软件:mysql
使用docker安装常用软件:redis
使用docker安装常用软件:tomcat
容器数据卷
容器(一)
容器(三)
容器(二)
使用pip install报错的解决办法
\ No newline at end of file diff --git a/page/9/index.html b/page/9/index.html new file mode 100644 index 000000000..70f56b39a --- /dev/null +++ b/page/9/index.html @@ -0,0 +1,289 @@ +Research • 呓语 - Research + + + + + + + +
镜像
本地镜像发布到阿里云
本地镜像发布到私有库
使用jmeter录制压测
Yaml的使用
性能测试主要关注点
\ No newline at end of file diff --git a/search.xml b/search.xml new file mode 100644 index 000000000..cb4f7fc08 --- /dev/null +++ b/search.xml @@ -0,0 +1,3358 @@ + + + + Hello World + /2023/10/07/hello-world/ + Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

+

Quick Start

Create a new post

$ hexo new "My New Post"
+

More info: Writing

+

Run server

$ hexo server
+

More info: Server

+

Generate static files

$ hexo generate
+

More info: Generating

+

Deploy to remote sites

$ hexo deploy
+

More info: Deployment

+]]>
+
+ + 2023立的flag + /2023/09/11/English/english-1/ + + + 学习日常 + + + English + + + + _3主3从的`Redis集群`搭建(下) + /2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA(%E4%B8%8B)/ + _3主3从的Redis集群搭建(下)

进入主机6381

+

redis-cli -p 6381

+
+
+ +
+ +

查看集群信息

+

cluster info

+
+
+ +
+ +

查看主机和从机之间的主从关系

+
+

cluster nodes

+
+

image-20220509101455220.assets\image-20220509101455220.png)

+
+ +
+ + +]]>
+ + 经验分享 + + + docker + +
+ + _3主3从的`Redis集群`搭建之哈希槽算法 + /2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%E4%B9%8B%E5%93%88%E5%B8%8C%E6%A7%BD%E7%AE%97%E6%B3%95/ + _3主3从的Redis集群搭建之哈希槽算法

目的

解决一致性哈希算法数据倾斜问题

+

实质

是一个数组,数组[0,2^14-1]形成hash slot空间

+

作用

解决均匀分配问题,在数据和节点之间加入一层(哈希槽slot)用于管理数据和节点之间的关系,现在相当于节点里放槽,槽里放数据

+
+ +
+ +

方便数据移动

+

哈希解决的映射问题,使用key的哈希值来计算所在的槽,便于数据分配

+

多少个hash槽

一个集群只能有16384个槽,编号0-16383(0-2^14-1)

+

这些槽会分配给集群中的所有主节点,分配策略没有要求。可以指定哪些编号的槽分配给哪个主节点。集群会记录节点和槽的对应关系。

+

接下来就需要对key求哈希值,然后对16384取余,余数是几key就落入对应的槽里。slot = CRC16(key) % 16384

+

以槽为单位移动数据,因为槽的数目是固定的,处理起来比较容易,这样数据移动问题就解决了。

+

举个栗子

Redis 集群中内置了 16384 个哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,也就是映射到某个节点上。如下代码,key之A 、B在Node2, key之C落在Node3上

+

首先有几个redis就把0-16383分成几个

+
+ +
]]>
+ + 经验分享 + + + docker + +
+ + _3主3从的`Redis集群`搭建(上) + /2022/08/26/docker/2022-08-25-_3%E4%B8%BB3%E4%BB%8E%E7%9A%84Redis%E9%9B%86%E7%BE%A4%E6%90%AD%E5%BB%BA%EF%BC%88%E4%B8%8A%EF%BC%89/ + _3主3从的Redis集群搭建(上)
    +
  • 关闭防火墙,启动docker
  • +
  • 新建6个docker容器docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
      +
    • docker run 创建并运行docker容器实例
    • +
    • —name redis-node-6 容器名字
    • +
    • —net host 使用宿主机的IP和端口,默认
    • +
    • —privileged=true 获取宿主机root用户权限
    • +
    • -v /data/redis/share/redis-node-6:/data 容器卷,宿主机地址:docker内部地址
    • +
    • redis:6.0.8 redis镜像和版本号
    • +
    • —cluster-enabled yes 开启redis集群
    • +
    • —appendonly yes 开启持久化
    • +
    • —port 6386 redis端口号
    • +
    +
  • +
+
docker run -d --name redis-node-1 --net host --privileged=true -v /data/redis/share/redis-node-1:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6381
docker run -d --name redis-node-2 --net host --privileged=true -v /data/redis/share/redis-node-2:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6382
docker run -d --name redis-node-3 --net host --privileged=true -v /data/redis/share/redis-node-3:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6383
docker run -d --name redis-node-4 --net host --privileged=true -v /data/redis/share/redis-node-4:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6384
docker run -d --name redis-node-5 --net host --privileged=true -v /data/redis/share/redis-node-5:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6385
docker run -d --name redis-node-6 --net host --privileged=true -v /data/redis/share/redis-node-6:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6386
+

运行成功,使用docker ps查看

+
    +
  • 进入容器redis-node-1并为6台机器构建集群关系

    +
      +
    • 进入一台redis进行配置docker exec -it redis-node-1 bash

      +
    • +
    • #进入后执行
      +redis-cli --cluster create 8.142.144.75:6381 8.142.144.75:6382 8.142.144.75:6383 8.142.144.75:6384 8.142.144.75:6385 8.142.144.75:6386 --cluster-replicas 1
      +
      + --cluster create    构建集群
      + --cluster-replicas 1    集群关联一比一的关系
      +
      +--cluster-replicas 1 表示为每个master创建一个slave节点
      +# 注意:上面的ip为真实IP
      +
      +
    • +
    +

    有下面的绿色ok字样显示运行成功

    +
  • +
+
+ +
+ +
+

如果运行不成功,一直显示Waiting for the cluster to join..一直………………………………….,则是端口没有全部开放,防火墙也要开放端口,以阿里云为例

+
+

就是需要在安全组上面配置6381~6386的6个端口,还需要配置16381~16386的6个端口,共12个端口都要开放,不然会一直提示等待

+
    +
  • 一切OK的话,3主3从搭建搞定
  • +
+]]>
+ + 经验分享 + + + docker + +
+ + _dockerfile + /2022/08/26/docker/2022-08-25-_dockerfile/ + _dockerfile

以dockerfile的方法来进行对centos的具有vim,ifconfig和jdk8的镜像

创建myfile文件夹

创建Dockerfile文件

+

注意:jdk8需要和Dockerfile放到同一个文件夹

+
+
FROM centos:7												
MAINTAINER zzyy<zzyybs@126.com>

ENV MYPATH /usr/local
WORKDIR $MYPATH

#安装vim编辑器
RUN yum -y install vim
#安装ifconfig命令查看网络IP
RUN yum -y install net-tools
#安装java8及lib库
RUN yum -y install glibc.i686
RUN mkdir /usr/local/java
#ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
#配置java环境变量
ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
ENV JRE_HOME $JAVA_HOME/jre
ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
ENV PATH $JAVA_HOME/bin:$PATH

EXPOSE 80

CMD echo $MYPATH
CMD echo "success--------------ok"
CMD /bin/bash
+

创建好Dockerfile后,运行docker build -t 新镜像名称:Tag .

注意:Tag后面有个空格,有个点 + +

虚悬镜像

+

仓库名和标签名全部为的镜像

+
+

碰到它还是进行删除的好

+

使用docker image ls -f dangling=true查找虚悬镜像

+

使用docker image prune删除镜像

+]]>
+ + 经验分享 + + + docker + +
+ + _mysql主从复制docker版 + /2022/08/26/docker/2022-08-25-_mysql%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6docker%E7%89%88/ + _mysql主从复制docker版

安装mysql主从复制(一主一从)

新建主服务器容器实例3307

+
docker run -p 3307:3306 --name mysql-master -v /mydata/mysql-master/log/:/var/log/mysql -v /mydata/mysql-master/data:/var/lib/mysql -v /mydata/mysql-master/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
+

进入/mydata/mysql-master/conf目录下新建my.cnf把下面内容粘贴到my.cnf

+
[mysqld]
## 设置server_id,同一局域网中需要唯一
server_id=101
## 指定不需要同步的数据库名称
binlog-ignore-db=mysql
## 开启二进制日志功能
log-bin=mall-mysql-bin
## 设置二进制日志使用内存大小(事务)
binlog_cache_size=1M
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
+

修改完配置后重启master容器

+

master容器实例内创建数据同步用户

+
# 建立一个用户
CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
# 对新建的用户进行授权
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'slave'@'%';
+
+ +
+ + +

新建从服务器实例3308

+
docker run -p 3308:3306 --name mysql-slave -v /mydata/mysql-slave/log/:/var/log/mysql -v /mydata/mysql-slave/data:/var/lib/mysql -v /mydata/mysql-slave/conf:/etc/mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
+

进入/mydata/mysql-slave/conf目录下新建my.cnf

+
## 设置使用的二进制日志格式(mixed,statement,row)
binlog_format=mixed
## 二进制日志过期清理时间。默认值为0,表示不自动清理。
expire_logs_days=7
## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
slave_skip_errors=1062
## relay_log配置中继日志
relay_log=mall-mysql-relay-bin
## log_slave_updates表示slave将复制事件写进自己的二进制日志
log_slave_updates=1
## slave设置为只读(具有super权限的用户除外)
read_only=1
+

重启从机实例docker restart mysql-slave

+

在主数据库中查看主从同步状态show master status;

+

进入mysql-slave从机容器

+

在从数据库中配置主从复制change master to master_host='宿主机ip', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000001', master_log_pos=617, master_connect_retry=30;

+
# 说明:
master_host:主数据库的IP地址;
master_port:主数据库的运行端口;
master_user:在主数据库创建的用于同步数据的用户账号;
master_password:在主数据库创建的用于同步数据的用户密码;
master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
master_connect_retry:连接失败重试的时间间隔,单位为秒。
+

在从数据库中查看主从同步状态show slave status \G;

+

在从数据库中开启主从同步start slave

+

查看从数据库状态发现已经同步

+
+ +
+ + +

主从复制测试

+

主机创建数据库,创建表,插入数据,搜索表的数据

+

从机直接搜索标的数据

+]]>
+ + 经验分享 + + + docker + +
+ + _主从容错切换迁移 + /2022/08/26/docker/2022-08-25-_%E4%B8%BB%E4%BB%8E%E5%AE%B9%E9%94%99%E5%88%87%E6%8D%A2%E8%BF%81%E7%A7%BB/ + _主从容错切换迁移

进入redis集群

+

注意:进入集群环境后,不能使用单机版的redis-cli -p 6381

+
+

因为这样会在增加数据时有error报错出现

+
+ +
+ + +

使用set k1 v1错误是因为1号主机里面的编号是0到5460,超过了这个范围就会报错

+
+

正确进入的方法redis-cli -p 6381 -c

+

-c 的作用是优化路由

+
+
+ +
+ + +注:FLUSHALL:作用是清除之前添加的记录 + +

集群检查

+

redis-cli —cluster check 8.142.144.75:6381

+
+注:可以进入任意一台主机 + + +
+ +
+ + +

主从容错切换迁移

+

主机宕机,从机自动切换成主机

+
+]]>
+ + 经验分享 + + + docker + +
+ + docker 帮助启动类命令(一) + /2022/08/26/docker/2022-08-25-docker%20%E5%B8%AE%E5%8A%A9%E5%90%AF%E5%8A%A8%E7%B1%BB%E5%91%BD%E4%BB%A4%EF%BC%88%E4%B8%80%EF%BC%89/ + docker 帮助启动类命令(一)

启动docker

+
+

systemctl start docker

+
+

停止docker

+
+

systemctl stop docker

+
+

查看docker状态

+
+

systemctl status docker

+
+

重启 docker,没有任何提示说明启动成功

+
+

systemctl restart docker

+
+]]>
+ + 经验分享 + + + docker + +
+ + docker 帮助启动类命令(二) + /2022/08/26/docker/2022-08-25-docker%20%E5%B8%AE%E5%8A%A9%E5%90%AF%E5%8A%A8%E7%B1%BB%E5%91%BD%E4%BB%A4%EF%BC%88%E4%BA%8C%EF%BC%89/ + docker 帮助启动类命令(二)

docker 开机启动

+
+

systemctl enable docker

+
+

查看 docker 概要信息

+
+

docker info

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker info
Client:
Context: default
Debug Mode: false
Plugins:
app: Docker App (Docker Inc., v0.9.1-beta3)
buildx: Docker Buildx (Docker Inc., v0.7.1-docker)
scan: Docker Scan (Docker Inc., v0.12.0)

Server:
Containers: 6
Running: 0
Paused: 0
Stopped: 6
Images: 5
Server Version: 20.10.12
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
userxattr: false
Logging Driver: json-file
Cgroup Driver: cgroupfs
Cgroup Version: 1
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: inactive
Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 7b11cfaabd73bb80907dd23182b9347b4245eb5d
runc version: v1.0.2-0-g52b36a2
init version: de40ad0
Security Options:
seccomp
Profile: default
Kernel Version: 3.10.0-1160.45.1.el7.x86_64
Operating System: CentOS Linux 7 (Core)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 1.795GiB
Name: iZ8vbfaek3x3ogtpxnpnwfZ
ID: NQOP:KCP6:LS6G:K52A:XOQX:E7FG:FEHL:K3QX:NSLP:VY5S:TFX5:UR42
Docker Root Dir: /var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
127.0.0.0/8
Registry Mirrors:
https://qp747t9w.mirror.aliyuncs.com/
Live Restore Enabled: false

+

查看 docker 总体帮助文档

+
+

docker —help

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker --help

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST
env var and default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit

Management Commands:
app* Docker App (Docker Inc., v0.9.1-beta3)


查看 docker 命令帮助文档
> docker 具体命令 --help

```shell
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps --help

Usage: docker ps [OPTIONS]

List containers

Options:
-a, --all Show all containers (default shows just running)
-f, --filter filter Filter output based on conditions provided
--format string Pretty-print containers using a Go template
-n, --last int Show n last created containers (includes all states) (default -1)
-l, --latest Show the latest created container (includes all states)
--no-trunc Don't truncate output
-q, --quiet Only display container IDs
-s, --size Display total file sizes
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#

+]]>
+ + 经验分享 + + + docker + +
+ + docker 镜像(一) + /2022/08/26/docker/2022-08-25-docker%20%E9%95%9C%E5%83%8F%EF%BC%88%E4%B8%80%EF%BC%89/ + 镜像(一)

查询本地主机上的镜像

+

docker images
OPTIONS说明:

+
    +
    • +
    • a 列出本地所有的镜像(含历史镜像)
    • +
    +
  • +
    • +
    • q 只显示镜像ID
    • +
    +
  • +
+
+

举个栗子

[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
tomcat latest fb5657adc892 4 months ago 680MB
hello-world latest feb5d9fea6a5 7 months ago 13.3kB
centos latest 5d0da3dc9764 7 months ago 231MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images -a
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
tomcat latest fb5657adc892 4 months ago 680MB
hello-world latest feb5d9fea6a5 7 months ago 13.3kB
centos latest 5d0da3dc9764 7 months ago 231MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images -q
b8e65a4d736d
fb5657adc892
feb5d9fea6a5
5d0da3dc9764
9b9cb95443b5
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#

+

查询镜像仓库是否有该镜像

+

docker search 镜像名称

+
+

举个栗子

STARS 点赞数
OFFICIAL 官方认证

+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker search hello-world
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
hello-world Hello World! (an example of minimal Dockeriz… 1718 [OK]
kitematic/hello-world-nginx A light-weight nginx container that demonstr… 151
+

显示前n条镜像

+

docker search —limit n 镜像名称

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker search --limit 5 redis
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
redis Redis is an open source key-value store that… 10851 [OK]
bitnami/redis Bitnami Redis Docker Image 214 [OK]
bitnami/redis-sentinel Bitnami Docker Image for Redis Sentinel 36 [OK]
circleci/redis CircleCI images for Redis 12 [OK]
bitnami/redis-exporter 6
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+

下载安装镜像到本地

+

docker pull 镜像名称:标签版本号

+
+

没有tag就是最新版

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker pull redis:6.0.8
6.0.8: Pulling from library/redis
bb79b6b2107f: Pull complete
1ed3521a5dcb: Pull complete
5999b99cee8f: Pull complete
3f806f5245c9: Pull complete
f8a4497572b2: Pull complete
eafe3b6b8d06: Pull complete
Digest: sha256:21db12e5ab3cc343e9376d655e8eabbdbe5516801373e95a8a9e66010c5b8819
Status: Downloaded newer image for redis:6.0.8
docker.io/library/redis:6.0.8
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+]]>
+ + 经验分享 + + + docker + +
+ + docker 镜像(二) + /2022/08/26/docker/2022-08-25-docker%20%E9%95%9C%E5%83%8F%EF%BC%88%E4%BA%8C%EF%BC%89/ + 镜像(二)

查看 镜像/容器/数据 卷所占的空间

+

docker system df

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker system df
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 6 3 1.173GB 921.1MB (78%)
Containers 6 0 4.517MB 4.517MB (100%)
Local Volumes 0 0 0B 0B
Build Cache 0 0 0B 0B
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+

删除镜像

+

docker rmi 镜像ID

+
+

```shell

+

如果提示报错

Error response from daemon: conflict: unable to delete feb5d9fea6a5 (must be forced) - image is being used by stopped container 13111f725991

+

说明之前运行过这个镜像,生成了容器,需要先删除容器,再删除镜像

+

使用 -f 删除一个

+

docker rmi -f 镜像id

+
+

使用 -f 删除多个

+

xxxxxxxxxx # 没有任何提示说明启动成功[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# systemctl restart docker[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#shell

+
+

使用 -f 删除全部

+

docker rmi -f $(docker images -qa)

+
+]]>
+ + 经验分享 + + + docker + +
+ + redis的3主3从扩容 + /2022/08/26/docker/2022-08-25-redis3%E4%B8%BB3%E4%BB%8E%E6%89%A9%E5%AE%B9/ + redis的3主3从扩容

首先添加两个redis

# 创建redis-node-7
docler run -d --name redis-node-7 --net host --privileged=true -v /data/redis/share/redis-node-7:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6387
# 创建redis-node-8
docler run -d --name redis-node-8 --net host --privileged=true -v /data/redis/share/redis-node-8:/data redis:6.0.8 --cluster-enabled yes --appendonly yes --port 6388
+注:在阿里云的安全组和防火墙上添加6387,16387 6388,16388四个端口 + +

配置步骤:

执行docker exec -it redis-node-1 bash进入redis-node-1里面
执行redis-cli --cluster add-node 8.142.144.75:6387 8.142.144.75:6381
+ +
+ + + +

6387 新加入的节点

+

6381 相当于6387的领路人

+
使用redis-cli --cluster check 8.142.144.75:6381检查
+ +
+ +
重新分配槽号
+

redis-cli —cluster reshard IP地址:端口号

+
+
+ +
+ +注:上图的1指的是:对主机数平分16384个节点,16384/主机数(包含想要添加的主机) + +注:上图的2指的是:新加入的6387节点的ID + +
+ +
+ +all:表示全部进行重新分配 + +

在重新加载过程会碰到Do you want to proceed with the proposed reshard plan (yes/no)?一句话,选择yes就可以

+
+ +
+ +
检查集群情况
+ +
+ +
为主节点6387分配从节点6388
+

redis-cli —cluster add-node ip:新slave端口 ip:新master端口 —cluster-slave —cluster-master-id 新主机节点ID

+
+
+ +
+ +
检查集群情况
+ +
+]]>
+ + 经验分享 + + + docker + +
+ + redis的4主4从缩容 + /2022/08/26/docker/2022-08-25-redis%E7%9A%844%E4%B8%BB4%E4%BB%8E%E7%BC%A9%E5%AE%B9/ + redis的4主4从缩容
目的:6387和6388下线
检查集群情况获得6388的节点ID
+

redis-cli —cluster check 8.142.144.75:6382

+
+
+ +
+ +
从集群中将4号从节点6388删除
+

redis-cli —cluster del-node ip:从机端口 从机6388节点ID

+
+
+ +
+ +
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
+ +

6388删除成功

+
将6387的槽号清空,重新分配

本例将清出来的槽号都给6381

+

使用redis-cli --cluster reshard ip:6381进行节点的重组

+
+ +
+ +注: + +

上图中1输入的4096是6387主机所拥有的槽点数量,把他们全部拿出来分掉

+

上图的2输入的ID是接收6387主机所放出的槽点数的主机id

+

上图中3输入的ID是放出槽点数的6387主机的id

+

上图中4输入的done指的是已经输入完所有的节点

+
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
+ +
删除6387节点的主机
+

redis-cli —cluster del-node ip:端口 6387节点ID

+
+
+ +
+ +
使用redis-cli --cluster check 8.142.144.75:6382进行集群检查
+ +
]]>
+ + 经验分享 + + + docker + +
+ + 使用docker安装常用软件:mysql + /2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Amysql/ + 使用docker安装常用软件:mysql

以mysql 5.7为例

使用docker pull mysql:5.7拉取mysql 5.7镜像

+

使用镜像创建容器

简单版

使用docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7运行镜像创建容器

+
+

因为linux系统自己装了mysql,避免端口冲突,先运行ps -ef|grep mysql查询

+
+

使用docker ps查询容器编号

+

使用docker exec -it 容器编号 bash进入mysql容器

+

使用mysql -uroot -p,输入密码,登录mysql

+
验证

show databases

+
mysql> show databases
-> ;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
+--------------------+
+
中文乱码问题
INSERT INTo t1 VALUES(3, "张三");
---
INSERT INTo t1 VALUES(3, "张三")
> 1366 - Incorrect string value: '\xE5\xBC\xA0\xE4\xB8\x89' for column 'name' at row 1
> 时间: 0.038s
+因为docker默认编码字符集隐患 + +
mysql> SHOW VARIABLES LIKE 'character%';
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
8 rows in set (0.00 sec)
mysql>
+

解决中文乱码问题

在宿主机的/ggls/mysql/conf目录下vim my.cnf文件,通过容器卷同步给容器实例

+
[client]
default_character_set=utf8
[mysqld]
collation_server = utf8_general_ci
character_set_server = utf8
+改完后重启mysql实例 + +
服务器输入SHOW VARIABLES LIKE 'character%';验证
docker安装好并run出容器后,先修改字符集编码在创建mysql库 + +
删库备份问题
只要本机上面的容器卷存在,容器卷位置没有改变的情况下,就算容器被删除,重新打开后,创建的数据库,表都还存在 + + +

工作使用版启动容器方法

+
docker run -d -p 3306:3306 --privileged=true
-v /ggls/mysql/log:/var/log/mysql
-v /ggls/mysql/data:/var/lib/mysql
-v /ggls/mysql/conf:/etc/mysql/conf.d
-e MYSQL_ROOT_PASSWORD=123456
--name mysql
mysql:5.7
+]]>
+ + 经验分享 + + + docker + +
+ + 使用docker安装常用软件:redis + /2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Aredis/ + 使用docker安装常用软件:redis

使用docker pull redis:6.0.8拉取redis:6.0.8镜像

+

创建容器

+
+

容器卷要加入--privileged=true

+
+

在宿主机下新建目录mkdir -p /app/redis

+]]>
+ + 经验分享 + + + docker + +
+ + 使用docker安装常用软件:tomcat + /2022/08/26/docker/2022-08-25-%E4%BD%BF%E7%94%A8docker%E5%AE%89%E8%A3%85%E5%B8%B8%E7%94%A8%E8%BD%AF%E4%BB%B6%EF%BC%9Atomcat/ + 使用docker安装常用软件:tomcat

安装流程

首先把tomcat在镜像源中pull下来,使用docker images 查看镜像

+

使用docker run -d -p 8080:8080 tomcat:9.0新建容器运行tomcat

+
+

运行后使用本地PC使用阿里云的ip和端口访问docker上面的tomcat

+
+
+ +
+ + + +

这是什么原因呢

使用docker ps查询到容器编号,docker exec -it 容器编号 bash 打开容器

+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c52ab6b8b8df b8e65a4d736d "catalina.sh run" 7 minutes ago Up 7 minutes 0.0.0.0:8080->8080/tcp, :::8080->8080/tcp inspiring_bohr
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker exec -it c52ab6b8b8df bash
root@c52ab6b8b8df:/usr/local/tomcat#
+

使用ls-l查看文件列表

+
root@c52ab6b8b8df:/usr/local/tomcat# ls -l
total 156
-rw-r--r-- 1 root root 18970 Dec 2 14:30 BUILDING.txt
-rw-r--r-- 1 root root 6210 Dec 2 14:30 CONTRIBUTING.md
-rw-r--r-- 1 root root 57092 Dec 2 14:30 LICENSE
-rw-r--r-- 1 root root 2333 Dec 2 14:30 NOTICE
-rw-r--r-- 1 root root 3378 Dec 2 14:30 README.md
-rw-r--r-- 1 root root 6898 Dec 2 14:30 RELEASE-NOTES
-rw-r--r-- 1 root root 16507 Dec 2 14:30 RUNNING.txt
drwxr-xr-x 2 root root 4096 Dec 22 17:16 bin
drwxr-xr-x 1 root root 4096 Apr 29 01:48 conf
drwxr-xr-x 2 root root 4096 Dec 22 17:16 lib
drwxrwxrwx 1 root root 4096 Apr 29 01:48 logs
drwxr-xr-x 2 root root 4096 Dec 22 17:16 native-jni-lib
drwxrwxrwx 2 root root 4096 Dec 22 17:16 temp
drwxr-xr-x 2 root root 4096 Dec 22 17:16 webapps
drwxr-xr-x 7 root root 4096 Dec 2 14:30 webapps.dist
drwxrwxrwx 2 root root 4096 Dec 2 14:30 work
root@c52ab6b8b8df:/usr/local/tomcat#
+

从列表可以看到有两个文件夹webappswebapps.dist,数据全部在webapps.dist里面,需要将webapps删除,把webapps.dist重命名成webapps即可访问

+

使用rm -rf webapps删除webapps文件夹

+

使用mv webapps.dist webapps重命名

+

再次使用本地访问

+
+ +
+ + +

使用免修改版的tomcat

+

docker pull billygoo/tomcat8-jdk8

+

docker run -d -p 8080:8080 —name tomcat8 billygoo/tomcat8-jdk8

+
+]]>
+ + 经验分享 + + + docker + +
+ + 容器数据卷 + /2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%E6%95%B0%E6%8D%AE%E5%8D%B7/ + 容器数据卷

运行带有容器数据卷的容器实例

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名
+

举个栗子

+

宿主vs容器之间映射添加容器卷

+
+
    +
  • 使用docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名 添加
  • +
+
docker run -it --privileged=true -v /tmp/host_data:/tmp/docker_data --name=ui ubuntu
+
    +
  • 查看数据卷是否挂载成功
  • +
+
`在容器内部创建一个dockerin.txt文件
root@48955acecd79:/tmp/docker_data# touch dockerin.txt
root@48955acecd79:/tmp/docker_data# ll
total 8
drwxr-xr-x 2 root root 4096 Apr 28 09:21 ./
drwxrwxrwt 1 root root 4096 Apr 28 09:18 ../
-rw-r--r-- 1 root root 0 Apr 28 09:21 dockerin.txt
`在宿主机目录下查看该文件
root@48955acecd79:/tmp/docker_data# [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# cd /tmp/host_data/
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# ll
total 0
-rw-r--r-- 1 root root 0 Apr 28 17:21 dockerin.txt
`在宿主机创建一个文件
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# touch host.txt

`在容器查看文件
[root@iZ8vbfaek3x3ogtpxnpnwfZ host_data]# docker exec -it 48955acecd79 bash
root@48955acecd79:/# cd /tmp/docker_data/

+ 容器和宿主机之间数据共享

[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m="vim cmd add ok" -a="ggls" 356e32244966 ggls/ubuntu:1.5sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# shell

+ 主机修改,docker同步获得

+ docker容器stop,主机修改,docker容器重启数据同步

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f562278524cdacdee90a8c77d

+ 默认是可读可写的

```shell
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名
+
    +
  • 修改成容器只读
  • +
+
docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名
+
+

卷的继承和共享

+
+
    +
  • 容器1完成和宿主机的映射
      +
    • 容器2继承容器1,则容器2操作后同步到容器1和宿主机
    • +
    • 宿主机操作同步到容器1,容器2
    • +
    • 容器1操作同步到宿主机,容器2
    • +
    +
  • +
+
docker run -it --privileged=true --volumes-from 父类 --name u2 ubuntu
+]]>
+ + 经验分享 + + + docker + +
+ + 容器(一) + /2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%B8%80%EF%BC%89/ + 容器(一)

新建和启动容器

OPTIONS说明:

    +
  • — name = “容器新名称” 为容器制定一个名称
  • +
  • -d 后台运行容器并返回容器id, 即启动守护式容器(后台运行)
  • +
  • -i 以交互模式运行容器,通常与 -t 同时使用
  • +
  • -t 为容器重新分配一个伪输入终端,通常与 -i 连用,也就是启动交互式容器
  • +
  • -P 随机端口映射
  • +
  • -p 指定端口映射
  • +
+

举个栗子

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
ubuntu 15.10 9b9cb95443b5 5 years ago 137MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker run -it ubuntu:15.10 /bin/bash
root@4fb757f69adb:/# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 03:26 pts/0 00:00:00 /bin/bash
root 11 1 0 03:26 pts/0 00:00:00 ps -ef
root@4fb757f69adb:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@4fb757f69adb:/# exit
exit
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

docker run -it ubuntu:15.10 /bin/bash
/bin/bash 希望有交互式shell 就用/bin/bash

+

查询正在运行的容器

+

docker ps [OPTIONS]

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cdee90a8c77d ubuntu "bash" 3 minutes ago Exited (0) 3 minutes ago ubuntu
0dcaa91afc0e ubuntu "/bin/bush" 5 minutes ago Created myubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

OPTIONS:

+
    +
  • -a 展示所有容器,包含历史用过容器
  • +
  • -d 只展示容器id
  • +
  • -l 显示最近创建的容器
  • +
  • -n 展示最近创建的前n个容器
    List containers
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -n 1
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -an 1
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -an 2
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    cdee90a8c77d ubuntu "bash" 17 minutes ago Exited (0) 17 minutes ago ubuntu
    0dcaa91afc0e ubuntu "/bin/bush" 19 minutes ago Created myubuntu
    [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

    +
  • +
+

退出容器

    +
  • exit
  • +
+

run进入容器,exit退出容器, 容器停止

+
    +
  • ctrl + p + q
  • +
+

run进入容器,exit退出容器, 容器不停止

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker run -it ubuntu bash
root@562278524cda:/# [root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 16 seconds ago Up 15 seconds loving_dewdney

+]]>
+ + 经验分享 + + + docker + +
+ + 容器(三) + /2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%B8%89%EF%BC%89%EF%BC%88%E9%87%8D%E8%A6%81%EF%BC%89/ + 容器(三)

创建后台守护式容器

(问题):使用docker run -d ubuntu命令启动后台模式的容器ubuntu,然后用docker ps 查询提示没有找到运行的容器

+
+

Docker容器后台运行就必须有一个前台进程,不然容器没事做,会自杀

+
+

解决方法:将运行的程序以前台进程的方式运行
常见方式:命令行模式

+

查看容器日志

+

docker logs 容器id

+
+

查看容器的进程

+

docker top 容器id

+
+

查看容器内部细节

+

docker inspect 容器id

+
+

重新进入

    +
  • 进入正在运行的容器并以命令行交互

    +
    +

    docker exec -it 容器id bashShell

    +
    +
  • +
  • 重新进入

    +
    +

    docker attach 容器id

    +
    +
  • +
+

(区别)
attach直接进入容器启动命令的终端,不会启动新的进程,用exit退出,会导致容器的停止
exec是在容器中打开新的终端,并且可以启动新的进程,用exit退出,不会导致容器的停止

+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED         STATUS         PORTS     NAME
S562278524cda   ubuntu    "bash"    20 minutes ago   Up 20 minutes             loving_dewdn
eycdee90a8c77d   ubuntu    "bash"    45 minutes ago   Up 15 minutes             ubuntu

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f562278524cdacdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS   PORTS     NAMES

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#​shell
+

从容器内拷贝文件到主机

+

docker cp 容器id:容器地址 主机地址

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker cp 26191ecfb227:/tmp/a.txt /opt/ab.txt
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# cd /opt/
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 8
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]#

+

导入和导出容器

    +
  • export 导出容器的内容留作为一个tar归档文件[对应import命令]

    +
    +

    docker export 容器id > 自定义文件名.tar

    +
    +
  • +
  • import从tar包中的内容创建一个新的文件系统再导入为镜像[export]

    +
    +

    cat 文件名.tar | docker import - 自定义/镜像名:3.5(3.5是自定义)

    +
    +
  • +
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
26191ecfb227 ubuntu "bash" 7 minutes ago Up 7 minutes quirky_jemison
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker export 26191ecfb227 > abcd.tar
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 73408
-rw-r--r-- 1 root root 75158016 Apr 27 15:21 abcd.tar
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]#

+
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# ll
total 73408
-rw-r--r-- 1 root root 75158016 Apr 27 15:21 abcd.tar
-rw-r--r-- 1 root root 0 Apr 27 15:13 ab.txt
drwx--x--x 4 root root 4096 Dec 28 16:17 containerd
drwxr-xr-x 4 root root 4096 Dec 8 16:49 downfile
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# cat abcd.tar | docker import - mytest/ubuntu:3.5
sha256:a92a27affdde8ad7f07bef2fdc0f04b8e3aeacb9d6919a77da2921d552ab940b
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mytest/ubuntu 3.5 a92a27affdde 11 seconds ago 72.8MB
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
ubuntu latest ba6acccedd29 6 months ago 72.8MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ opt]# docker run -it mytest/ubuntu:3.5 bash
root@356e32244966:/#
root@356e32244966:/# cd /tmp/
root@356e32244966:/tmp# ll
total 8
drwxrwxrwt 2 root root 4096 Apr 27 07:13 ./
drwxr-xr-x 1 root root 4096 Apr 27 07:32 ../
-rw-r--r-- 1 root root 0 Apr 27 07:13 a.txt
root@356e32244966:/tmp#

]]>
+ + 经验分享 + + + docker + +
+ + 容器(二) + /2022/08/26/docker/2022-08-25-%E5%AE%B9%E5%99%A8%EF%BC%88%E4%BA%8C%EF%BC%89/ + 容器(二)

启动已经停止运行的容器

+

docker start 容器id/容器名

+
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 4 minutes ago Up 4 minutes loving_dewdney
9a1a43aee837 ubuntu "bush" 4 minutes ago Created admiring_wiles
cdee90a8c77d ubuntu "bash" 29 minutes ago Exited (0) 29 minutes ago ubuntu
0dcaa91afc0e ubuntu "/bin/bush" 31 minutes ago Created myubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 4 minutes ago Up 4 minutes loving_dewdney
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker start cdee90a8c77d
cdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 5 minutes ago Up 5 minutes loving_dewdney
cdee90a8c77d ubuntu "bash" 30 minutes ago Up 3 seconds ubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#
+

重启容器

+

docker restart 容器id/容器名

+
+

停止容器

+

docker stop 容器id/容器名

+
+

强制停止容器

+

docker kill 容器id/容器名

+
+

删除已经停止的容器

+

docker rm 容器id

+
+

一次性删除多个容器

    +
  • docker rm -f $(docker ps -a -q)
  • +
  • docker ps -a -q | xargs docker rm
  • +
+

注:xargs是linux系统的可变参数,把分隔符前面的结果传给xargs里面,然后执行分隔符后面的命令

[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562278524cda ubuntu "bash" 20 minutes ago Up 20 minutes loving_dewdney
cdee90a8c77d ubuntu "bash" 45 minutes ago Up 15 minutes ubuntu
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps -a -q | xargs docker rm -f
562278524cda
cdee90a8c77d
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@iZ8vbfaek3x3ogtpxnpnwfZ ~]#

+]]>
+ + 经验分享 + + + docker + +
+ + git提示Timed out的解决办法 + /2022/09/26/error/2022-09-26-git%E6%8F%90%E7%A4%BATimed_out%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/ + 报错代码

运行git代码会提示Timed out错误

+
使用git,会发生报错:Failed to connect to github.com port 443 after 21098 ms: Timed out
+

解决办法

设置代理

+
git config --global https.proxy
+

取消代理

+
git config --global --unset https.proxy
+

然后输入git 命令使用

+]]>
+ + 经验分享 + + + Git + +
+ + 使用pip install报错的解决办法 + /2022/08/26/error/2022-11-08-%E4%BD%BF%E7%94%A8pip%20install%E6%8A%A5%E9%94%99%E7%9A%84%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/ + 报错提示

今天使用PyCharm下载一个模块pip.exe install locust,有错误提示

+
https://visualstudio.microsoft.com/visual-cpp-build-tools/
[end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.
// 报错位置
ERROR: Failed building wheel for psutil

ERROR: Could not build wheels for psutil, which is required to install pyproject.toml-based projects
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
WARNING: Ignoring invalid distribution -ip (d:\work software\python3.8\lib\site-packages)
+

原因

+

缺少对应的whl文件

+
+

解决办法

碰到了这个错误ERROR: Failed building wheel for psutil,就需要下载psutil.whl

+

下载网站点击进入网站

+

下载psutil-5.9.0-cp38-cp38-win_amd64.whl文件

+

然后使用(pip install 文件的绝对路径)进行安装,然后使用pip.exe install locust正常安装

+

pip.exe install D:\Appium\psutil-5.9.0-cp38-cp38-win_amd64.whl

pip.exe install locust

+]]>
+ + 经验分享 + + + error + +
+ + 镜像 + /2022/08/26/docker/2022-08-25-%E9%95%9C%E5%83%8F/ + 镜像

背景

docker镜像是最小的,被精简过的Linux系统,是不带vim命令的

+
+

使用命令 ‘vim a.txt’ 进行新建编辑a.txt文件,就会提示找不到命令

+
+

给镜像容器新增vim命令

    +
  1. 更新镜像

    +
    +

    apt-get update

    +
    +
  2. +
  3. 下载vim功能

    +
    +

    apt-get -y install vim

    +
    +
  4. +
  5. 提交副本使成为一个新镜像

    +
    +

    docker commit -m=”提交的描述信息” -a=”作者” 容器id 要创建的目标镜像名:[标签名]

    +
    +
  6. +
+
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
356e32244966 mytest/ubuntu:3.5 "bash" 2 hours ago Up 2 hours elated_aryabhata
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m="vim cmd add ok" -a="ggls" 356e32244966 ggls/ubuntu:1.5
sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ggls/ubuntu 1.5 87e99e19eeef 7 seconds ago 176MB
mytest/ubuntu 3.5 a92a27affdde 2 hours ago 72.8MB
tomcat 9.0 b8e65a4d736d 4 months ago 680MB
ubuntu latest ba6acccedd29 6 months ago 72.8MB
redis 6.0.8 16ecd2772934 18 months ago 104MB
[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#
+]]>
+ + 经验分享 + + + docker + +
+ + 使用Java解析Properties文件 + /2022/09/21/java/2022-09-21-%E4%BD%BF%E7%94%A8Java%E8%A7%A3%E6%9E%90Properties%E6%96%87%E4%BB%B6/ + 主要函数
+ + + + + + + + + + + + + + + + + + + + + + + + + +
文件后缀函数方法
.Propertiesload加载文件
setProperty设置
getProperty获取
+
+

编写逻辑

创建加载文件的方法

+
/**
* 加载文件
* @return Properties 对象
* @throws IOException I/O输入异常
*/
private Properties readProperties() throws IOException{
// 实例化,创建 Properties 对象
Properties properties = new Properties();
try {
// 创建文件输入对象 FileInputStream("testpro.properties")
InputStream inputStream = new FileInputStream(filepath);
// 把文件输入对象放入缓存输入对象 new BufferedInputStream 里面
BufferedInputStream in = new BufferedInputStream(inputStream);
// 加载文件 in = ParseProperties.class.getResourceAsStream("testpro.properties"),自动获取 resources 文件夹下路径
properties.load(in);
}catch (IOException e){
e.printStackTrace();
}
return properties;
}
+

获取key后面的数据

+
/**
* 获取数据
* @param key 数据名称
* @return 数据等号右边的值
* @throws Exception 异常
*/
public String getPro(String key) throws Exception {
// 判断文件里面有没有这个 Key
if (prop.containsKey(key)) {
// 获得key后面的value值
return prop.getProperty(key);
}else {
System.out.println("你获取的key值不对");
return "";
}
}
+

获取定位类型或者定位表达式

+
/**
* 返回定位类型或者定位表达式
* @param key 数据名称
* @param num 输入0/1
* @return num=0时,返回定位类型,num=1时,返回定位表达式
*/
public String get_pro_element(String key, int num){
return (num!=0 & num!=1) ? "num:参数输入错误" : prop.getProperty(key).split("->")[num];
}
+]]>
+ + 经验分享 + + + java + Properties + +
+ + java基础之方法和函数 + /2022/09/21/java/2022-12-06-%E6%96%B9%E6%B3%95%E5%92%8C%E5%87%BD%E6%95%B0/ + 方法和函数
+ + + + + + + + + + + + + + + + + + + + + + + +
定义方式作用调用方式
函数public static void 函数名(){}封装指定功能的代码块函数名()
方法public [static] void 方法名(){}类的行为,对象可以执行的一些功能对象名.方法名
+
+

定义函数

+

使用static修饰的内容成为静态的内容

+
+
public static void function1(){
}
+

调用函数

function1()
+

定义方法

public void class className1{

String name;
//静态变量
static String age;

//静态方法
public static function1(){
}

//类方法
//非静态方法可以调用静态变量和非静态变量、静态方法和非静态方法
public function2(){
}
}
+

调用方法

    +
  • 调用静态方法,不需要实例化
  • +
+
className1.function1()
+
    +
  • 调用方法
  • +
+
className1的对象,需要实例化
+

静态方法注意事项:

    +
  • 静态方法无法直接引用非静态的变量
  • +
  • 静态方法不能直接调用非静态的方法
  • +
+

代码块

    +
  • 定义在方法内部,和局部变量处于平行的位置
  • +
  • 生命周期随着方法的调用而加载,随着方法的结束而消亡
  • +
  • 可以在局部代码块中定义一些使用范围和时间都很短的变量,用完就消失啦
  • +
+
public void class className1{

String name;
static String age;

//类方法
//非静态方法可以调用静态变量和非静态变量、静态方法和非静态方法
public void function2(){

//定义代码块
{
int i = 100;
System.out.println("方法中的变量i=" + i);
}

}
}
+

构造代码块

    +
  • 构造代码快写在和构造方法平行的位置
  • +
  • 只要创建对象,构造代码块就会执行,不论是采用有参的还是无参数的构造方法
  • +
+
public void class{
//有参构造
class(String name){
}
//无参构造
class(){
}
//构造代码块
{
int i=100;
System.out.println("构造代码块i=" + i);
}

}
+

静态代码块

    +
  • 被static修饰的代码块称为静态代码块
  • +
  • 随着类的加载而加载
  • +
  • 静态代码块只执行一次,在程序中可以完成加载驱动等只执行一次的操作
  • +
+
public void className1{
static{
System.out.println("我是静态代码块i=" + i);
}
}
]]>
+ + 经验分享 + + + java + +
+ + 包装类 + /2022/12/07/java/2022-12-07-%E5%8C%85%E8%A3%85%E7%B1%BB/ + +
  • 基本数据类型对应的包装类
  • + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    基本数据类型包装类大小(字节)
    byteByte1—(-128~127)
    shortShort2—(-32768~32767)
    intInteger4
    longLong8
    floatFloat4
    doubleDouble8
    charCharacter2
    booleanBoolean1
    +
    +

    包装类方法

      +
    • Integer的作用主要是对int、Integer、String几种类型的数据进行转换,还能获取一些常量
    • +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    方法描述
    compareTo()用于将对象与方法的参数进行比较(相同类型)
    decode()将方法的参数转为包装类对象
    equals()判断对象是否与参数相等
    Integer.parseInt(“字符串’)将字符串转为Int类型
    Integer.toString(int数据)将Int类型转为字符串
    +
    +

    compareTo()方法

      +
    • 如果指定的数与参数相等返回 0。
    • +
    • 如果指定的数小于参数返回 -1。
    • +
    • 如果指定的数大于参数返回 1。
    • +
    +]]>
    + + 经验分享 + + + java + +
    + + 字符串 + /2022/12/07/java/2022-12-07-%E5%AD%97%E7%AC%A6%E4%B8%B2/ + 字符串的方法
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    方法描述
    str.concat()将参数拼接到字符串上
    trim()去除字符串两端的字符串,不能去除中间
    replace(oldChar, newChar)将字符串的old参数替换为new参数
    length()返回此字符串的长度
    isEmpty()判断字符串是否为空
    +
    +

    concat()方法

      +
    • 返回字符串类型
    • +
    • 字符串在后面拼接

      +
      String str = "床前明月光";
      String str1 = str.concat("疑是地上霜。");
      System.out.println(str1);
      +

      trim()方法

      String str = "    床  前明   月光   ";
      String str1 = str.trim();
      System.out.println(str1);
      +

      replace(oldChar, newChar)方法

      String str = "床前明月光";
      String str1 = str.replace("床", "llll");
      System.out.println(str1);
      +

      length()方法

    • +
    • 返回int类型

      +
      String str = "床前明月光";
      int str1 = str.length();
      System.out.println(str1);
      +

      isEmpty()方法

    • +
    • 返回布尔类型

      +
      String str = "床前明月光";
      boolean str1 = str.isEmpty();
      System.out.println(str1);
      +
    • +
    +]]>
    + + 经验分享 + + + java + +
    + + 本地镜像发布到阿里云 + /2022/08/26/docker/2022-08-25-%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%E5%8F%91%E5%B8%83%E5%88%B0%E9%98%BF%E9%87%8C%E4%BA%91/ + 本地镜像发布到阿里云
    +

    使用docker进行对docker镜像功能的新增后,需要发布到阿里云上对镜像进行同步,下次pull镜像就不要pull缩减版的镜像,直接pull更新后的镜像,方便后续使用

    +

    执行顺序

      +
    • 阿里云开发者平台
    • +
    • 点击镜像容器服务
    • +
    • 创建镜像仓库
        +
      • 创建命名空间
      • +
      • 创建镜像仓库
      • +
      +
    • +
    +

    然后在基本信息上面就可以看到仓库指南

    +
    +

    根据指南进行操作

    +
    + +
    + +
    +
    + +
    + +
    + +
    +]]>
    + + 经验分享 + + + docker + +
    + + 抽象类与接口 + /2022/12/07/java/2022-12-07-%E6%8A%BD%E8%B1%A1%E7%B1%BB%E4%B8%8E%E6%8E%A5%E5%8F%A3/ + 抽象类

    使用abstract修饰一个类,把这个类变成抽象类,抽象类不能直接创建对象,需要其他类进行继承该抽象类

    +
      +
    • 抽象方法不能有方法体
    • +
    • 抽象方法必须使用abstract进行修饰,不能有方法体
    • +
    • 子类必须实现父抽象类的方法

      +
      public abstract class Ahsse {
      String name;
      int age;

      //普通方法
      public String aaa(){
      return name;
      };
      // 抽象方法
      public abstract String bbb();
      }

      class sss extends Ahsse{

      @Override
      public String bbb() {
      System.out.println("实现抽象类的抽象方法");
      return "ces ";
      }
      }
      +

      接口

      使用interface定义接口,相当于class

      +
    • +
    • 接口可以多继承

      +
    • +
    • 变量全部默认使用public static final修饰,使用之前必须赋值
    • +
    • 类里面全部是抽象方法(默认使用public abstract修饰,没有方法体)需要被实现类进行实现
    • +
    • 接口可以被多实现—implements
    • +
    +]]>
    + + 经验分享 + + + java + +
    + + 继承、重写与重载 + /2022/12/07/java/2022-12-07-%E7%BB%A7%E6%89%BF%E3%80%81%E9%87%8D%E5%86%99%E4%B8%8E%E9%87%8D%E8%BD%BD/ + 继承

    继承是相对于类来说,通过关键字extends来实现

    +
      +
    • 可以获取父类的属性和方法
    • +
    • 提高代码的复用性
    • +
    • 父类修改了内容,子类也会修改

      +

      调用

      父类的属性和方法

      +
    • +
    • this表示当前对象的引用

      +
    • +
    • super表示父类对象的引用
    • +
    • 调用构造方法
        +
      • this(参数列表)表示调用当前类中的构造方法
      • +
      • super(参数列表)表示调用父类的构造方法,必须放在方法中的第一行
      • +
      +
    • +
    • 调用属性
        +
      • this.属性表示调用当前对象的属性
      • +
      • super.属性表示调用父类的属性,可以拿到被重写之前的数据
      • +
      +
    • +
    • 调用方法

      +
        +
      • this.方法表示调用当前对象的方法
      • +
      • super.方法表示调用父类的方法,可以拿到被重写之前的方法,不用放在代码的第一行

        重写

        重写是子类可以重写父类的方法,使用override标识
      • +
      +
    • +
    • 方法名和参数不变,只修改方法体

      +
    • +
    • 访问权限不能比父类的范围更小
    • +
    • 私有的方法能被子类继承,但不能使用和重写
    • +
    • 静态的方法能被子类继承,能使用但不能被重写

      +
      public class testeass {

      public void aa(String name, int age){
      System.out.println(name + age);
      }
      }

      class testaaa extends testeass{

      @Override
      public void aa(String name, int age) {
      System.out.println("这是重写方法,方法名、参数和返回数据都不变,只能修改方法体");
      System.out.println(name + age);
      }
      }
      +

      重载

      重载是同一个类下对方法进行重载

      +
    • +
    • 方法名相同,参数不相同 (参数个数不同/参数类型不同/参数排列顺序不同)

      +
    • +
    • 返回类型不限制
      public class jichu {

      // 原方法
      public void hello(String name, int aa){
      System.out.println("拼接起来的值是:"+ name + aa );
      }

      // 重载后的方法
      public void hello(int aa, String name){
      System.out.println("aaaaaaa:" + aa);
      }
      }
      +
    • +
    +]]>
    + + 经验分享 + + + java + +
    + + 本地镜像发布到私有库 + /2022/08/26/docker/2022-08-25-%E6%9C%AC%E5%9C%B0%E9%95%9C%E5%83%8F%E5%8F%91%E5%B8%83%E5%88%B0%E7%A7%81%E6%9C%89%E5%BA%93/ + 本地镜像发布到私有库
    +

    步骤

    +
    +
      +
    • 下载Docker Registry
    • +
    +
    docker pull registry
    +
      +
    • 运行私有库 Registry,相当于本地有Docker Registry
    • +
    +
    docker run -d -p 5000:5000 -v/ggls/myregistry/:/tmp/registry --privileged=true registry
    +
      +
    • 新启动ubuntu容器,新增ifconfig命令

      +
        +
      • ​ 进入容器中输入apt-get update命令
      • +
      • ​ 输入apt-get install net-tools命令
      • +
      • xxxxxxxxxx [root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES356e32244966 mytest/ubuntu:3.5 “bash” 2 hours ago Up 2 hours elated_aryabhata[root@iZ8vbfaek3x3ogtpxnpnwfZ /]#[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker commit -m=”vim cmd add ok” -a=”ggls” 356e32244966 ggls/ubuntu:1.5sha256:87e99e19eeef47d4f0daaffc8498690614e0d95eae60ef61b439abe97b62fd16[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEggls/ubuntu 1.5 87e99e19eeef 7 seconds ago 176MBmytest/ubuntu 3.5 a92a27affdde 2 hours ago 72.8MBtomcat 9.0 b8e65a4d736d 4 months ago 680MBubuntu latest ba6acccedd29 6 months ago 72.8MBredis 6.0.8 16ecd2772934 18 months ago 104MB[root@iZ8vbfaek3x3ogtpxnpnwfZ /]# shell
      • +
      +
    • +
    • 容器外部执行docker commit -m="ifconfig cmd add" -a="ggls" ffcc5edf5071 ubuntu:1.6命令

      +
    • +
    • curl验证私服库上有什么镜像

      +
    • +
    +
    curl -XGET http://8.142.144.75:5000/v2/_catalog
    +
      +
    • 将新镜像修改为符合私服库格式的镜像
    • +
    +
    docker tag 镜像:Tag Host:Port/Repository:Tag
    #
    docker tag ubuntu:1.6 8.142.144.75:5000/ubuntu:1.3
    +
      +
    • 修改配置文件使之支持http

      +
      +

      docker 默认不允许http方式推送镜像,通过此配置取消这个限制,若不生效,重启docker

      +
      +
        +
      • 使用命令vim /etc/docker/daemon.json打开配置文件
      • +
      • 在阿里云加速后面新增一个json
      • +
      +
      {
      "registry-mirrors": ["https://qp747t9w.mirror.aliyuncs.com"],
      "insecure-registries": ["8.142.144.75:5000"]
      }
      +
        +
      • 重启docker,重启docker私服仓库
      • +
      +
    • +
    • push推送到私服库

      +
    • +
    +
    docker push 符合私服库格式的镜像名称:tag
    +
      +
    • curl验证私服库上有什么镜像
    • +
    • pull到本地并运行
    • +
    +
    docker pull 8.142.144.75:5000/ubuntu:1.6
    +]]>
    + + 经验分享 + + + docker + +
    + + 使用jmeter录制压测 + /2022/08/26/jmeter/2022-10-30-%E7%AC%AC%E4%B8%80%E6%AC%A1%E4%BD%BF%E7%94%A8jmeter%E5%8E%8B%E6%B5%8B/ + 业务
      +
    • 压测对象:http://news.baidu.com
    • +
    • 压测页面:首页、国际频道、财经频道
    • +
    • 步骤
        +
      • 访问首页
      • +
      • 单击“国际”(频道)
      • +
      • 单击“财经”(频道)
      • +
      +
    • +
    • 操作手段:录制回放
    • +
    +

    操作步骤

      +
    • 添加录制器“HTTP(S) Test Script Recorder”

      +
        +
      • 右键Test Plan,点击add
      • +
      • 点击Non-Test Elements
      • +
      • 点击HTTP(S) Test Script Recorder
      • +
      +
    • +
    • 添加线程组“Thread Group”

      +
    • +
    • 添加录制控制器“Recording Controller”,

      +
        +
      • 右键线程组,点击and
      • +
      • 点击Logic Controller
      • +
      • 点击Recording Controller
      • +
      +
    • +
    • 录制脚本的配置(Test Plan Creation)

      +
        +
      • Port=8088
      • +
      • Target Controller = TestPlan > Tread Group > Recording Controller
      • +
      • 其他的配置保持默认
      • +
      +
    • +
    • 录制脚本的配置(Requests Filtering 请求过滤器)

      +
        +
      • URl Patterns to Include上添加正则.*\.(baidu\.com).*;表示只抓取百度URL的内容,不抓取其他网站的
      • +
      • URl Patterns to Exclude上添加正则.*\.(js|css|PNG|jpg|jpeg|ico|png|gif).*;去掉一些静态请求
      • +
      • 目的是:避免录制过多没必要的请求
      • +
      +
    • +
    • 单击保存按钮,将Jmeter脚本存储

      +
    • +
    • +
    • 打开浏览器,设置代理,将浏览器的代理服务地址指向http://localhost:8088,然后就可以进行访问录制了
    • +
    • +
    • 访问百度新闻的首页、国际、财经页面
    • +
    • +
    • 查看jmeter,录制结果在Recording Controller下面看到,然后停止录制
    • +
    +

    校验

    录制结束后,要对录制的代码进行校验

    +
      +
    • 添加查看结果树组件
    • +
    +

    运行录制的代码,在查看结果树上查看运行的结果

    +]]>
    + + 工具教程 + + + jmeter + +
    + + jmeter自动化压力测试 + /2022/11/19/jmeter/2022-11-14-jmeter%E8%87%AA%E5%8A%A8%E5%8C%96%E5%8E%8B%E5%8A%9B%E6%B5%8B%E8%AF%95/ + 思路
      +
    • jmeter脚本实现压测逻辑
    • +
    • Shell控制逻辑
    • +
    • 使用jmeter进行静默压测
    • +
    +]]>
    + + 工具教程 + + + jmeter + +
    + + Jmeter之断言和聚合报告 + /2022/11/16/jmeter/2022-11-16-Jmeter%E4%B9%8B%E6%96%AD%E8%A8%80/ + 怎么对请求进行响应断言
      +
    • 右键 HTTP Request

      +
    • +
    • 点击add --> Assertions --> Response Assertion

      +
    • +
    +

    断言组件就添加成功

    +

    配置响应断言

    Field to Test 下面就是断言的各种方法

    +
      +
    • Text Response 文本断言
    • +
    +
    +

    Patterns to Test输入title之间包含的文字,及配置成功

    +
    +
      +
    • Response Code 响应码断言
    • +
    +
    +

    Patterns to Test输入响应码,比如 200

    +
    +
      +
    • Response Message
    • +
    • Request Headers
    • +
    • URL Sampled
    • +
    • Document(text)
    • +
    • Request Data
    • +
    +

    然后运行但并发压测,验证断言添加是否正确,在View Results Tree中查看结果

    +

    怎么使用聚合报告

      +
    • 右键 Thread Group

      +
    • +
    • 点击 Add --> Listener --> Aggregate Report

      +
    • +
    +

    聚合报告就添加了

    +

    性能指标解读

      +
    • Average: 单个请求的平均响应时间
    • +
    • Median: 中位数,也就是50%用户的响应时间
    • +
    • 90%Line: 90%用户的响应时间
    • +
    • 95%Line: 95%用户的响应时间
    • +
    • 99%Line: 99%用户的响应时间
    • +
    • Min: 最小的请求响应时间
    • +
    • Max: 最大的请求响应时间
    • +
    • Error%: 错误率
    • +
    • Throughput: 吞吐量
    • +
    • Received KB/sec: 每秒从服务器接收到的数据量
    • +
    • Sent KB/sec: 每秒从客户端发送的请求的数量
    • +
    +]]>
    + + 工具教程 + + + jmeter + +
    + + Jmeter之静默压测 + /2022/11/17/jmeter/2022-11-17-jmeter%E6%80%8E%E4%B9%88%E8%84%B1%E7%A6%BBUI%E8%BF%9B%E8%A1%8C%E5%8E%8B%E6%B5%8B/ + 静默压测
    +

    jmeter -n -t $jmx_file -l $jtl_file

    +
    +

    如: jmeter -n -t HTTP代理服务器luzhi.jmx -l result.jtl

    +

    jmx: Jmeter压测程序脚本文件
    jtl: Jmeter压测请求响应数据的原始文件,查看结果树和聚合报告可以导入该文件查看

    +]]>
    + + 工具教程 + + + jmeter + +
    + + Jmeter之json数据提取和参数传递 + /2022/11/18/jmeter/2022-11-18-Jmeter%E4%B9%8Bjson%E6%95%B0%E6%8D%AE%E6%8F%90%E5%8F%96%E5%92%8C%E5%8F%82%E6%95%B0%E4%BC%A0%E9%80%92/ + 安装组件JSON Extractor
      +
    • 右键Http Request
    • +
    • 点击Add -> Post Processors -> JSON Extractor
    • +
    +

    组件安装成功

    +

    组件配置

      +
    • Names of created variables : 参数变量名称,提取出来的json使用这个变量
    • +
    • Json Path expressions : JSON提取的正则 比如:$.access_token这个是提取response里面的token
    • +
    • Match NO.(0 for Random):这个是写提取出json的第几条, 比如使用正则能匹配多条,使用这个输入数字就可以匹配对应的
    • +
    +
    引用json变量
      +
    • Jmeter中引用变量的方法${变量名}
    • +
    +

    调试脚本 Debug Sampler

    +

    帮助检查变量值,调试脚本

    +
    +
      +
    • 右键Thread Group
    • +
    • 点击Add -> Sampler -> Debug Sampler
    • +
    +

    注意:把Debug放到所有请求的最底下,运行的后可以查看变量参数,方便调试

    +]]>
    + + 工具教程 + + + jmeter + +
    + + Jmeter之全局参数设置和csv数据导入 + /2022/11/18/jmeter/2022-11-18-jmeter%E4%B9%8B%E5%85%A8%E5%B1%80%E5%8F%82%E6%95%B0%E8%AE%BE%E7%BD%AE%E5%92%8Ccsv%E6%95%B0%E6%8D%AE%E5%AF%BC%E5%85%A5/ + 全局参数设置
    添加组件
      +
    • 右键Thread Group
    • +
    • 点击Add -> Config Element -> User Defined Variables
    • +
    +
    添加对应的变量
      +
    • hostname:localhost
    • +
    • port:9090
    • +
    • protocol:http
    • +
    +

    然后再请求参数中使用对应的参数变量名

    +
      +
    • ${hostname}
    • +
    • ${port}
    • +
    • ${protocol}
    • +
    +

    csv数据导入

    创建csv文件
      +
    • 使用Excel创建csv文件
    • +
    • csv数据之间使用英文逗号来分割
    • +
    • 保存成.csv文件
    • +
    +
    添加csv导入组件
      +
    • 右键Thread Group
    • +
    • 点击Add -> Config Element -> CSV Data Set Config
    • +
    +
    配置
      +
    • Filename:文件位置
    • +
    • File encoding:编码格式
    • +
    • Variable Names(comma-delimited):数据参数 如:no,username,password
    • +
    • lgnore first lline (only user if Variable Names is not empty):是否忽略第一行(表头)
    • +
    • Delimiter(use "\t" for tab):分隔符
    • +
    • Allow quoted data?:是否允许双引号括住数据
    • +
    • Recycle on EOF?:到了文件结尾是否循环
    • +
    • Stop thread on EOF?:到了文件结尾是否停止
    • +
    • Sharinng mode:共享模式
    • +
    +注意:把请求的参数修改为:`${变量}`]]>
    + + 工具教程 + + + jmeter + +
    + + jmeter对数据库进行增删改查 + /2022/11/20/jmeter/2022-11-20-jmeter%E5%AF%B9%E6%95%B0%E6%8D%AE%E5%BA%93%E6%95%B0%E6%8D%AE%E8%BF%9B%E8%A1%8C%E5%A2%9E%E5%88%A0%E6%94%B9%E6%9F%A5/ + 环境
      +
    • jmeter版本(5.1.1)
    • +
    • mysql-connector-java-8.0.15.jar
    • +
    +

    mysql.jar放在jmeter的lib目录下

    +

    配置

    连接配置组件

      +
    • 右键Thread Group
    • +
    • 点击Add -> Config Element -> JDBC Connection Configuration
    • +
    +

    参数配置

      +
    • ==Varianle Name for created pool==:db_connnection_pool # 连接池名称
    • +
    • ==Validation Query==:select 1
    • +
    • ==Database URL==:jdbc:mysql://8.142.144.75:3306/jmeter_class?alloMultiQueries = true&useSSL=false
    • +
    • ==JDBC Driver class==:选择com.mysql.jbc.Driver
    • +
    • 输入username
    • +
    • 输入password
    • +
    +

    Jmeter数据库JDBC请求

      +
    • 右键Thread Group
    • +
    • 点击Add -> Sampler -> JDBC Request
    • +
    +
    配置介绍

    Variable Name Bound to Pool: 配置参数区
    SQL Query:sql语句区
    其他:变量配置区

    +
    举个栗子:通过Insert语句,向数据库添加测试数据
      +
    • JDBC Connection Configuration: db_connnection_pool #输入连接池名称
    • +
    • Query Type:选择Prepared Updata Statement
    • +
    • Quert:输入sql语句
    • +
    +
    INSERT INTO jmeter_class.user (`username`,`password`) VALUES(?,?)
    +
      +
    • Paeameter values:testuser,aaaaaa
    • +
    • Paeameter types:varchar,varchar
    • +
    • Query timeout(s):6
    • +
    • 添加查看结果树
    • +
    • 运行
    • +
    +

    运行结果ResponseBody:

    1 updates.

    这就配置成功

    +]]>
    + + 工具教程 + + + jmeter + +
    + + Constant Timer定时器 + /2022/11/29/jmeter/2022-11-29-Constant%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/ + 作用

    就是loadrunner上面的思考时间,就是模拟真实用户操作过程的等待时间

    +

    生效范围

    定时器的父节点和子节点,如果想让一个请求强制停止一段时间,就把定时器放在这个请求的下面

    +

    单位是以ms为单位,1s=1000ms

    +]]>
    + + 工具教程 + + + jmeter + +
    + + 循环控制器Loop Controller + /2022/11/29/jmeter/2022-11-29-Loop%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/ + 作用

    指定子节点运行的次数,使用变量或数值进行控制

    +
      +
    • Infinite:表示一直循环
    • +
    • 如果同时设置线程组循环次数和循环控制器的循环次数,那控制器子节点运行的次数为两个数值相乘的结果
    • +
    +

    添加

    ]]>
    + + 工具教程 + + + jmeter + +
    + + Modeule Controller和Include Controller + /2022/11/29/jmeter/2022-11-29-Modeule%20Controller/ + Modeule Controller介绍]]> + + 工具教程 + + + jmeter + + + + 随机控制器Random Controller和Random Order Controller + /2022/11/29/jmeter/2022-11-29-Random%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/ + 作用
      +
    • Random Controller:控制器子节点随机运行一个请求
        +
      • lgnore sub-controller blocks:忽略子控制器块
      • +
      +
    • +
    • Random Order Controller:控制器子节点随机运行全部请求
    • +
    +]]>
    + + 工具教程 + + + jmeter + +
    + + 逻辑控制器Simple Controller + /2022/11/29/jmeter/2022-11-29-Simple%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/ + 作用

    把多个请求放入Simple Controller,可以多个请求进行同时操作

    +]]>
    + + 工具教程 + + + jmeter + +
    + + 事务控制器Transcation Controller + /2022/11/29/jmeter/2022-11-29-Transcation%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/ + 作用

    一个事务会包含并请求,然后查看一个事务的QPS等性能指标

    +

    指标

    QPS:每秒处理完请求的次数,具体指1s内发出请求到服务器处理完成并返回结果的次数

    +

    TPS:每秒处理完的事务次数,一般TPS是对整个系统来讲的,一个应用系统1s能完成多少事务处理,一个事务在分布式处理中,可能对应多个请求,对于衡量单个接口服务的处理能力,一般使用QPS

    +

    参数

      +
    • Generate Parent sample:生成父样例,就是控制器里面的请求不展示
    • +
    +

    没有选中Generate Parent sample,运行后的结果是

    +
    + +
    +
    + +
    +选中后`Generate Parent sample`,运行后的结果是 +
    + +
    +
    + +
    + + +]]>
    + + 工具教程 + + + jmeter + +
    + + 逻辑控制器If Controller + /2022/11/29/jmeter/2022-11-29-if%20Controller%E6%8E%A7%E5%88%B6%E5%99%A8/ + 逻辑控制器If Controller]]> + + 工具教程 + + + jmeter + + + + Constant Throughput Timer定时器 + /2022/11/30/jmeter/2022-11-30-Constant%20Throughput%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/ + 作用

    限制整个运行过程中的生成的吞吐量不要超过某一个值,防止压死系统

    +

    参数

      +
    • Target throughput(in samples per minute):目标吞吐量,指的是每分钟发送的请求数,对应测试要求的20 QPS,这里应该输入1200
    • +
    • Calculate Throughput based on:有5个选项
        +
      • This Thread only:控制每个线程的吞吐量,这个模式的作用是:总的吞吐量=Target throughput * 线程的数量
      • +
      • All active threads:设置的Target throughput将分配在每个活跃线程上,每个活跃线程在上一次运行结束后等待合理时间后再次运行。活跃线程指的是同一时刻同时运行的线程
      • +
      • All active threads in current thread group:设置的`Target throughput将分配在当前线程祖的每一个活跃线程上,当测试计划只有一个线程组,这个模式作用和All active threads一样
      • +
      • All active threads(shared):与All active threads选项基本一致,唯一区别是,每一个活跃线程都会在所有活跃线程上一次运行结束后等待合理时间再次运行
      • +
      • All active threads in current thread group(shared):与All active threads in current thread group选项基本一致,唯一区别是,每个活跃线程都会在所有活跃线程的上一次运行结束等待合理的时间后再次运行
      • +
      +
    • +
    +]]>
    + + 工具教程 + + + jmeter + +
    + + Gaussian Random Timer定时器 + /2022/11/30/jmeter/2022-11-30-Gaussian%20Random%20Timer%E5%AE%9A%E6%97%B6%E5%99%A8/ + 作用

    生成随机等待时间

    +

    参数

      +
    • Deviation(in milliseconds):高斯定时器参数,随机的
    • +
    • Constant Delay Offset(in milliseconds):固定等待时长
    • +
    +

    生成的时长是Deviation + Constant Delay Offset

    +]]>
    + + 工具教程 + + + jmeter + +
    + + Regular Expression Extractor正则表达式处理器 + /2022/11/30/jmeter/2022-11-30-%E5%90%8E%E7%BD%AE%E5%A4%84%E7%90%86%E5%99%A8%E4%B9%8B%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F%E5%A4%84%E7%90%86%E5%99%A8/ + 正则表达式规则
      +
    • ():括起来的部分是要提取的
    • +
    • .:匹配任何字符串
    • +
    • +:一次或多次
    • +
    • ?:在找到第一个匹配项后停止
    • +
    +

    模板

    2$等,表示解析到的第几个值给title,$1$表示第一个

    +

    匹配数字

    0代表随机,1代表全部取值,通常使用0

    +

    缺省值

    若参数没有取到值,那默认给一个值让他取

    +]]>
    + + 工具教程 + + + jmeter + +
    + + Groovy编写方法 + /2022/11/30/jmeter/2022-12-1-Groovy%E7%BC%96%E5%86%99%E6%96%B9%E6%B3%95/ + 关键字:
      +
    • log:写入信息到jmeterlog文件,使用方法:log.info(*Thisisloginfo
    • +
    • ctx:该变量引用了当前线程的上下文,使用方法可参考:org.apache.imeter.threads.JMeterContext。
    • +
    • vars-(JMeterVariables):操作imeter变量,这个变量实际引用了JMeter线程中的局部变量容器(本质上是Map),它是测试用例与BeanShell交互的桥梁,
      常用方法:
        +
      • a)vars.get(Stringkey):从imeter中获得变量值
      • +
      • b)vars.put(Stringkey,Stringvalue):数据存到imeter变量中
        更多方法可参考:org.apache.imeter.threads.JMeterVariables
      • +
      +
    • +
    • props-(JMeterProperties-classjava.util.Properties):操作imeter属性,该变量引用了JMeter的配置信息,可以获取Jmeter的属性,它的使用方法与vars类似,但是只能put进去String类型的值,而不能是一个对象。
      对应于iava.util.Properties。
        +
      • a)props.get(“START.HMS”); 注:START.HMS为属性名,在文件imeter.properties中定义
      • +
      • b)props.put(“PROP1”,”1234”);
      • +
      +
    • +
    • prey-(SampleResult):获取前面的sample返回的信息,
      常用方法:
        +
      • a)getResponseDataAsString():获取响应信息
      • +
      • b)getResponseCode():获取响应code
        更多方法可参考:org.apache.imeter.samplers.SampleResult
      • +
      +
    • +
    • sampler-(Sampler):gives access to the current sampler
    • +
    +]]>
    + + 工具教程 + + + jmeter + +
    + + 使用moko编写测试接口(无) + /2022/11/28/moko/2022-11-28-moko/ + 测试

    测试

    测试moko


    +

    测试

    +

    🐱

    +

    ❄️

    +]]>
    + + 经验分享 + + + java + +
    + + 使用moko编写Get和Post测试接口(二) + /2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99Get%E5%92%8CPost%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%BA%8C%EF%BC%89/ + 上一节已经写了规则,这次直接来编写Get和Post请求

    +

    模拟一个没有参数的get请求

    {
    "description": "模拟一个没有参数的get请求",
    "request": {
    "uri": "/getdemo",
    "method": "get"
    },
    "response": {
    "text": "这是一个没有参数的get请求"
    }
    }

    模拟一个带参数的请求
    {
    "description": "模拟一个带参数的请求",
    "request": {
    "uri": "getwithparam",
    "method": "get",
    "queries": {
    "name": "胡汉三",
    "age": "18"
    }
    },
    "response": {
    "text": "我胡汉三又回来了!!!!!"
    }
    }

    +

    模拟一个Post请求

    {
    "description": "模拟一个Post请求",
    "request": {
    "uri": "/postdemo",
    "method": "post"
    },
    "response": {
    "text": "这是我的第一个mosk的post请求"
    }
    }

    +

    这是一个带参数的post请求

    {
    "description": "这是一个带参数的post请求",
    "request": {
    "uri": "/postwithparam",
    "method": "post",
    "forms": {
    "name": "胡汉三",
    "sex": "男人"
    }
    },
    "response": {
    "text": "我胡汉三带着参数来了!!!!"
    }
    }

    +]]>
    + + 经验分享 + + + java + +
    + + 使用moko编写包含cookie信息的测试接口(二) + /2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E5%8C%85%E5%90%ABcookie%E4%BF%A1%E6%81%AF%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%B8%89%EF%BC%89/ + 上一节已经写了规则,这次直接来编写Get和Post请求

    +

    这是一个会返回cookie的get请求

    {
    "description": "这是一个会返回cookie的get请求",
    "request": {
    "uri": "/getCookies",
    "method": "get"
    },
    "response": {
    "cookies": {
    "login": "true"
    },
    "text": "恭喜你获得cookies信息成功",
    "status": 200,
    "msg": "成功"
    }
    }
    +

    这是一个携带cookies信息的get请求

    {
    "description": "这是一个带cookies信息的get请求",
    "request": {
    "uri": "/get/with/cookies",
    "method": "get",
    "cookies": {
    "login": "true"
    }
    },
    "response": {
    "text": "这是一个需要携带cookies信息才能访问的get请求"
    }
    }
    +

    这是一个携带cookies信息的post请求

    {
    "description": "这是一个带cookies信息的post请求",
    "request": {
    "uri": "/post/with/cookies",
    "method": "post",
    "cookies": {
    "login": "true"
    },
    "json": {
    "name": "huhansan",
    "age": "18"
    }
    },
    "response": {
    "status": 200,
    "json": {
    "huhansan": "success",
    "status": "1"
    }
    }
    }
    +]]>
    + + 经验分享 + + + java + +
    + + 使用moko编写测试接口(一) + /2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%B8%80%EF%BC%89/ + 编写规则
      +
    • []包裹着以{}包起来的接口脚本

      +
    • +
    • description:接口简介

      +
    • +
    • request:使用{}包含接口的请求信息

      +
        +
      • uri:接口的地址名称
      • +
      • method:请求方法
      • +
      • queries:get请求参数
      • +
      • forms:post请求参数
      • +
      • headers:请求头信息
      • +
      +
    • +
    • response:返回的数据,使用{}

      +
        +
      • text:返回的文字数据
      • +
      • cookies:返回的cookie信息
      • +
      • status:返回的响应码
      • +
      +
    • +
    +

    举个栗子demo

    +
    [
    {
    "description": "这是我们的第一个mock栗子",
    "request": {
    "uri": "/demo"
    },
    "response": {
    "text": "第一个mock响应demo"
    }
    }
    ]
    +

    get请求demo

    [
    {
    "description": "接口的get请求",
    "request": {
    "uri": "/#/test/xml",
    "method": "get"
    },
    "response": {
    "text": "get请求接口"
    }
    }
    ]

    +]]>
    + + 经验分享 + + + java + +
    + + 使用moko编写测试接口(五) + /2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E4%BA%94%EF%BC%89/ + 下载jar包

    点击moke选择版本进行下载,我下载的的是moco-runner-0.11.0-standalone.jar

    +

    使用命令启动测试脚本

    java -jar jar包的存放路径 http -p 端口 -c json文件路径
    ]]>
    + + 经验分享 + + + java + +
    + + 使用moko编写重定向测试接口(四) + /2022/11/28/moko/2022-11-28-%E4%BD%BF%E7%94%A8moko%E7%BC%96%E5%86%99%E9%87%8D%E5%AE%9A%E5%90%91%E7%9A%84%E6%B5%8B%E8%AF%95%E6%8E%A5%E5%8F%A3%EF%BC%88%E5%9B%9B%EF%BC%89/ + 上一节已经写了规则,这次直接来编写Get和Post请求

    +

    重定向的测试接口

      +
    • 使用了redirectTo:目标地址
    • +
    +
    [
    {
    "description": "重定向到百度",
    "request": {
    "uri": "/redirect"
    },
    "redirectTo": "http://www.baidu.com"
    },
    {
    "description": "重定向到自己的网页上",
    "request": {
    "uri": "/redirect/topath"
    },
    "redirectTo": "/redirect/new"
    },
    {
    "description": "这是被重定到的请求",
    "request": {
    "uri": "/redirect/new"
    },
    "response": {
    "text": "重定向成功了"
    }
    }
    ]
    +]]>
    + + 经验分享 + + + java + +
    + + Yaml的使用 + /2022/08/26/other/2020-08-26-Yaml%E4%BD%BF%E7%94%A8/ + 编写字符串
    #字符串
    #单行
    username: admin
    username1: "周杰\n伦" #双引号不转义
    username2: '周杰\n伦' ##单引号转义
    #多行
    william:



    william2: |




    william3: >



    +

    回显的结果是:

    +
    { username: 'admin',
    username1: '周杰\n伦',
    username2: '周杰\\n伦',
    william: '一 二 三',
    william2: '一\n二\n三\n',
    william3: '一 二 三\n' }
    +
    强制转换
    forceStr: !!str 123
    forceBoll: !!str true
    forceInt: !!int "123"
    +

    回显的结果是:

    +
    forceStr: '123',
    forceBoll: 'true',
    forceInt: 123 }
    +
    编写数组
    #数组
    myFavourite:
    - backaetball
    - football

    myFavourite2: ["bass","bahddd"]
    +

    回显的结果是:

    +
    myFavourite: [ 'backaetball', 'football' ],
    myFavourite2: [ 'bass', 'bahddd' ],
    +
    编写对象
    #对象
    autotest:
    username: root
    password: root
    age: 18
    male: true

    autotest2: [{username: admin, password: root, age: 22, male: false}]
    +

    回显的结果是:

    +
    autotest: { username: 'root', password: 'root', age: 18, male: true },
    autotest2: [ { username: 'admin', password: 'root', age: 22, male: false } ],
    +
    编写复合结构的
    #复合结构
    companies:
    -
    id: 1
    name: zhangsan
    value: 10e+11

    -
    id: 2
    name: lisi
    value: 10e+12


    websites:
    baidu: www.baidu.com
    google: www.google.com
    +

    回显的结果是:

    +
    companies: 
    [ { id: 1, name: 'zhangsan', value: 1000000000000 },
    { id: 2, name: 'lisi', value: 10000000000000 } ],
    websites: { baidu: 'www.baidu.com', google: 'www.google.com' } }
    +
    引用
    #引用
    father: &father_lastName
    lastName:

    son:
    <<: *father_lastName
    firstName:
    age: 18
    +

    回显的结果是:

    +
    father: { lastName: '周' },
    son: { lastName: '周', firstName: '董', age: 18 } }
    +]]>
    + + 经验分享 + + + yaml + +
    + + 使用Postman如何做接口测试 + /2022/09/02/other/2022-09-02-%E4%BD%BF%E7%94%A8postman%E5%A6%82%E4%BD%95%E5%81%9A%E6%8E%A5%E5%8F%A3%E6%B5%8B%E8%AF%95/ + Postman安装
    +

    Postman下载:https://www.postman.com/downloads/

    +
    +

    image
    下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

    +

    postman主要功能说明

    postman主要模块功能介绍

    image
    点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
    image
    image
    image
    image
    创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
    image
    image

    +

    发送http请求和分析响应数据

    +

    在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
    请求的方法:get或post
    请求的URL:协议+域名/IP+端口+资源路径

    +
    +

    不带参数的请求:
    image
    发送需要认证的get接口:
    image

    +

    ------------恢复内容开始------------

    ## Postman安装

    +
    +

    Postman下载:https://www.postman.com/downloads/

    +
    +

    image
    下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

    +

    postman主要功能说明

    1、postman主要模块功能介绍

    image
    点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
    image
    image
    image
    image
    创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
    image
    image

    +

    发送http请求和分析响应数据

    +

    在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
    请求的方法:get或post
    请求的URL:协议+域名/IP+端口+资源路径

    +
    +

    get请求

    不带参数的请求:
    image
    发送需要认证的get接口:
    image

    +

    post请求

    选择请求格式为post
    传参:

    +
      +
    • Body中raw:支持任意格式的数据编辑,选json(也可xml或html传参)
    • +
    • Body中Form-data:以表单的方式进行数据编辑
    • +
    • Body中x-www-form-urlencoded:与form-data类似,也是以表单的方式进行数据编辑,但是表单中的每一条数据只能是键值对.
    • +
    • Body中Binary:用来上传文件.并且由于没有键值,因此一次只能上传一个文件.
    • +
    +

    Pre-request Scrip

    image

    +

    Tests

    image

    +

    postman保存测试用例

    image

    +

    postman批量运行

    image
    image

    +

    选择文件进行参数化

    json文件

    image

    +

    txt文件

    image
    使用参数时,变量名称要与文件里的变量名保持一致

    +

    postman环境管理

    image
    image
    引用环境信息:

    +

    postman全局变量

    image
    也可以用javascript写变量:
    image
    引用全局变量信息:
    image
    image
    Cookie用途:一个请求需要用到用户的登录状态(sessionid或token),一般 登录状态会记录在cookie ,postman会自动记录登录状态写入cookies.所以执行非登录接口的请求前,需要先执行登录接口请求。
    image

    +

    关联

    ------------恢复内容结束------------

    +

    ------------恢复内容开始------------

    ## Postman安装

    +
    +

    Postman下载:https://www.postman.com/downloads/

    +
    +

    image
    下载后双击即可安装,安装后需要创建账号,登录后可以在不同平台同步数据。

    +

    postman主要功能说明

    1、postman主要模块功能介绍

    image
    点击最上面的测试集的添加目录图标,来新增一个根目录,这样等于新建了一个项目.可以将一个项目或一个模块的用例都存放在这个目录之下,并且在根目录下还可以创建子目录进行用例的细分.
    image
    image
    image
    image
    创建了目录后可以进行用例的新建,具体是通过测试集右侧区域中的三个点来新增一个空的用例模板,当然也可以通过复制一个已有的用例来达到新建用例的目的.
    image
    image

    +

    发送http请求和分析响应数据

    +

    在postman中新建用例对应即将要执行的一次请求,默认为空,测试人员需要添加相应的请求信息,需要添加的信息包括:
    请求的方法:get或post
    请求的URL:协议+域名/IP+端口+资源路径

    +
    +

    get请求

    不带参数的请求:
    image
    发送需要认证的get接口:
    image

    +

    post请求

    选择请求格式为post
    传参:

    +
      +
    • Body中raw:支持任意格式的数据编辑,选json(也可xml或html传参)
    • +
    • Body中Form-data:以表单的方式进行数据编辑
    • +
    • Body中x-www-form-urlencoded:与form-data类似,也是以表单的方式进行数据编辑,但是表单中的每一条数据只能是键值对.
    • +
    • Body中Binary:用来上传文件.并且由于没有键值,因此一次只能上传一个文件.
    • +
    +

    Pre-request Scrip

    image

    +

    Tests

    image

    +

    postman保存测试用例

    image

    +

    postman批量运行

    image
    image

    +

    选择文件进行参数化

    json文件

    image

    +

    txt文件

    image
    使用参数时,变量名称要与文件里的变量名保持一致

    +

    postman环境管理

    image
    image
    引用环境信息:

    +

    postman全局变量

    image
    也可以用javascript写变量:
    image
    引用全局变量信息:
    image
    image
    Cookie用途:一个请求需要用到用户的登录状态(sessionid或token),一般 登录状态会记录在cookie ,postman会自动记录登录状态写入cookies.所以执行非登录接口的请求前,需要先执行登录接口请求。
    image

    +

    关联

    断言

    Postman通过tests插入断言
    image

    +

    关联

    +

    把上一个接口的返回数据作为下一个参数的输入参数使用

    +
    +
      +
    • 先发送一个接口,查看返回值
    • +
    • 在上一个接口的tests里面添加js脚本
        +
      • 获取上一个接口返回值并赋值给变量
      • +
      • 定义全局变量,并获取要作为下一个接口输入的数据字段
      • +
      +
    • +
    • 引用全局变量
    • +
    +

    生成并导出接口脚本

    导出接口测试脚本

    image

    +

    导出测试集

    image
    image

    +

    导入测试集

    image

    +]]>
    + + 工具教程 + + + postman + +
    + + 测试必会的sql基本操作 + /2022/10/22/other/2022-10-22-SQL%E8%AF%AD%E8%A8%80%E7%9A%84%E5%9F%BA%E6%9C%AC%E6%93%8D%E4%BD%9C/ + 1、创建数据库
    create database 数据库名;
    create database 数据库名 character set 字符集;
    +
    2、查看全部的数据库
    show databases;   
    +

    3、查看某个数据库的定义的信息:

    +
    show create database 数据库名;         
    +
    4、删除数据库
    drop database 数据库名称;
    +

    5、切换数据库:

    +
    use 数据库名;
    +

    6、查看正在使用的数据库:

    +
    select database();          
    +

    7、查看数据库中的所有表:

    +
    show tables;
    +

    8、查看表结构:

    +
    desc 表名;    
    +

    9、修改表删除列.

    +
    alter table 表名 drop 列名;            
    +

    10、修改表名

    +
    rename table 表名 to 新表名;              
    +

    11、修改表的字符集

    +
    alter table 表名 character set 字符集;
    +

    12、数据类型与约束

    +
      +
    • int :整数 有符号和无符号,长度不受限制
    • +
    • varchar:字符串 中文/数字/字母都是一字字符,受长度限制
    • +
    • decimal :小数 decimal(5,2)总长度5位,整数3位,小数2位
    • +
    • 主键 id :int unsigned primary key auto_increment
    • +
    • 非空 :not null
    • +
    • 唯一 :unique
    • +
    • 默认 :default
    • +
    +

    SQL中表的操作

    1、创建表

    create table 表名(字段名 类型 约束,.....)
    +

    2、删除表

    drop table 表名
    drop table if exists 表名
    +

    3、表数据操作

    3.1、添加数据
    insert into 表名 values(值1,值2...)给表中所有字段插入数据
    insert into 表名(字段2,字段1values(值2,值1
    +
    3.2、修改数据
    update 表名 set 字段1=1,字段2=2 where 条件
    isdelete 逻辑删除
    +
    3.3、删除数据
    delete from 表名 where 条件
    +
    3.4、查询数据
      +
    • 3.4.1、查询表中所有信息
      select * from 表名 where 条件
      +
    • +
    • 3.4.2、查询表中指定字段
      select 字段1,字段2,字段3...from 表名 where 条件
      +
    • +
    • 3.4.3、给字段取别名
      select 字段1as) 别名,字段2 别名 from 表名 where 条件
      +
    • +
    • 3.4.4、去重
      select distinct 字段 from 表名 where 条件
      +
    • +
    • 3.4.5、比较运算符
      select * from 表名 where age>20
      +
    • +
    • 3.4.6、逻辑运算符
        +
      • and 满足所有条件

        +
      • +
      • or 满足其中任意一个条件

        +
      • +
      • not 不满足条件

        +
      • +
      +
    • +
    • 3.4.7、模糊查询
        +
      • like
      • +
      • % 0到任意多个字符
      • +
      • _表示任意一个字符
      • +
      +
    • +
    • 3.4.8、范围查询
        +
      • in 在一个非连续的范围内
      • +
      • between and 在一个连续的范围内 闭区间 小的数据在前
      • +
      +
    • +
    • 3.4.9、空查询
        +
      • is null
      • +
      • ‘’空字符串
      • +
      +
    • +
    +
    3.5、多表查询
      +
    • 3.5.1、排序

      +
      select * from 表名 where 条件 order by1asc|desc,列2 asc|desc
      select * from student where 条件 order by convert(字段 using gbk)asc|desc 纯中文转换后排序
      +
    • +
    • 3.5.2、聚合函数

      +
      count: 总数 select count(*/字段)from 表名 where 条件 
      max: 最大值 select max(age) from 表名 where 条件
      min: 最小值 select min(age) from 表名 where 条件
      avg: 平均值 select avg(grade) from 表名 where 条件
      sum: 求和 select sum(grade) from 表名 where 条件
      select avg(age)as 平均年龄,max(age)最大年龄,min(age)最小年龄 from 表名 where 条件
      +
    • +
    • 3.5.3、分组

      +
      select * from 表名 group by 字段,字段2 having 条件
      +
    • +
    • 3.5.4、分页

      +
      select * from 表名 limit 05 从第一行数据开始,显示5
      select * from 表名 limit (n-1*m,m n代表第几页,m代表每页显示多少条数据
      +
    • +
    • 3.5.5、等值连接

      +
      方式一 :
      select * from1,表2,表3 where1.=2.and2.=3.where 条件
      方式二 内连接 取交集:
      select * from1 inner join2 on1.=2.inner join3 on2.=3.where 条件
      +
    • +
    • 3.5.6、左连接

      +
      +

      左边的表全显示,右边表能匹配的上的数据连接显示,匹配不上(没有的)以null补充

      +
      +
      select * from1 left join2 on1.=2.left join3 on2.=3.where 条件
      +
    • +
    • 3.5.7、右连接

      +
      +

      右边的表全显示,左边表能匹配上的数据连接显示,匹配不上(没有的)以null补充

      +
      +
      select * from1 right join2 on1.=2.right join3 on2.=3.where 条件
      +
    • +
    • 3.5.8、自关联

      +
      select * from 表 别名1 inner join 表 别名2 on 别名1.aid=别名2.pid
      +
    • +
    • 3.5.9、子查询
        +
      • 标量子查询
      • +
      +
      +

      子查询结果输出的是一行一列

      +
      +
      select * from student where age>(select avg(age) from student)
      +
        +
      • 列子查询
      • +
      +
      +

      子查询的结果输出的是一列多行

      +
      +
      in:  
      select * from student where age in
      (select age from student where age=18)

      any/some: >:大于最小的; <: 小于最大的
      select * from student where age>/< any
      (select age from student where age between 18 and 22)

      all: >:大于最大的; <: 小于最小的
      select * from student where age>/<all
      (select age from student where age between 18 and 22
      +
        +
      • 行子查询
      • +
      +
      +

      子查询的结果输出的是一行多列

      +
      +
      select * from student where(name,sex)=select name,sex from student where sex='男' order by age desc limit 1
      +
        +
      • 表子查询
      • +
      +
      +

      子查询的输出结果是一个表

      +
      +
      select * from scores inner joinselect cno from courses where cname in('数据库',‘系统测试’) as c on scores.cno=c.cno
      +
    • +
    +
    3.6、数据分表
    insert into goods_cate(cate_name) select distinct cate from goods;

    create table goods_cate (id int unsigned primary key auto_incremen,cate varchar(10)) select distinct cate from goods;

    update goods inner join goods_cate on goods_cate.cate=goods.cate set goods.cate=goods_cate.id
    ]]>
    + + 经验分享 + + + sql + +
    + + 性能测试主要关注点 + /2022/08/26/other/2022-10-22-%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E4%B8%BB%E8%A6%81%E5%85%B3%E6%B3%A8%E7%82%B9/ + 性能关注点

    接口响应时间

    +

    吞吐量

    +

    TPS: 事务处理能力,每秒处理事务数(打开页面、登录、选择商品、加入购物车、下单、付款)

    +

    注意:“日活” 每日活跃用户数,是运营数据,与性能无关

    +

    八二原则

    +
    +

    计算QPS/TPS

    +
    +

    相信80%会集中在20%时间内,24小时的流量集中在白天8小时内,同时在午高峰达到高峰

    +

    举个栗子

    根据相应耗时计算公式预估所需并发,一次请求100ms

    +

    根据 QPS = Vue * Rt

    +

    1000000 80% / 8 3600 * 20% = 277 QPS

    +

    需要27个并发

    +]]>
    + + 经验分享 + + + 性能测试 + +
    + + 自动化基础之Xpath定位 + /2022/09/05/other/%E8%87%AA%E5%8A%A8%E5%8C%96%E5%9F%BA%E7%A1%80%E4%B9%8BXpath%E5%AE%9A%E4%BD%8D/ + 常用函数定位
    + + + + + + + + + + + + + + + + + +
    定位函数position
    //*contains(text(),’文字’)/li[position()=3]找到第三个 li
    //*contains(text(),’文字’)/li[position()<=2]找到前两个 li
    +
    +
    Xpath函数进行定位
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    定位方式描述实例
    contains匹配在元素文本中查找包含 ‘文字’ 的元素//*contains(text(),’文字’)
    starts-with匹配所有id开头为 ‘s’ 的元素//*[starts-with(@id,’s’)]
    ends-with匹配所有id结尾头为 ‘s’ 的元素//*[ends-with(@id,”s”)]
    following-sibling匹配和 ‘ul’ 元素同级别的下一个元素//div/following-sibling::ul
    preceding-sibling匹配当前节点之前的所有同级节点
    ancestor匹配当前节点的所有父级,祖父级还有更高级//div/ancestor::li[@role=”menuitem”]
    parent匹配当前节点的父节点,相当于 ..//div/parent::button
    +
    +]]>
    + + 经验分享 + + + xpath + +
    + + 使用docker的ubuntu容器安装code-server + /2022/10/20/project/2022-10-20-%E4%BD%BF%E7%94%A8ubuntu%E5%AE%B9%E5%99%A8%E5%AE%89%E8%A3%85code-server/ + 搭建code-server

    拉取Ubuntu 镜像

    # 拉取镜像
    docker pull aliyun
    # 进入镜像
    docker run --name [自定义名称] -u root --privileged=true -p 3300:8881 -v /opt/testubuntu/:/opt/main_file -it [镜像id]
    +

    安装code-server

    github上下载安装包,解压后剪切到/home目录

    +

    运行code-server

    # 找到bin目录下的code-server*
    cd /home/code-server/bin
    # 输入运行命令
    export PASSWORD="123456" && ./code-server --host 0.0.0.0 --port 8881
    +

    然后在浏览器输入http://ip:3000查看搭建情况

    +

    但是这样搭建有问题

    +
    +

    使用上面方法部署的code-server,因为是http的,导致一些功能不好用,比如写md文档无法预览

    +
    +

    下面就是配置使用https运行

    +

    配置HTTPS

    +

    使用openssl为IP签发证书

    +
    +

    安装openssl

    一般的linux系统已经内置openssl,可以输入openssl进行查看,没有的话就需要安装

    +

    创建证书请求文件

    新建openssl.cnf,并编辑如下内容

    +
    [req]
    distinguished_name = req_distinguished_name
    req_extensions = v3_req

    [req_distinguished_name]
    countryName = Country Name (2 letter code)
    countryName_default = CH
    stateOrProvinceName = State or Province Name (full name)
    stateOrProvinceName_default = ZJ
    localityName = Locality Name (eg, city)
    localityName_default = HangZhou
    organizationalUnitName = Organizational Unit Name (eg, section)
    organizationalUnitName_default = THS
    commonName = Internet Widgits Ltd
    commonName_max = 64

    [ v3_req ]
    # Extensions to add to a certificate request
    basicConstraints = CA:FALSE
    keyUsage = nonRepudiation, digitalSignature, keyEncipherment
    subjectAltName = @alt_names

    [alt_names]

    # 改成自己的域名
    # DNS.1 = your_domain_name.com

    # 改成自己的ip
    IP.1 = 8.142.144.75
    IP.2 = 0.0.0.0
    +

    生成私钥

    san_domain_com 为最终生成的文件名,一般以服务器命名,可改。

    +
    openssl genrsa -out san_domain_com.key 2048
    +

    生成CSR文件

    openssl req -new -out san_domain_com.csr -key san_domain_com.key -config openssl.cnf
    +

    执行后,系统提示输入组织等信息,按[]内容提示输入如即可。

    +

    需要测试CSR文件是否生成成功

    > openssl req -text -noout -in san_domain_com.csr

    有下面的信息,说明生成成功

    +
    Certificate Request:
    Data:
    Version: 0 (0x0)
    Subject: C=US, ST=MN, L=Minneapolis, OU=Domain Control Validated, CN=zz
    Subject Public Key Info:
    Public Key Algorithm: rsaEncryption
    Public-Key: (2048 bit)
    //...
    +

    自签名并生成证书

    openssl x509 -req -days 3650 -in san_domain_com.csr -signkey san_domain_com.key -out san_domain_com.crt -extensions v3_req -extfile openssl.cnf
    +

    在当前目录会生成三个文件

    san_domain_com.crt

    san_domain_com.csr

    san_domain_com.key

    +

    在用户电脑安装证书

    .crt证书发给用户,用户双击进行安装,然后重启浏览器

    +

    code server启动

    在code-server的bin目录下运行如下命令,设置端口号为8881,指定对应生成的crt和key密钥文件,即可正常访问https域名

    # 给ssh创建密码
    export PASSWORD="123456"
    # 启动ssh
    nohup ./code-server --port 8881 --host 0.0.0.0 --cert ../san_domain_com.crt --cert-key ../san_domain_com.key > vscode.log 2>&1 &

    然后通过浏览器访问https://ip:3000

    +]]>
    + + 经验分享 + + + ubuntu + +
    + + 性能监控平台 + /2022/10/20/project/2022-11-24-%E6%90%AD%E5%BB%BA%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B9%B3%E5%8F%B0/ + 搭建容器
    +

    拉取CentOS7镜像,下载安装Grafana和Influxdb

    +
    +
    
    +        # 拉取阿里云的centos7镜像
    +        git pull registry.cn-zhangjiakou.aliyuncs.com/ggls/centos:7.1
    +        # 运行镜像生成容器
    +        docker run -itd --name centos7-influx 
    +        -p 8083:8083 -p 8086:8086 
    +        -p 2003:2003 -p 3000:3000 
    +        -v /opt/centos7_influx:/opt 
    +        --privileged=true 
    +        registry.cn-zhangjiakou.aliyuncs.com/ggls/centos:7.1 /usr/sbin/init
    +        # 进入容器
    +        docker exec -it centos7-influx bash
    +    
    +

    端口说明:

    +
      +
    • 8083:InfluxDB的UI界面展示的端口
    • +
    • 8086:Grafana用来从数据库取数据的端口
    • +
    • 2003:Jmeter往数据库发数据的端口
    • +
    • 3000:本地访问服务器内部docker容器的端口
    • +
    +

    安装Influxdb

      +
    1. 下载influxDB
    2. +
    +

    新版本可以点击influxDB官网进行下载

    + + # 下载安装包 + wget https://dl.influxdata.com/influxdb/releases/influxdb-1.6.3.x86_64.rpm + # 安装运行 + yum localinstall influxdb-1.6.3.x86_64.rpm + +
      +
    1. influxDB配置
    2. +
    +

    安装运行后,然后对influxDB进行配置,主要是配置Jmeter连接的数据库和端口号

    + + vim /etc/influxdb/influxdb.conf + +

    找到graphite并且修改它的库与端口

    enabled = true
    database = "jmeter"
    retention-policy = ""
    bind-address = ":2003"
    protocol = "tcp"
    consistency-level = "one"

    +
      +
    1. 找到[http],将前面的#号去掉
    2. +
    +
    + +
    + +
      +
    1. 配置成功,启动influxDB
    2. +
    +
      +
    • 启动命令: systemctl start influxdb.service
    • +
    • 查看状态命令: systemctl status influxdb.service
    • +
    +
    + +
    + +

    安装Grafana

    新版本下载位置:Grafana官网下载:https://grafana.com/grafana/download

    +
    wget https://dl.grafana.com/oss/release/grafana-6.5.2-1.x86_64.rpm

    sudo yum localinstall grafana-6.5.2-1.x86_64.rpm
    +

    然后启动

    启动命令: systemctl start grafana-server.service

    +

    查看状态命令: systemctl status grafana-server.service

    +

    然后在浏览器访问登录http://ip:3000

    +

    配置Jmeter

    一、添加监听器:Backend Listener

      +
    • 右键点击Thread Group
    • +
    • 点击Add -> Listener -> Backend Listener
    • +
    +

    二、配置监听器:Backend Listener

    Backend Listener implementation 默认选择GraphiteBackendListenerClient

    +
      +
    • graphiteHost:InfluxDB安装的服务器的ip
    • +
    • graphitePort:端口;默认就是2003,除非你自己安装InfluxDB时设置了其他端口是哦(可见上面安装InfluxDB后关于graphite的配置)
    • +
    • rootMetricsPrefix:指标的根前缀;将测试结果存入数据库时,不同指标会生成不同表,但这些表都最好要有一个共同的前缀,这个就是了;后面会讲到不同的指标的含义(重点哦)
    • +
    • summaryOnly:当你线程组有多个请求又想知道每个请求的结果数据时,最好填false,因为true只会返回所有请求的集合数据报告,不会输出每条请求的数据报告
    • +
    • samplersList:取样器列表;想收集哪些请求就填哪些,最好用正则去匹配,减轻工作量
    • +
    • useRegexpForSamplersList:是否使用正则;如果true则使用,samplersList里可以匹配正则表达式
    • +
    • percentiles:百分比;即类似聚合报告里90% Line,95% Line,99% Line的数据;倘若想要99.9时,需要写成【99_9】,用下划线代替点
    • +
    +

    三:运行Jmeter脚本,查看数据库

    数据库里面有两个库,jmeter库就是jmeter运行生成表的数据库

    +

    可以看到生成了三类前缀的表,分别是: jmeter.all 、 jmeter.[请求名称];最后还有 jmeter.test 开头的表,这个后面会单独拿出来说

    +

    前缀的含义

    +
      +
    • jmeter.all :代表了所有请求;当summaryOnly=true时,就只有samplerName=all的表了
    • +
    • jmeter.[请求名称]:代表了HTTP请求,即samplerName=[请求名称]
    • +
    +

    Thread/Virtual Users metrics - 线程/虚拟用户指标
    跟线程组设置相关的

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    指标全称含义
    jmeter.test.minATMin active threads最小活跃线程数
    jmeter.test.maxATMax active threads最大活跃线程数
    jmeter.test.meanATMean active threads平均活跃线程数
    jmeter.test.startedTStarted threads启动线程数
    jmeter.test.endedTFinished threads结束线程数
    +
    +

    Response times metrics - 响应时间指标

    +

    划重点:每个sampler(请求)都包含了所有响应时间指标,每个sampler(请求)的每个指标都会有单独的一个表存储结果数据

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    指标含义
    .ok.countsampler的成功响应数
    .h.count服务器每秒命中次数(每秒点击数,即TPS)
    .ok.minsampler响应成功的最短响应时间
    .ok.maxsampler响应成功的最长响应时间
    .ok.avgsampler响应成功的平均响应时间
    .ok.pctsampler响应成功的所占百分比
    .ko.countsampler的失败响应数
    .ko.minsampler响应失败的最短响应时间
    .ko.maxsampler响应失败的最长响应时间
    .ko.avgsampler响应失败的平均响应时间
    .ko.pctsampler响应失败的所占百分比
    .a.countsampler响应数(ok.count+ko.count)
    .sb.bytes已发送字节
    .rb.bytes已接收字节
    .a.minsampler响应的最短响应时间(ok.count和ko.count的最小值)
    .a.maxsampler响应的最长响应时间(ok.count和ko.count的最大值)
    .a.avgsampler响应的平均响应时间(ok.count和ko.count的平均值)
    .a.pctsampler响应的百分比(根据成功和失败的总数来计算)
    +
    +

    四、配置Grafana

    步骤:

    +
      +
    • 配置数据源

      +
    • +
    • 创建数据面板

      +
    • +
    +
    + +
    + +

    配置数据源

    点击首页的Create your first data source,然后进行配置

    +
    + +
    + +

    点击选择influxDB

    +
    + +
    + +
    + +
    + +

    配置数据面板

    + +
    + +

    选择Add Query,然后进行配置

    +
    + +
    + +

    当我们只想看数据而不想看数据趋势图的话,可以改变它的类型;

    +

    在同一个界面,点击左侧列表选中第二个icon,然后选择Singlestat即可

    +
    + +
    + +

    基本的配置完成,Jmeter使用GraphiteBackendListenerClient来采集数据的,因为请求多起来的时候会有非常多的表,维护成本也会增加;后面将会介绍如何通过InfluxDBBackendListenerClient来采集数据

    +

    给Jmeter的Backend Listener配置为InfluxDBBackendListenerClient

    +

    首先来看看每个配置项的含义

    +
      +
    1. influxdbUrl:安装influxdb的路径;主要格式:http://主机地址:8086/write?db=数据库名
    2. +
    3. application:应用名称;在 events 表中对应的字段是 application
    4. +
    5. measurement:表名;数据存储到哪个表,默认是jmeter,不用改即可
    6. +
    7. summaryOnly:同GraphiteBackendListenerClient
    8. +
    9. samplersRegex:同GraphiteBackendListenerClient
    10. +
    11. percentiles:同GraphiteBackendListenerClient
    12. +
    13. testTitle:测试名称;在 events 表中对应的字段是 text ,JMeter在测试的开始和结束时自动生成注释,该注释的值以’start’和’end’结尾
    14. +
    15. eventTags:Grafana允许为每个注释显示标签;在 events 表中对应的字段是 tags
    16. +
    +

    inDB数据库
    使用InfluxDBBackendListenerClient好处就是,再多的请求也只会生成两张表:

    +

    events :主要拿存事件的

    +

    jmeter :存测试结果数据的,Grafana也是从这个表获取数据再展示

    +

    配置数据面板

    +

    首先,进入官方模板库: https://grafana.com/dashboards ,然后跟着图片导入模板并初始化即可

    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +

    然后jmeter再次执行一下测试计划

    +
    + +
    + +

    模板自带了三个下拉筛选框

    +
      +
    1. data_source:数据源,在Grafana配置了多少个就显示多少个

      +
    2. +
    3. application:在Jmeter配置好的application,如果每次测试计划执行时的application都不一样,你就可以通过这个筛选出对应测试时机的结果数据了

      +
    4. +
    5. transaction:在Jmeter配置好的sampleList,譬如我只发了get、post请求,这里就只会给你选get、post;可以滑到页面下面看到针对某个请求的数据展示

      +
    6. +
    +

    卸载Grafana

    停止Grafana服务。

    systemctl stop grafana-server.service

    systemctl disable grafana-server.service

    查看要卸载的包的名称
    yum list installed

    输入命令行卸载Grafana
    yum remove grafana.x86_64

    +]]>
    + + 经验分享 + + + 监控 + +
    + + 硬件性能监控平台 + /2022/12/01/project/2022-12-1-%E6%90%AD%E5%BB%BA%E7%A1%AC%E4%BB%B6%E6%80%A7%E8%83%BD%E7%9B%91%E6%8E%A7%E5%B9%B3%E5%8F%B0/ + 拉取prometheus镜像
    docker pull prom/prometheus
    +

    创建prometheus容器并启动

    docker run -itd --name=docker_prometheus --restart=always -p 3090:9090 -v /opt/prometheus:/ prom/prometheus
    +

    验证

    +

    通过浏览器访问http://ip:3090进行访问

    +

    方法一:服务器上直接安装node_export

    首先,用浏览器访问:node_export 下载,然后上传到被监控的服务器并解压
    进入解压文件夹,直接启动./node_exporter

    +

    方法二:拉取docker node_export镜像

    docker pull prom/node-exporter
    +

    创建node_export容器并启动

    docker run -itd --name=node-exporter \
    --restart=always \
    -p 9100:9100 \
    -v "/proc:/host/proc:ro" \
    -v "/sys:/host/sys:ro" \
    -v "/:/rootfs:ro" \
    prom/node-exporter
    +

    验证

    +

    在浏览器访问http://ip:9100/metrics进行访问

    +

    配置prometheus + node_export

    node_export的作用收集硬件数据

    +

    使用vim修改yum文件容器内:/etc/prometheus/prometheus.yml

    +
    scrape_configs:
    - job_name: prometheus
    static_configs:
    - targets: ['localhost:9090']
    labels:
    instance: prometheus

    - job_name: linux
    static_configs:
    - targets: ['被监控的服务器ip:9100']
    labels:
    instance: localhost
    +

    重启prometheus容器

    docker restart docker_prometheus
    +

    配置Grafana

    使用Grafana下载版本

    +

    配置数据源

      +
    • 数据源:选择prometheus

      +
    • +
    • URL输入http://prometheus机器ip:3090

      +
    • +
    • 点击Save & Test保存

      +
    • +
    +

    添加仪表盘

    使用官方仪表盘进行下载仪表盘
    导入仪表盘
    import via grafana.com输入框输入模板ID12884

    +

    ID:12633也可以使用。

    +

    点击 load,然后底部选择刚弄的数据源,点击import

    +

    注意:
    点击json下载12884的json文件

    +]]>
    + + 经验分享 + + + 监控 + +
    + + 如何使用pyyaml获取yaml里面的数据 + /2022/08/31/python/2022-09-01-pyyaml%E8%8E%B7%E5%8F%96yaml%E6%95%B0%E6%8D%AE/ + 准备数据

    在config目录下创建environment.yaml文件

    +
    username: 周杰伦
    password: 123456
    +
    使用pyyaml获取yaml中的数据
    解析yaml文件

    首先创建yaml_config文件,为了方便自动化后面的引用,需要创建一个类,在__init__里面打开yaml文件,使用yaml.load(文件名称, Loader=yaml.FullLoader )方法获取数据

    +

    打印出字典格式的数据{'username': '周杰伦', 'password': 123456}

    +
    import yaml
    from common.tools import get_project_path, sep


    class GetConf:
    def __init__(self):
    with open(../config.environment.yaml), "r", encoding="utf-8")\
    as env_file:
    self.env = yaml.load(env_file, Loader=yaml.FullLoader)
    +

    现在使用的是相对路径,后期如果换系统,或者更换文件位置,就需要自己获得文件路径,下面对代码进行优化

    +
    优化项:获得项目名称的url地址

    创建get_project_path方法,获取项目根目录的绝对路径

    +

    首先定义一个变量,变量的值是项目的名称project_name = "trading_system_autotest"

    +

    获取当前文件的所在目录的绝对路径,需要使用python的os模块file_path=os.path.dirname(__file__)

    +

    在绝对路径中找到项目名称的下标位置file_path.find(project_name)

    +

    找到项目所在目录的绝对路径下标+项目名称的长度=项目根目录的绝对路径的下标file_path.find(project_name)+len(project_name)

    +

    然后对所在目录的绝对路径file_path进行切片获得项目根目录的绝对路径

    +

    file_path[: file_path.find(project_name)+len(project_name)]

    +
    def get_project_path():
    """
    获取项目根目录的绝对路径
    :return:
    """
    project_name = "trading_system_autotest"
    # 获取当前文件的所在目录的绝对路径
    file_path = os.path.dirname(__file__)
    # # 在绝对路径中找到项目名称的下标位置
    # print(file_path.find(project_name))
    # 找到项目所在目录的绝对路径+项目名称的长度=项目的绝对路径
    # print(len(project_name))
    return file_path[: file_path.find(project_name)+len(project_name)]
    +
    优化项:获得拼接后的目录和文件

    创建sep(path, add_sep_before=False, add_sep_after=False)方法,获得文件和目录的拼接

    +

    变量

    +

    path变量需要传输一个列表,列表里面是文件所在目录和文件名称,如[文件所在目录,文件名称]

    +

    首先使用os.sep.join对列表的字段进行拼接all_path = os.sep.join(path)

    +

    add_sep_before进行判断,如果是True,就在前面添加拼接符all_path = os.sep + all_path

    +

    add_sep_after进行判断,如果是True,就在后面添加拼接符all_path = all_path + os.sep

    +

    windows格式拼接符有可能错误,就要对拼接符转换格式all_path = all_path.replace('\\', '/'),就算没有这个代码,也可以运行出来,只是调试该代码看起来不好看

    +

    然后返回all_path

    +
    def sep(path, add_sep_before=False, add_sep_after=False):
    """
    :param path: is list format:[Current directory , Current file]
    :param add_sep_before: Add before directory "/"
    :param add_sep_after: Add after directory "/"
    :return: Current directory/Current file
    """
    all_path = os.sep.join(path)
    # 在前面添加\
    if add_sep_before:
    all_path = os.sep + all_path
    # 在后面添加\
    if add_sep_after:
    all_path = all_path + os.sep
    # 转换格式 把\转换为/
    all_path = all_path.replace('\\', '/')
    return all_path
    +
    优化后的代码
    class GetConf:
    def __init__(self):
    with open(get_project_path()+sep(["config", "environment.yaml"], add_sep_before=True), "r", encoding="utf-8")\
    as env_file:
    self.env = yaml.load(env_file, Loader=yaml.FullLoader)
    print(self.env)

    def get_username_password(self):
    return self.env["username"], self.env["password"]
    +]]>
    + + 经验分享 + + + python + +
    + + 解析Excel用于数据驱动 + /2022/09/02/python/2022-09-02-%E8%A7%A3%E6%9E%90Excel%E7%94%A8%E4%BA%8E%E6%95%B0%E6%8D%AE%E9%A9%B1%E5%8A%A8/ + 新建Excel
    +

    创建Excel数据表:learn.xlsx

    +
    +
    + +
    + +

    解析excel

    +

    使用python的openpyxl模块来解析Excel

    +

    1、读取Excel文件

    openpyxl.load_workbook(‘文件路径’)

    excel = openpyxl.load_workbook('learn.xlsx')

    +

    2、获取sheet页里面的数据

    # 获取当前活动的表单
    sheet = excel.active
    # 获取指定的表单
    for sheets in excel.sheetnames: #获取所有表单的名称
    print(sheets)
    sheet = excel[sheets] #获取指定表单
    +

    3、获取单元格里面的内容

    for values in sheet.values:
    if type(value[0]) == int: #从第二行开始
    print(values)
    +

    运行代码:

    +
    +
    + +
    + +

    把Excel表里面的数据以字典格式展示:

    +
    data = {}
    data["name"] = values[0]
    data["value"] = values[1]
    print(data)
    +

    运行代码:

    +
    + +
    +]]>
    + + 经验分享 + + + python + +
    + + 解析ini文件用于数据驱动 + /2022/09/02/python/2022-09-21-python%E8%A7%A3%E6%9E%90ini%E6%96%87%E4%BB%B6/ + 背景
      +
    • PO设计模式是selenum自动化测试中比较好的设计模式
    • +
    • 在项目的开发过程中,UI界面上的元素不确定,会经常变化
    • +
    +

    过程解析

      +
    • 在PyCharm创建ini文件
    • +
    • 创建一个可以解析ini文件的python模块(parse_ini)
    • +
    • 其他模块引用parse_ini文件里面的方法把ini文件解析出来
    • +
    +

    创建ini文件

    image

    +

    创建parse_ini模块

    import configparser
    +
    +class Parse_Ini(object):
    +
    +    def __init__(self):
    +        self.file = r"D:\dingdang_project\test\config.ini"
    +        self.parse = configparser.ConfigParser()
    +        self.parse.read(self.file, encoding="utf-8")
    +
    +    def get_sections(self):
    +        """
    +        :return: 由sections组成的列表
    +        """
    +        return self.parse.sections()
    +
    +    def get_options(self, sections):
    +        """
    +        :return: 返回指定 section 中可用选项的列表。
    +        """
    +        return self.parse.options(sections)
    +
    +    def get_sections_options(self, sections, options):
    +        """
    +        :param sections: 元素名称
    +        :param options: 元素地址
    +        :return: 指定sections下的options
    +        """
    +        try:
    +            option = self.parse.get(sections, options)
    +            if ("-->" in option):
    +                option = tuple(option.split("-->"))
    +                return option
    +        except configparser.NoOptionError as e:
    +            return 'error: No option "{}" in section: "{}"'.format(options, sections)
    +
    +
    +if __name__ == "__init__":
    +    pass
    +

    举个栗子:

    栗子1

    image

    +
    运行结果:

    image

    +
    栗子2

    image

    +
    运行结果:

    image

    +]]>
    + + 经验分享 + + + python + +
    + + Shell脚本初探 + /2022/08/30/shell/2022-08-29-shell%E8%84%9A%E6%9C%AC%E5%88%9D%E6%8E%A2/ + 编写shell脚本时,必须以 #! /bin/bash 开头

    在linux创建helloworld.sh文件,在文件内输入:

    +
    #!/bin/bash
    #################
    echo "hello World"
    +

    然后保存该文件

    +

    运行.sh文件时,有两种方法可以运行

    +
    第一种是给该文件添加可执行权限
    chmod +x ./helloworld.sh
    +

    运行文件:./ 不能省略

    +
    ./helloworld.sh
    +
    第二种是使用bash或sh 文件路径运行该文件
    bash helloworld.sh
    #
    sh helloworld.sh
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell变量 + /2022/08/30/shell/2022-08-30-shell%E5%8F%98%E9%87%8F/ + shell变量分为系统变量和自定义变量,变量默认字符串类型
    系统变量

    $HOME 获取当前用户的家目录

    +

    $PWD 获取当前目录的路径

    +

    $SHELL 获取shell的执行引擎

    +

    $USER 获取当前用户的名称

    +
    自定义变量

    在linux系统中定义变量A=1,等号两边不能有空格,使用echo $A显示A的值

    +

    使用unset A命令,撤销变量

    +

    定义只读变量readonly b=3,使用echo $b显示b的值,不能unset

    +

    export命令进行设置全局变量,可以让其他shell命令进行使用

    +
    特殊变量:$n

    定义

    +

    n表示数字,范围是0~9,$0表示脚本名称,$1~9表示1~9个参数,10以上的参数要用花括号包裹,如${10}

    +

    运行apple.sh文件时可以传递参数

    +

    举个栗子

    +
    #!/bin/bash
    #
    echo "filename:" $0
    echo "filename_1:" $1
    echo "filename_2:" $2
    echo "filename_3:" $3
    echo "filename_4:" $4
    echo "filename_5:" $5
    +

    运行后传递参数bash apple.sh 001 002 test "test sss" "hsgd_dee"

    +
    特殊变量:$

    定义

    +

    获取所有输入参数的个数,常用于循环

    +

    举个栗子

    +
    #!/bin/bash
    #
    echo "filename:" $0
    echo "filename_1:" $1
    echo "filename_2:" $2
    echo "filename_3:" $3
    #
    echo $#
    +
    特殊变量:$#,$*

    定义

    +

    $*代表命令行中所有参数,把参数作为一个整体

    +

    $@代表命令行中所有参数,把参数区分对待

    +
    特殊变量:$?

    定义

    +

    最后一次命令的返回状态,如果返回变量的值为0,则表示最后一次命令执行正确,如果变量的值非0,则证明上一条变量返回不正确

    +

    举个栗子

    +
    [root@b09ed0cc2c9d opt]# $?
    bash: 0: command not found
    [root@b09ed0cc2c9d opt]# echo $?
    127
    [root@b09ed0cc2c9d opt]# echo $?
    0
    [root@b09ed0cc2c9d opt]#
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell脚本入门 + /2022/08/30/shell/2022-08-30-shell%E8%84%9A%E6%9C%AC%E5%85%A5%E9%97%A8/ + 创建txt文件并向txt文件追加数据

    首先创建test_shell.sh文件

    +
    touch test_shell.sh
    +

    test_shell.sh文件输入shell脚本

    +
      +
    • 使用shell创建banzhang.txt文件

      +
    • +
    • 在文件中追加数据echo "aabbccdd" >> banzhang.txt

      +
    • +
    +
    #!/bin/bash
    # 指定目录
    cd /opt/
    # 创建文件
    touch banzhang.txt
    # 向文件追加数据
    echo "touch banzhang" >> banzhang.txt
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell函数 + /2022/08/31/shell/2022-08-31-shell%E5%87%BD%E6%95%B0/ + 系统函数
    basename基本语法
    basename [string/ pathname][文件后缀] 
    +

    basename命令会删掉所有的前缀,只留一个文件名

    +

    选项:

    +

    如果指定后缀,basename会将pathname或string中的文件后缀去掉

    +
    举个栗子

    截取该/opt/banzhang.txt路径的文件名称

    +
    [root@b09ed0cc2c9d opt]# basename /opt/banzhang.txt
    banzhang.txt
    [root@b09ed0cc2c9d opt]# basename /opt/banzhang.txt .txt
    banzhang
    [root@b09ed0cc2c9d opt]#
    +
    dirname基本语法
    dirname 文件绝对路径
    +

    从给定的包含绝对路径的文件名中去除文件名(非目录的部分),然后返回剩下的路径(目录部分)

    +
    举个栗子
    [root@b09ed0cc2c9d opt]# dirname /opt/banzhang.txt
    /opt
    [root@b09ed0cc2c9d opt]#
    +
    自定义函数
    基本语法
    [function] funname[()]
    {
    Action;
    [retion int;]
    }

    funname
    +
    举个栗子
    #!/bin/bash

    function sum()
    {
    s=0;
    s=$[$1+$2]
    echo $s
    }

    read -p "input your paratemer1:" p1
    read -p "input your oaeayemer2:" p2

    sum $p1 $p2
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell工具(一) + /2022/08/31/shell/2022-08-31-shell%E5%B7%A5%E5%85%B7%EF%BC%88%E4%B8%80%EF%BC%89/ + Cut工具
    +

    用于剪切数据

    +
    +
    基本用法

    cut[选项参数] filename

    +

    说明:默认分隔符是制表符

    +
    + + + + + + + + + + + + + + + + + +
    选项参数功能
    -f列号,提取第几列
    -d分隔符,按照指定分隔符分割列
    +
    +
    举个栗子

    准备数据

    +
    [root@b09ed0cc2c9d local]# touch cut.txt
    [root@b09ed0cc2c9d local]# vim cut.txt

    dong shen
    guan zhen
    wo wo
    lai lai
    le le
    +

    切割第一列数据

    +
    [root@b09ed0cc2c9d local]# cut -d " " -f 1 cut.txt
    dong
    guan
    wo
    lai
    le
    +

    切割第二,三列

    +
    [root@b09ed0cc2c9d local]# cut -d " " -f 2,3 cut.txt
    shen
    zhen
    wo
    lai
    le
    +

    在cut.txt文件切割出guan

    +
    [root@b09ed0cc2c9d local]# cat cut.txt
    dong shen
    guan zhen
    wo wo
    lai lai
    le le
    [root@b09ed0cc2c9d local]#
    [root@b09ed0cc2c9d local]# cat cut.txt | grep guan
    guan zhen
    [root@b09ed0cc2c9d local]# cat cut.txt | grep guan | cut -d " " -f 1
    guan
    [root@b09ed0cc2c9d local]#
    +

    选取系统PATH变量值,第二个“:”之后的所有路径

    +
    [root@b09ed0cc2c9d local]# echo $PATH
    /usr/local/java/jdk1.8.0_181/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    [root@b09ed0cc2c9d local]# echo $PATH | cut -d : -f 3- # 不加-表示第三列,加上-表示第三列之后
    /usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    +

    切割ifconfig后打印的IP地址

    +
    [root@b09ed0cc2c9d local]# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 172.17.0.2 netmask 255.255.0.0 broadcast 0.0.0.0
    inet6 fe80::42:acff:fe11:2 prefixlen 64 scopeid 0x20<link>
    ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
    RX packets 8 bytes 656 (656.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 8 bytes 656 (656.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    [root@b09ed0cc2c9d local]# ifconfig eth0 | grep "inet " | cut -d "t" -f 2 | cut -d " " -f 2
    172.17.0.2
    [root@b09ed0cc2c9d local]#
    +
    sed工具
    +

    一种流编辑器,一次处理一行内容

    +
    +
    基本用法

    sed [选项参数] command filename

    +

    选项参数说明

    +
    + + + + + + + + + + + + + +
    选项参数功能
    -a直接在指定列模式上进行sed的动作编辑
    +
    +

    命令功能描述

    +
    + + + + + + + + + + + + + + + + + + + + + +
    命令功能描述
    a新增,a的后面可以接字串,在下一行出现
    d删除
    s查找并替换
    +
    +
    举个栗子

    数据准备

    +
    [root@b09ed0cc2c9d opt]# touch sed.txt
    [root@b09ed0cc2c9d opt]# vim sed.txt

    dong shen
    guan zhen
    wo wo
    lai lai

    le le
    +

    将mei nv 这个单词插入到 sed.txt 第二行下,打印

    +
    [root@b09ed0cc2c9d opt]# sed "2a mei nv" sed.txt
    dong shen
    guan zhen
    mei nv
    wo wo
    lai lai

    le le
    [root@b09ed0cc2c9d opt]#
    +

    删除sed.txt文件所有包含 wo 的行

    +
    [root@b09ed0cc2c9d opt]# sed "/wo/d" sed.txt
    dong shen
    guan zhen
    lai lai

    le le
    [root@b09ed0cc2c9d opt]#
    +

    将sed.txt文件中 wo 替换为 ni

    +
    [root@b09ed0cc2c9d opt]# sed "s/wo/ni/g" sed.txt
    dong shen
    guan zhen
    ni ni
    lai lai

    le le
    [root@b09ed0cc2c9d opt]#
    +注意:g表示global,全部替换 + +

    将sed.txt文件中的第二行删除并将wo替换成ni

    +
    [root@b09ed0cc2c9d opt]# sed -e "2d" -e "s/wo/ni/g" sed.txt
    dong shen
    ni ni
    lai lai

    le le
    [root@b09ed0cc2c9d opt]#
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell条件判断 + /2022/08/31/shell/2022-08-31-shell%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD/ + 基本语法

    [ condition ] (注意,condition 前后要有空格

    +

    注意:条件非空即为 true,[ atguigu ]返回 true, [] 返回 false.

    +
    常用条件判断
    两个整数之间进行比较
    = 字符串比较
    -lt 小于
    -le 小于等于
    -eq 等于
    -gt 大于
    -ge 大于等于
    -ne 不等于
    +

    举个栗子

    +
    [23 -lt 80]
    echo $? # 判断上一步操作是不是正确
    +
    按照文件权限进行判断
    -r 读
    -w 写
    -x 执行
    +

    举个栗子

    +
    [ -w 1.sh ]
    echo $?
    +
    文件类型判断
    -f 文件存在且是一个常规文件
    -e 文件存在
    -d 文件存在且是一个目录
    +

    举个栗子

    +
    [ -e 2.sh ]
    echo $?
    +
    多条件判断

    $$$$ 与 ,前对,才执行后

    +

    ||

    +]]>
    + + 经验分享 + + + shell + +
    + + Shell流程控制 + /2022/08/31/shell/2022-08-31-shell%E6%B5%81%E7%A8%8B%E6%8E%A7%E5%88%B6/ + if判断
    基本语法
      +
    • [ 条件判断式 ],中括号和条件判断式之间必须有空格

      +
    • +
    • if后要有空格

      +
    • +
    +
    if [ 条件判断式 ]:then
    程序
    fi
    #或者
    if[ 条件判断式 ]
    then
    程序
    fi
    +
    举个栗子

    输入一个数字,如果是1,则输出 banzhang zhen shuai,如果是2,则输出 cls zhen mei ,如果是其他,则什么都不输出

    +
    #!/bin/bash
    if [ $1 -eq 1 ]
    then
    echo "banzhang zhen shuai"
    elif [ $1 -eq 2 ]
    then
    echo "cls zhen mei"
    fi
    +
    case 语句
    基本语法
      +
    • case行尾必须是单词 “in”,每一个模式匹配必须以右括号 “)” 结束
    • +
    • 双分号 “;;” 表示命令序列结束,相当于java的break
    • +
    • 最后的 “*)” 表示默认模式,相当于java的default
    • +
    +
    case $变量名 in  
    "值 1")
    如果变量的值等于1,执行程序1
    ;;
    "值 2")
    如果变量的值等于2,执行程序2
    ;;
    *)
    如果变量的值不是以上的值,则执行此程序
    esac
    +
    举个栗子

    输入一个数字,如果是 1,则输出 banzhang,如果是 2,则输出 cls,如果是其他,输出 renyao

    +
    #!/bin/bash
    case $1 in
    "1")
    echo "banzhang"
    ;;

    "2")
    echo "cls"
    ;;

    *)
    echo "renyou"
    esac
    +
    For循环
    基本语法1
    for(( 初始值;循环控制添加;变量变化 ))
    do
    程序
    done
    +
    举个栗子1

    输出从1加到100的值

    +
    #!/bin/bash

    s=0
    for ((i=1;i<=100;i++))
    do
    s=$[$s+$i]
    done
    echo "cong1jiadao100:$s"
    +
    基本语法2
    for 变量 in 值1 值2 值3...
    do
    程序
    done
    +
    举个栗子2

    打印所有输入参数

    +
    #!/bin/bash

    for i in "$*"
    do
    echo "banzhang xihuan $i"
    done
    #-----------------------------------
    for j in "$@"
    do
    echo "banzhang xihuan $j"
    done
    +
    while 循环
    基本语法
    while[ 条件判断式 ]
    do
    程序
    done
    +
    举个栗子

    输出从1加到100的值

    +
    #!/bin/bash

    i=1
    while [ $i -le 100 ]
    do
    s=$[$s + $i]
    i=$[$i + 1]
    done

    echo $s
    +
    read 读取控制台输入
    基本语法
    read(选项)(参数)
    选项:
    -p:指定读取值时的提示符
    -t:指定读取值时的等待的时间(秒)
    参数:
    变量:指定读取值的变量名
    +
    举个栗子

    提示7秒内,读取控制台输入的名称

    +
    #!/bin/bash

    read -t 7 -p "input your name" NAME

    echo $NAME
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell运算符 + /2022/08/31/shell/2022-08-31-shell%E8%BF%90%E7%AE%97%E7%AC%A6/ + 基本语法
      +
    1. $((运算式)) 或 $[运算式]
    2. +
    3. expr + - * /
    4. +
    +注意,运算符号间要有空格 + +
    举个加法栗子
    expr 3 + 2
    5
    +
    举栗子[(2+3)*4]

    需要使用键盘左上角的`,把需要提前运算的包起来

    +
    expr `expr 2 + 3` \* 4
    +

    或者

    +
    s=$[(2+3)*4]
    echo $s
    +]]>
    + + 经验分享 + + + shell + +
    + + Shell工具(二) + /2022/08/31/shell/2022-09-01-shell%E5%B7%A5%E5%85%B7%EF%BC%88%E4%BA%8C%EF%BC%89/ + awk工具
    +

    强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行分析处理。

    +
    +

    awk [选项参数] ‘pattern1{action1}’ filename

    +
      +
    • pattern:表示awk在数据中查找的内容
    • +
    • action:找到匹配内容时执行命令
    • +
    +
    + + + + + + + + + + + + + + + + + +
    选项参数功能
    -F指定输入文件分隔符
    -v赋值一个用户定义变量
    +
    +
    举个栗子

    数据准备的是/etc/passwd

    +
    [root@b09ed0cc2c9d opt]# cat passwd
    root:x:0:0:root:/root:/bin/bash
    bin:x:1:1:bin:/bin:/sbin/nologin
    daemon:x:2:2:daemon:/sbin:/sbin/nologin
    adm:x:3:4:adm:/var/adm:/sbin/nologin
    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
    sync:x:5:0:sync:/sbin:/bin/sync
    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
    halt:x:7:0:halt:/sbin:/sbin/halt
    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
    operator:x:11:0:operator:/root:/sbin/nologin
    games:x:12:100:games:/usr/games:/sbin/nologin
    ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
    nobody:x:99:99:Nobody:/:/sbin/nologin
    systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
    dbus:x:81:81:System message bus:/:/sbin/nologin
    +

    搜素passwd文件以root关键字开头的所有航,并输出该行的第7列

    +
    [root@b09ed0cc2c9d opt]# awk -F : '/^root/{print $7}' passwd
    /bin/bash
    [root@b09ed0cc2c9d opt]#
    +

    搜素passwd文件以root关键字开头的所有航,并输出该行的第1列和第7列,输出时以逗号分隔

    +
    [root@b09ed0cc2c9d opt]# awk -F : '/^root/{print $1","$7}' passwd
    root,/bin/bash
    +

    只显示/etc/passwd的第一列和第7列,以逗号分隔,且在所有航前面添加列名 user,shell在最后一行添加 ddd, /bin/zuishuai

    +
    [root@b09ed0cc2c9d opt]# awk -F : 'BEGIN{print "user,shell"} {print $1","$7} END{print "ddd,bin/zuishuai"}' passwd
    +注意:BEGIN 在所有数据读取行之前执行; END 在所有数据执行之后执行 + +

    将passwd 文件中的用户id增加数值1并输出

    +
    [root@b09ed0cc2c9d opt]# awk -F : -v i=1 '{print $3+i}' passwd
    +
    内置变量
    + + + + + + + + + + + + + + + + + + + + + +
    变量说明
    filename文件名
    nr已读的记录数
    nf浏览记录的域的个数
    +
    +
    举个栗子

    数据准备

    +
    [root@b09ed0cc2c9d opt]# cat sed.txt
    dong shen
    guan zhen
    wo wo
    lai lai

    le le
    +

    统计passwd文件名,每行的行号,每列的列数

    +
    [root@b09ed0cc2c9d opt]# awk -F : '{print FILENAME "," NR "," NF}' passwd
    +

    打印空行所在的行号

    +
    awk '/^$/ {print NR}' sed.txt
    +
    sort工具
    +

    文件排序

    +
    +

    sort(选项)(参数)

    +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    选项说明
    -n按照数值大小排序
    -r以相反的顺序排序
    -t设置排序使用的分隔字符
    -k指定需要排序的列
    +
    +

    参数是指定待排序文件列表

    +]]>
    + + 经验分享 + + + shell + +
    + + 开发时遇到端口冲突解决办法 + /2022/10/21/springboot/2022-10-21-%E5%BC%80%E5%8F%91%E6%97%B6%E9%81%87%E5%88%B0%E7%AB%AF%E5%8F%A3%E5%86%B2%E7%AA%81%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95/ + 解决办法

    resources下面新建文件application.properties,名称不能变,只能是这个,运行时系统会自动获取这个端口数据

    +

    在里面输入代码数据

    +
    server.port=${port:8888}
    +]]>
    + + 经验分享 + + + SpringBoot + +
    + + 接口开发环境部署 + /2022/10/21/springboot/2022-10-21-%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83%E9%83%A8%E7%BD%B2/ + 开发环境
      +
    • IDEA
    • +
    • Maven
    • +
    • Spring Boot
    • +
    • JDK_86001
    • +
    +

    在idea安装SpringBoot插件

    在maven下安装插件,需要在pox.xml文件输入下面的数据,然后更新文件


    <properties>
    <maven.compiler.source>8</maven.compiler.source>
    <maven.compiler.target>8</maven.compiler.target>
    <springboot.version>2.5.6</springboot.version>
    <swagger.version>2.9.2</swagger.version>
    </properties>

    <dependencies>
    <!-- springboot 2.5.6 -->
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>${springboot.version}</version>
    <type>pom</type>
    </dependency>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>${springboot.version}</version>
    </dependency>
    </dependencies>


    上面的${springboot.version}是在上面里面定义的版本信息,如果多个插件的版本一致就可以在属性上进行定义,然后使用变量进行引用

    +]]>
    + + 经验分享 + + + SpringBoot + +
    + + 返回cookie的Get接口开发 + /2022/10/21/springboot/2022-10-21-%E8%BF%94%E5%9B%9Ecookie%E7%9A%84Get%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91/ + 位置布局
    - java
    - com.course.server
    - intertype
    MyGetMethod
    Application
    - resources
    - application.properties
    +

    Application 类

    创建Application.java类,用来运行接口,类名只能是Application,不能自定义

    +
    @SpringBootApplication
    @Controller("com.course.server.intertype")
    public class Application {

    public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
    }
    }
    +
      +
    • @SpringBootApplication 作用是给当前类标明是运行的主类,相当于被SpringBoot托管了
    • +
    • @Controller("com.course.server.intertype") 钩子标识符,扫描包下面的类,被Springboot托管
    • +
    +

    编写Get接口

    创建MyGetMethod

    +

    类名上有修饰符@RestController@Api(value = "/")

    +
      +
    • @RestController 标识该类会被扫描到,然后被SpringBoot托管
    • +
    • @Api(value = "/") 可加可不加
    • +
    • @RequestMapping(value = "访问路径", method = 访问方法) 定义接口的访问路径及访问方法
    • +
    • @ApiOperation(value = "接口信息", httpMethod = "接口的请求方法") 展示接口的基本信息和它的请求方法,可加可不加
    • +
    +

    下面是代码信息,之后的所有GET接口都在该类里面写接口方法

    +
    @RestController
    @Api(value = "/", tags = {SwaggerConfig.TagGet} )
    public class MyGetMethod {

    @RequestMapping(value = "/getCookies", method = RequestMethod.GET)
    @ApiOperation(value = "通过这个方法可以获得cookies", httpMethod = "GET")
    public String getCookies(HttpServletResponse response){

    // HttpServerletRequest 装请求信息类
    // HttpServerletResponse 装响应信息类

    Cookie cookie = new Cookie("login", "True");

    response.addCookie(cookie);

    return "恭喜获得cookies信息成功";
    }
    }
    +

    上面就是返回cookie的get接口开发,接下来就是 需要携带cookies信息才能访问的get请求

    +]]>
    + + 经验分享 + + + SpringBoot + +
    + + 需要cookie访问的Get接口开发 + /2022/10/21/springboot/2022-10-21-%E9%9C%80%E8%A6%81cookie%E8%AE%BF%E9%97%AE%E7%9A%84Get%E6%8E%A5%E5%8F%A3%E5%BC%80%E5%8F%91/ + 编写需要cookie才能访问的接口

    这个接口还是在MyGetMethod类里面编写方法

    +
    /**
    * 要求客户端携带cookie访问
    * 这是一个需要携带cookies信息才能访问的get请求
    */
    @RequestMapping(value = "/get/with/cookies", method = RequestMethod.GET)
    @ApiOperation(value = "要求客户端携带cookie访问", httpMethod = "GET")
    public String getWithCookies(HttpServletRequest request){
    Cookie[] cookies = request.getCookies();
    if(Objects.isNull(cookies)){
    return "你必须携带cookies信息来";
    }
    for(Cookie cookie : cookies){
    if(cookie.getName().equals("login") && cookie.getValue().equals("True")){
    return "恭喜你,访问成功!,这是一个需要携带cookies信息才能访问的get请求";
    }
    }
    return "你必须携带cookies信息来";
    }
    ]]>
    + + 经验分享 + + + SpringBoot + +
    + + 需要参数才能访问的get请求 + /2022/10/21/springboot/2022-10-21-%E9%9C%80%E8%A6%81%E5%8F%82%E6%95%B0%E6%89%8D%E8%83%BD%E8%AE%BF%E9%97%AE%E7%9A%84get%E8%AF%B7%E6%B1%82/ + 编写需要参数才能访问的get请求

    使用参数就要用到@RequestParam 参数类型 参数变量,可以有多个参数

    +

    这个接口还是在MyGetMethod类里面编写方法,有两种方法

    +

    第一种url:key=value&&key=value

    +
    /**
    * 开发一个需要参数才能访问的get请求
    * 模拟获取商品列表
    */
    @RequestMapping(value = "/get/with/param", method = RequestMethod.GET)
    @ApiOperation(value = "需要参数才能访问的get请求的第一种实现方法", httpMethod = "GET")
    public Map<String, Integer> getList(@RequestParam Integer start,
    @RequestParam Integer end){

    Map<String, Integer> myList = new HashMap<>();

    myList.put("鞋",400);
    myList.put("电脑",5000);
    myList.put("手机",3500);

    return myList;

    }
    +

    方法二url: ip:port/get/with/param/10/20

    +

    /**
    * 第二种需要携带参数访问的get请求
    */

    @RequestMapping(value = "/get/with/param/{start}/{end}", method = RequestMethod.GET)
    @ApiOperation(value = "需要参数才能访问的get请求的第二种实现方法", httpMethod = "GET")
    public Map<String,Integer> myGetList(@PathVariable Integer start,
    @PathVariable Integer end){

    Map<String, Integer> myList = new HashMap<>();

    myList.put("鞋",400);
    myList.put("电脑",5000);
    myList.put("手机",3500);

    return myList;
    }
    +]]>
    + + 经验分享 + + + SpringBoot + +
    + + 开发获取用户列表的Post接口 + /2022/10/22/springboot/2022-10-22-%E5%BC%80%E5%8F%91%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%88%97%E8%A1%A8%E7%9A%84post%E8%AF%B7%E6%B1%82/ + 开发获取用户列表的post请求

    开发添加人员信息时需要的字段数据

    首先,写一个User类,这将是添加时的字段数据

    +
    @Data
    public class User {
    private String userName;
    private String password;
    private String name;
    private String age;
    private String sex;
    }
    +

    然后开始写怎么获取用户列表,相当于添加用户

    @RequestBody User u请求post接口时,在Body填写上传的数据

    +
    @RequestMapping(value = "/getUserList", method = RequestMethod.POST)
    @ApiOperation(value = "获取用户列表", httpMethod = "POST")
    public String getUserList(HttpServletRequest request,
    @RequestBody User u){
    User user;
    // 获取cookies
    Cookie[] cookies= request.getCookies();
    // 验证cookies是否合法
    for(Cookie c:cookies){
    if (c.getName().equals("login")
    && c.getValue().equals("true")
    && u.getUserName().equals("zhangsan")
    && u.getPassword().equals("123456")){
    user = new User();
    user.setName("lisi");
    user.setAge("18");
    user.setSex("man");
    return user.toString();
    }
    }
    return "参数不合法";
    }
    ]]>
    + + 经验分享 + + + SpringBoot + +
    + + 开发获得cookie的Post登录接口 + /2022/10/22/springboot/2022-10-22-%E5%BC%80%E5%8F%91%E8%8E%B7%E5%BE%97cookie%E7%9A%84Post%E7%99%BB%E5%BD%95%E6%8E%A5%E5%8F%A3/ + 开发获得cookie的Post登录接口

    @RequestMapping(value = "/v1")的作用是把这个value和方法上的登录地址进行拼接,比如:/v1/login

    +

    @RestController标识该接口可以被托管

    +

    方法参数@RequestParam(value = "userName", required = true) String userName,代码中的required = true起到必填的作用

    +

    举个栗子

    @RestController
    @Api(value = "/", tags = {SwaggerConfig.TagPost})
    @RequestMapping(value = "/v1")
    public class MyPostMethod {

    //这个变量用来装cookie信息的
    private static Cookie cookie;

    //用户登录成功获取到cookies,然后访问其他接口获取到列表
    @RequestMapping(value = "/login",method = RequestMethod.POST)
    @ApiOperation(value = "登录接口,成功后获取到cookies信息",httpMethod = "POST")
    public String login(HttpServletResponse response,
    @RequestParam(value = "userName", required = true) String userName,
    @RequestParam(value = "password", required = true) String password){
    if (userName.equals("zhangsan") && password.equals("123456")){
    cookie = new Cookie("login","true");
    response.addCookie(cookie);
    return "恭喜你登录成功!";
    }
    return "用户名或密码错误!";

    }
    ]]>
    + + 经验分享 + + + SpringBoot + +
    + + 2023立的flag + /2023/09/11/%E7%9B%AE%E6%A0%87&%E4%BC%98%E5%8C%96/2023%E7%9B%AE%E6%A0%87/ + 目前所拥有的进度
      +
    • 考研恋练有词必背词全部背锅一边

      +
    • +
    • 自动化测试已部署

      +
    • +
    • +
    • +
    +]]>
    + + 生活日常 + + + 目标&优化 + +
    + + Arrivals Thread Group的使用 + /2022/11/30/jmeter/jmeter_plugins/2022-12-07-Arrivals%20Thread%20Group%E7%9A%84%E4%BD%BF%E7%94%A8/ + 前提
      +
    • 安装插件,下载Custom Thread Groupsan插件

      +
    • +
    • 添加Arrivals Thread Group

      +
    • +
    +

    配置

      +
    • Target Rate (arrivals/sec) : 相当于QPS, 输入10就是10QPS
    • +
    • Ramp Up Time (sec) : 在多少秒内达到最大的QPS,4代表在4秒内获得最大的QPS
    • +
    • Ramp-Up Steps Count : 代表并发数,4代表实现4次的并发
    • +
    • Hold Target Rate Time (sec) : 对系统压多长时间就输入多长时间 ,10代表压上10s
    • +
    • Concurrency Limit : 最大启动多少线程,100代表最多启动100线程
    • +
    +
    + +
    ]]>
    + + 工具教程 + + + jmeter + +
    + + Ultimate Thread Group的使用 + /2022/11/30/jmeter/jmeter_plugins/2022-12-07-Ultimate%20Thread%20Group%E7%9A%84%E4%BD%BF%E7%94%A8/ + 前提
      +
    • 安装插件,下载Custom Thread Groupsan插件

      +
    • +
    • 添加Ultimate Thread Group

      +
    • +
    +

    配置

      +
    • Start Threads Count : 线程数
    • +
    • Initial Delay,sec : 线程延迟启动,0指的是立即启动;5代表五秒后启动
    • +
    • Startup Time,sec : 线程及时启动,0代表立即启动,5代表五秒之内启动完成
    • +
    • Hold Load For,sec : 启动后运行的时间,120代表运行120秒
    • +
    • Shutdown Time : 代表运行结束后停止的时间,0代表运行结束后立即停止,5代表运行结束后五秒内停止
    • +
    +
    + +
    +]]>
    + + 工具教程 + + + jmeter + +
    +
    diff --git a/self/css/bolang.css b/self/css/bolang.css new file mode 100644 index 000000000..cb4c910b5 --- /dev/null +++ b/self/css/bolang.css @@ -0,0 +1,74 @@ +/* 波浪css */ +.main-hero-waves-area { + width: 100%; + position: absolute; + left: 0; + bottom: -11px; + z-index: 5; + } + .waves-area .waves-svg { + width: 100%; + height: 5rem; + } + /* Animation */ + + .parallax > use { + animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite; + } + .parallax > use:nth-child(1) { + animation-delay: -2s; + animation-duration: 7s; + fill: #f7f9febd; + } + .parallax > use:nth-child(2) { + animation-delay: -3s; + animation-duration: 10s; + fill: #f7f9fe82; + } + .parallax > use:nth-child(3) { + animation-delay: -4s; + animation-duration: 13s; + fill: #f7f9fe36; + } + .parallax > use:nth-child(4) { + animation-delay: -5s; + animation-duration: 20s; + fill: #f7f9fe; + } + /* 黑色模式背景 */ + [data-theme="dark"] .parallax > use:nth-child(1) { + animation-delay: -2s; + animation-duration: 7s; + fill: #18171dc8; + } + [data-theme="dark"] .parallax > use:nth-child(2) { + animation-delay: -3s; + animation-duration: 10s; + fill: #18171d80; + } + [data-theme="dark"] .parallax > use:nth-child(3) { + animation-delay: -4s; + animation-duration: 13s; + fill: #18171d3e; + } + [data-theme="dark"] .parallax > use:nth-child(4) { + animation-delay: -5s; + animation-duration: 20s; + fill: #18171d; + } + + @keyframes move-forever { + 0% { + transform: translate3d(-90px, 0, 0); + } + 100% { + transform: translate3d(85px, 0, 0); + } + } + /*Shrinking for mobile*/ + @media (max-width: 768px) { + .waves-area .waves-svg { + height: 40px; + min-height: 40px; + } + } \ No newline at end of file diff --git a/self/css/daohanglanjuzhong.css b/self/css/daohanglanjuzhong.css new file mode 100644 index 000000000..5ee551cd1 --- /dev/null +++ b/self/css/daohanglanjuzhong.css @@ -0,0 +1,134 @@ +#nav-right{ + flex:1 1 auto; + justify-content: flex-end; + margin-left: auto; + display: flex; + flex-wrap:nowrap; +} +/* 菜单栏居中 */ + +#blog-info a:hover { + background: var(--icat-blue); + transition: background .3s; + border-radius: 8px; +} +#blog-info a:hover .site-name { + color: var(--icat-blue) !important; + position: relative; + text-shadow: 0 0 transparent; +} +#blog-info a:hover .site-name:after { + position: absolute; + display: flex; + top: 0; + width: 100%; + height: 100%; + content: "\e03a"; + font-family: "iconfont" !important; + font-size: 22px; + line-height: 1; + color: var(--icat-white); + justify-content: center; + align-items: center; +} +@media screen and (max-width: 768px) { + #blog-info a:hover { + background: 0; + transition: unset; + border-radius: 0; + } + #blog-info a:hover .site-name { + color: var(--icat-blue) !important; + position: relative; + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + } + #blog-info a:hover .site-name:after { + display: none; + } +} +/* 主页按钮 */ + +#nav.show { + display: flex; + justify-content: center; +} +#nav .site-page { + padding-bottom: 14px; +} +#page-header.not-top-img #nav { + display: flex; + justify-content: center; + border-bottom: 1px solid var(--icat-secondbg); +} +#nav-group { + width: 1400px; + display: flex; + align-items: center; + padding: 0 0.6rem; + margin-left: auto; + margin-right: auto; +} +/* 顶部栏宽度定义 */ + +#nav .menus_items .menus_item .menus_item_child, #nav .menus_items .icat_menus_item .menus_item_child { + margin-top: 14px; + border: 1px solid var(--icat-secondbg); +} +#nav .menus_items .menus_item .menus_item_child li a, #nav .menus_items .icat_menus_item .menus_item_child li a { + padding: 8px 34px; + text-align: center; +} +#travellings { + padding: 0 14px 0 0; +} + +/* PC菜单栏美化 */ + + +#nav #menus { + display: flex; + justify-content: center; + width: 100%; + position: absolute; + left: 0; + margin: 0; + transform: translateZ(0); +} +#nav #blog-info { + flex-wrap: nowrap; + display: flex; + align-items: center; + z-index: 102; + max-width: fit-content; +} +@media screen and (max-width: 900px) { + #nav { + padding: 0 15px; + } + #nav-group { + padding: 0 0.2rem; + } + #rightside { + right: -42px; + } +} +/* IPAD菜单栏调整 */ + + + +/* 子菜单横向显示 */ +.menus_item_child li:not(#sidebar-menus li){ + float: left; + border-radius: 6px!important; + -webkit-border-radius: 6px!important; + -moz-border-radius: 6px!important; + -ms-border-radius: 6px!important; + -o-border-radius: 6px!important; +} +.menus_item_child:not(#sidebar-menus ul){ + /* + left:calc(-150%)!important;这是估算值,为了保持元素居中的,如果不合适可以自己调 + 改为:*/ + left:50%; + translate:-50%; +} diff --git a/self/css/font.css b/self/css/font.css new file mode 100644 index 000000000..51b62720b --- /dev/null +++ b/self/css/font.css @@ -0,0 +1,9 @@ +@font-face{ + font-family: 'FangZhengKaiTi-GBK-1'; + font-display: swap; + src: url('/self/font/FangZhengKaiTi-GBK-1.ttf') format("truetype"); +} +/* quanzikuzhengkaiti */ +body { + font-family: 'FangZhengKaiTi-GBK-1'; +} \ No newline at end of file diff --git a/self/css/iconfont.css b/self/css/iconfont.css new file mode 100644 index 000000000..d98a85af0 --- /dev/null +++ b/self/css/iconfont.css @@ -0,0 +1,57 @@ + + +@font-face { + font-family: "iconfont"; /* Project id 3498204 */ + src: url('iconfont.woff2?t=1659311976990') format('woff2'), + url('iconfont.woff?t=1659311976990') format('woff'), + url('iconfont.ttf?t=1659311976990') format('truetype'); +} + +.iconfont { + font-family: "iconfont" !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.icon-danmu:before { + content: "\e612"; +} + +.icon-biaoqian:before { + content: "\e63d"; +} + +.icon-fenlei:before { + content: "\e601"; +} + +.icon-fanti:before { + content: "\e6d8"; +} + +.icon-baidu:before { + content: "\e60a"; +} + +.icon-csdn:before { + content: "\e600"; +} + +.icon-RSS:before { + content: "\e78a"; +} + +.icon-bilibili:before { + content: "\e609"; +} + +.icon-gitee:before { + content: "\e60c"; +} + +.icon-zhihu:before { + content: "\e60d"; +} + diff --git a/self/css/mouse.css b/self/css/mouse.css new file mode 100644 index 000000000..fff29059c --- /dev/null +++ b/self/css/mouse.css @@ -0,0 +1,10 @@ +body { + cursor:url(https://cdn.jsdelivr.net/gh/sviptzk/HexoStaticFile@latest/Hexo/img/default.cur), + default; + } + a, + img { + cursor:url(https://cdn.jsdelivr.net/gh/sviptzk/HexoStaticFile@latest/Hexo/img/pointer.cur), + default; + } + \ No newline at end of file diff --git a/self/css/paiban.css b/self/css/paiban.css new file mode 100644 index 000000000..8d22c2ea9 --- /dev/null +++ b/self/css/paiban.css @@ -0,0 +1,31 @@ +/* 宽屏适配 */ +.layout{ + max-width:1400px; +} + + +/* 修改边栏卡片大小 */ +#archive,#page,#category,#tag{ + width:100%; +} +.page:not(.page.home) .aside-content{ + display: none; +} + +/* 根据屏幕大小自适应显示边栏框 */ +@media screen and (max-width: 900px){ + .aside-content{ + max-width:none!important; + } +} + + +/* 友链一行增加多个栏目 */ +.flink-list-item{ + width:calc(100% / 4 - 15px)!important; +} +@media screen and (max-width: 1250px) { + .flink-list-item{ + width:calc(100% / 3 - 15px)!important; + } +} \ No newline at end of file diff --git a/self/css/qu_lanchangtiao.css b/self/css/qu_lanchangtiao.css new file mode 100644 index 000000000..54deecbcf --- /dev/null +++ b/self/css/qu_lanchangtiao.css @@ -0,0 +1,34 @@ +/* 去除导航栏选项中底下的蓝条 */ +#nav *::after{ + background-color: transparent!important; +} + +/* 导航栏菜单鼠标移入字体放大 */ +#nav #site-name:hover, +#nav .menus_item:hover, +#nav #search-button:hover{ + font-size:28px; +} + +/* 导航栏常驻 */ +.nav-fixed #nav{ + transform: translateY(58px)!important; + -webkit-transform: translateY(58px)!important; + -moz-transform: translateY(58px)!important; + -ms-transform: translateY(58px)!important; + -o-transform: translateY(58px)!important; +} +#nav{ + transition: none!important; + -webkit-transition: none!important; + -moz-transition: none!important; + -ms-transition: none!important; + -o-transition: none!important; +} + +/*顶栏美化*/ +#nav .site-page { + font-size: 0.79em; /*字体大小*/ + letter-spacing: 3px; /*字体间距*/ + font-weight: 600; /*字体粗细*/ + } \ No newline at end of file diff --git a/self/css/rightMenu.css b/self/css/rightMenu.css new file mode 100644 index 000000000..8e571eeb8 --- /dev/null +++ b/self/css/rightMenu.css @@ -0,0 +1,199 @@ +/* #rightMenu { + display: none; + position: fixed; + padding: 0 .25rem; + width: 9rem; + height: fit-content; + top: 10%; + left: 10%; + background-color: rgba(238, 255, 255, .85); + -webkit-backdrop-filter: blur(20px); + backdrop-filter: blur(20px); + color: #363636; + border-radius: 12px; + z-index: 99994; + border: #e3e8f7; + user-select: none; + box-shadow: rgba(0, 0, 0, .05); +} + +#rightMenu a { + color: #363636; +} + +#rightMenu .rightMenu-group { + padding: .35rem .3rem; + transition: .3s +} + +#rightMenu .rightMenu-line { + border-top: 1px dashed #4259ef23 +} + +#rightMenu .rightMenu-group.rightMenu-small { + display: flex; + justify-content: space-between +} + +#rightMenu .rightMenu-group .rightMenu-item { + border-radius: 8px; + transition: .3s; + cursor: pointer +} + +#rightMenu .rightMenu-line .rightMenu-item { + margin: .25rem 0; + padding: .25rem 0 +} + +#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item { + display: flex +} + +#rightMenu .rightMenu-group .rightMenu-item:hover { + background-color: #6f42c1; + color: #fff; +} + +#rightMenu .rightMenu-group .rightMenu-item:active { + transform: scale(.97) +} + +#rightMenu .rightMenu-group .rightMenu-item i { + display: inline-block; + text-align: center; + line-height: 1.5rem; + width: 1.5rem; + padding: 0 .25rem +} + +#rightMenu .rightMenu-line .rightMenu-item i { + margin: 0 .25rem +} + +#rightMenu .rightMenu-group .rightMenu-item span { + line-height: 1.5rem +} + +.rightMenu-small .rightMenu-item { + width: 30px; + height: 30px; + line-height: 30px +} + +#rightmenu-mask { + position: fixed; + width: 100vw; + height: 100vh; + background: 0 0; + top: 0; + left: 0; + display: none; + z-index: 101; + margin: 0 !important; + z-index: 99993 +} + */ + +/* rightMenu */ +[data-theme='light'] #rightMenu{ + display: none; + position: fixed; + width: 160px; + height: fit-content; + top: 10%; + left: 10%; + background-color: var(--card-bg); + border: 1px solid rgb(210,210,210);; + border-radius: 8px; + z-index: 100; + box-shadow: 3px 3px 5px #88888894; + background-color: var(--lyx-white-acrylic1); + backdrop-filter: blur(30px); +} +[data-theme='dark'] #rightMenu{ + display: none; + position: fixed; + width: 160px; + height: fit-content; + top: 10%; + left: 10%; + background-color: var(--card-bg); + border: 1px solid rgb(210,210,210);; + border-radius: 8px; + z-index: 100; + box-shadow: 3px 3px 5px #88888894; + background-color: var(--lyx-black-acrylic1); + backdrop-filter: blur(30px); +} +#rightMenu .rightMenu-group{ + padding: 7px 6px; +} +#rightMenu .rightMenu-group:not(:nth-last-child(1)){ + border-bottom: 1px solid rgb(180,180,180); +} +#rightMenu .rightMenu-group.rightMenu-small{ + display: flex; + justify-content: space-between; +} +#rightMenu .rightMenu-group .rightMenu-item{ + height: 30px; + line-height: 30px; + border-radius: 8px; + transition: 0.3s; + color: var(--font-color); +} +#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item{ + display: flex; + height: 40px; + line-height: 40px; + padding: 0 4px; +} +#rightMenu .rightMenu-group .rightMenu-item:hover{ + background-color: var(--text-bg-hover); + box-shadow: 0px 0px 5px var(--lyx-border); +} +#rightMenu .rightMenu-group .rightMenu-item i{ + display: inline-block; + text-align: center; + line-height: 30px; + width: 30px; + height: 30px; + padding: 0 5px; +} +#rightMenu .rightMenu-group .rightMenu-item span{ + line-height: 30px; +} +#rightMenu:hover{ + border: 1px solid var(--lyx-blue); + /* box-shadow:0 0 3px var(--lyx-blue)!important; */ +} +#rightMenu .rightMenu-group.rightMenu-line .rightMenu-item *{ + height: 40px; + line-height: 40px; +} +.rightMenu-group.hide{ + display: none; +} +.rightMenu-item:hover{ + color:white!important; + background-color:var(--lyx-blue)!important; +} +:root{ + --lyx-border:#c9c9c9; + --lyx-blue:#6cf; + --lyx-gray:#e2e2e2; + --lyx-theme:#6cf; + --lyx-green:#39c5bb; + --lyx-black-acrylic1: #0008; + --lyx-black-acrylic2: #000a; + --lyx-black-acrylic3:#00000099; + --lyx-black:black; + --lyx-white:white; + --lyx-white-acrylic1:#fffd; + --lyx-white-acrylic2:#fffa; + --lyx-blackgray:#797979; + --lyx-0:#0000; + --lyx-scrollbar: #acacacDD; +} + diff --git a/self/css/shuanglan.css b/self/css/shuanglan.css new file mode 100644 index 000000000..76ec8a9a8 --- /dev/null +++ b/self/css/shuanglan.css @@ -0,0 +1,60 @@ +/* 首页卡片适配 */ +@media screen and (min-width: 1200px) { + #recent-posts{ + /* margin-top:-1rem; 头部为空时抵消间隔,若有磁贴或日历请注释掉该行 */ + align-content:flex-start; + display: flex; + flex-wrap: wrap; /*规定灵活的项目在必要的时候拆行或拆列。*/ + justify-content: space-between; /*。*/ + } + #recent-posts > .recent-post-item { + /*max-height:324px;*/ /*文章容器最大高度*/ + margin-top: 1rem; /*最小间距*/ + display: inline-block; + height:auto; /*高度自动*/ + width:49%;/*文章容器容器宽度*/ + } + #recent-posts > .recent-post-item .post_cover { + width: 100%; /*图片封面宽度*/ + height: 200px;/*图片封面高度*/ + } + #recent-posts > .recent-post-item .post_cover img.post_bg { + width: 100%;/*图片宽度*/ + height: 100%;/*图片高度*/ + } + #recent-posts > .recent-post-item { + + -webkit-flex-direction: column; /*容器内部纵向排列*/ + -ms-flex-direction: column; /*容器内部纵向排列*/ + flex-direction: column; /*容器内部纵向排列*/ + + } + #recent-posts > .recent-post-item .left_radius { + border-radius: 8px 8px 0 0;/*圆角修改*/ + } + #recent-posts > .recent-post-item .right_radius { + border-radius: 8px 8px 0 0;/*圆角修改*/ + } + .recent-post-item{ + height:auto !important;/*容器高度自动*/ + } + + .recent-post-info { + + padding: 0 40px;/*容器内部文字左右间距*/ + margin-top: 1em;/*容器内部文字上间距*/ + width: 100%!important;/*容器宽度*/ + } + #recent-posts > .recent-post-item > .recent-post-info > .article-title { + -webkit-line-clamp: 1;/*控制标题的行数*/ + margin-top: 0.3rem; /*控制标题的上间距*/ + margin-bottom: 0.3rem;/*控制标题的下间距*/ + font-size: 1.2em; /*控制标题的字体大小*/ + line-height: 1.4;/*控制标题的行高*/ + + } + #recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap { + margin-bottom: 1rem;/*控制标题meta信息的底部间距*/ + } +} + diff --git a/self/font/FangZhengKaiTi-GBK-1.ttf b/self/font/FangZhengKaiTi-GBK-1.ttf new file mode 100644 index 000000000..1079aa029 Binary files /dev/null and b/self/font/FangZhengKaiTi-GBK-1.ttf differ diff --git a/self/font/FangZhengKaiTi.ttf b/self/font/FangZhengKaiTi.ttf new file mode 100644 index 000000000..1079aa029 Binary files /dev/null and b/self/font/FangZhengKaiTi.ttf differ diff --git a/self/font/quanzikuzhengkaiti.ttf b/self/font/quanzikuzhengkaiti.ttf new file mode 100644 index 000000000..4967f3b45 Binary files /dev/null and b/self/font/quanzikuzhengkaiti.ttf differ diff --git a/self/js/foot.js b/self/js/foot.js new file mode 100644 index 000000000..7e1f20a94 --- /dev/null +++ b/self/js/foot.js @@ -0,0 +1,28 @@ +// 动态心跳,更改自己的名称 +$(document).ready(function(e){ + $('.copyright').html('路漫漫其修远兮 吾将上下而求索'); +}) + +$(document).ready(function(e){ + show_date_time(); +}) + +//本站运行时间 +function show_date_time(){ +$('.framework-info').html('本站已运行'); +window.setTimeout("show_date_time()", 1000); +BirthDay=new Date("9/21/2023 0:0:0"); +today=new Date(); +timeold=(today.getTime()-BirthDay.getTime()); +sectimeold=timeold/1000 +secondsold=Math.floor(sectimeold); +msPerDay=24*60*60*1000 +e_daysold=timeold/msPerDay +daysold=Math.floor(e_daysold); +e_hrsold=(e_daysold-daysold)*24; +hrsold=Math.floor(e_hrsold); +e_minsold=(e_hrsold-hrsold)*60; +minsold=Math.floor((e_hrsold-hrsold)*60); +seconds=Math.floor((e_minsold-minsold)*60); +span_dt_dt.innerHTML=''+daysold+''+hrsold+''+minsold+''+seconds+' 秒'; +} \ No newline at end of file diff --git a/self/js/jquery.js b/self/js/jquery.js new file mode 100644 index 000000000..9b1731997 --- /dev/null +++ b/self/js/jquery.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,y=n.hasOwnProperty,a=y.toString,l=a.call(Object),v={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.1",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&v(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!y||!y.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ve(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ye(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ve(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],y=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||y.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||y.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||y.push(".#.+[+~]"),e.querySelectorAll("\\\f"),y.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),y=y.length&&new RegExp(y.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),v=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&v(p,e)?-1:t==C||t.ownerDocument==p&&v(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!y||!y.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),v.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",v.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",v.option=!!ce.lastChild;var ge={thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Ut,Xt=[],Vt=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Xt.pop()||S.expando+"_"+Ct.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Vt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Vt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Vt,"$1"+r):!1!==e.jsonp&&(e.url+=(Et.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Xt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),v.createHTMLDocument=((Ut=E.implementation.createHTMLDocument("").body).innerHTML="
    ",2===Ut.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(v.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return B(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=_e(v.pixelPosition,function(e,t){if(t)return t=Be(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return B(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0 0) { + myField.scrollTop = restoreTop; + } + + myField.focus(); + myField.selectionStart = startPos + myValue.length; + myField.selectionEnd = startPos + myValue.length; + } else { + myField.value += myValue; + myField.focus(); + } +} +let rmf = {}; +rmf.showRightMenu = function (isTrue, x = 0, y = 0) { + let $rightMenu = $('#rightMenu'); + $rightMenu.css('top', x + 'px').css('left', y + 'px'); + + if (isTrue) { + $rightMenu.show(); + } else { + $rightMenu.hide(); + } +} +rmf.switchDarkMode = function () { + const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + if (nowMode === 'light') { + activateDarkMode() + saveToLocal.set('theme', 'dark', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) + } else { + activateLightMode() + saveToLocal.set('theme', 'light', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) + } + // handle some cases + typeof utterancesTheme === 'function' && utterancesTheme() + typeof FB === 'object' && window.loadFBComment() + window.DISQUS && document.getElementById('disqus_thread').children.length && setTimeout(() => window.disqusReset(), 200) +}; +rmf.yinyong=function(){ + var e = document.getElementsByClassName("el-textarea__inner")[0], + t = document.createEvent("HTMLEvents"); + t.initEvent("input", !0, !0), e.value = d.value = "> "+getSelection().toString()+"\n\n", e.dispatchEvent(t); + console.log(getSelection().toString()); + document.getElementsByClassName("el-textarea__inner")[0].value="> "+getSelection().toString()+"\n\n"; + Snackbar.show({ + text: '为保证最佳评论阅读体验,建议不要删除空行', + pos: 'top-center', + showAction: false, + }) +} +rmf.copyWordsLink = function () { + let url = window.location.href + let txa = document.createElement("textarea"); + txa.value = url; + document.body.appendChild(txa) + txa.select(); + document.execCommand("Copy"); + document.body.removeChild(txa); + Snackbar.show({ + text: '链接复制成功!快去分享吧!', + pos: 'top-right', + showAction: false + }); +} +rmf.switchReadMode = function () { + const $body = document.body + $body.classList.add('read-mode') + const newEle = document.createElement('button') + newEle.type = 'button' + newEle.className = 'fas fa-sign-out-alt exit-readmode' + $body.appendChild(newEle) + + function clickFn() { + $body.classList.remove('read-mode') + newEle.remove() + newEle.removeEventListener('click', clickFn) + } + + newEle.addEventListener('click', clickFn) +} + +//复制选中文字 +rmf.copySelect = function () { + document.execCommand('Copy', false, null); + //这里可以写点东西提示一下 已复制 +} + +//回到顶部 +rmf.scrollToTop = function () { + document.getElementsByClassName("menus_items")[1].setAttribute("style",""); + document.getElementById("name-container").setAttribute("style","display:none"); + btf.scrollToDest(0, 500); +} +rmf.translate = function () { + document.getElementById("translateLink").click(); +} +rmf.searchinThisPage=()=>{ + document.body.removeChild(mask); + document.getElementsByClassName("local-search-box--input")[0].value=window.getSelection().toString() + document.getElementsByClassName("search")[0].click() + var evt = document.createEvent("HTMLEvents");evt.initEvent("input", false, false);document.getElementsByClassName("local-search-box--input")[0].dispatchEvent(evt); +} +document.body.addEventListener('touchmove', function(e){ + +}, { passive: false }); +function popupMenu() { + //window.oncontextmenu=function(){return false;} + window.oncontextmenu = function (event) { + if(event.ctrlKey||document.body.clientWidth<900) return true; + $('.rightMenu-group.hide').hide(); + if (document.getSelection().toString()) { + $('#menu-text').show(); + } + if (document.getElementById('post')) { + $('#menu-post').show(); + } else { + if (document.getElementById('page')) { + $('#menu-post').show(); + } + } + var el = window.document.body; + el = event.target; + var a=/^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\*\+,;=.]+$/ + if (a.test(window.getSelection().toString())&&el.tagName!="A"){ + $('#menu-too').show() + } + if (el.tagName == 'A') { + $('#menu-to').show() + rmf.open = function () { + if(el.href.indexOf("http://")==-1&&el.href.indexOf("https://")==-1||el.href.indexOf("yisous.xyz")!=-1){ + pjax.loadUrl(el.href) + } + else{ + location.href = el.href + } + } + rmf.openWithNewTab = function () { + window.open(el.href); + // window.location.reload(); + } + rmf.copyLink = function () { + let url = el.href + let txa = document.createElement("textarea"); + txa.value = url; + document.body.appendChild(txa) + txa.select(); + document.execCommand("Copy"); + document.body.removeChild(txa); + } + } + if (el.tagName == 'IMG') { + $('#menu-img').show() + rmf.openWithNewTab = function () { + window.open(el.src); + // window.location.reload(); + } + rmf.click = function () { + el.click() + } + rmf.copyLink = function () { + let url = el.src + let txa = document.createElement("textarea"); + txa.value = url; + document.body.appendChild(txa) + txa.select(); + document.execCommand("Copy"); + document.body.removeChild(txa); + } + rmf.saveAs=function(){ + var a = document.createElement('a'); + var url = el.src; + var filename = url.split("/")[-1]; + a.href = url; + a.download = filename; + a.click(); + window.URL.revokeObjectURL(url); + } + } else if (el.tagName == "TEXTAREA" || el.tagName == "INPUT") { + $('#menu-paste').show(); + // rmf.paste=function(){ + // input.addEventListener('paste', async event => { + // event.preventDefault(); + // const text = await navigator.clipboard.readText(); + // el.value+=text; + // }); + // } + rmf.paste = function () { + navigator.permissions + .query({ + name: 'clipboard-read' + }) + .then(result => { + if (result.state == 'granted' || result.state == 'prompt') { + //读取剪贴板 + navigator.clipboard.readText().then(text => { + console.log(text) + insertAtCursor(el, text) + }) + } else { + Snackbar.show({ + text: '请允许读取剪贴板!', + pos: 'top-center', + showAction: false, + }) + } + }) + } + } + let pageX = event.clientX + 10; + let pageY = event.clientY; + let rmWidth = $('#rightMenu').width(); + let rmHeight = $('#rightMenu').height(); + if (pageX + rmWidth > window.innerWidth) { + pageX -= rmWidth + 10; + } + if (pageY + rmHeight > window.innerHeight) { + pageY -= pageY + rmHeight - window.innerHeight; + } + mask=setMask(); + window.onscroll=()=>{ + rmf.showRightMenu(false); + window.onscroll=()=>{} + document.body.removeChild(mask); + } + $(".rightMenu-item").click(()=>{ + document.body.removeChild(mask); + }) + $(window).resize(()=>{ + rmf.showRightMenu(false); + document.body.removeChild(mask); + }) + mask.onclick=()=>{ + document.body.removeChild(mask); + } + rmf.showRightMenu(true, pageY, pageX); + return false; + }; + + window.addEventListener('click', function () { + rmf.showRightMenu(false); + }); +} +if (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) { + popupMenu() +} +const box = document.documentElement + +function addLongtabListener(target, callback) { + let timer = 0 // 初始化timer + + target.ontouchstart = () => { + timer = 0 // 重置timer + timer = setTimeout(() => { + callback(); + timer = 0 + }, 380) // 超时器能成功执行,说明是长按 + } + + target.ontouchmove = () => { + clearTimeout(timer) // 如果来到这里,说明是滑动 + timer = 0 + } + + target.ontouchend = () => { // 到这里如果timer有值,说明此触摸时间不足380ms,是点击 + if (timer) { + clearTimeout(timer) + } + } +} + +addLongtabListener(box, popupMenu) \ No newline at end of file diff --git a/self/js/snow.js b/self/js/snow.js new file mode 100644 index 000000000..d258682ad --- /dev/null +++ b/self/js/snow.js @@ -0,0 +1,151 @@ +var stop, staticx; +var img = new Image(); +img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUgAAAEwCAYAAADVZeifAAAACXBIWXMAAACYAAAAmAGiyIKYAAAHG2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4gPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPiA8cmRmOlJERiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiPiA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIiB4bWxuczp4bXBSaWdodHM9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9yaWdodHMvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iIHhtcFJpZ2h0czpNYXJrZWQ9IkZhbHNlIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6NDFDMjQxQjYyNjIwNjgxMTgwODNEMjE2MDAzOTU1NDQiIHhtcE1NOkRvY3VtZW50SUQ9ImFkb2JlOmRvY2lkOnBob3Rvc2hvcDozNDVjOWViOC04NDc4LTFkNDctOGRjMi0yZDkyOGNhYTYxZWQiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6YjAzN2ZiMGItNTU5Mi0xYjRkLWJjZGQtOWU4NGExMDJiMGM2IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAoV2luZG93cykiIHhtcDpDcmVhdGVEYXRlPSIyMDE4LTA1LTA5VDE0OjQ5OjM3KzA4OjAwIiB4bXA6TW9kaWZ5RGF0ZT0iMjAxOC0wNS0wOVQxNDo1MToyNSswODowMCIgeG1wOk1ldGFkYXRhRGF0ZT0iMjAxOC0wNS0wOVQxNDo1MToyNSswODowMCIgZGM6Zm9ybWF0PSJpbWFnZS9wbmciIHBob3Rvc2hvcDpDb2xvck1vZGU9IjMiIHBob3Rvc2hvcDpJQ0NQcm9maWxlPSJzUkdCIElFQzYxOTY2LTIuMSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjEyMjVlZWE3LTEyY2QtMTY0NC04ZDAzLWFjOTE2ZTAxZDQ1YyIgc3RSZWY6ZG9jdW1lbnRJRD0idXVpZDoxRDIwNUFGNjZCRDlFNTExOUM5REMwMzg2RjlEQjFGNyIvPiA8eG1wTU06SGlzdG9yeT4gPHJkZjpTZXE+IDxyZGY6bGkgc3RFdnQ6YWN0aW9uPSJzYXZlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDphYmMzNjIzMy1hOWNkLWNiNDQtODViYi0zZTgyMjEwYmIxMjYiIHN0RXZ0OndoZW49IjIwMTgtMDUtMDlUMTQ6NTE6MjUrMDg6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChXaW5kb3dzKSIgc3RFdnQ6Y2hhbmdlZD0iLyIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6YjAzN2ZiMGItNTU5Mi0xYjRkLWJjZGQtOWU4NGExMDJiMGM2IiBzdEV2dDp3aGVuPSIyMDE4LTA1LTA5VDE0OjUxOjI1KzA4OjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPC9yZGY6U2Vx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"; + +function Sakura(x, y, s, r, fn) { + this.x = x; + this.y = y; + this.s = s; + this.r = r; + this.fn = fn; +} +Sakura.prototype.draw = function (cxt) { + cxt.save(); + var xc = 40 * this.s / 4; + cxt.translate(this.x, this.y); + cxt.rotate(this.r); + cxt.drawImage(img, 0, 0, 40 * this.s, 40 * this.s) + cxt.restore(); +} +Sakura.prototype.update = function () { + this.x = this.fn.x(this.x, this.y); + this.y = this.fn.y(this.y, this.y); + this.r = this.fn.r(this.r); + if (this.x > window.innerWidth || this.x < 0 || this.y > window.innerHeight || this.y < 0) { + this.r = getRandom('fnr'); + if (Math.random() > 0.4) { + this.x = getRandom('x'); + this.y = 0; + this.s = getRandom('s'); + this.r = getRandom('r'); + } else { + this.x = window.innerWidth; + this.y = getRandom('y'); + this.s = getRandom('s'); + this.r = getRandom('r'); + } + } +} +SakuraList = function () { + this.list = []; +} +SakuraList.prototype.push = function (sakura) { + this.list.push(sakura); +} +SakuraList.prototype.update = function () { + for (var i = 0, len = this.list.length; i < len; i++) { + this.list[i].update(); + } +} +SakuraList.prototype.draw = function (cxt) { + for (var i = 0, len = this.list.length; i < len; i++) { + this.list[i].draw(cxt); + } +} +SakuraList.prototype.get = function (i) { + return this.list[i]; +} +SakuraList.prototype.size = function () { + return this.list.length; +} + +function getRandom(option) { + var ret, random; + switch (option) { + case 'x': + ret = Math.random() * window.innerWidth; + break; + case 'y': + ret = Math.random() * window.innerHeight; + break; + case 's': + ret = Math.random(); + break; + case 'r': + ret = Math.random() * 6; + break; + case 'fnx': + random = -0.5 + Math.random() * 1; + ret = function (x, y) { + return x + 0.5 * random - 1.7; + }; + break; + case 'fny': + random = 1.5 + Math.random() * 0.7 + ret = function (x, y) { + return y + random; + }; + break; + case 'fnr': + random = Math.random() * 0.03; + ret = function (r) { + return r + random; + }; + break; + } + return ret; +} + +function startSakura() { + requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame; + var canvas = document.createElement('canvas'), + cxt; + staticx = true; + canvas.height = window.innerHeight; + canvas.width = window.innerWidth; + canvas.setAttribute('style', 'position: fixed;left: 0;top: 0;pointer-events: none;'); + canvas.setAttribute('id', 'canvas_sakura'); + document.getElementsByTagName('body')[0].appendChild(canvas); + cxt = canvas.getContext('2d'); + var sakuraList = new SakuraList(); + for (var i = 0; i < 50; i++) { + var sakura, randomX, randomY, randomS, randomR, randomFnx, randomFny; + randomX = getRandom('x'); + randomY = getRandom('y'); + randomR = getRandom('r'); + randomS = getRandom('s'); + randomFnx = getRandom('fnx'); + randomFny = getRandom('fny'); + randomFnR = getRandom('fnr'); + sakura = new Sakura(randomX, randomY, randomS, randomR, { + x: randomFnx, + y: randomFny, + r: randomFnR + }); + sakura.draw(cxt); + sakuraList.push(sakura); + } + stop = requestAnimationFrame(function () { + cxt.clearRect(0, 0, canvas.width, canvas.height); + sakuraList.update(); + sakuraList.draw(cxt); + stop = requestAnimationFrame(arguments.callee); + }) +} +window.onresize = function () { + var canvasSnow = document.getElementById('canvas_snow'); +} +img.onload = function () { + startSakura(); +} + +function stopp() { + if (staticx) { + var child = document.getElementById("canvas_sakura"); + child.parentNode.removeChild(child); + window.cancelAnimationFrame(stop); + staticx = false; + } else { + startSakura(); + } +} diff --git a/tags/English/index.html b/tags/English/index.html new file mode 100644 index 000000000..79a7a08a5 --- /dev/null +++ b/tags/English/index.html @@ -0,0 +1,171 @@ +标签: English | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/Git/index.html b/tags/Git/index.html new file mode 100644 index 000000000..3667f8fb6 --- /dev/null +++ b/tags/Git/index.html @@ -0,0 +1,171 @@ +标签: Git | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/Properties/index.html b/tags/Properties/index.html new file mode 100644 index 000000000..eb95cefcc --- /dev/null +++ b/tags/Properties/index.html @@ -0,0 +1,171 @@ +标签: Properties | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/SpringBoot/index.html b/tags/SpringBoot/index.html new file mode 100644 index 000000000..9f4f2f6d1 --- /dev/null +++ b/tags/SpringBoot/index.html @@ -0,0 +1,171 @@ +标签: SpringBoot | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/docker/index.html b/tags/docker/index.html new file mode 100644 index 000000000..b666de74f --- /dev/null +++ b/tags/docker/index.html @@ -0,0 +1,171 @@ +标签: docker | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/docker/page/2/index.html b/tags/docker/page/2/index.html new file mode 100644 index 000000000..e6415b349 --- /dev/null +++ b/tags/docker/page/2/index.html @@ -0,0 +1,171 @@ +标签: docker | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/docker/page/3/index.html b/tags/docker/page/3/index.html new file mode 100644 index 000000000..2c7bae71f --- /dev/null +++ b/tags/docker/page/3/index.html @@ -0,0 +1,171 @@ +标签: docker | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/error/index.html b/tags/error/index.html new file mode 100644 index 000000000..bd4804e7e --- /dev/null +++ b/tags/error/index.html @@ -0,0 +1,171 @@ +标签: error | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 000000000..ae45626f4 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,173 @@ +标签 | Research • 呓语 + + + + + + + + + +
    \ No newline at end of file diff --git a/tags/java/index.html b/tags/java/index.html new file mode 100644 index 000000000..4e879df03 --- /dev/null +++ b/tags/java/index.html @@ -0,0 +1,171 @@ +标签: java | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/java/page/2/index.html b/tags/java/page/2/index.html new file mode 100644 index 000000000..d5ba417dd --- /dev/null +++ b/tags/java/page/2/index.html @@ -0,0 +1,171 @@ +标签: java | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/jmeter/index.html b/tags/jmeter/index.html new file mode 100644 index 000000000..2e464d908 --- /dev/null +++ b/tags/jmeter/index.html @@ -0,0 +1,171 @@ +标签: jmeter | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/jmeter/page/2/index.html b/tags/jmeter/page/2/index.html new file mode 100644 index 000000000..051741cb7 --- /dev/null +++ b/tags/jmeter/page/2/index.html @@ -0,0 +1,171 @@ +标签: jmeter | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/postman/index.html b/tags/postman/index.html new file mode 100644 index 000000000..abade53f9 --- /dev/null +++ b/tags/postman/index.html @@ -0,0 +1,171 @@ +标签: postman | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/python/index.html b/tags/python/index.html new file mode 100644 index 000000000..f9dda2bc3 --- /dev/null +++ b/tags/python/index.html @@ -0,0 +1,171 @@ +标签: python | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/shell/index.html b/tags/shell/index.html new file mode 100644 index 000000000..7dfaa87ef --- /dev/null +++ b/tags/shell/index.html @@ -0,0 +1,171 @@ +标签: shell | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/sql/index.html b/tags/sql/index.html new file mode 100644 index 000000000..7d9d3eaf2 --- /dev/null +++ b/tags/sql/index.html @@ -0,0 +1,171 @@ +标签: sql | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/ubuntu/index.html b/tags/ubuntu/index.html new file mode 100644 index 000000000..58c5a3403 --- /dev/null +++ b/tags/ubuntu/index.html @@ -0,0 +1,171 @@ +标签: ubuntu | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/xpath/index.html b/tags/xpath/index.html new file mode 100644 index 000000000..f0ca29eda --- /dev/null +++ b/tags/xpath/index.html @@ -0,0 +1,171 @@ +标签: xpath | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git a/tags/yaml/index.html b/tags/yaml/index.html new file mode 100644 index 000000000..ae7e882b0 --- /dev/null +++ b/tags/yaml/index.html @@ -0,0 +1,171 @@ +标签: yaml | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\346\200\247\350\203\275\346\265\213\350\257\225/index.html" "b/tags/\346\200\247\350\203\275\346\265\213\350\257\225/index.html" new file mode 100644 index 000000000..24fd92331 --- /dev/null +++ "b/tags/\346\200\247\350\203\275\346\265\213\350\257\225/index.html" @@ -0,0 +1,171 @@ +标签: 性能测试 | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\347\233\221\346\216\247/index.html" "b/tags/\347\233\221\346\216\247/index.html" new file mode 100644 index 000000000..734841857 --- /dev/null +++ "b/tags/\347\233\221\346\216\247/index.html" @@ -0,0 +1,171 @@ +标签: 监控 | Research • 呓语 + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\347\233\256\346\240\207-\344\274\230\345\214\226/index.html" "b/tags/\347\233\256\346\240\207-\344\274\230\345\214\226/index.html" new file mode 100644 index 000000000..7ad9b62b6 --- /dev/null +++ "b/tags/\347\233\256\346\240\207-\344\274\230\345\214\226/index.html" @@ -0,0 +1,171 @@ +标签: 目标&优化 | Research • 呓语 + + + + + + + +
    \ No newline at end of file