├── README.md ├── Python ├── 技巧 │ ├── 字符串格式化填充 format f-string.md │ ├── 优雅的打印嵌套类型的数据.md │ ├── 终端进度条.md │ ├── 从 String 中提取 bytes.md │ └── namedtuple 和 dataclass 定义简单功能类.md ├── 包库 │ ├── list.md │ ├── schedule 定时器.md │ ├── Requests 使用.md │ └── psycopg.md ├── 知识点 │ ├── 海象运算符.md │ ├── Python 可迭代解包.md │ └── Python 3.8 仅位置参数.md ├── 基础 │ └── Python3 其他.md ├── 知识点.md ├── 方法函数 │ ├── 字符串方法.md │ ├── 数学方法.md │ └── range.md ├── 虚拟环境 │ └── Python 虚拟环境中使用 Git.md ├── Python 内置模块 — hashlib.md ├── 安装 │ └── Python pip.md ├── 装饰器 │ ├── dataclass.md │ └── lru_cache.md └── Python 3 新特性.md ├── 杂项 ├── vc_git.icns ├── Sublime Text.icns ├── markdown img.alfredworkflow ├── Sublime Text-predawn-dark-round-icon.icns ├── Postman │ ├── Postman Variables 变量.md │ └── Postman Response.md ├── Sublime Text │ ├── Sublime Text 更换图标.md │ ├── Sublime Text 3 常用插件.md │ └── Sublime Text 3 配置.md ├── 微信 │ ├── 微信开发.md │ └── 微信小程序.md ├── Chrome │ └── Chrome 地址栏快捷搜索.md ├── 钉钉 │ └── 钉钉网页分享设置.md ├── Markdown │ └── Markdown 高级用法.md ├── localhost 与 127.0.0.1 原理简介.md └── MQ 消息队列的优劣势.md ├── 计算机与网络 ├── 乱码探源.pdf ├── 计算机是如何做加法的.pdf ├── 深入图解字符集与字符集编码.pdf ├── 理解 inode - 阮一峰的网络日志.pdf └── 二进制原码与补码.md ├── Git ├── git-cheatsheet.pdf ├── 命令 │ ├── show.md │ ├── restore.md │ ├── switch.md │ └── revert.md ├── 技巧 │ ├── Git 选择部分修改作为提交.md │ ├── Git 查看、比对其他分支中的文件.md │ ├── Git 回滚远程版本并删除提交日志.md │ ├── Git 从其他分支合并个别文件或文件夹.md │ ├── Git 仓库瘦身.md │ └── Git 从仓库中永久删除文件或目录.md ├── 杂项 │ └── GitHub 问题.md ├── 配置 │ └── Git 设置 commit 默认模板.md └── Git 父提交.md ├── Linux ├── 杂项 - 临时.md ├── 杂项 │ ├── RPM.md │ ├── 关闭“您在 :var:spool:mail:root 中有新邮件”提示.md │ ├── 阿里云 ECS 常用文档.md │ └── Linux alias 支持参数.md ├── 设置 │ └── 设置时间.md ├── IO │ └── * 磁盘命令.md ├── CentOS │ ├── Centos 修改环境变量 PATH.md │ ├── CentOS 常用安全设置.md │ ├── CentOS 更新 wget.md │ ├── CentOS 8 安装 PHP 7.4.md │ ├── CentOS user 用户操作.md │ └── CentOS 安装中文字体.md ├── Command │ ├── su sudo.md │ ├── tail.md │ ├── rsync.md │ ├── wc.md │ └── grep.md ├── 符号 │ └── Linux &.md ├── Service │ ├── Memcached.md │ └── firewall.md ├── Shell │ ├── Shell 脚本中切换用户.md │ ├── Shell 获取当前正在执行脚本的绝对路径.md │ └── Linux Shell $* 和 $@ 的区别.md └── 网络 │ └── 连接不存在的 IP 地址或端口的处理.md ├── Mac ├── 问题 │ ├── Mac 软连接.md │ ├── Mac 使用代理后出现 502.md │ ├── Mac 10.12+ 允许任何来源的 APP.md │ ├── Mac zsh scp 命令使用 * 通配符无法匹配.md │ ├── Mac OS X 系统更新后提示 xcrun error.md │ └── Mac Brew.md ├── 应用 │ ├── Mac Visual Studio Code.md │ └── Redis Desktop Manager.md ├── 杂项 │ ├── macOS Mojave 深色和浅色模式混合.md │ ├── Mac Chrome 将非官方扩展程序加入白名单.md │ └── Mac 百度云加速下载.md └── SSH │ └── SCP 通过 ssh 拷贝本地文件到远程服务器.md ├── Go ├── Go Reflect.md ├── 问题 │ ├── Go 问题集锦.md │ ├── Go 不定参数的默认值.md │ └── Go 值为 nil 能调用函数吗.md ├── 杂项 │ ├── Go 工具链.md │ └── Go 杂项.md ├── 知识点 │ └── Go 基本特性.md ├── Go 内置函数.md ├── packages │ ├── Go bufio.md │ ├── Go fmt.md │ └── encoding │ │ └── json │ │ └── Go JSON.md ├── 数据类型 │ ├── Go Array.md │ └── struct │ │ └── Go struct 特例 - DoNotCompare.md └── 工具调试 │ └── Go test 禁用缓存.md ├── Vagrant ├── 使用 Vagrant 打造跨平台开发环境.pdf └── Vagrant 常用命令.md ├── CSS ├── demo │ └── CSS 秘密花园 - 交互式图像对比 │ │ ├── 11.jpg │ │ └── 22.jpg ├── Bugs │ └── Safari overflow hidden 在 border-radius 和 transform 时无效.md ├── 知识点 │ └── CSS margin 的计算方式.md ├── CSS 效果片段 - 移动端.md ├── 小技巧 │ └── CSS flex 布局中 text-overflow 无效.md ├── 属性 │ ├── cursor.md │ └── user-select.md └── CSS 效果片段 - 动画.md ├── JavaScript ├── 杂项 │ ├── JavaScript-prototype.png │ └── jQuery 笔记.md ├── 知识点 │ └── JavaScript 大于等于的判断.md ├── Node │ ├── NPM │ │ └── NPM 报错 chmod.md │ ├── Node Express 知识点记录.md │ └── Yarn.md ├── Vue │ ├── 相关 │ │ └── 杂项笔记.md │ ├── Vue 自定义过滤器.md │ ├── Vue-router.md │ └── vue-cli │ │ ├── vue-cli 3 静态资源部署到 CDN.md │ │ └── Vue-cli 问题.md ├── 小技巧 │ ├── JavaScript ~ 按位取反的使用.md │ ├── JavaScript String hash.md │ ├── JavaScript 阻止浏览器后退.md │ ├── ES6 尾调用优化.md │ ├── JavaScript Debouncing 防抖动.md │ ├── JavaScript 使用 HTML5 Blob 实现文本信息文件下载.md │ ├── ES6 通过参数默认值强制传参.md │ └── JavaScript 快速排序算法.md ├── 问题 │ ├── JavaScript Math.min() 为什么比 Math.max() 大.md │ ├── Babel 相关.md │ ├── try...catch...finally 语句中 return 的问题.md │ ├── JavaScript 0.._ 为什么等于 undefined.md │ └── JavaScript (a == 1 && a == 2 && a == 3) 可能为 true 吗?.md ├── DOM │ └── Table 表格 DOM.md ├── 事件 │ └── @JavaScript Event Loop.md ├── 实例 │ ├── JavaScript 实现质数算法.md │ ├── JavaScript 移动端判断横屏还是竖屏.md │ └── JavaScript 获取文件扩展名.md ├── 内置对象 │ └── JavaScript Boolean.md └── 原生方法 │ └── encodeURI:decodeURI:encodeURIComponent:decodeURIComponent.md ├── Web ├── 技巧 │ └── 使用 gif 打点的好处.md ├── 浏览器渲染过程.md ├── Cookie.md ├── HTML │ ├── HTML 音标注释标记 ruby:rt:rp.md │ ├── HTML a 元素打开新窗口或刷新已打开窗口.md │ └── HTML 知识点.md ├── FireFox 浏览器内置的网页截屏功能.md └── Unicode 字符在 HTML、CSS、JavaScript 中的不同处理.md ├── PHP ├── Homestead │ └── Homestead 服务使用.md ├── Lumen │ ├── Lumen 自定义配置文件.md │ ├── Lumen 路由参数.md │ ├── Lumen 问题笔记.md │ └── Lumen 缓存 Redis.md ├── 杂项 │ ├── Guzzle.md │ └── 编译安装 PHP 7.1 pdo_mysql 扩展.md ├── Laravel │ ├── 实用技巧 │ │ ├── Laravel Eloquent 多对对关联 按中间表字段排序.md │ │ └── Laravel 5.6 生产环境优化.md │ ├── 功能 │ │ └── Laravel Policy.md │ ├── Laravel Fluent 注释.md │ ├── Laravel 学习笔记(零)杂项.md │ ├── 问题 │ │ └── Laravel 数据库返回的整型数据被转换成了字符串类型.md │ ├── Laravel 杂项知识点.md │ ├── src │ │ └── Container │ │ │ └── train.php │ └── Laravel env.md ├── ThinkPHP │ ├── ThinkPHP 5 自动验证.md │ ├── ThinkPHP 禁用某个页面的缓存.md │ └── ThinkPHP 自动验证 多字段验证bug.md ├── 问题 │ ├── imagejpeg 函数输出图片是一个红叉.md │ ├── PHP 无法开启 session.md │ ├── PHP 循环时引用的问题.md │ ├── PHP strtotime 的一些计算问题.md │ ├── PHP Windows 生成文本文件乱码.md │ └── PHP 文件上传问题.md ├── Swoole │ └── Swoole 常用方法.md ├── 实用技巧 │ ├── 隐藏 PHP 信息.md │ ├── PHP 替换换行符.md │ ├── PHP 数组去重的几种方式.md │ ├── PHP 输出 a 到 z 之间的字符.md │ ├── PHP 较准确校验邮箱地址是否存在.md │ ├── PHP 实现 linux tail -f 效果.php │ ├── PHP 下载远程图片.md │ ├── 不使用 mb 系列函数分隔字符串.md │ └── PHP 文件操作.md ├── 知识点 │ ├── PHP 中 unset 和 array_splice 删除数组元素的区别.md │ ├── SCRIPT_FILENAME 与 __FILE__ 的区别.md │ └── PHP 权限笔记.md ├── PHP Const 常量.md └── 内置函数 │ ├── get_class()、get_called_class() 和 __CLASS__ 获取类名称.md │ └── trim 逐字符匹配.md ├── 编程思想 ├── 排序算法 │ └── 排序 - @总结.md └── 算法实例 │ └── 查找整数二进制中最低位 1 的位置.md ├── DB ├── MySQL │ ├── 设置 │ │ ├── MySQL 设置 TIMESTAMP 默认值.md │ │ ├── 自动备份.md │ │ └── MySQL 时区设置.md │ ├── 实用技巧 │ │ ├── MySQL 一次查询多个统计.md │ │ ├── MySQL 行行比较.md │ │ └── MySQL 一个字段包含多个数据的关联查询.md │ ├── 查询指令 │ │ ├── LIMIT 限制数据量.md │ │ ├── DISTINCT 过滤重复.md │ │ └── GROUP BY 数据分组.md │ ├── 数据类型 │ │ └── BLOB 类型.md │ ├── 错误 │ │ ├── MySQL 错误 2019.md │ │ ├── MySQL 错误 1215.md │ │ └── MySQL 错误 1290.md │ ├── 内置方法 │ │ ├── 加密混淆方法.md │ │ ├── 条件判断方法.md │ │ └── 其他方法.md │ └── 问题 │ │ ├── MySQL Authentication plugin.md │ │ └── MySQL 问答—分区.md ├── SQL 技巧.md ├── PostgreSQL │ ├── PostgreSQL 排序.md │ ├── 模块-插件 │ │ ├── uuid-ossp.md │ │ └── @安装插件准备和问题.md │ └── 设置 │ │ ├── PostgreSQL 定时备份.md │ │ └── PostgreSQL 更改数据存储路径.md └── Redis │ ├── Rdis 技巧.md │ └── 数据结构 │ ├── Redis ziplist 压缩列表.md │ ├── Redis List 链表.md │ ├── Redis String 字符串.md │ └── Redis IntSet 整数集合.md ├── Nginx ├── 实例 │ ├── Nginx 隐藏版本号.md │ ├── Nginx 自动下载指定类别的文件.md │ ├── Nginx Nodejs.md │ ├── Nginx 合并多个 X-Forwarded-For.md │ └── Nginx 防盗链.md ├── 问题 │ ├── Nginx PHP-FPM fastCGI 超时.md │ ├── Nginx 是否支持 http2.md │ ├── Nginx Etag 改变了是否意味着文件发生了变化.md │ └── Nginx 无法上传文件.md ├── 正向代理与反向代理定义.md ├── 指令 │ └── Nginx add_header.md └── 知识点 │ └── Nginx root 与 alias 的区别.md ├── ElasticSearch └── ElasticSearch.md └── Docker ├── 问题 └── 问题集合.md └── Docker 命令.md /README.md: -------------------------------------------------------------------------------- 1 | # notes 2 | 这个文件夹记录一些日常学习时做的笔记,以供日后查看。 3 | -------------------------------------------------------------------------------- /Python/技巧/字符串格式化填充 format f-string.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /杂项/vc_git.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/杂项/vc_git.icns -------------------------------------------------------------------------------- /计算机与网络/乱码探源.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/计算机与网络/乱码探源.pdf -------------------------------------------------------------------------------- /Git/git-cheatsheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/Git/git-cheatsheet.pdf -------------------------------------------------------------------------------- /Linux/杂项 - 临时.md: -------------------------------------------------------------------------------- 1 | ### 查看端口占用 2 | 3 | ```shell 4 | lsof -i tcp:8080 5 | ``` 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /杂项/Sublime Text.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/杂项/Sublime Text.icns -------------------------------------------------------------------------------- /计算机与网络/计算机是如何做加法的.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/计算机与网络/计算机是如何做加法的.pdf -------------------------------------------------------------------------------- /Mac/问题/Mac 软连接.md: -------------------------------------------------------------------------------- 1 | Mac 中,使用`ln`命令创建连接的时候,源地址需要使用绝对地址,如果使用`../`这样的相对地址,则会创建失败。 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /计算机与网络/深入图解字符集与字符集编码.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/计算机与网络/深入图解字符集与字符集编码.pdf -------------------------------------------------------------------------------- /Go/Go Reflect.md: -------------------------------------------------------------------------------- 1 | * `reflect.DeepEqual(got, want)` 不是类型安全的,比如两个不同类型的数据这样比较可能会得到 true。 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Git/命令/show.md: -------------------------------------------------------------------------------- 1 | ### 查看提交的内容 2 | 3 | 使用`git show `可以查看这个提交的具体信息,包括:更改的文件、更改的内容、提交信息等。 4 | 5 | -------------------------------------------------------------------------------- /Vagrant/使用 Vagrant 打造跨平台开发环境.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/Vagrant/使用 Vagrant 打造跨平台开发环境.pdf -------------------------------------------------------------------------------- /杂项/markdown img.alfredworkflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/杂项/markdown img.alfredworkflow -------------------------------------------------------------------------------- /计算机与网络/理解 inode - 阮一峰的网络日志.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/计算机与网络/理解 inode - 阮一峰的网络日志.pdf -------------------------------------------------------------------------------- /CSS/demo/CSS 秘密花园 - 交互式图像对比/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/CSS/demo/CSS 秘密花园 - 交互式图像对比/11.jpg -------------------------------------------------------------------------------- /CSS/demo/CSS 秘密花园 - 交互式图像对比/22.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/CSS/demo/CSS 秘密花园 - 交互式图像对比/22.jpg -------------------------------------------------------------------------------- /Python/包库/list.md: -------------------------------------------------------------------------------- 1 | timeit 测试代码运行时间 2 | PySnooper 是一个专用于调试程序的库,Never use print for debugging again。 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /JavaScript/杂项/JavaScript-prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/JavaScript/杂项/JavaScript-prototype.png -------------------------------------------------------------------------------- /Linux/杂项/RPM.md: -------------------------------------------------------------------------------- 1 | ### 安装软件时更改路径 2 | 3 | ```shell 4 | # 将 abc.rpm 包安装到 /usr/bin 目录下 5 | rpm -i –prefix=/usr/bin abc.rpm 6 | ``` 7 | 8 | -------------------------------------------------------------------------------- /杂项/Sublime Text-predawn-dark-round-icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Lin07ux/notes/HEAD/杂项/Sublime Text-predawn-dark-round-icon.icns -------------------------------------------------------------------------------- /Mac/应用/Mac Visual Studio Code.md: -------------------------------------------------------------------------------- 1 | [Visual Studio Code](https://code.visualstudio.com/)是微软开发的一款开源、免费的代码开发 IDE,对多种语言都有很好的支持。 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /JavaScript/知识点/JavaScript 大于等于的判断.md: -------------------------------------------------------------------------------- 1 | JavaScript 中大于等于的判断是通过小于判断来得到的,也即是: 2 | 3 | > 如果`a < b`为 false,则`a >= b`为 true。 4 | 5 | 6 | 那么,因为`null < 0`是 false,所以`null >= 0`就为 true。 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Web/技巧/使用 gif 打点的好处.md: -------------------------------------------------------------------------------- 1 | 为了对前端页面进行监控、数据分析、访问记录等,都需要在前端中使用一定的方式进行数据上报,一般使用 gif 图片进行打点上报,主要是因为: 2 | 3 | * 没有跨域问题; 4 | * 不会阻塞页面加载,影响用户体验; 5 | * 支持透明色; 6 | * 在所有图片中体积最小,相较 BMP/PNG,可以节约 41%/35% 的网络资源。 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /PHP/Homestead/Homestead 服务使用.md: -------------------------------------------------------------------------------- 1 | ### 重启 php-fpm 服务 2 | 3 | Homestead 中有多个 PHP 版本,对应也有多个 php-fpm 进程在运行。如果修改了某个版本的 PHP 的配置文件,需要重启 php-fpm,则需要指定对应的版本才能正常重启: 4 | 5 | ```shell 6 | sudo systemctl restart php7.1-fpm.service 7 | ``` 8 | 9 | 10 | -------------------------------------------------------------------------------- /Go/问题/Go 问题集锦.md: -------------------------------------------------------------------------------- 1 | ### 1. []byte 的打印 2 | 3 | ```go 4 | package main 5 | 6 | import "fmt" 7 | 8 | func main() { 9 | x := []byte{} 10 | fmt.Printf("%#v %T\n", x, x) 11 | } 12 | ``` 13 | 14 | 输出结果为: 15 | 16 | ``` 17 | []byte{} []uint8 18 | ``` 19 | 20 | 21 | -------------------------------------------------------------------------------- /Linux/设置/设置时间.md: -------------------------------------------------------------------------------- 1 | 1. 修改时区 2 | 3 | ```shell 4 | sudo vi /etc/timezone 5 | ``` 6 | 7 | 将其内容改成`Asia/Shanghai`。 8 | 9 | 2. 修改时间 10 | 11 | ```shell 12 | sudo dpkg-reconfigure tzdata 13 | ``` 14 | 15 | 然后选择正确的时区,确定之后时间就自动更正了。 16 | 17 | -------------------------------------------------------------------------------- /PHP/Lumen/Lumen 自定义配置文件.md: -------------------------------------------------------------------------------- 1 | 在 Lumen 框架中实现自定义配置文件,需要如下步骤: 2 | 3 | * 首先在根目录下新建`config`文件夹,在文件夹中放入配置文件,例如`times.php`; 4 | * 在`bootstrap/app.php`中通过`$app->configure('times')`进行全局引入; 5 | * 然后在需要调用配置文件时,直接使用`Config::get('times')`或`config('times')`即可获取。 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /JavaScript/Node/NPM/NPM 报错 chmod.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | NPM 安装依赖的时候,提示错误: 4 | 5 | ``` 6 | npm ERR! enoent ENOENT: no such file or directory, chmod ... 7 | ``` 8 | 9 | ### 原因 10 | 11 | 排除运行安装依赖命令的用户权限不足的原因,一般是在升级 NPM 之后会有这种情况。 12 | 13 | ### 解决 14 | 15 | 重新安装 Node。 16 | 17 | -------------------------------------------------------------------------------- /PHP/杂项/Guzzle.md: -------------------------------------------------------------------------------- 1 | ### Guzzle 请求和 set_time_limit 2 | 3 | Guzzle 的请求一般是通过异步方式发送的,而使用`set_time_limit()`函数无法限制该请求的时间。如果需要限制请求时间,可以使用`timeout`选项: 4 | 5 | ```php 6 | $client = new Client([ 7 | 'base_uri' => $base_uri, 8 | 'timeout' => 50 9 | ]); 10 | ``` 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /JavaScript/Vue/相关/杂项笔记.md: -------------------------------------------------------------------------------- 1 | ## ESLint 2 | ESLint 可以用来对 js 代码做规范性检查。本身不提供规则,但是可以扩展自其它的规则,比如 airbnb 或者 standard 标准。 3 | 4 | 另外,还可以在扩展其它规则之后,再适当根据自身喜好更改部分规则。 5 | 6 | 简单介绍:[ESLint配置参数介绍](https://segmentfault.com/a/1190000004468428) 7 | 8 | 官方文档:[ESLint](http://eslint.org/docs/rules/) 9 | 10 | -------------------------------------------------------------------------------- /Vagrant/Vagrant 常用命令.md: -------------------------------------------------------------------------------- 1 | 2 | ```shell 3 | vagrant init # 初始化 4 | vagrant up # 启动虚拟机 5 | vagrant halt # 关闭虚拟机 6 | vagrant reload # 重启虚拟机 7 | vagrant ssh # SSH 至虚拟机 8 | vagrant status # 查看虚拟机运行状态 9 | vagrant destroy # 销毁当前虚拟机 10 | vagrant package # 打包当前文件夹中的虚拟机 11 | ``` 12 | 13 | 14 | -------------------------------------------------------------------------------- /Python/知识点/海象运算符.md: -------------------------------------------------------------------------------- 1 | Python 3.8 中新增加了一个海象运算符`:=`,使得可以在赋值的同时,做其他运算。 2 | 3 | 比如: 4 | 5 | ```Python 6 | a = 6 7 | if b:=a+1 > 6: 8 | print(b) 9 | ``` 10 | 11 | 这段代码会先计算变量 b 的值,然后判断 b 的值是否大于 6。等价于: 12 | 13 | ```Python 14 | a = 6 15 | b = a + 1 16 | if b > 6: 17 | print(b) 18 | ``` 19 | 20 | -------------------------------------------------------------------------------- /Linux/IO/* 磁盘命令.md: -------------------------------------------------------------------------------- 1 | ### 查看空间使用情况 2 | 3 | `df -h` 4 | 5 | ### 分区工具查看分区信息 6 | 7 | `fdisk -l` 8 | 9 | ### 查看分区 10 | 11 | `cfdisk /dev/sda` 12 | 13 | ### 查看分区和磁盘 14 | 15 | `lsblk` 16 | 17 | ### 参考 18 | 19 | 1. [Linux 格式化和挂载数据盘](https://help.aliyun.com/document_detail/25426.html) 20 | 21 | 22 | -------------------------------------------------------------------------------- /Git/技巧/Git 选择部分修改作为提交.md: -------------------------------------------------------------------------------- 1 | 使用 Git 时的最佳做法是确保每次提交都只包含一个逻辑修改 —— 无论这是修复错误还是添加新功能。然而在工作时,经常会在一个文件做多处修改来确保功能是可用的,这些修改最终应该使用多个提交。 2 | 3 | 怎样才能设法把这些修改区分分开,使每个提交只包含适当的修改呢?可以使用`--patch`开关参数: 4 | 5 | ```shell 6 | git add --patch 7 | ``` 8 | 9 | 这个标志会让`git add`命令查看工作副本中的所有变化,并为每个变化进行询问是否想要将它提交、跳过,或者推迟决定(可以在运行该命令后选择`?`来查看其他更强大的选项)。 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Web/浏览器渲染过程.md: -------------------------------------------------------------------------------- 1 | 浏览器中 JS 引擎线程和渲染线程是互斥的。普通的脚本会阻塞浏览器解析,加上`defer`或`async`属性,脚本就变成异步,可等到解析完毕再执行: 2 | 3 | * `async`异步执行,异步下载完毕后就会执行,不确保执行顺序,一定在`onload`前,但不确定在`DOMContentLoaded`事件的前后。 4 | 5 | * `defer`延迟执行,相对于放在`body`最后(理论上在`DOMContentLoaded`事件前)。 6 | 7 | 操作 DOM 具体的成本,说到底是造成浏览器回流`reflow`和重绘`reflow`,从而消耗 GPU 资源。 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Linux/杂项/关闭“您在 :var:spool:mail:root 中有新邮件”提示.md: -------------------------------------------------------------------------------- 1 | 安装完 Linux 后经常使用终端远程登录后经常出现`You have new mail in /var/spool/mail/root`的提示。这是 Linux 的邮年提示功能。Linux 会定时查看 Linux 各种状态做汇总,每经过一段时间会把汇总的信息发送的 root 的邮箱里,以供有需之时查看。 2 | 3 | 要想关闭 Linux 系统的邮件功能自动提示非常简单,只需要运行以下命令就可以: 4 | 5 | ```shell 6 | echo "unset MAILCHECK" >> /etc/profile 7 | ``` 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Go/杂项/Go 工具链.md: -------------------------------------------------------------------------------- 1 | ### 1. 环境变量 2 | 3 | * `GOOS` 指定编译的操作系统,如指定编译的程序用于 Linux 系统上,可以设置为`GOOS=linux`; 4 | * `GOARCH` 指定编译的 CPU 架构,常见的如`GOARCH=amd64`; 5 | 6 | ### 2. 编译工具 7 | 8 | * `go build -gcflags="-N -l" main.go` 禁止内联编译代码; 9 | * `go tool compile -S -N -l main.go` 禁止内联并生成伪汇编代码; 10 | * `go tool objdump -S -s main main.go` 反汇编,生成伪汇编代码,这样生成的汇编更完整,并翻译了很多符号表。 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Mac/问题/Mac 使用代理后出现 502.md: -------------------------------------------------------------------------------- 1 | ### 问题描述 2 | 3 | 本地使用 host 将域名`develop.test`域名解析到`127.0.0.1`,开启代理之前浏览器访问一切正常,开启代理之后就会出现 502。 4 | 5 | ### 解决方法 6 | 7 | 在系统配置中找到`代理`配置项,将自己的域名添加到`忽略这些主机与域的代理设置`中,保存即可。 8 | 9 | ![](https://cnd.qiniu.lin07ux.cn/markdown/4480da1910b3b9fcda8596b6447a01a7.jpg) 10 | 11 | ### 参考 12 | 13 | > [Mac 使用代理后出现 502](https://blog.csdn.net/hjin_/article/details/118277911) -------------------------------------------------------------------------------- /杂项/Postman/Postman Variables 变量.md: -------------------------------------------------------------------------------- 1 | Postman 中可以定义变量,在请求中引用,从而实现数据的复用情况。 2 | 3 | Postman 的变量分为多个层级: 4 | 5 | * Global:`pm.globals` 6 | * Collection:`pm.collectionVariables` 7 | * Environment:`pm.environment` 8 | * Data:`pm.iterationData` 9 | * Local:`pm.variables` 10 | 11 | 各层级变量的存取方式如下: 12 | 13 | ![](http://cnd.qiniu.lin07ux.cn/markdown/ZKl4qM-20210122145353.jpg) 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /编程思想/排序算法/排序 - @总结.md: -------------------------------------------------------------------------------- 1 | 排序算法可以分为**内部排序**和**外部排序**:内部排序是数据记录在内存中进行排序;而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。 2 | 3 | 常见的内部排序算法有:**插入排序**、**希尔排序**、**选择排序**、**冒泡排序**、**归并排序**、**快速排序**、**堆排序**、**基数排序**等。 4 | 5 | 6 | 7 | 关于稳定性: 8 | 9 | 1. 稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。 10 | 2. 不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。
 11 | 
 12 | 13 | 14 | -------------------------------------------------------------------------------- /Git/技巧/Git 查看、比对其他分支中的文件.md: -------------------------------------------------------------------------------- 1 | 当在一个分支中进行开发时,经常需要查看别的分支的文件内容,如果要切换分支,就需要先整理当前的工作目录,否则无法正常的切换分支,比较麻烦。 2 | 3 | 一个简单的方式是使用`git show`命令,并指定分支和文件名。比如,下面的命令用来查看 master 分支中的`README`文件的内容: 4 | 5 | ```shell 6 | git show master:README 7 | ``` 8 | 9 | 同样的,对于`git diff`命令,也可以指定分支和文件名,实现比对其他分支的文件的功能。比如,下面的命令用来将当前分支上的`README`文件和 master 分支上的`README`文件进行比对: 10 | 11 | ```shell 12 | git diff master:README 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /DB/MySQL/设置/MySQL 设置 TIMESTAMP 默认值.md: -------------------------------------------------------------------------------- 1 | MySQL 5.6 中,如果有类似如下提示,或者 MySQL 日志文件中有类似如下警告: 2 | 3 | ``` 4 | TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details 5 | ``` 6 | 7 | 则说明需要更改 MySQL 的配置文件,显示增加对 Timestamp 使用默认值的设置: 8 | 9 | ```cnf 10 | -- /etc/my.cnf 11 | [mysqld] 12 | explicit_defaults_for_timestamp=true 13 | ``` 14 | 15 | -------------------------------------------------------------------------------- /Web/Cookie.md: -------------------------------------------------------------------------------- 1 | Cookie 的两个重要属性: 2 | 3 | `Set-Cookie: id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOnly` 4 | 5 | 被标记为`Secure`的 Cookie 信息在 HTTP 请求中不会被传送,它只会在 HTTPS 请求中传送,避免数据被泄露。 6 | 7 | 被标记为`HttpOnly`的 Cookie 信息是无法通过 Javascript API 获取到的,它只会在请求中传送。这样可以避免黑客通过网页脚本方式窃取Cookie中的敏感信息。 8 | 9 | 因为 HTTP 协议的不安全性,请求数据包很容易被窃听,Cookie 中的会话信息很容易被盗。解决方案之一就是在会话中记录用户的终端信息和 IP 地址信息,如果这些信息突然发生改变,需要强制用户重新认证。 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /CSS/Bugs/Safari overflow hidden 在 border-radius 和 transform 时无效.md: -------------------------------------------------------------------------------- 1 | Safari 浏览器中,元素在设置了`border-radius`和`transform`时,`overflow: hidden`无法正常将超出边界的内容隐藏掉,甚至`box-shadow`也无法起作用。 2 | 3 | 这个问题可以通过为该元素添加如下的 CSS 来解决: 4 | 5 | ```css 6 | // Add on element with overflow 7 | -webkit-mask-image: -webkit-radial-gradient(white, black); 8 | ``` 9 | 10 | > 转摘:[gistfile1.css](https://gist.github.com/ayamflow/b602ab436ac9f05660d9c15190f4fd7b) 11 | 12 | 13 | -------------------------------------------------------------------------------- /DB/MySQL/实用技巧/MySQL 一次查询多个统计.md: -------------------------------------------------------------------------------- 1 | 在查询中可能需要统计不同字段值的数量,可以通过 GROUP BY 来分别统计,也可以一次性统计得到一条数据。 2 | 3 | 如,需要区分不同颜色的商品数量: 4 | 5 | ```sql 6 | SELECT color, COUNT(*) AS counts FROM items GROUP BY color; 7 | 8 | SELECT COUNT(color = 'blue' OR NULL) as blue, COUNT(color = 'red' OR NULL) AS red FROM items; 9 | 10 | SELECT SUM(auditPass) AS total, SUM(IF(process = 50, auditPass, 0)) AS processCount FROM orders WHERE id <= 9; 11 | ``` 12 | 13 | 14 | -------------------------------------------------------------------------------- /DB/SQL 技巧.md: -------------------------------------------------------------------------------- 1 | ### 1. 将特定的某个值排在最前面 2 | 3 | 有如下需求: 4 | 5 | > 将获取到的结果中,某一列为特定的值时,将该条数据排在前面。 6 | 7 | 此时可以通过在`order by`子句中,使用等值判断来实现,如: 8 | 9 | ```sql 10 | SELECT * FROM users ORDER BY type = 2 DESC, id ASC LIMIT 100; 11 | ``` 12 | 13 | 这里,`order by`子句中的`type = 2`是一个等值判断,当某条记录的的`type`字段的值是 2 时,该等值判断的结果为 1,否则判断结果为 0。然后对这个等值判断的结果按照倒序排列,也就是对 1 和 0 进行倒序,自然 1 排在 0 前面。 14 | 15 | 这样就实现了某列为特定值的记录排在前面的需求。 16 | 17 | > 有些数据库或者数据库中间件不支持该语法。 18 | 19 | -------------------------------------------------------------------------------- /Go/知识点/Go 基本特性.md: -------------------------------------------------------------------------------- 1 | ### 1. 显式大于隐喻 2 | 3 | Go 语言的设计理念就是“**显式大于隐喻**”,追求**明确、显式**。 4 | 5 | 也因此,Go 不支持函数重载和缺省参数。在 Go FAQ《Why does Go not support overloading of methods and operators?》中对此有相关解释: 6 | 7 | * 函数重载:拥有各种同名但不同签名的方法有时是很有用的,但在实践中可能是混乱和脆弱的; 8 | * 参数默认值:这更像是一种便利,没有它程序会更简单一些。 9 | 10 | ### 2. 类型断言 11 | 12 | `v.(I)`: `v`表示一个接口值,`I`表示一个接口类型。 13 | 14 | 这个实际就是 Golang 中的类型断言,用于判断一个接口值的实际类型是否为某个类型,或一个非接口值的类型是否实现了某个接口类型。 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /PHP/Laravel/实用技巧/Laravel Eloquent 多对对关联 按中间表字段排序.md: -------------------------------------------------------------------------------- 1 | 比如,用户可以收藏文章,如何按照用户的收藏时间进行排序? 2 | 3 | 在`User`模型中,可以如下构建喜欢的文章的关联: 4 | 5 | ```php 6 | public function favorites() 7 | { 8 | return $this->belongsToMany(Article::class, 'favorites') 9 | ->orderBy('favorites.created_at', 'desc') 10 | ->withTimestamps(); 11 | } 12 | ``` 13 | 14 | 这里的`orderBy`语句就是设置按照中间表的`created_at`字段进行倒序排序。 15 | 16 | -------------------------------------------------------------------------------- /PHP/ThinkPHP/ThinkPHP 5 自动验证.md: -------------------------------------------------------------------------------- 1 | ### 验证规则中的引号 2 | 3 | 验证规则中,不需要特别的加上引号来表示字符串,ThinkPHP 会自动进行处理的。如果加上了引号,反而会被认为规则就是包含引号的字符串。 4 | 5 | 比如,设置某个字段需要在“企业”、“政府事业”、“个人”中,需要这样设置:`in:企业,政府事业,个人`,而不能设置成`in:"企业","政府事业","个人"`。 6 | 7 | ### 时间日期验证 8 | 9 | TP5 的验证中的时间日期一类的验证(如:`after`、`before`),其是使用`strtotime()`函数来进行处理后比对的,所以在这一类的验证中,条件可以使用符合`strtotime()`函数的参数规则。比如: 10 | 11 | * 不晚于日期前:`before:-1 day ago` 12 | * 不早于指定日期:`after:2008-10-01` 13 | 14 | 15 | -------------------------------------------------------------------------------- /Python/基础/Python3 其他.md: -------------------------------------------------------------------------------- 1 | ### pass 2 | 3 | `pass`语句什么也不做。当语法上需要一个语句,但程序需要什么动作也不做时,可以使用它。一般用其作为占位符。例如: 4 | 5 | ```Python 6 | while True: 7 | pass # Busy-wait for keyboard interrupt (Ctrl+C) 8 | ``` 9 | 10 | 也可以用其定义最小类: 11 | 12 | ```Python 13 | class MyEmptyClass: 14 | pass 15 | ``` 16 | 17 | 或者在编写新的代码时作为一个函数或条件子句体的占位符: 18 | 19 | ```Python 20 | def initlog(*args): 21 | pass # Remember to implement this! 22 | ``` 23 | 24 | 25 | -------------------------------------------------------------------------------- /Go/Go 内置函数.md: -------------------------------------------------------------------------------- 1 | * `close` 用于管道通信; 2 | * `len` 用于返回某个类型的长度或数量(字符串、数组、切片、map 和管道); 3 | * `cap` 用于返回某个类型的最大容量(只能用于切片和 map); 4 | * `make` 用于内置引用类型(切片、map、管道)的初始化。如`make(T)`返回类型 T 的初始化之后的值; 5 | * `new` 用于值类型和用户定义类型(如自定义结构)的初始化。如`new(T)`分配类型 T 的零值并返回其地址,也就是指向类型 T 的指针; 6 | * `append` 连接切片; 7 | * `copy` 复制切片; 8 | * `panic`、`recover` 用于错误处理机制; 9 | * `print`、`println` 底层打印函数,在部署环境中建议使用 fmt 包; 10 | * `complex`、`real`、`imag` 用于创建和操作复数。 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /DB/MySQL/查询指令/LIMIT 限制数据量.md: -------------------------------------------------------------------------------- 1 | ## 一、简介 2 | 3 | LIMIT 子句用来限制返回的结果的数量。其格式如下: 4 | 5 | `LIMIT [位置偏移量],行数` 6 | 7 | 其中,位置偏移量可以省略,省略时表示偏移量为 0,也就是从选择到的结果中的第一条进行选择;行数用来限制返回的结果的数量,也即是返回的结果最多不能超过指定的行数,当然,可以少于指定的行数。 8 | 9 | > 注意:位置偏移量是从 0 开始计数的,也即是,0 表示从第一条结果开始选择。 10 | 11 | ```sql 12 | SELECT * FROM fruits LIMIT 4,3 13 | ``` 14 | 15 | 上面的语句表示,从选择到的结果中的第 5 条开始,选择 3 条结果返回。 16 | 17 | MySQL 5.6 之后,可以使用`LIMIT pos OFFSET rows`的方式来选择结果,和前面的方式的意义是相同的。 18 | 19 | 20 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript ~ 按位取反的使用.md: -------------------------------------------------------------------------------- 1 | 在计算机中,数据都是二进制编码的,对于正数就直接存储对应的二进制编码原码,对于负数则是使用其绝对值的二进制的补码存储的。 2 | 3 | > 求负整数的补码,将其原码除符号位外的所有位取反(0 变 1,1 变 0,符号位为 1 不变)后加 1。 4 | 5 | 例如: 6 | 7 | ```JavaScript 8 | // 9 9 | 00000000000000000000000000001001 10 | 11 | // -9 12 | 11111111111111111111111111110111 13 | ``` 14 | 15 | 那么,**使用`~`对任一数值`x`进行按位非操作的结果为`-(x + 1)`**。 16 | 17 | 比如: 18 | 19 | ```JavaScript 20 | ~9 // -10 21 | ~-9 // 8 22 | ``` 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Nginx/实例/Nginx 隐藏版本号.md: -------------------------------------------------------------------------------- 1 | 2 | 1、编辑 nginx.conf 文件,在 http 模块添加`server_tokens`指令,并配置为 off。 3 | 4 | ```shell 5 | vim /etc/nginx/nginx.conf 6 | 7 | http { 8 | ... 9 | server_tokens off; 10 | ... 11 | } 12 | ``` 13 | 14 | 2、编辑 nginx 的 php-fpm 配置文件,如 fastcgi_params.conf 文件, 15 | 修改`SERVER_SOFTWARE`指令的值为 nginx 即可。 16 | 17 | ```conf 18 | # fastcgi_param SERVER_SOFTWARE nginx/$nginx_version; 19 | fastcgi_param SERVER_SOFTWARE nginx; 20 | ``` 21 | 22 | 3、重新 reload nginx 之后即可生效。 23 | -------------------------------------------------------------------------------- /JavaScript/Vue/Vue 自定义过滤器.md: -------------------------------------------------------------------------------- 1 | ### 截取字符串并补全省略号 2 | 根据给定长度,截取字符串的一部分,可以从字符串起始和结束处截取,并分别在截取得到的子串后面或前面添加省略号。如果字符串长度不足截取长度,则直接返回,不做处理。 3 | 4 | ```javascript
Vue.filter('subtext', function (value, length) {
 var arr = value.split('');

 if (Math.abs(length) < arr.length) {
 if (length >= 0) {
 return arr.slice(0, length).join('') + '...';
 } else {
 return '...' + arr.slice(length).join('')
 }
 }

 return value;
}); 5 | ``` 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Mac/应用/Redis Desktop Manager.md: -------------------------------------------------------------------------------- 1 | Redis Desktop Manager 是一款基于 Qt5 的跨平台 Redis 桌面管理软件。项目地址:[https://github.com/uglide/RedisDesktopManager](https://github.com/uglide/RedisDesktopManager)。 2 | 3 | ### 安装方法 4 | 5 | ```shell 6 | # 安装 brew cask 7 | ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null ; brew install caskroom/cask/brew-cask 2> /dev/null 8 | 9 | # 安装 Redis Desktop Manager 10 | brew cask install rdm 11 | ``` 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /PHP/问题/imagejpeg 函数输出图片是一个红叉.md: -------------------------------------------------------------------------------- 1 | ## 问题 2 | 3 | 使用 imagejpeg 函数向浏览器输出图片的时候,无法正常显示:显示一个红叉或者一个四不像。 4 | 5 | ## 原因 6 | 7 | 一般情况,排除代码的错误问题,就是输出缓存引起的了。因为输出图片的时候,如果 PHP 代码已经输出了数据,那么就会导致输出缓存区就不仅仅是图片数据了,从而导致最终浏览器接收收据进行解析的时候出错。 8 | 9 | ## 解决 10 | 11 | 在输出图片的时候,清理输出缓存即可。 12 | 13 | ```php 14 | // 使用 ob_end_clean() 函数保证程序的输出缓存区是很干净的二进制图像数据 15 | ob_end_clean(); 16 | header('Content-type: image/jpeg'); 17 | 18 | // 创建一个图片流 19 | $img = imagecreatetruecolor(500, 500); 20 | imagejpeg($img); 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /DB/MySQL/数据类型/BLOB 类型.md: -------------------------------------------------------------------------------- 1 | BLOB 是一个二进制大对象,用来存储可变数量的数据。BLOB 类型分为 4 种:`TinyBlob`、`Blob`、`MediumBlob`、`LongBlob`。 2 | 3 | 这几个类型之间的唯一区别是在存储文件的最大大小上不同: 4 | 5 | * TinyBlob 最大 255B 6 | * Blob 最大 65K 7 | * MediumBlob 最大 16M 8 | * LongBlob 最大 4G 9 | 10 | BLOB 类型和字符类型的区别: 11 | 12 | * BLOB 列存储的是二进制字符串(字节字符串);字符类型列存储的是非二进制字符串(字符字符串)。 13 | * BLOB 列没有字符集,并且排序和比较基于列值字节的数值;字符类型列有一个字符集,并且根据字符集对值进行排序和比较。 14 | * BLOB 是二进制字符串,字符类型是非二进制字符串,两者均可存放大容量的信息。BLOB 主要存储图片、音频信息等,而字符类型只能存储文本。 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Go/问题/Go 不定参数的默认值.md: -------------------------------------------------------------------------------- 1 | ### 1. 问题 2 | 3 | 如下的代码,会打印出什么? 4 | 5 | ```go 6 | package main 7 | 8 | import "fmt" 9 | 10 | func foo(a ...int) { 11 | fmt.Printf("%#v\n", a) 12 | } 13 | 14 | func main() { 15 | foo() 16 | } 17 | ``` 18 | 19 | 选项: 20 | 21 | - A `[]int{}` 22 | - B `[]int(nil)` 23 | - C panic 24 | - D 编译错误 25 | 26 | ### 2. 答案 27 | 28 | B。 29 | 30 | 首先,参数`a`的类型是`[]int`,在调用`foo()`方法的时候没有传入任何参数,因此其值就相当于是`[]int`的空值,也就是`nil`。 31 | 32 | 在打印的时候,格式化参数是`%#v`,会同时打印类型和值。 33 | 34 | 所以结果就是 B:`[]int(nil)`。 35 | 36 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript String hash.md: -------------------------------------------------------------------------------- 1 | JavaScript 中没有内置 hash 相关函数,需要自行开发。 2 | 3 | ### 1. md5 4 | 5 | ```JavaScript 6 | String.prototype.hashCode = function () { 7 | var hash = 0, i, chr; 8 | 9 | if (this.length > 0) { 10 | for (i = 0; i < this.length; i++) { 11 | chr = this.charCodeAt(i); 12 | hash = (hash << 5) - hash + chr; 13 | hash != 0; // Convert to 32bit integer 14 | } 15 | } 16 | 17 | return hash; 18 | } 19 | ``` 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /CSS/知识点/CSS margin 的计算方式.md: -------------------------------------------------------------------------------- 1 | margin 的计算方式: 2 | 3 | * 普通元素的百分比 margin 都是相对于容器的宽度; 4 | * 绝对定位元素的百分比 margin 是相对于第一个定位祖先元素的宽度。 5 | 6 | 重叠条件: 7 | 8 | * 必须是 block 元素; 9 | * 不考虑 writing-mode 的话,只发生在垂直方向 10 | 11 | margin 重叠的情形: 12 | 13 | * 相邻兄弟元素 14 | * 父级和第一个 / 最后一个子元素 15 | * 空的 block 元素 16 | 17 | 父子 margin 重叠的其他条件: 18 | 19 | * 父元素不是 BFC 20 | * 父元素没有 border-top 21 | * 父元素没有 padding-top 22 | * 父元素和第一个子元素之间没有 inline 元素分割 23 | * 父元素没有设置 height min-height max-height 24 | 25 | margin 重叠的计算规则: 26 | 27 | * 正正取最大 28 | * 正负取相加 29 | * 负负取最小 30 | 31 | 32 | -------------------------------------------------------------------------------- /PHP/ThinkPHP/ThinkPHP 禁用某个页面的缓存.md: -------------------------------------------------------------------------------- 1 | 如果要禁用所有页面的缓存,可以在 config.php 文件中设置`HTTP_CACHE_CONTROL`为对应的值,如`no-store, no-cache, must-revalidate, post-check=0, pre-check=0 2 | `。 3 | 4 | 而如果要单独设置某个页面禁用缓存,可以在对应的控制器中的 ACTION 中重写`HTTP_CACHE_CONTROL`,并设置其他的一些缓存控制头信息: 5 | 6 | ```php 7 | C('HTTP_CACHE_CONTROL', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT');
header('Pragma: no-cache'); // 兼容 http1.0 和 https 8 | ``` 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /DB/PostgreSQL/PostgreSQL 排序.md: -------------------------------------------------------------------------------- 1 | ### null 排序规则 2 | 3 | 在数据库中 NULL 值是指 UNKNOWN 的值,不存储任何值,在排序时,它排在有值的行前面还是后面通过语法来指定: 4 | 5 | ```sql 6 | nulls first -- null 值排在最前 7 | nulls last -- null 值排在最后 8 | ``` 9 | 10 | 默认情况下,NULL 会排在所有值前面。 11 | 12 | 示例: 13 | 14 | ```sql 15 | -- 根据 id 列升序排列,null 排在所有行前 16 | select * from tb order by id nulls first; 17 | select * from tb order by id asc nulls first; 18 | 19 | -- 根据 id 列升序排列,null 排在所有行前 20 | select * from tb order by id nulls last; 21 | select * from tb order by id desc nulls last; 22 | ``` 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /DB/MySQL/错误/MySQL 错误 2019.md: -------------------------------------------------------------------------------- 1 | ## 错误 2 | ``` 3 | SQLSTATE[HY000] [2019] Can't initialize character set utf8mb4 4 | ``` 5 | 6 | 系统是 CentOS 6.7,MySQL 5.6.29。 7 | 8 | 虽然已经设置了 MySQL 的配置文件中字符集为`utf8mb4`,但是在链接数据库(PHP 中使用 PDO 链接)的时候还是会出现这个错误。 9 | 10 | ## 原因 11 | 这是由于 MySQL 自身的驱动问题导致的。 12 | 13 | ## 解决 14 | 执行如下的命令: 15 | 16 | ```shell 17 | yum erase php56w-mysql 18 | yum install php56w-mysqlnd 19 | ``` 20 | 21 | 参考:[stack overflow](http://stackoverflow.com/questions/33834191/php-pdoexception-sqlstatehy000-2019-cant-initialize-character-set-utf8mb4) 22 | 23 | 24 | -------------------------------------------------------------------------------- /DB/Redis/Rdis 技巧.md: -------------------------------------------------------------------------------- 1 | ### 批量删除 2 | 3 | Redis 没有提供批量删除的命令,但是自从 Redis 2.8 以后开始支持的`scan`命令可以使用模式匹配扫描键,然后利用 Linux 的`xargs`命令即可批量删除命令。 4 | 5 | ```shell 6 | redis-cli -n -a -p --scan --pattern "yum:12:*" | xargs -L 5000 redis-cli -n -a -p del 7 | ``` 8 | 9 | ### 寻找 bigkey 10 | 11 | 大 key 对 redis 是一个挑战,包括 redis 集群(集群会迁移节点),内存申请、扩容、删除等场景造成卡顿。 12 | 13 | 可以通过如下的命令来查找 redis 中的大 key: 14 | 15 | ```shell 16 | redis-cli --bigkeys -i 0.1 17 | ``` 18 | 19 | 这里的`-i 0.1`代表每执行 100 条指令休息 0.1 秒。 20 | 21 | -------------------------------------------------------------------------------- /DB/PostgreSQL/模块-插件/uuid-ossp.md: -------------------------------------------------------------------------------- 1 | uuid-ossp 模块提供了几个方法,可以生成 uuid,也可以用于给 uuid 字段设置默认值。 2 | 3 | 使用之前,需要先安装该模块。 4 | 5 | ```sql 6 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; 7 | ``` 8 | 9 | 只有成功安装该模块之后,才能使用`uuid_generate_v1()`和`uuid_generate_v4()`这两个方法来生成 uuid。如: 10 | 11 | ```sql 12 | SELECT uuid_generate_v1(); 13 | SELECT uuid_generate_v4(); 14 | 15 | -- 作为默认值 16 | CREATE TABLE customers ( 17 |     id uuid PRIMARY KEY DEFAULT uuid_generate_v4(), 18 |     name VARCHAR(36) 19 | ); 20 | ``` 21 | 22 | > [9.5 文档](https://www.postgresql.org/docs/9.5/static/uuid-ossp.html) 23 | 24 | -------------------------------------------------------------------------------- /JavaScript/Vue/Vue-router.md: -------------------------------------------------------------------------------- 1 | ### beforeRouteLeave 2 | 该导航钩子在页面进行跳转之前被触发,所以可以在该钩子中做相应的处理工作。 3 | 4 | 但是`beforeRouteLeave`钩子可能不会被触发,一般是因为在 SPA 项目中,该组件并未直接在路由定义中被引用,而是用在某个路由对应的组件中,作为子组件存在。 5 | 6 | 此时可以在父组件中注册`beforeRouteLeave`钩子,来做相应的处理。 7 | 8 | 参考:[Vue Router beforeRouteLeave doesn't stop subcomponents](http://stackoverflow.com/questions/42045433/vue-router-beforerouteleave-doesnt-stop-subcomponents) 9 | 10 | ### next 11 | 在导航钩子中,`next`会作为第三个参数传递进去,而且可以通过这个方法来决定是取消导航,还是继续导航,抑或导航到指定路由去。 12 | 13 | 不过需要注意的是,在导航钩子中必须使用这个方法,否则路由不会做改变,而且改方法还不能在 Promise 中被使用,只能在正常的同步代码中调用才有效。 14 | 15 | -------------------------------------------------------------------------------- /Linux/杂项/阿里云 ECS 常用文档.md: -------------------------------------------------------------------------------- 1 | ### 一、VPC 网络和经典网络 2 | 3 | VPC 网络是虚拟专属网络,与其他的网络互相隔离,有相对较高的安全性。 4 | 5 | VPC 网络和经典网络之间是不能通过内网/私有 IP 进行访问的,只能通过各自的公网 IP 进行访问。 6 | 7 | 经典网络可以迁移至 VPC 网络,有两种方式: 8 | 9 | * 混挂和混访方案:适用于服务器上有依赖于其他经典网络资源的情况。 10 | * 单 ECS 迁移方案:适用于服务器上的所有服务都在该服务器上,不依赖其他经典网络资源的情况。 11 | 12 | ECS 迁移到 VPC 网络之后,需要设置安全组的规则,设置相关端口和 IP 的联通情况,相当于服务器端安装的 iptables 服务。 13 | 14 | **资料** 15 | 16 | 1. [VPC通信](https://help.aliyun.com/document_detail/53597.html) 17 | 2. [迁移方案概述](https://help.aliyun.com/document_detail/55051.html) 18 | 3. [单ECS迁移示例](https://help.aliyun.com/document_detail/57954.html) 19 | 20 | -------------------------------------------------------------------------------- /Linux/CentOS/Centos 修改环境变量 PATH.md: -------------------------------------------------------------------------------- 1 | 如果需要把一个路径加入到系统的 PATH 路径中,有三种方法: 2 | 3 | > 下面以将`/usr/pgsql-9.5/bin`加入到 PATH 中为例。 4 | 5 | 1. 在当前命令行中执行`PATH=$PATH:/usr/pgsql-9.5/bin`。 6 | 7 | 使用这种方法,只对当前会话有效,也就是说每当登出或注销系统以后,PATH 设置就会失效 8 | 9 | 2. 在`~/.bash_profile`文件中修改`PATH`的值,在最后加入`:/usr/pgsql-9.5/bin`。 10 | 11 | 这种方式仅对当前用户起作用,如果用其他用户登录则无效果。修改之后,使用`soucre ~/.bash_profile`立即启用改变。 12 | 13 | 3. 在`/etc/profile`文件中的适当位置添加`PATH=$PATH:/usr/pgsql-9.5/bin`。 14 | 15 | 使用这种方法会对所有的用户都有影响,也即是所有用户都能使用新加入的路径中的程序了。 16 | 17 | > 注意:`=`等号两边不能有任何空格,保存之后,可以重新登陆,或者使用`source /etc/profile`来立即应用改变。 18 | 19 | -------------------------------------------------------------------------------- /JavaScript/Vue/vue-cli/vue-cli 3 静态资源部署到 CDN.md: -------------------------------------------------------------------------------- 1 | vue-cli 3 中,可以通过在配置文件`vue.config.js`文件中增加`publicPath`来设置生成的静态资源的路径,类似如下: 2 | 3 | ```JavaScript 4 | module.exports = { 5 | publicPath: isProduction ? 'https://cdn.example.com' : '/', 6 | } 7 | ``` 8 | 9 | > `publicPath`替代了之前的`baseUrl`。 10 | 11 | 需要注意的是,`publicPath`会在多个地方使用,而且会将`process.env.VUE_APP_BASE_URL`的值也设置成这个值。而默认的`vue-router`的配置中,有`base: process.env.VUE_APP_BASE_URL`。也就是说,默认情况下,`publicPath`的值会被用于路由的前缀。这就会导致,编译出来的结果中,每次路由切换都会带有 CDN 的域名信息,所以为了配置更准确,还需要修改 router 的`base`项设置。比如,可以在`.env`配置文件中增加一个 router base 值选项,并在 router 定义的时候引用即可。 12 | 13 | 14 | -------------------------------------------------------------------------------- /Mac/问题/Mac 10.12+ 允许任何来源的 APP.md: -------------------------------------------------------------------------------- 1 | Mac OS 10.12 系统开始,在`系统偏好 -> 安全&隐私`中默认去除了允许安装任意来源 APP 的选项,很多不是从 AppStore 中下载的 APP 都不能安装了。 2 | 3 | 有两种方式来安装其他来源的 APP: 4 | 5 | ### 1. 官方方法 6 | 7 | Apple 官方对这个问题给出的解决办法是:按住键盘上的`Control`键,然后点击要打开的 App 安装文件即可。 8 | 9 | ### 2. 显示允许暗转任何来源 APP 的选项 10 | 11 | 如果经常需要安装非 AppStore 中的 APP 时,使用官方方法可能并不方便。 12 | 13 | 查看官方资料,这个选项之所以消失是因为 10.12 系统默认开启了 Gatekeeper 服务,所以只要关闭这个服务即可找到这个选项了。关闭命令如下(在终端中输入): 14 | 15 | ```shell 16 | sudo spctl --master-disable 17 | ``` 18 | 19 | 关闭后就能在`安全&隐私`中找到允许安装任意来源 APP 的选项了。 20 | 21 | 如果之后再次选择了其他的设置项,那么就会再次打开 Gatekeeper 服务,从而再次隐藏该选项。要重新开启,就再次执行上面的命令即可。 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Python/技巧/优雅的打印嵌套类型的数据.md: -------------------------------------------------------------------------------- 1 | 默认情况下,打印 JSON 字符串或者字典数据的时候,会打印出一堆杂乱在一起、没有层次的字符串。这可以通过如下的方式来进行处理。 2 | 3 | ### 1. 层次化格式 4 | 5 | json 库格式的时候,可以传入`indent`和`sort_keys`参数来指定数据进行 json 格式化时的格式。 6 | 7 | ```Python 8 | import json 9 | 10 | my_mapping = {'a': 23, 'b': 42, 'c': 0xc0ffee} 11 | print(json.dumps(my_mapping, indent=4, sort_keys=True)) 12 | ``` 13 | 14 | ### 2. 使用 pprint 库 15 | 16 | `json.dumps()`方法的格式对由字典组成的列表是无效的。可以使用标准库 pprint 来进行格式化: 17 | 18 | ```Python 19 | import pprint 20 | 21 | my_mapping = [{'a': 23, 'b': 42, 'c': 0xc0ffee}, {'a': 32, 'b': 24, 'c': 0xc0ff11}] 22 | pprint.pprint(my_mapping, width=4) 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /Nginx/问题/Nginx PHP-FPM fastCGI 超时.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | Nginx 通过 PHP-FPM 这个 fastCGI 接口来转发执行 PHP 程序。但是如果 FastCGI 接口长时间没有返回的时候,就会造成超时,导致 Nginx 直接返回 404 错误。 4 | 5 | ### 原因 6 | 7 | 这是由于 Nginx 对 FastCGI 接口有默认的等待时间(60s)的,当 Nginx 将请求转发给 PHP-FPM 执行的时候,会等待一定的时间,如果在这个时间内,PHP 有返回数据,那么就一切正常,否则就会出现 Nginx 等待超时,然后就关闭与 PHP-FPM 的链接,直接返回 404 了。 8 | 9 | ### 解决 10 | 11 | 在 Nginx 的转发到 FastCGI 的配置中,增加`fastcgi_read_timeout`指令,设置一个较长的时间来解决该问题。如下: 12 | 13 | ```conf 14 | location ~ .*\.(php|php5)?$ { 15 |   fastcgi_pass 127.0.0.1:9000; 16 |   fastcgi_read_timeout 700; 17 |   fastcgi_index index.php; 18 |   include fastcgi.conf; 19 | } 20 | ``` 21 | 22 | 23 | -------------------------------------------------------------------------------- /PHP/Swoole/Swoole 常用方法.md: -------------------------------------------------------------------------------- 1 | ### 定时器 2 | 3 | `swoole_timer_tick`重复执行指定方法,`swoole_timer_after`延迟指定时间后执行回调。这两者分别类似于 JavaScript 中的`setInterval`方法和`setTimeout`方法。 4 | 5 | 这两个方法设置的定时器都可以使用`swoole_timer_clear`方法进行清除。 6 | 7 | ```php 8 | // 重复执行定时任务 9 | $tick_timer_id = swoole_timer_tick(1000, function ($timer_id) { 10 | echo 'same as setInterval.And this timer id :'.$timer_id.PHP_EOL; 11 | }); 12 | 13 | var_dump($tick_timer_id); 14 | 15 | // 一次性延时定时任务 16 | swoole_timer_after(2000, function () { 17 | echo 'same as setTimeout'.PHP_EOL; 18 | }); 19 | 20 | // 清除定时任务 21 | swoole_timer_clear($tick_timer_id); 22 | ``` 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /编程思想/算法实例/查找整数二进制中最低位 1 的位置.md: -------------------------------------------------------------------------------- 1 | 对于一个整数,要找到二进制表示中的最低 1 的位置,可以使用按位遍历的方式,但是这样的话时间复杂度是`O(n)`,性能上有提升的空间。 2 | 3 | 利用`x & ~(x - 1)`可以将时间复杂度为减小到`O(1)`。 4 | 5 | 对于一个二进制数字 x,将其值减 1 会影响 x 中最后一个 1 位及其之后的位。再对`x - 1`的值取反之后,其结果就会与`x`的值仅有最低 1 的位相同,而其他位都相反。 6 | 7 | 比如,`x = 56`: 8 | 9 | * `x`其二进制为`00111000`,`x - 1`的二进制表示就是`00110111`。可以看出`x - 1`的值和`x`的值的二进制表示中,高位的 0 和 1 位相同,仅`x`的最后一个 1 及其之后的位发生了变化。 10 | * 此时再对`x - 1`取反,得到`11001000`,这个结果与`x`的二进制表示中,仅有第五位相同,其他的位都相反。 11 | * 将`x`与`~(x - 1)`做位与操作,就可以得到`x`的最后一位了。 12 | 13 | JavaScript 的实现代码如下: 14 | 15 | ```JavaScript 16 | function lowBit (x) { 17 | return (x & ~(x - 1)) >> 1; 18 | } 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /ElasticSearch/ElasticSearch.md: -------------------------------------------------------------------------------- 1 | [不懂Elasticsearch?看这一篇就够了!](https://juejin.cn/post/6914161229820854285) 2 | 3 | ES -> 数据库 4 | 索引 index -> 表 5 | 文档 document -> 行(记录) 6 | 字段 fields -> 列 7 | 映射 mapping -> 表结构 8 | 近实时 NRT -> Near real time 近实时的搜索 9 | 节点 node -> 每一个服务器 10 | 分片 shard -> 水平拆表 11 | 备份 replica -> 备用库中对应的分表 12 | 13 | 倒排序:根据单词去搜索包含单词的文档,并且显示在文档中的词频(TF)和位置(POS)。 14 | 15 | 响应数据中: 16 | 17 | * `_index`:文档数据所属那个索引,理解为数据库的某张表即可。 18 | * `_type`:文档数据属于哪个类型,新版本使用_doc 。 19 | * `_id`:文档数据的唯一标识,类似数据库中某张表的主键。可以自动生成或者手动指定。 20 | * `_score`:查询相关度,是否契合用户匹配,分数越高用户的搜索体验越高。 21 | * `_version`:版本号。 22 | * `_source`:文档数据,json格式。 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Linux/杂项/Linux alias 支持参数.md: -------------------------------------------------------------------------------- 1 | Linux 可以通过在配置文件中使用 alias 来配置命令的别名,从而实现简化命令参数输入的目的。比如: 2 | 3 | ```shell 4 | alias ohmyzsh="mate ~/.oh-my-zsh" 5 | ``` 6 | 7 | 不过 alias 默认不支持参数,如果要使用参数则可以定义一个方法,然后在 alias 中执行这个方法,例如: 8 | 9 | ```shell 10 | rdbLogin() { 11 | redis-cli -h rdb.example.com -p 63791 -n $1 12 | } 13 | alias rdb="rdbLogin" 14 | ``` 15 | 16 | > 注意:shell 中的参数要从`$1`开始取,因为`$0`表示的时脚本/函数名。 17 | 18 | 如果想要使用默认值参数,可以使用 shell 脚本中的`:-`语法,如: 19 | 20 | ```shell 21 | rdbLogin() { 22 | redis-cli -h rdb.example.com -p 63791 -n ${1:-10} 23 | } 24 | alias rdb="rdbLogin" 25 | ``` 26 | 27 | 这里的`${1:-10}`表示如果没有传入参数,则使用 10 作为`$1`参数的值,所以这里默认是连接 10 号库。 -------------------------------------------------------------------------------- /PHP/实用技巧/隐藏 PHP 信息.md: -------------------------------------------------------------------------------- 1 | 一些简单的方法可以帮助隐藏 PHP,这样做可以提高攻击者发现系统弱点的难度: 2 | 3 | * 在`php.ini`文件里设置`expose_php = off`,可以去除响应头信息中的`X-Powered_By`。 4 | * 让 Web 服务器用 PHP 解析不同扩展名。无论是通过`htaccess`文件还是 Apache 的配置文件,都可以设置能误导攻击者的文件扩展名。 5 | 6 | **使 PHP 看上去像其它的编程语言** 7 | 8 | `AddType application/x-httpd-php .asp .py .pl` 9 | 10 | **使 PHP 看上去像未知的文件类型** 11 | 12 | `AddType application/x-httpd-php .bop .foo .133t` 13 | 14 | **使 PHP 代码看上去像 HTML 页面** 15 | 16 | `AddType application/x-httpd-php .htm .html` 17 | 18 | 要让此方法生效,必须把 PHP 文件的扩展名改为以上的扩展名。这样就通过隐藏来提高了安全性,虽然防御能力很低而且有些缺点。 19 | 20 | > 参考:[隐藏 PHP](http://php.net/manual/zh/security.hiding.php) 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /杂项/Sublime Text/Sublime Text 更换图标.md: -------------------------------------------------------------------------------- 1 | Sublime Text 可以使用自己的图标来替换默认的 icon。不过,如果只是简单的直接替换源程序文件中的`sublime text.icns`文件,并不能更换其快捷方式上的图标。可以使用下面的方式来替换。 2 | 3 | 参考:[Changing sublime text 3 icon in dock on Yosemite](http://apple.stackexchange.com/questions/153176/changing-sublime-text-3-icon-in-dock-on-yosemite) 4 | 5 | 1. 先删除 Dock 上的 Sublime text 的图标。 6 | 2. 打开两个 Finder 窗口:一个是 Application 窗口,找到 Sublime Text 程序;一个是你的新 icon 图片文件所在的文件夹窗口。 7 | 3. 选中 Sublime Text,然后按`Cmd + i`打开 App 信息简介窗口。 8 | 4. 拖放新的图标到 Sublime Text 的 App 信息简介窗口中,左上角的那个图标上(最顶部,App 名称前面的那个图标)。然后你就会看到信息简介窗口上的两个图标都被更换了。 9 | 5. 此时重新打开 Sublime Text 并固定快捷方式在 Dock 中,Dock 中显示的就是新的图标了。 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /PHP/知识点/PHP 中 unset 和 array_splice 删除数组元素的区别.md: -------------------------------------------------------------------------------- 1 | PHP 中删除元素中的数组,一般常用的是`unset()`方法,如果是批量删除,则会使用`array_splice()`方法。这两者的实际执行效果也是有所不同的。 2 | 3 | > 这两个方法都在原数组上进行改变。 4 | 5 | * `unset()`方法是直接删除数组中指定的元素,不做其他改变。 6 | * `array_splice()`删除数组中的元素后,会对数组的数值索引进行重排。 7 | 8 | 下面通过示例来展示两者的区别: 9 | 10 | ```php 11 | $a = [1, 'a' => 'aaa', 2, 'b' => 'bbb', 3]; 12 | $a; 13 | 14 | unset($a[1]); 15 | $a; 16 | 17 | array_splice($a, 1, 1); 18 | $a; 19 | ``` 20 | 21 | 三次展示的数组的结果如下图所示: 22 | 23 | 24 | 25 | 可以看到,使用`unset()`方法删除了索引为`1`的值后,其他数值索引没有发生变化,而使用`array_splice()`方法删除一个元素后,数值索引被重新排序了。 26 | 27 | 28 | -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 替换换行符.md: -------------------------------------------------------------------------------- 1 | PHP 替换换行符有多种方法: 2 | 3 | 1. 使用`str_replace`来替换换行 4 | 5 | `$str = str_replace(array("\r\n", "\r", "\n"), "", $str);` 6 | 7 | 2. 使用正则替换 8 | 9 | `$str = preg_replace('//s*/', '', $str);` 10 | 11 | 3. 使用 php 定义好的变量(建议使用) 12 | 13 | `$str = str_replace(PHP_EOL, '', $str);` 14 | 15 | 4. 还可以转换成前台可显示的字符串:使用[`nl2br`](http://www.php.net/nl2br)函数转为前台可显示的换行。 16 | 17 | ```php 18 | $str = "a 19 | b 20 | e 21 | f 22 | c"; 23 | 24 | echo nl2br($str); 25 | 26 | /* 显示如下 27 | a
28 | b
29 | e
30 | f
31 | c 32 | */ 33 | ``` 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Python/包库/schedule 定时器.md: -------------------------------------------------------------------------------- 1 | schedule 是一个 Python 中的定时器模块,提供了非常语义化的 API。 2 | 3 | * [schedule - GitHub](https://github.com/dbader/schedule) 4 | * [文档](https://schedule.readthedocs.io/) 5 | 6 | 使用示例如下: 7 | 8 | ```Python 9 | import schedule 10 | import time 11 | 12 | def job(): 13 | print("I'm working...") 14 | 15 | schedule.every(10).minutes.do(job) 16 | schedule.every().hour.do(job) 17 | schedule.every().day.at("10:30").do(job) 18 | schedule.every().monday.do(job) 19 | schedule.every().wednesday.at("13:15").do(job) 20 | schedule.every().minute.at(":17").do(job) 21 | 22 | while True: 23 | schedule.run_pending() 24 | time.sleep(1) 25 | ``` 26 | 27 | -------------------------------------------------------------------------------- /Python/知识点.md: -------------------------------------------------------------------------------- 1 | ### 相等和全等 2 | 3 | Python 中的值都会作为对象处理,变量都是对象的引用,所以 Python 中的对两个变量的判断有相等和全等之分:相等是指变量的值相等,而全等则是两个变量指向同一个对象。 4 | 5 | ```Python 6 | x = 1.0 7 | y = 1.0 8 | 9 | # 相等:True 10 | x == y 11 | # 全等:False 12 | x is y 13 | 14 | # 4539216256 15 | id(x) 16 | # 4539216308 17 | id(y) 18 | 19 | y = x 20 | 21 | # 相等:True 22 | x == y 23 | # 全等:True 24 | x is y 25 | 26 | # 4539216256 27 | id(x) 28 | # 4539216256 29 | id(y) 30 | ``` 31 | 32 | ### 比较 33 | 34 | 内建函数`cmp(obj1, obj2)`用于比较两个对象:如果 obj1 小于 obj2 则返回一个负整数;如果 obj1 等于 obj2 则返回 0;如果 obj1 大于 obj2 则返回一个正整数; 35 | 36 | 这里的比较是在对象之间进行的,不管是标准类型对象还是用户自定义对象。对于自定义对象,`cmp()`会调用该类的特殊方法`__cmp__()`进行比较。 37 | 38 | 39 | -------------------------------------------------------------------------------- /Linux/Command/su sudo.md: -------------------------------------------------------------------------------- 1 | > 转摘:[sudo,代表了Linux的绝对霸权!](https://mp.weixin.qq.com/s/r4g4CgE1QJdMbDwuC_T6ZA) 2 | 3 | sudo 命令可以使用其他的身份来执行命令,而 su 命令就是直接切换到别的用户。 4 | 5 | ### 1. `-s`和`-i`选项的区别 6 | 7 | `sudo -s`的意思是: 8 | 9 | 1. 使用当前用户的环境变量; 10 | 2. 不跳转切换用户后的 home 目录; 11 | 3. 切换到超级管理员或者目标用户的权限。 12 | 13 | 这种方式通常会带来一些问题。比如在当前用户 A 下设置了自己的一套环境变量。当使用`sudo -s`切换到超级管理员权限,依然使用的是 A 账号的环境变量。这样,就可能会发生找不到命令、语言错误、甚至配置错误的结果。 14 | 15 | 相对应的,`sudo -i`就干净利索的多,它的意思是: 16 | 17 | 1. 使用 root 或者目标用户的环境变量; 18 | 2. 切换到`/root`或者目标用户的 home 目录; 19 | 3. 切换到 root 或者目标用户的权限。 20 | 21 | 大多数情况下,推荐使用`sudo -i`替代`sudo -s`,这样出问题的几率会小很多。 22 | 23 | 如果只运行`su`,它的效果和`sudo -s`是一样的;如果使用了`su -`,那么它的效果就是`sudo -i`。 24 | 25 | -------------------------------------------------------------------------------- /Linux/CentOS/CentOS 常用安全设置.md: -------------------------------------------------------------------------------- 1 | ### 设置密码最长有效期 2 | 3 | 将系统的密码最长使用时间设置为较短时间,建议为 1095 天。 4 | 5 | ```shell 6 | vim /etc/login.defs 7 | ``` 8 | 9 | 找到其中的`PAS_MAX_DAYS`项,设置为`PASS_MAX_DAYS 1095`。 10 | 11 | ### crontab 权限设置 12 | 13 | 设置可以创建 crontab 任务的白名单,而不是用黑名单机制: 14 | 15 | ```shell 16 | rm -f /etc/cron.deny /etc/at.deny 17 | touch /etc/cron.allow /etc/at.allow 18 | chmod 0600 /etc/cron.allow /etc/at.allow 19 | ``` 20 | 21 | ### 禁止转发 ICMP 重定向报文 22 | 23 | 先关闭重定向: 24 | 25 | ```shell 26 | sysctl -w net.ipv4.conf.all.send_redirects=0 27 | ``` 28 | 29 | 然后检查`/etc/sysctl.conf`文件中是否有如下的设置,没有的话就添加进去: 30 | 31 | ```conf 32 | net.ipv4.conf.all.send_redirects=0 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /Git/杂项/GitHub 问题.md: -------------------------------------------------------------------------------- 1 | ### 1. Connection closed by remote host 2 | 3 | > 参考:[ssh_exchange_identification: Connection closed by remote host under Git bash [closed]](https://stackoverflow.com/questions/10127818/ssh-exchange-identification-connection-closed-by-remote-host-under-git-bash) 4 | 5 | 在使用 Git 命令连接远程仓库的时候,有如下的错误提示: 6 | 7 | ```text 8 | ssh_exchange_identification: Connection closed by remote host 9 | ``` 10 | 11 | 在国内出现这个问题主要出现在通过 VPN 访问 GitHub 的情况,此时使用默认的 22 端口和`github.com`主机名访问时会被禁掉,但是可以使用 HTTPS 来访问。 12 | 13 | 所以,可以通过在`~/.ssh/config`文件中对`github.com`主机做如下的配置来解决无法链接 GitHub 仓库的问题: 14 | 15 | ```conf 16 | Host github.com 17 | Hostname ssh.github.com 18 | Port 443 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /Python/包库/Requests 使用.md: -------------------------------------------------------------------------------- 1 | ### 下载图片 2 | 3 | 可以使用流式下载: 4 | 5 | ```python 6 | import requests 7 | 8 | url = 'http://52kantu.cn/static/photos/full/5f483af86df016c855cb9af9b76c7f4271f700c2.jpg' 9 | r = requests.get(url, stream=True) 10 | 11 | with open('123.jpg', 'wb') as fd: 12 | for chunk in r.iter_content(): 13 | fd.write(chunk) 14 | ``` 15 | 16 | 也可以直接整个下载: 17 | 18 | ```python 19 | import requests 20 | 21 | url = 'http://52kantu.cn/static/photos/full/5f483af86df016c855cb9af9b76c7f4271f700c2.jpg' 22 | r = requests.get(url) 23 | 24 | if r.status_code == requests.code.ok: 25 | with open('logo.jpg', 'wb') as image: 26 | image.write(r.content) 27 | ``` 28 | 29 | -------------------------------------------------------------------------------- /Linux/符号/Linux &.md: -------------------------------------------------------------------------------- 1 | > 转摘:[Linux 中的 &](https://linux.cn/article-10587-1.html) 2 | 3 | ### 1. 后台运行 4 | 5 | 使用`&`号可以将命令放到后台运行: 6 | 7 | ```shell 8 | cp -R original/dir/ backup/dir/ & 9 | ``` 10 | 11 | 将`original/dir/`的内容递归地复制到`backup/dir/`中时,如果原目录里面的文件太大,在执行过程中终端就会一直被卡住。在命令的末尾加上一个`&`号,将这个任务放到后台去执行,从而可以立即继续在同一个终端上工作了,甚至关闭终端也不影响这个任务的正常执行。 12 | 13 | > 需要注意的是,如果要求这个任务输出内容到标准输出中(例如`echo`或`ls`),即使使用了`&`,也会等待这些输出任务在前台运行完毕。 14 | 15 | 当使用`&`将一个进程放置到后台运行的时候,Bash 会提示这个进程的进程 ID。在 Linux 系统中运行的每一个进程都有一个唯一的进程 ID,可以使用进程 ID 来暂停、恢复或者终止对应的进程,因此进程 ID 是非常重要的。 16 | 17 | 18 | 19 | ```shell 20 | mkdir test_dir 2>/dev/null || touch images.txt && find . -iname "*jpg" > backup/dir/images.txt & 21 | ``` 22 | 23 | -------------------------------------------------------------------------------- /Nginx/实例/Nginx 自动下载指定类别的文件.md: -------------------------------------------------------------------------------- 1 | 浏览器的功能越来越丰富,很多文件都支持在浏览器中自动打开了,但是有时候访问一个链接的时候,并不希望浏览器自动打开对应的文件,而是希望弹出下载框。此时可以考虑针为这些文件自动添加下载响应头,使浏览器能够自动弹出下载框: 2 | 3 | ```conf 4 | location / { 5 | root /usr/share/nginx/html/edp/web; 6 | 7 | if ($uri ~* \.(txt|doc|pdf|rar|gz|zip|docx|exe|xlsx|ppt|pptx)$) { 8 | add_header Content-Disposition 'attachment;'; 9 | } 10 | 11 | try_files $uri $uri/ /index.php$uri$is_args$query_string; 12 | } 13 | ``` 14 | 15 | 有时候即便已经配置了这个响应头,Chrome 浏览器依旧会打开文件。比如对于 PDF 文件,Chrome 浏览器总是会尝试自动打开,此时可以编辑 Nginx 的 mime 配置,使 PDF 文件的类别对应为二进制流即可: 16 | 17 | ``` 18 | # /etc/nginx/mime.types 19 | application/pdf                       octet-stream; 20 | ``` 21 | 22 | 23 | -------------------------------------------------------------------------------- /CSS/CSS 效果片段 - 移动端.md: -------------------------------------------------------------------------------- 1 | ### 移动端标签点击后变暗 2 | 3 | 在移动端使用 a,button,input,optgroup,select,textarea 标签的时候,点击后会出现一个"暗色的"背景,这时候我们需要在css加入如下代码即可禁用这个效果: 4 | 5 | ```css 6 | a,button,input,optgroup,select,textarea{ 7 | -webkit-tap-highlight-color: rgba(0,0,0,0); 8 | } 9 | ``` 10 | 11 | ### webkit 表单输入框 placeholder 的颜色值改变: 12 | 13 | 如果想要默认的颜色显示红色,代码如下: 14 | 15 | `input::-webkit-input-placeholder { color: red; }` 16 | 17 | 如果想要用户点击变为蓝色,代码如下: 18 | 19 | `input:focus::-webkit-input-placeholder { color: blue; }` 20 | 21 | ### 移动端 iOS 手机下清除输入框内阴影 22 | 23 | `input, textarea { -webkit-appearance: none; }` 24 | 25 | ### 在 iOS 中 禁止长按链接与图片弹出菜单 26 | 27 | `a, img { -webkit-touch-callout: none; }` 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /PHP/Laravel/功能/Laravel Policy.md: -------------------------------------------------------------------------------- 1 | ### 传参 2 | 3 | Policy 类中,不仅仅可以设置 User 和相应数据 Model 参数,还可以增加其他的参数。 4 | 5 | 在进行授权验证的时候,可以将附加参数合成一个数组。比如,对于如下的一个 Policy: 6 | 7 | ```php 8 | class AccountPolicy 9 | { 10 | public function list (User $user, $cooperator_id) 11 | { 12 | return $user->isAdmin() && $user->cooperator_id === (int)$cooperator_id; 13 | } 14 | } 15 | ``` 16 | 17 | 在 Controller 中进行授权验证时,可以使用如下方式传递参数: 18 | 19 | ```php 20 | class AccountController extends Controller 21 | { 22 | public function show ($id) 23 | { 24 | $this->authorize('list', [Account::class, $id]); 25 | } 26 | } 27 | ``` 28 | 29 | 这样就可以正常使用`AccountPolicy`授权策略中的`list()`方法,并将`$id`参数传入进去了。 30 | 31 | -------------------------------------------------------------------------------- /DB/MySQL/查询指令/DISTINCT 过滤重复.md: -------------------------------------------------------------------------------- 1 | ## 一、简介 2 | 3 | `DISTINCT`关键字用来查询出某个字段不重复的记录。一般用于查询某个或某几个字段不完全相同的记录。 4 | 5 | 比如,下面的语句会获取 fruits 表中 name 字段不重复的记录: 6 | 7 | ```sql 8 | SELECT DISTINCT name FROM fruits; 9 | ``` 10 | 11 | ## 二、使用 12 | 13 | ### 2.1 多个字段 14 | 15 | 如果同时指定了多个字段,那么会按照这多个字段的值同时不重复的条件来过滤,而这一般并不是想要的效果,往往只用它来返回不重复记录的条数,而不是用它来返回不重记录的所有值。 16 | 17 | 但是如果同时想要其他的字段,比如 id 字段的值,使用下面的语句并不能获取到按照 name 字段过滤重复值后的结果: 18 | 19 | ```sql 20 | SELECT DISTINCT name, id FROM fruits; 21 | ``` 22 | 23 | 上面的这个语句会按照`(name, id)`两个字段同时不重复来过滤。 24 | 25 | 如果要只根据 name 字段来过滤重复值,但是还要获取其他字段的值,可以使用`GROUP BY`子句来完成: 26 | 27 | ```sql 28 | SELECT id, name FROM fruits GROUP BY name; 29 | ``` 30 | 31 | 这获取结果的时候,对具有相同的`name`的记录只会返回第一条。 32 | 33 | -------------------------------------------------------------------------------- /Web/HTML/HTML 音标注释标记 ruby:rt:rp.md: -------------------------------------------------------------------------------- 1 | HTML 里有一种专门用来显示音标或注释的标记,叫做`ruby`,它还有两个子元素`rt`和`rp`。 2 | 3 | * `` 将需要注释或注音标的文字内容包围住。 4 | * `` 放置音标或注释,这个标记要跟在需要注释的文本后边。 5 | * `` 这个标记是防备那些不支持`ruby`标记的浏览器,主要用来放置括弧。对于支持这个标记的浏览器,`rp`标记的 CSS 样式默认是`{display:none;}`,也就是不可见。 6 | 7 | `rt`里的文字,对于水平排版,会显示在文字上方;对于竖向排版,它会显示到文字右边。也可以使用 CSS 样式调整音标的样式,如字体、颜色等。 8 | 9 | 最新版的火狐、谷歌等浏览器都支持这个标记。这个标记还支持嵌套使用,显示双层标注。 10 | 11 | 示例如下: 12 | 13 | ```html 14 | 15 | 北(bei) 16 | 京(jing) 17 | 18 | ``` 19 | 20 | 显示效果类似如下: 21 | 22 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1570522651116.png) 23 | 24 | > 转摘:[HTML拼音/音标注释标记ruby和它的子元素rt/rp](http://www.webhek.com/html-ruby-rt-rp) 25 | 26 | 27 | -------------------------------------------------------------------------------- /Nginx/问题/Nginx 是否支持 http2.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | 如何查看安装的 Nginx 是否支持 HTTP 2.0?如果支持,如何使网站使用 http 2.0? 4 | 5 | ### 解决 6 | 7 | **1. 查看是否支持** 8 | 9 | 使用`nginx -V`命令,查看 Nginx 的详细配置信息。在显示的信息中,查看是否有`--with-http_v2_module`,如果有则说明是支持的。 10 | 11 | **2. 启用 http 2.0** 12 | 13 | 由于 HTTP 2.0 需要使用 HTTPS 协议,所以要先确保服务器已经配置了 SSL 证书。而且 HTTP 2.0 在客户端不支持的时候,会自动降级到 HTTP 1.1,所以只需要在服务器中进行配置即可。 14 | 15 | 参考配置如下: 16 | 17 | ```conf 18 | server { 19 | # listen 80; 20 | listen 443 ssl http2; 21 | #.... 22 | } 23 | ``` 24 | 25 | 配置好之后,重启 Nginx 即可。 26 | 27 | 然后在谷歌浏览器上打开你使用 http2 的站点,打开调试工具(F12),进入 Network,刷新页面,点击第一个请求,在`Headers --> Response Headers`中查看。如果 Response Headers 右边有一个`view source`,点进去就能看到 http 版本,如果没有,说明是 http2 ,因为 http2 是采用二进制传输。 28 | 29 | -------------------------------------------------------------------------------- /Python/技巧/终端进度条.md: -------------------------------------------------------------------------------- 1 | 一般在下载文件或者处理耗时任务时,会需要在终端中展示进度,并进行动态变更。 2 | 3 | 在终端中打印信息时,可以使用`\r`符号来将输出回到当前行首,这就使得后续的输出会覆盖当前行的内容了。 4 | 5 | 另外,Python 3 中的`print()`方法可以传入`sep`参数设置每个输出的分隔符(默认是空格),传入`end`参数设置本次输出结束后的结束符(默认是回车换行符),传入`flush`参数控制是否立即将内容刷新并输出(默认是先存到内容中)。 6 | 7 | 如下,就是一个动态展示进度条的方法: 8 | 9 | ```Python 10 | from time import sleep 11 | 12 | def progress(percent=0, width=30): 13 | left = width * percent // 100 14 | right = width - left 15 | print('\r[', '#' * left, ' ' * right, ']', f' {percent:.0f}%', sep='', end='', flush=True) 16 | 17 | for i in range(101): 18 | progress(i) 19 | sleep(0.1) 20 | ``` 21 | 22 | 展示效果如下: 23 | 24 | ![](http://cnd.qiniu.lin07ux.cn/markdown/3729329214-5d68e0aab3ff3.gif) 25 | 26 | 27 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript 阻止浏览器后退.md: -------------------------------------------------------------------------------- 1 | 浏览器的前进后退是属于 BOM 层面的操作,通过 JavaScript 并不能真正意义上的禁止浏览器的后退操作,但是可以通过一些方法来事实上实现即便触发了浏览器的后退操作,也不会退回到上一页的效果。 2 | 3 | 可以借助`history.pushState`来实现这种效果。思路如下: 4 | 5 | 1. 进入当前页面之后,向浏览历史中压入一个空的浏览历史; 6 | 2. 浏览器后退时触发的`popstate`事件处理函数中,再次压入一个空的浏览历史。 7 | 8 | 这样,浏览器就总会处于退出当前浏览历史,再次压入新的浏览历史的循环中。 9 | 10 | > 这种方式是需要浏览器的支持的。 11 | 12 | 具体的代码示例如下: 13 | 14 | ```JavaScript 15 | 22 | ``` 23 | 24 | > 参考:[利用js实现 禁用浏览器后退](https://blog.csdn.net/zc474235918/article/details/53138553) 25 | 26 | -------------------------------------------------------------------------------- /DB/MySQL/实用技巧/MySQL 行行比较.md: -------------------------------------------------------------------------------- 1 | 行行比较是 SQL92 规范中提出来的,MySQL 也已实现该功能。 2 | 3 | 行行比较常用于多组多个字段条件的查询,能够将`(... AND ...) OR (... AND ...) ...`方式的查询条件转换为 IN 查询条件。 4 | 5 | 例如,对于如下的表: 6 | 7 | ```sql 8 | CREATE TABLE `sys_user` ( 9 | `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', 10 | `user_name` varchar(32) DEFAULT NULL COMMENT 'name', 11 | `account` varchar(200) NOT NULL COMMENT 'account', 12 | PRIMARY KEY (`id`) 13 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='user'; 14 | ``` 15 | 16 | 对于如下的查询语句: 17 | 18 | ```sql 19 | SELECT * FROM sys_user WHERE (id=1 AND user_name='u1') OR (id=2 AND user_name = 'u2'; 20 | ``` 21 | 22 | 改为行行比较查询方式: 23 | 24 | ```sql 25 | SELECT * FROM sys_user WHERE (id, user_name) IN ((1, 'u1'), (2, 'u2')); 26 | ``` -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 数组去重的几种方式.md: -------------------------------------------------------------------------------- 1 | ### 1. array_unique() 2 | 3 | PHP 中提供了一个`array_unique()`方法可以用来移除一个数组的重复值,返回一个拥有唯一值的数组。 4 | 5 | ```php 6 | $arr = [1, 2, 3, 2, 1, 'four', 'five', 'five']; 7 | 8 | array_unique($arr); // [1, 2, 3, 'four', 'five']; 9 | ``` 10 | 11 | 但是,如果尝试用`array_unique()`函数来过滤一个大的数组里的重复值,会运行的较慢。 12 | 13 | ### 2. array_flip() 14 | 15 | `array_flip()`函数用来将数组的键和值互换,而 PHP 中数组的键是唯一的,利用这个特性,可以通过`array_flip()`函数来实现过滤数组中的重复值。 16 | 17 | ```php 18 | $arr = [1, 2, 3, 2, 1, 'four', 'five', 'five']; 19 | $arr = array_flip($arr); 20 | 21 | array_flip($arr); // [4 => 1, 3 => 2, 2 => 3, 5 => 'four', 7 => 'five'] 22 | 23 | array_keys($arr); // [1, 2, 3, 'four', 'five'] 24 | ``` 25 | 26 | 通过两次键值翻转,或者一次键值翻转和一次取数组键,即可实现对原数组的去重处理。 27 | 28 | 29 | -------------------------------------------------------------------------------- /杂项/微信/微信开发.md: -------------------------------------------------------------------------------- 1 | ### 动态设置分享 2 | 3 | 如果需要动态设置分享的内容,每次在更改分享的设置数据之后,都重新调用`wx.onMenuShareTimeline(data)`等方法即可。 4 | 5 | 6 | ### 接受微信发过来的数据 7 | 8 | 微信发过来的数据,在 PHP 中需要使用`$GLOBALS["HTTP_RAW_POST_DATA"]`来获取,而不能通过`$_POST`来获取。 9 | 10 | `$GLOBALS["HTTP_RAW_POST_DATA"]` 和`$_POST`基本相同,主要的区别在于: 11 | 如果 post 过来的数据不是 PHP 能够识别的(比如`text/xml`或者`soap`等等),可以用`$GLOBALS['HTTP_RAW_POST_DATA']`来接收,而用`$_POST`接收则可能会有问题。 12 | 13 | PHP 默认识别的数据类型是`application/x-www.form-urlencoded`标准的数据类型。 14 | 对形如`text/xml`的内容无法解析为`$_POST`数组,故保留原型,交给`$GLOBALS['HTTP_RAW_POST_DATA']`来接收。 15 | 16 | > 另外,还可以使用`file_get_contents("php://input")`来接。相比`$GLOBALS["HTTP_RAW_POST_DATA"]`,其对内存的压力更小,而且不需要设置`php.ini`配置文件。因为很多服务器会设置`register_globals`禁止,此时就不能用`$GLOBALS["HTTP_RAW_POST_DATA"]`了。 17 | 18 | 19 | -------------------------------------------------------------------------------- /Python/方法函数/字符串方法.md: -------------------------------------------------------------------------------- 1 | ### 1. len 字符串长度 2 | 3 | 该函数用于返回参数字符串的长度: 4 | 5 | ```python 6 | >>> s = 'supercalifragilisticexpialidocious' 7 | >>> len(s) 8 | 34 9 | ``` 10 | 11 | > 该函数还可以用于返回列表的长度。 12 | 13 | ### 2. format f-string 格式化字符串填充 14 | 15 | `format`方法可以结构化的处理字符串,也可以使用`f-string`方式来处理。 16 | 17 | 相比于常见的字符串格式符`%s`或`format()`方法,`f-string`直接在占位符中插入变量显得更加方便,也更好理解。 18 | 19 | > `f-string`是 Python 3.6 新增的方式。 20 | 21 | ```python 22 | user = "Jane Doe" 23 | action = "buy" 24 | 25 | print('User {} has logged in and did an action {}.'.format(user, action)) 26 | # User Jane Doe has logged in and did an action buy. 27 | 28 | print(f'User {user} has logged in and did an action {action}.') 29 | # User Jane Doe has logged in and did an action buy. 30 | ``` 31 | 32 | -------------------------------------------------------------------------------- /杂项/Chrome/Chrome 地址栏快捷搜索.md: -------------------------------------------------------------------------------- 1 | > 转摘:[这个 Chrome 地址栏的隐藏技能真是酷炫呢!](https://mp.weixin.qq.com/s/jeiSMon9AWMSOWWE7ab9zA) 2 | 3 | 4 | 任何支持搜索功能的网站都可以被添加成 Chrome 的搜索引擎,设置关键词以后就可以在地址栏快速启动它们。以添加必应词典为例: 5 | 6 | 1. 先打开必应词典的网站随便搜索一个单词,比如「apple」,然后复制地址栏网址。 7 | 8 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1531918970356.png) 9 | 10 | 2. 依次进入Chrome 设置 > 管理搜索引擎 > 添加,先自定义一个关键字,然后把刚刚复制的网址粘贴到网址那一栏,将上一步搜索的词汇「apple」替换成`%s`。 11 | 12 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1531919000941.png) 13 | 14 | > 后面那一截在这里可以不要,那么得到的`https://cn.bing.com/dict/search?q=%s`就是必应词典的查询网址,直接添加即可。 15 | 16 | 3. 设置好以后,就可以直接在 Chrome 地址栏输入上一步设置的关键字「cd」来进行必应查词了,依次输入 cd、空格、查询的单词,再回车跳转,出来的就是查词结果的页面。 17 | 18 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1531919180573.gif) 19 | 20 | 21 | -------------------------------------------------------------------------------- /CSS/小技巧/CSS flex 布局中 text-overflow 无效.md: -------------------------------------------------------------------------------- 1 | CSS 中设置一行元素超过指定长度之后自动隐藏,可以使用如下的样式: 2 | 3 | ```css 4 | .text-ellipsis { 5 | display: block; 6 | text-overflow: ellipsis; 7 | overflow-x: hidden; 8 | white-space: nowrap; 9 | } 10 | ``` 11 | 12 | 但是这种样式**只对有设置宽度的块级元素有效**,使用 flex 后不会显示。 13 | 14 | 这是由于,在 flex 中如果容器的宽度小于 flex item 本身的宽度,flex item 会拒绝收缩,除非给 flex item 的`min-width`、`max-width`或`width`指定一个值。所以,为了在 flex 布局中生效,可以为 flex item 设置一个最小宽度即可: 15 | 16 | ```css 17 | .text-ellipsis { 18 | display: block; 19 | text-overflow: ellipsis; 20 | overflow-x: hidden; 21 | white-space: nowrap; 22 | min-width: 0; 23 | } 24 | ``` 25 | 26 | > 参考:[Text not truncated with ellipsis](https://bugzilla.mozilla.org/show_bug.cgi?id=1086218#c4) 27 | 28 | 29 | -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 输出 a 到 z 之间的字符.md: -------------------------------------------------------------------------------- 1 | PHP 中没有单字符`char`数据类型,只有字符串`string`类型,但是 PHP 中依旧可以将一个字符串进行算术加减法运算,只是其结果和 C 语言中的结果有所出入。 2 | 3 | 如下的代码: 4 | 5 | ```php 6 | for ($c = 'a'; $c <= 'z'; $c++) { 7 | echo $c . "\n"; 8 | } 9 | ``` 10 | 11 | 上面的代码的输出结果是先输出`a`到`z`,然后继续输出`aa`到`yz`。 12 | 13 | 之所以会这样,是因为在 PHP 中,字符串的比较是按照字符串的顺序一个个的进行比较,而且比较的是每个字符的字典顺序。所以,`aa`到`yz`的字典顺序是**小于**`z`的,而`za`的字典顺序是是大于`z`的,于是程序一直运行到了`yz`然后就跳出循环了。 14 | 15 | 如果想循环出`a`到`z`的全部字符,那么可以结合`ord()`和`chr()`函数: 16 | 17 | ```php 18 | for ($i = ord('a'); $i <= ord('z'); $i++) { 19 | echo chr($i) . "\n"; 20 | } 21 | ``` 22 | 23 | 还可以使用数组的方式来实现: 24 | 25 | ```php 26 | $letters = range('a', 'z'); 27 | 28 | for ($i = 0; $i < count($letters); $i++) { 29 | echo $letters[$i] . "\n"; 30 | } 31 | ``` 32 | 33 | 34 | -------------------------------------------------------------------------------- /DB/MySQL/错误/MySQL 错误 1215.md: -------------------------------------------------------------------------------- 1 | ## 错误 2 | 3 | 向一个数据库中增加表的时候,正常;从这个表创建外键到其他表的时候,就遇到了问题,提示: 4 | 5 | ``` 6 | ERROR 1215 (HY000): Cannot add foreign key constraint 7 | ``` 8 | 9 | ## 原因 10 | 11 | 提示这个错误一般都是由于两个表创建外键的字段类型未能完全匹配,或者外键指向的字段不是自增字段或 Unique Index 字段。 12 | 13 | ## 解决 14 | 15 | 1. 首先检查两个表中做外键字段的类型。 16 | 如果类型不完全相同,则需要进行修改。需要注意的是,`int`类型有和没有`unsigned`标记是不相同的;字符如果长度不同也是不同的。 17 | 18 | 2. 检查外键指向的字段是否是自增主键或者唯一索引。 19 | > A foreign key can only reference a primary or unique column. 20 | 21 | 3. 如果还是没有问题,那么就要检查数据库的引擎和数据表的字符集。 22 | 使用`show create table table_name \G;`就可以查看到表创建时的引擎和字符集。 23 | 24 | 显示的结果类似如下: 25 | 26 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1495702369207.png) 27 | 28 | 可以从红框中的地方看到对应的表信息。 29 | 30 | 经过三步检查之后应该就能找到对应的问题了。 31 | 32 | -------------------------------------------------------------------------------- /Mac/杂项/macOS Mojave 深色和浅色模式混合.md: -------------------------------------------------------------------------------- 1 | > 转摘:[macOS Mojave黑暗深色模式混合改造:深色風格與淺色視窗結合](https://mrmad.com.tw/macos-mojave-dark-mode-mixed-light-mode) 2 | 3 | macOS Mojave 系统的深色模式会将系统上所有的 Dock、Finder、系统偏好设定和原生的内建程序都会变成深色底的风格,但是颜色太深会造成眼睛疲乏,可以将其改造成深色和浅色混合模式,类似上一代系统中的设定:导航栏、Dock 维持深色,系统内建应用不再使用深色底。 4 | 5 | ### 设置混合色模式 6 | 7 | 1. 在`系统偏好设置 --> 通用`中将外观改成`浅色`模式。 8 | 9 | 2. 在终端中执行指令:`defaults write -g NSRequiresAquaSystemAppearance -bool Yes` 10 | 11 | 3. 点击导航栏左上角中的 Apple Logo,选择最下面的`退出登录..`,登出当前账号。 12 | 13 | 4. 重新登录自己的账号。 14 | 15 | 5. 在`系统偏好设置 --> 通用`中将外观改成`深色`模式。 16 | 17 | 这样就会将系统自带的应用改成浅白色的底,而导航栏、Dock 却是深色的。 18 | 19 | ### 取消混合色模式 20 | 21 | 1. 在终端中执行指令:`defaults write -g NSRequiresAquaSystemAppearance -bool No` 22 | 23 | 2. 登出当前账号。 24 | 25 | 3. 重新登录账号。 26 | 27 | 这样就会重新变成全深色模式了。 28 | 29 | -------------------------------------------------------------------------------- /Nginx/问题/Nginx Etag 改变了是否意味着文件发生了变化.md: -------------------------------------------------------------------------------- 1 | > 转摘:[面试官:如果 http 响应头中 ETag 值改变了,是否意味着文件内容一定已经更改](https://segmentfault.com/a/1190000021273854) 2 | 3 | ### 1. 解答 4 | 5 | Nginx 响应中的 HTTP Etag 头发生了变化时,并不一定意味着对应的文件也发生了变化。 6 | 7 | Nginx 的 Etag 的值是由文件的`last_modified`和响应的`content_length`组成,而`last_modified`又由`mtime`组成。当编辑文件却未更改文件内容时,其`mtime`也会改变,此时文件内容未发生变化而 Etag 的值却改变了。 8 | 9 | ### 2. 为什么使用`mtime`而不是`ctime` 10 | 11 | 文件系统中,一个文件有`mtime`和`ctime`两个时间。 12 | 13 | 在 Linux 系统中: 14 | 15 | * `mtime`表示`modified time`,也就是文件内容改变的时间戳。 16 | * `ctime`表示`change time`,也就是指文件属性改变的时间戳,这些属性包括`mtime`。 17 | 18 | 在 Windows 系统中: 19 | 20 | * `mtime`和 Linux 系统中的`mtime`一样 21 | * `ctime`表示的则是`creation time`,也就是文件的创建时间。 22 | 23 | 所以文件的`mtime`属性才能正确的反应文件内容是否发生了变化。由此属性生成的 Etag 才能更好的反应文件是否需要更新。 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /PHP/ThinkPHP/ThinkPHP 自动验证 多字段验证bug.md: -------------------------------------------------------------------------------- 1 | ThinkPHP 在设置自动验证的时候,如果需要同时根据两个或多个字段来进行验证,可以使用如下的多字段验证: 2 | 3 | ```php 4 | protected $_validate = array( 5 |      array('field1,field2', 'check', '错误提示', 0, 'callback', 3), 6 | ); 7 | ``` 8 | 9 | 但是上面的代码并不会调用`check`方法进行自动验证,只有当字段为 1 个的时候才会正常。 10 | 11 | 解决的方法是: 12 | 13 | * 将第 4 个参数设置为 1(也就是必须验证); 14 | * 或者,修改 ThinkPHP 核心文件进行修复。 15 | 16 | ```php 17 | // TP多字段验证存在BUG: 18 | // 在“值不为空时才验证”和“存在该字段就验证”的情况下,多字段验证不会激活 19 | // 这是因为获取data字段值的时候,检查时使用的数组索引是字符串'field1,field2' 20 | // 这边临时解决的方法是只检查第一个字段是否存在或者不为空。 21 | // if(isset($data[$val[0]]))         原代码 22 | $fields = explode(",",$val[0]);   // 新代码 23 | if(isset($data[$fields[0]]))      // 新代码 24 | ``` 25 | 26 | 转摘:[thinkphp 自动验证 多字段验证BUG](http://www.thinkphp.cn/topic/9640.html) 27 | 28 | 29 | -------------------------------------------------------------------------------- /Mac/问题/Mac zsh scp 命令使用 * 通配符无法匹配.md: -------------------------------------------------------------------------------- 1 | > 转摘:[zsh使用scp命令时*通配符无法使用](https://blog.webfsd.com/post_zshscp.html) 2 | 3 | Mac 中,使用 zsh 终端时,scp 命令无法使用通配符来匹配所有的相关文件,如: 4 | 5 | ```shell 6 | scp host:~/*.conf . 7 | # 提示错误如下: 8 | # zsh: no matches found: host:~/*.conf 9 | ``` 10 | 11 | 但是这条命令在 bash 中是可以正常工作的,出现这个问题是 zsh 的解析错误:zsh 试图将`*`通配符展开,在本地查找文件,由于本地没有对应的文件,所以就出现了 no matches 的错误。 12 | 13 | 有两种方式可以解决这个问题: 14 | 15 | 1. 不要让 zsh 将通配符展开:将路径用引号(单引号和双引号都可以)包裹起来,或者使用转义。比如,可以将上面的命令改写成下面的方式: 16 | 17 | ```shell 18 | scp host:~/\*.conf . 19 | scp host:"~/*.conf" . 20 | scp "host:~/*.conf" . 21 | ``` 22 | 23 | 2. 设置`nonomatch`选项,让 zsh 在匹配失败时不报错,并使用原本的内容: 24 | 25 | ```shell 26 | setopt nonomatch 27 | ``` 28 | 29 | 也可以将这个设置写入到`.zshrc`配置文件,让以后使用时自动生效。 30 | 31 | -------------------------------------------------------------------------------- /Linux/Service/Memcached.md: -------------------------------------------------------------------------------- 1 | ## 配置 2 | 3 | Memcached 的配置文件位于`/etc/sysconfig/memcached`,修改之后,重启 Memcached 服务即可。默认的配置文件的内容如下: 4 | 5 | ```conf 6 | PORT="11211" 7 | USER="memcached" 8 | MAXCONN="1024" 9 | CACHESIZE="64" 10 | OPTIONS="" 11 | ``` 12 | 13 | > 可以通过`ps -ef | grep memcached`查看启动参数。 14 | 15 | 为了安全,一般建议修改 Memcached 的端口,避免被利用。另外,还有如下的方式来进行加固: 16 | 17 | ### 监听在本机 18 | 19 | Memcached 默认情况下,如果不指定`-l`参数,则会监听在`0.0.0.0`地址上,这样会让外部也能访问,一般可以将其固定监听在某个内网 IP 上,增加其安全性,或者可以直接设置成`127.0.0.1`来监听本机即可。 20 | 21 | > 这个配置可以写在 Memcached 配置文件中的`OPTIONS`中。 22 | 23 | ### 关闭 UDP 24 | 25 | Memcached 在 1.5.6 版本之后默认关闭 UDP,但是之前的版本需要手动关闭 UDP。因为目前 Memcached 的 UDP 开启时,如果没有做好防护措施,会被用来进行反射攻击,消耗服务器的出网带宽和 CPU 资源。 26 | 27 | 关闭 UDP 很简单,就是增加一个参数即可:`-U 0`。 28 | 29 | > 这个配置可以写在 Memcached 配置文件中的`OPTIONS`中。 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /DB/MySQL/设置/自动备份.md: -------------------------------------------------------------------------------- 1 | 借助 Crontab 服务,可以使用如下的脚本实现每天自动备份 MySQL 数据: 2 | 3 | ```shell 4 | #!/bin/bash 5 | 6 | # 数据库认证 7 | user="" 8 | password="" 9 | host="" 10 | db_name="" 11 | 12 | # 路径 13 | backup_path="/path/to/your/backup" 14 | date=$(date +"%d-%b-%Y") 15 | 16 | # 设置导出文件的缺省权限 17 | umask 177 18 | 19 | # Dump 数据库到 SQL 文件 20 | mysqldump --user=$user --password=$password --host=$host $db_name > $backup_path/$db_name-$date.sql 21 | 22 | # 删除30天之前的就备份文件 23 | find $backup_path/* -mtime +30 -exec rm {} \ 24 | ``` 25 | 26 | 通过上面的脚本,可以每天导出一份 sql 备份文件,文件的名称按当日日期生成,并删除一些老旧的备份的文件。 27 | 28 | 如果 Crontab 定时执行脚本导出没有报错,但导出的是空的 SQL 文件,登录到控制台手工执行这个脚本是备份成功的,一般是由于 Crontab 执行脚本是缺少系统环境信息,找不到 mysqldump ,改正的方法是使用 mysqldump 全路径就行了。 29 | 30 | > 之所以没有报错信息,是因为 mysqldump 把错误信息输出到了 stderr。 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /DB/MySQL/错误/MySQL 错误 1290.md: -------------------------------------------------------------------------------- 1 | ## 错误 2 | 在执行类似下面的 sql 导出部分数据到文件中的时候,会发生错误: 3 | 4 | ```sql 5 | select * from course into outfile 'course.bak'; 6 | ``` 7 | 8 | 错误提示为: 9 | 10 | ``` 11 | ERROR 1290 (HY000): The MySQL server is running with the --secure-file-priv option so it cannot execute this statement 12 | ``` 13 | 14 | ## 原因 15 | 这是由于 MySQL 设置了安全文件夹选项的缘故。开启该选项后,导出数据到文件的时候,仅能将导出文件的路径设置为安全文件夹中。 16 | 17 | ## 解决 18 | 首先执行如下的命令,查看安全文件夹的设置: 19 | 20 | ```sql 21 | show variables like '%secure%'; 22 | ``` 23 | 24 | 会看到类似如下的设置: 25 | 26 | 27 | 28 | 其中`secure_file_priv`对应的值即为安全路径。在导出的时候,将导出文件的路劲前缀改成这个即可。 29 | 30 | 比如: 31 | 32 | ```sql 33 | select * from course into outfile '/var/lib/mysql-files/course.bak'; 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /CSS/属性/cursor.md: -------------------------------------------------------------------------------- 1 | 摘自:[CSS秘密花园: 挑选合适的光标](http://www.w3cplus.com/css3/css-secrets/picking-the-right-cursor.html) 2 | 3 | 鼠标指针的意义并不仅仅是为了显示目前屏幕上的光标在何处,还是为了告诉用户可以进行哪些交互动作。 4 | 5 | ### 光标类别 6 | 7 | 目前,CSS 中有如下一些光标,其中,后者是新增的光标: 8 | 9 | ![css-cursor-01](http://cnd.qiniu.lin07ux.cn/2016-04-13%20css-cursor-01.png) 10 | 11 | ![css-cursor-02](http://cnd.qiniu.lin07ux.cn/2016-04-13%20css-cursor-02.png) 12 | 13 | ### 隐藏光标 14 | 15 | 在些情景下,也需要隐藏掉光标,如,那些用于消息展示和机上娱乐的东西,或者是观看视频时。 16 | 17 | 在 CSS 2.1 中是可以使用一个透明的 1x1 的透明 GIF 图来隐藏光标,如下: 18 | 19 | ```css 20 | video { 21 | cursor: url(transparent.gif); 22 | } 23 | ``` 24 | 25 | 现在,可以直接设置元素的光标为 none 即可:`cursor: none;`。不过,为了兼容和优雅降级,一般可以如下设置: 26 | 27 | ```css 28 | video { 29 | cursor: url('transparent.gif'); 30 | cursor: none; 31 | } 32 | ``` 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Go/packages/Go bufio.md: -------------------------------------------------------------------------------- 1 | `bufio`包对输入输出的处理方便又高效。 2 | 3 | ## 一、类型 4 | 5 | ### 1.1 Scanner 6 | 7 | `Scanner`是`bufio`包中最有用的特性之一,它可以读取输入,并将其拆分成行或单词,通常这是处理行形式的输入最简单的方法。 8 | 9 | 每次调用`Scanner.Scan()`方法就会读入下一行,并移除行末的换行符;读取到的内容可以通过`Scanner.Text()`得到。如果读取完全部的输入,则`Scanner.Scan()`方法就会返回 false,否则会返回 true。 10 | 11 | 比如,下面的代码可以从标准输入中读取每一行的内容: 12 | 13 | ```go 14 | package main 15 | 16 | import ( 17 | "bufio" 18 | "fmt" 19 | "os" 20 | ) 21 | 22 | func main() { 23 | counts := make(map[string]int) 24 | input := bufio.NewScanner(os.Stdin) 25 | 26 | for input.Scan() { 27 | counts[input.Text()]++ 28 | } 29 | 30 | fmt.Println() 31 | 32 | // Note: ignore potential errors from input.Err() 33 | for line, n := range counts { 34 | if n > 1 { 35 | fmt.Printf("%d\t%s\n", n, line) 36 | } 37 | } 38 | } 39 | ``` 40 | 41 | -------------------------------------------------------------------------------- /Nginx/正向代理与反向代理定义.md: -------------------------------------------------------------------------------- 1 | ### 正向代理 2 | 3 | 以访问 google.com 为例: 4 | 5 | 6 | 7 | 如上图,因为 google 被墙,我们需要 vpn 翻墙才能访问 google.com。vpn 对于“我们”来说,是可以感知到的(我们连接 vpn),但对于"google服务器"来说,是不可感知的(google 只知道有 http 请求过来)。 8 | 9 | **对于人来说可以感知到,但服务器感知不到的服务器,我们叫他正向代理服务器。** 10 | 11 | ### 反向代理 12 | 13 | 以访问 baidu.com 为例: 14 | 15 | 16 | 17 | 我们访问 baidu.com 的时候,baidu 有一个代理服务器,通过这个代理服务器,可以做负载均衡,路由到不同的 server。 18 | 19 | 此代理服务器,对于“我们”来说是不可感知的(我们只能感知到访问的是百度的服务器,不知道中间还有代理服务器来做负载均衡)。但是对于"server1 server2 server3"是可感知的(代理服务器负载均衡路由到不同的 server)。 20 | 21 | **对于人来说不可感知,但对于服务器来说是可以感知的,我们叫他反向代理服务器。** 22 | 23 | ### 总结 24 | 25 | “正向”、“反向”是相对于人的感知来说的。 26 | 27 | 人能感受到的代理就是正向代理,人感受不到的代理就是反向代理。 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /杂项/Postman/Postman Response.md: -------------------------------------------------------------------------------- 1 | `pm.response`变量用于引用当前的响应数据。 2 | 3 | ## 一、格式化响应数据 4 | 5 | * Text 6 | 7 | ```JavaScript 8 | const responseText = pm.response.text(); 9 | ``` 10 | 11 | * JSON 12 | 13 | ```JavaScript 14 | const responseJson = pm.response.json(); 15 | ``` 16 | 17 | > 如果响应数据不是有效的 JSON 字符串,则会抛出异常 18 | 19 | * XML 20 | 21 | ```JavaScript 22 | const responseJson = xml2Json(pm.response.text()); 23 | ``` 24 | 25 | * CSV 26 | 27 | ```JavaScript 28 | const parse = require('csv-parse/lib/sync'); 29 | const responseJson = parse(pm.response.text()); 30 | ``` 31 | 32 | * HTML 33 | 34 | ```JavaScript 35 | const $ = cheerio.load(pm.response.text()); 36 | // output the html for testing 37 | console.log($.html()); 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /Python/方法函数/数学方法.md: -------------------------------------------------------------------------------- 1 | ### 1. divmod 获取除法的商和余数 2 | 3 | 使用`divmod(num1, num2)`可以计算 num1 除以 num2 后得到的商和余数。 4 | 5 | ```shell 6 | >>> divmod(5, 2) #表示5除以2,返回了商和余数 7 | (2, 1) 8 | >>> divmod(9, 2) 9 | (4, 1) 10 | >>> divmod(5.0, 2) 11 | (2.0, 1.0) 12 | ``` 13 | 14 | ### 2. round 四舍五入 15 | 16 | `round(num, length)`可以使用四舍五入法则保留参数 num 的指定位数的小数。 17 | 18 | ```shell 19 | >>> round(1.234567, 2) 20 | 1.23 21 | >>> round(1.234567, 3) 22 | 1.235 23 | >>> round(10.0/3, 4) 24 | 3.3333 25 | >>> round(1.234) 26 | 1.0 27 | >>> round(1.2345, 3) 28 | 1.234 # 应该是:1.235 29 | >>> round(2.235, 2) 30 | 2.23 # 应该是:2.24 31 | ``` 32 | 33 | 可以看到,最后的两个四舍五入并不符合预期,这是由于二进制与十进制之间的转换造成的。 34 | 35 | ### 3. abs 绝对值 36 | 37 | `abs()`获取数值的绝对值。 38 | 39 | ```shell 40 | >>> abs(10) 41 | 10 42 | >>> abs(-10) 43 | 10 44 | >>> abs(-1.2) 45 | 1.2 46 | ``` 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Python/知识点/Python 可迭代解包.md: -------------------------------------------------------------------------------- 1 | Python 3.8 中对可迭代对象的解包语法进行了增强,使其可以设置一个接收所有解包之后的剩下的未赋值给常规命名的值。具体可以参看:[PEP 3132 -- Extended Iterable Unpacking](https://www.python.org/dev/peps/pep-3132/)。 2 | 3 | 具体示例如下: 4 | 5 | ```Python 6 | a, *b, c = range(5) 7 | a # 0 8 | c # 4 9 | b # [1, 2, 3] 10 | 11 | *a, = range(5) 12 | a # [0, 1, 2, 3, 4] 13 | 14 | for a, *b in [(1, 2, 3), (4, 5, 6, 7)]: 15 | print(b) 16 | # [2, 3] 17 | # [5, 6, 7] 18 | ``` 19 | 20 | 也可以将可迭代解包语法运行的结果直接用在`return`和`yield`语句中,这在 Python 3.8 之前是不可行的: 21 | 22 | ```Python 23 | def a(): 24 | rest = (4, 5, 6) 25 | return 1, 2, 3, *rest 26 | 27 | def b(): 28 | rest = (4 , 5, 6) 29 | yield 1, 2, 3, *rest 30 | 31 | for i in b(): 32 | print(i) 33 | 34 | # 1, 2, 3, 4, 5, 6 35 | ``` 36 | 37 | 这段代码在 Python 3.8 之前会抛出 SyntaxError 错误,而 Python 3.8 解决了这个 bug。 38 | 39 | -------------------------------------------------------------------------------- /Mac/SSH/SCP 通过 ssh 拷贝本地文件到远程服务器.md: -------------------------------------------------------------------------------- 1 | 在命令行中,可以通过 scp 命令将本地的文件或目录拷贝到远程服务器上,也可以将远程服务器上的文件或目录拷贝下载到本地。 2 | 3 | ### 命令格式 4 | 5 | 命令格式如下: 6 | 7 | ```shell 8 | # 拷贝本地文件到远程 9 | scp @: 10 | 11 | # 拷贝远程文件到本地 12 | scp @: 13 | 14 | # 将本地目录拷贝到远程 15 | scp -r @: 16 | 17 | # 从远程将目录拷回本地 18 | scp -r @: 19 | ``` 20 | 21 | 在执行拷贝的时候,会提示输入登录远程服务器的用户的密码。 22 | 23 | ### 示例 24 | 25 | 比如,下面的命令将本地的`root`目录下的所有以`install.`开头的文件都拷贝到远程的`/usr/local/src`目录中: 26 | 27 | ```shell 28 | scp /root/install.* root@192.168.1.12:/usr/local/src 29 | ``` 30 | 31 | 下面的命令将远程`/usr/local/src`目录中的文件都下载到本地的`root`目录中。 32 | 33 | ```shell 34 | scp root@192.168.1.12:/usr/local/src/*.log /root/ 35 | ``` 36 | 37 | 38 | -------------------------------------------------------------------------------- /Git/技巧/Git 回滚远程版本并删除提交日志.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | 远程 master 分支下代码被不小心提交了很多垃圾代码或项目删掉,想要回滚到以前的某一版本并删除 commit log。怎么办? 4 | 5 | > 情景举例:老板上传了个文件,我把他删掉了。但是这个不该删除。我们可以把文件再 push 下,但是这样会留下 commit log,发现了会被 fire 的 :(。 6 | 7 | 上面场景的代码如下: 8 | 9 | ```shell 10 | vim A.txt 11 | git add . 12 | git commit -a -m "add A.txt" 13 | git push 14 | rm A.txt 15 | git commit -a -m "我删除了老板的东西" 16 | git push 17 | ``` 18 | 19 | ### 解决方案 20 | 21 | push 到远程的提交默认是不能修改的,但是一定要修改不是不行:`git push -f`。 22 | 23 | 简单来说,要解决上述场景的问题,首先是需要回退版本到删除之前的状态,然后再将删除前的版本强制提交到远程仓库,这样就完成了撤销删除和消除 commit log 的目的。 24 | 25 | 实际操作如下: 26 | 27 | ```shell 28 | # 查看 git 的提交日志,找到要回滚的版本 29 | git log 30 | # 重置到删除前的版本,--soft 将之前的修改退回到暂存区 31 | # hard 参数:修改记录都没了。soft 参数:则会保留修改记录 32 | git reset --soft ${commit-id} 33 | # 暂存,为了保险 34 | git stash 35 | # 将本地 master push 到远程版本库中, -f 强制覆盖 36 | git push -f 37 | ``` 38 | 39 | -------------------------------------------------------------------------------- /JavaScript/问题/JavaScript Math.min() 为什么比 Math.max() 大.md: -------------------------------------------------------------------------------- 1 | #对于下面的代码,输出却是`false`: 2 | 3 | ```javascript 4 | var min = Math.min(); 5 | var max = Math.max(); 6 | console.log(min < max); 7 | ``` 8 | 9 | 查看 MDN 文档可以发现,`Math.min()`和`Math.max()`都可以接受 0 个或者多个参数: 10 | 11 | * 如果传入多个参数,有任何一个不能转成数字,那么就返回 NaN,否则返回其中的最小值/最大值 12 | * 如果传入 0 个参数,则分别会返回**`Infinity`和`-Infinity`**,也即是分别返回 JavaScript 中的最大的正数,和最小的负数。 13 | 14 | 所以,不传入参数的时候,`Math.min()`是比`Math.max()`大的。 15 | 16 | 那么,为什么会这样呢?`min`不是应该返回最小值吗?`max`不是应该返回最大值吗?其实这个和代码的实现有关。 17 | 18 | 一般我们比较数值的大小的时候,会设置一个初始标准值。比如,`Math.min()`需要将其参数和一个标准值来进行比较,较小的值作为中间结果,然后将中间结果与下一个参数继续比较,这样最终的最小值就是结果了。可以考虑如下的一个填空题: 19 | 20 | ```javascript 21 | var min = ___; 22 | arr.forEach(function(n) { 23 | if (n > min) { 24 | min = n; 25 | } 26 | }); 27 | ``` 28 | 29 | 自然,这里我们应该讲`min`变量设置初始值为`Infinity`才能符合实际情况。 30 | 31 | -------------------------------------------------------------------------------- /Linux/Command/tail.md: -------------------------------------------------------------------------------- 1 | tail 命令可以查看文件的内容,并默认输出到标准输出中。利用该命令可以监听文件的变动,并实时的输出最新的内容,方便的查看最新日志。 2 | 3 | ### 选项 4 | 5 | #### 1. -f 和 -F 的区别 6 | 7 | 这两个选项都可以用来指定一直监听文件,即便已经到达文件末尾了。不同点在于: 8 | 9 | * `-f` 根据文件描述符进行追踪,即便文件被重命名,也会继续监听重命名后的文件; 10 | * `-F` 根据文件名进行追踪,如果文件被重命名,那么会继续尝试重新监听指定的名称的文件。 11 | 12 | 比如,对一个日志文件,想每天都重新生成一个文件来记录,可以通过定时方式,将日志文件重命名,然后新建一个空的日志文件的方式来实现,对应如下的操作: 13 | 14 | ```shell 15 | mv access.log access-2020-11-05.log 16 | touch access.log 17 | ``` 18 | 19 | 如果使用`-f`和`-F`分别来监听 access.log 文件,再执行上面的命令的过程中,两者的表现就会出现差异了: 20 | 21 | * `-f` 使用该选项的时候,重命名文件之前会监听 access.log 文件的变动;重命名之后,会监听重命名后的 access-2020-11-05.log 文件的变动; 22 | * `-F` 使用该选项的时候,重命名文件之前会监听 access.log 文件的变动;重命名之后,会重试对 access.log 文件的监听;新创建 access.log 文件之后,会自动继续监听新的 access.log 文件的变动。 23 | 24 | > 转摘:[别小看tail 命令,它难倒了技术总监](https://mp.weixin.qq.com/s/q7zRiye8ufX34ayGKjy1Rw) 25 | 26 | 27 | -------------------------------------------------------------------------------- /Python/虚拟环境/Python 虚拟环境中使用 Git.md: -------------------------------------------------------------------------------- 1 | 在 Python 项目中,如果使用了虚拟环境,则一般会有单独的虚拟环境目录和文件,而且项目所需的依赖也都在虚拟环境中。此时使用 Git 进行版本控制的时候,虚拟环境和依赖如何管理也就需要考虑了。 2 | 3 | 有三种可能的方案: 4 | 5 | * 将虚拟环境也添加到 Git 里面 6 | * 用`.gitignore`忽略掉 venv 目录 7 | * 用 venv 建立一个大的目录,然后在下面建立项目子目录,Git 只管理这个子目录 8 | 9 | 由于虚拟环境和库依赖在不同的环境中会有所不同,如果直接使用 Git 追踪全部的虚拟环境文件和库依赖,那么会造成部署项目到其他机器时,可能无法正常运行。如果不追踪虚拟环境目录,那么需要有一个方法能够知道该项目所需要的库依赖有哪些,否则否则正常部署了。 10 | 11 | 综合考虑,推荐使用如下的最佳实践方式: 12 | 13 | 1. 不追踪虚拟环境目录和文件; 14 | 2. 使用`pip freeze > requirements.txt`将依赖都添加到`requirements.txt`文件中,包含依赖的版本信息; 15 | 3. 部署项目时,重建虚拟环境,并通过`pip install -r requirements.txt`来安装所需的依赖。 16 | 17 | > 参考:[When working with a venv virtual environment, which files should I be commiting to my git repository?](https://stackoverflow.com/questions/45394653/when-working-with-a-venv-virtual-environment-which-files-should-i-be-commiting) 18 | 19 | 20 | -------------------------------------------------------------------------------- /Linux/Command/rsync.md: -------------------------------------------------------------------------------- 1 | ### 1. cp & scp 2 | 3 | `cp`命令可以在单机上进行复制,`scp`命令则可以实现跨机器复制,比如: 4 | 5 | ```shell 6 | scp -Crvp -l 1024 logs/ root@remoteserver:/opt/logs 7 | ``` 8 | 9 | 其中, 10 | 11 | * `-C`表示压缩 12 | * `-r`是循环传输整个目录 13 | * `-p`表示保留源文件的一些属性 14 | * `-l`表示限制带宽,单位是 kb/s 15 | * `-v` 表示显示详细信息 16 | 17 | ### 2. rsync 18 | 19 | scp 命令虽然好用,但是如果传输的文件非常的大,比如每天上 T 的日志文件,不可能每次都把这些文件重新传输一遍,所以采用增量备份会成为一个首要的需求。当然,如果在传入过程中,能够排除一些文件,就更好了。 20 | 21 | 这就是 rsync 命令的适用场景了,例如: 22 | 23 | ```shell 24 | rsync -prz --exclude 'bin' --bwlimit=1024 logs/ root@remoteserver:/opt/logs 25 | ``` 26 | 27 | 同样的: 28 | 29 | * `-r` 表示递归 30 | * `-p` 表示保留属性 31 | * `-z` 表示开启压缩 32 | * `--bwlimit` 表示限制带宽 33 | * `--exclude` 指定要忽略的文件 34 | * `--progress` 显示拷贝的进度 35 | 36 | 当然,rsync 和 scp 两者还是有点小区别的: 37 | 38 | * rsync 默认是只拷贝有变动的文件,scp 则是全量拷贝,所以 rsync 很适合做增量备份; 39 | * scp 是加密传输,而 rsync 不是。 40 | 41 | 42 | -------------------------------------------------------------------------------- /PHP/PHP Const 常量.md: -------------------------------------------------------------------------------- 1 | ### DIRECTORY_SEPARATOR 2 | 3 | DIRECTORY_SEPARATOR 是一个返回跟操作系统相关的路径分隔符的 php 内置命令,在 windows 上返回`\`,而在 linux 或者类 unix 上返回`/`,就是这么个区别,通常在定义包含文件路径或者上传保存目录的时候会用到。 4 | 5 | 虽然在 Window 中也能够将`/`识别为路径分隔符,但是有时候也会出现问题。所以建议使用该常量。 6 | 7 | ### 其他 8 | 9 | * `__FILE__` 当前 PHP 文件的相对路径 10 | * `__LINE__` 当前 PHP 文件中所在的行号 11 | * `__FUNCTION__` 当前函数名,只对函数内调用起作用 12 | * `__CLASS__` 当前类名,只对类起作用 13 | * `__METHOD__` 表示类方法名,比如 B::test 14 | * `PHP_VERSION` 当前使用的 PHP 版本号 15 | * `PHP_OS` 当前 PHP 环境的运行操作系统 16 | * `E_ERROR` 最近的错误之处 17 | * `E_WARNING` 最近的警告之处 18 | * `E_PARSE` 剖析语法有潜在问题之处 19 | * `$_SERVER` 返回服务器相关信息,返回一个数组 20 | * `$_GET` 所有 GET 请求过来的参数 21 | * `$_POST` 所有 POST 过来的参数 22 | * `$_COOKIE` 所有 HTTP 提交过来的 cookie 23 | * `$_FILES` 所有 HTTP 提交过来的文件 24 | * `$_ENV` 当前的执行环境信息 25 | * `$_REQUEST` 相当于`$_POST`、`$_GET`、`$_COOKIE`提交过来的数据,因此这个变量不值得信任 26 | * `$_SESSION` session 会话变量 27 | 28 | -------------------------------------------------------------------------------- /JavaScript/问题/Babel 相关.md: -------------------------------------------------------------------------------- 1 | ### 1. (0, _classCallCheck3.default)(this, Person) 2 | 3 | 通过`transform-runtime`插件转换类之后,会出现类似下面的代码: 4 | 5 | ```js 6 | var Person = function Person() { 7 | (0, _classCallCheck3.default)(this, Person); 8 | }; 9 | ``` 10 | 11 | 这里奇怪的是为什么要写成`(0, _classCallCheck3.default)(this, Person);`。 12 | 13 | 首先,对于这个语句,第一个括号中的语句会按照 [comma operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator) 来执行,也就是先执行语句`0`,再执行语句`_classCallCheck3.default`,最终这个括号的返回值是最后一个语句的返回值,也就是函数`_classCallCheck3.default`。 14 | 15 | 然后,第一个括号执行完成之后,得到一个函数。函数后跟随一个小括号就是立即执行该函数。 16 | 17 | 那么,整个语句的作用就是调用`_classCallCheck3.default`函数。 18 | 19 | 为什么要这样调用呢?其实这是一个小技巧,为了能够在调用`_classCallCheck3.default`函数时,`this`不会指向其自身。 20 | 21 | 也就说,这个语句的作用,和下面的代码相同: 22 | 23 | ```js 24 | const func = _classCallCheck3.default; 25 | func(this, Person); 26 | ``` 27 | 28 | -------------------------------------------------------------------------------- /Linux/Shell/Shell 脚本中切换用户.md: -------------------------------------------------------------------------------- 1 | 在 Shell 脚本中,会遇到切换到其他用户执行命令的情况,甚至,使用某个无权登录的用户执行命令。此时可以使用`su`命令来切换,但在 Shell 脚本中,会有一些其他的需要注意的地方。 2 | 3 | > `su`命令一般用于切换登录用户,比如使用`su root`就可以从当前用户切换到`root`用户,使用`root`账户来登录系统。 4 | > 5 | > 如果切换到指定的用户需要验证,那么就需要输入密码以便完成切换。所以一般情况下,会在当前用户是`root`的时候使用。 6 | 7 | ### 1. 不切换用户,使用指定用户执行命令: 8 | 9 | ```shell 10 | su - username -c "command" 11 | ``` 12 | 13 | 这表示,切换到用户`username`的登录状态,并执行命令`command`,执行完成之后,切换回当前的用户。 14 | 15 | ### 2. 不重置登录环境指定用户执行命令: 16 | 17 | ```shell 18 | su -m username -c 'command' 19 | ``` 20 | 21 | 这种和上面基本相同,不同的地方在于,这种方式可以使用不能登录系统的用户来执行命令。 22 | 23 | ### 3. 批量执行命令 24 | 25 | 如果需要切换用户,然后执行多个命令,使用`-c`选项可能就不太方便,此时可以使用 heredoc 方式来写多条命令进行执行。 26 | 27 | ```shell 28 | su - username << 更多`filter_var()`函数的参数,可以参考 [PHP 官方文档](http://php.net/manual/zh/filter.filters.validate.php) 28 | 29 | -------------------------------------------------------------------------------- /DB/MySQL/设置/MySQL 时区设置.md: -------------------------------------------------------------------------------- 1 | MySQL 的时区默认是其所在服务器的时区,所以一般直接设置服务器的时区和时间即可。 2 | 3 | 可以通过以下命令查看 MySQL 的时区: 4 | 5 | ```sql 6 | mysql> show variables like '%time_zone%'; 7 | +------------------+--------+ 8 | | Variable_name | Value | 9 | +------------------+--------+ 10 | | system_time_zone | CST | 11 | | time_zone | SYSTEM | 12 | +------------------+--------+ 13 | ``` 14 | 15 | 如果要修改,可以通过修改`my.cnf`配置文件来实现: 16 | 17 | - 方法一: 18 | 19 | 在`[mysqld]`之下加`default-time-zone=timezone`来修改时区。 20 | 21 | 如:`default-time-zone = '+8:00'` 22 | 23 | > 改了记得重启 msyql。 24 | > 注意:一定要在`[mysqld]`之下加 ,否则会出现`unknown variable 'default-time-zone=+8:00'`。 25 | 26 | - 方法二: 27 | 28 | 另外也可以通过命令`set time_zone = timezone`在 mysql 中直接修改。 29 | 30 | 比如北京时间(GMT+0800)`set time_zone = '+8:00';` 31 | 32 | 这个和 php 的时区设置格式又有点差别,比如北京时间在 php 中是`date_default_timezone_set('Etc/GMT-8');` 33 | 34 | -------------------------------------------------------------------------------- /PHP/Laravel/Laravel Fluent 注释.md: -------------------------------------------------------------------------------- 1 | `src/Illuminate/Support/Fluent.php` 2 | 3 | 4 | ```php 5 | /** 6 | * Class Fluent 7 | * 8 | * @package Illuminate\Support 9 | * @method $this after($column) 将该列置于另一个列之后(MySQL) 10 | * @method $this autoIncrement() 设置 INTEGER 列为自增主键 11 | * @method $this charset($charset) 指定数据列字符集(MySQL) 12 | * @method $this collation($collation) 指定数据列字符序(MySQL/SQL Server) 13 | * @method $this comment($comment) 添加注释信息 14 | * @method $this default($value) 指定列的默认值 15 | * @method $this first() 将该列置为表中第一个列 - MySQL 16 | * @method $this nullable($value = true) 允许该列的值为 NULL 17 | * @method $this storedAs($expression) 创建一个存储生成列(MySQL) 18 | * @method $this unsigned() 设置 INTEGER 列为 UNSIGNED(MySQL) 19 | * @method $this useCurrent() 设置 TIMESTAMP 列使用 CURRENT_TIMESTAMP 作为默认值 20 | * @method $this virtualAs($expression) 创建一个虚拟生成列(MySQL) 21 | */ 22 | ``` 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /计算机与网络/二进制原码与补码.md: -------------------------------------------------------------------------------- 1 | 计算机中,负数的二进制表示使用的是其补码,正数使用的就是原码。 2 | 3 | 原码即按照正常的方式将一个十进制正数转成二进制,如 4,转成二进制为`00000100`。 4 | 5 | 补码则是在十进制负数的绝对值的原码的基础上取反之后加 1。比如: 6 | 7 | * `-1`:1 的原码表示是`00000001`,取反是`11111110`,然后再加 1,就是`11111111`。 8 | * `-2`:2 的原码表示是`00000010`,取反是`11111101`,然后再加 1,就是`11111110`。 9 | * `-127`:127 的原码表示是`01111111`,取反是`10000000`,然后再加 1,就是`10000001`。 10 | 11 | 给定一个负数二进制表示,要想知道它的十进制值,可以采用相同的补码运算。比如:`10010010`,首先取反,变为`01101101`,然后减 1,结果为`01101110`,它的十进制值为 110,所以原值就是 -110。 12 | 13 | 之所以负数采用补码的形式表示,是因为计算机只能做加法,如`1-1`其实就是`1+(-1)`,如果负数采用原码(最高位置1),那么计算就会出错。 14 | 15 | 下面是使用原码方式计算: 16 | 17 | ``` 18 | 1 -> 00000001 19 | -1 -> 10000001 20 | + ------------------ 21 | -2 -> 10000010 22 | ``` 23 | 24 | 可以看到,用原码方式得到的结果是 -2,显然是错误的。 25 | 26 | 而使用补码计算,如下: 27 | 28 | ``` 29 | 1 -> 00000001 30 | -1 -> 11111111 31 | + ------------------ 32 | 0 -> 00000000 33 | ``` 34 | 35 | 结果就是正确的了。 36 | 37 | -------------------------------------------------------------------------------- /DB/MySQL/内置方法/加密混淆方法.md: -------------------------------------------------------------------------------- 1 | ### PASSWORD 2 | 3 | `PASSWORD(str)`从原文 str 计算并返回加密后的密码字符串,当参数为 NULL 时,返回 NULL。 4 | 5 | PASSWOR() 函数在 MYSQL 服务器的鉴定系统中使用;不应将他用在个人应用程序中,该函数加密是单向的(不可逆)。PASSWORD 执行密码加密与 UNIX 中密码加密方式不同。 6 | 7 | ### MD5 8 | 9 | `MD5(str)`为字符串算出一个 MD5 128 比特校验和。该值以 32 位十六进制数字的二进制字符串形式返回,若参数为 NULL,则会返回 NULL。 10 | 11 | ### ENCODE 12 | 13 | `ENCODE(str,pswd_str)`使用 pswd_str 作为密码,加密 str。可以使用 DECODE() 解密结果,结果是一个和 str 长度相同的二进制字符串。 14 | 15 | ```sql 16 | SELECT ENCODE('nihao','123'); 17 | ``` 18 | ![ENCODE](http://cnd.qiniu.lin07ux.cn/markdown/1472346560109.png) 19 | 20 | ### DECODE 21 | 22 | `DECODE(crypt_str,pswd_str)`使用 pswd_str 作为密码,解密加密字符串 crypt_str,crypt_str 是由 ENCODE() 返回的字符串。 23 | 24 | ```sql 25 | SELECT DECODE(ENCODE('nihao','123'),'123') 26 | ``` 27 | 28 | ![DECODE](http://cnd.qiniu.lin07ux.cn/markdown/1472346729913.png) 29 | 30 | ENCODE() 和 DECODE() 互为反函数。 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Mac/问题/Mac OS X 系统更新后提示 xcrun error.md: -------------------------------------------------------------------------------- 1 | 从 App Store 升级或更新 Mac OS X 之后,在系统自带的终端中执行某些命令的时候,会出现如下的错误: 2 | 3 | ``` 4 | xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrun 5 | ``` 6 | 7 | 这时候可以在终端中执行如下的命令即可解决: 8 | 9 | ```shell 10 | xcode-select --install 11 | ``` 12 | 13 | 如果执行上面的命令的时候提示如下的错误: 14 | 15 | ``` 16 | xcode-select: error: command line tools are already installed, use "Software Update" to install updates 17 | ``` 18 | 19 | 则可以尝试重置 xcode 即可: 20 | 21 | ```shell 22 | sudo xcode-select -r 23 | ``` 24 | 25 | 并可使用如下面命令进行验证: 26 | 27 | ```shell 28 | $ xcode-select -p 29 | /Library/Developer/CommandLineTools 30 | ``` 31 | 32 | 参考:[xcrun: error](http://tips.tutorialhorizon.com/2015/10/01/xcrun-error-invalid-active-developer-path-library-developer-commandline-tools-missing-xcrun/) 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Docker/问题/问题集合.md: -------------------------------------------------------------------------------- 1 | ### php-fpm 启动失败 2 | 3 | Docker 中的 php-fpm 启动时,提示`php7-fpm (exit status 70; not expected)`,使得网站服务无法正常执行。 4 | 5 | 这个问题一般是由于开启了 php-fpm 的 `daemonize` 配置的同时,还是用了 Supervisor 来对 php-fpm 保活。 6 | 7 | 所以,解决该问题的方法也很简单:修改 php-fpm 的配置文件,关闭 daemonize;或者取消是用 Supervisor 对 php-fpm 的保活处理。 8 | 9 | 下面采用修改配置的方式,先关闭 php-fpm 的后台自动运行: 10 | 11 | ```ini 12 | daemonize = no 13 | ``` 14 | 15 | 然后再使用 Supervisor 启动 php-fpm: 16 | 17 | ```shell 18 | supervisorctl start php7-fpm 19 | ``` 20 | 21 | ### 重启 php-fpm 22 | 23 | 使用 Alpine 系统的 PHP 镜像时,没有相关的重启 php-fpm 服务的命令,可以通过`kill`来发送重启信号进行重启: 24 | 25 | ```shell 26 | # 查看 php-fpm 的 pid 27 | > ps aux|grep php-fpm 28 | 1 root 0:01 php-fpm: master process (/usr/local/etc/php-fpm.conf) 29 | 7 www-data 0:01 php-fpm: pool www 30 | 8 www-data 0:01 php-fpm: pool www 31 | 41 root 0:00 grep php 32 | 33 | # 发送重启信号 34 | > kill -USR2 1 35 | ``` 36 | 37 | -------------------------------------------------------------------------------- /JavaScript/DOM/Table 表格 DOM.md: -------------------------------------------------------------------------------- 1 | 为了协助建立表格,HTML DOM 给`table`、`tbody`和`tr`等元素添加了一些特性和方法。 2 | 3 | 给`table`元素添加了以下内容: 4 | 5 | * `caption` 指向`caption`元素(如果存在) 6 | * `tBodies` `tbody`元素的集合 7 | * `tFoot` 指向`tfoot`元素(如果存在) 8 | * `tHead` 指向`thead`元素(如果存在) 9 | * `rows` 表格中所有行的集合 10 | * `createTHead()` 创建`thead`元素并将其放入表格 11 | * `createTFoot()` 创建`tfoot`元素并将其放入表格 12 | * `createCaption()` 创建`caption`元素并将其放入表格 13 | * `deleteTHead()` 删除`thead`元素 14 | * `deleteTFood()` 删除`tfoot`元素 15 | * `deleteCaption()` 删除`caption`元素 16 | * `deleteRow(index)` 删除指定位置上的行 17 | * `insertRow(index)` 在 rows 集合中的指定位置上插入一个新行 18 | 19 | `tbody`元素添加了以下内容: 20 | 21 | - `rows` `tbody`中所有行的集合 22 | - `deleteRow(index)` 删除指定位置上的行 23 | - `insertRow(index)` 在 rows 集合中的指定位置上插入一个新行 24 | 25 | `tr`元素添加了以下内容: 26 | 27 | - `cells` `tr`元素中所有的单元格的集合 28 | - `deleteCell(index)` 删除给定位置上的单元格 29 | - `insertCell(index)` 在 cells 集合的给点位置上插入一个新的单元格 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /JavaScript/小技巧/ES6 尾调用优化.md: -------------------------------------------------------------------------------- 1 | JavaScript 中,程序运行到一个函数,它就会将其添加到调用栈中,成为一个调用帧。当从这个函数返回的时候,就会将这个调用帧从调用栈中删掉。 2 | 3 | 当函数调用嵌套的层级比较深了,调用栈中的调用帧比较多,这对内存消耗是非常大的。ES6 提供了“尾调用优化”来解决调用帧过多引起的内存消耗过大的问题。 4 | 5 | ### 什么是尾调用 6 | 7 | 尾调用指的是:**函数的最后一步是返回调用另一个函数的结果**。 8 | 9 | ```JavaScript 10 | function f(x){ 11 | return g(x); // 最后一步调用另一个函数并且使用 return 12 | } 13 | 14 | function f(x){ 15 | g(x); // 没有 return 不算尾调用,因为不知道后面还有没有操作 16 | // return undefined; // 隐式的 return 17 | } 18 | ``` 19 | 20 | ### 尾调用的作用 21 | 22 | 尾调用用来**删除外层无用的调用帧**,只保留内层函数的调用帧,来节省浏览器的内存。但是需要注意的是: 23 | 24 | 1. 只有**内层函数不再用到外层函数的变量**时,外层调用帧才是无用的,内层函数的调用帧才会取代外层函数的调用帧。如果要使用外层函数的变量,可以通过参数的形式传到内层函数中。 25 | 2. 尾调用优化只在严格模式下开启,非严格模式是无效的。 26 | 27 | ```JavaScript 28 | function a(){ 29 | var aa = 1; 30 | let b = val => aa + val // 使用了外层函数的参数aa 31 | return b(2) // 无法进行尾调用优化 32 | } 33 | ``` 34 | 35 | 当然,如果环境不支持“尾调用优化”,代码还可以正常运行,是无害的! 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /PHP/Lumen/Lumen 路由参数.md: -------------------------------------------------------------------------------- 1 | Lumen 中的路由参数会优先按照名称来生成对应的回调的参数列表。如果路由参数名称和回调参数的名称不同,则会优先获取回调参数的默认值。在调用前,还会将获取到的回调依赖参数值数组和剩余的路由参数值数组进行合并,合并后的数组作为调用时的参数值。 2 | 3 | 如,对于如下的路由: 4 | 5 | ```php 6 | $router->get('companies/{cId}/employees/{id}', function ($companyId, $employeeId = null) { 7 | return $companyId . '-' . $employeeId; 8 | }) 9 | ``` 10 | 11 | 在访问`companies/1/employees/2`时,回调函数会接收到三个参数,分别为:`null`、`'1'`、`'2'`。这是由于路由参数和回调参数的名称不匹配,而且回调中的参数`$employeeId`有默认值`null`,解析得到的回调依赖参数的值为`[null]`,与路由参数`['1', '2']`合并后,就得到实际调用时回调函数的列表`null`、`'1'`、`'2'了。 12 | 13 | 如果将路由改成如下形式: 14 | 15 | ```php 16 | $router->get('companies/{companyId}/employees/{employeeId}', function ($companyId, $employeeId = null) { 17 | return $companyId . '-' . $employeeId; 18 | }) 19 | ``` 20 | 21 | 此时再访问`companies/1/employees/2`,回调函数实际只会接受到两个参数,而且值分别为`'1'`、`'2'`。这样就是正常预期的结果了。 22 | 23 | 综上:**Lumen 中,路由参数和相应回调的参数名称应尽量保持相同,以避免意外情况**。 24 | 25 | -------------------------------------------------------------------------------- /JavaScript/事件/@JavaScript Event Loop.md: -------------------------------------------------------------------------------- 1 | 异步任务可分为 task 和 microtask 两类,不同的 API 注册的异步任务会依次进入自身对应的队列中,然后等待 Event Loop 将它们依次压入执行栈中执行。 2 | 3 | * **(macro)task** 也就是宏任务,是由宿主环境协助管理的,主要包含:script(整体代码)、setTimeout、setInterval、I/O、UI 交互事件、postMessage、MessageChannel、setImmediate(Node.js 环境)。 4 | 5 | * **microtask** 也就是微任务,是由 JavaScript 引擎自身管理的,主要包含:Promise.then、MutaionObserver、process.nextTick(Node.js 环境)。 6 | 7 | 每一次 Event Loop 触发时,会按照如下的步骤进行: 8 | 9 | 1. 执行完主执行线程中的任务。 10 | 2. 取出 micro-task 中任务执行直到*清空*。 11 | 3. 取出 macro-task 中*一个*任务执行。 12 | 4. 重复 2 和 4。 13 | 14 | 所以:**微任务队列中的事件会比宏任务队列中的事件有更高的响应级别**。同一次事件循环中,微任务永远在宏任务之前执行。
 15 | 下面的代码的输出就是`2、3、1`: 16 | 17 | ```js 18 | setTimeout(function () { 19 | console.log(1); 20 | }); 21 | 22 | new Promise(function(resolve,reject){ 23 | console.log(2) 24 | resolve(3) 25 | }).then(function(val){ 26 | console.log(val); 27 | }) 28 | ``` 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 实现 linux tail -f 效果.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 0) { 24 | if ($add_size > MAX_SHOW) { 25 | $ignore_size = $add_size - MAX_SHOW; 26 | $add_size = MAX_SHOW; 27 | fseek($fp, $file_size + $ignore_size); 28 | } 29 | 30 | fwrite(STDOUT, fread($fp, $add_size)); 31 | $file_size = $file_size_new; 32 | } 33 | 34 | usleep(50000); 35 | } 36 | 37 | fclose($fp); -------------------------------------------------------------------------------- /PHP/Laravel/Laravel 学习笔记(零)杂项.md: -------------------------------------------------------------------------------- 1 | ### 表单方法伪造 2 | 3 | HTML 表单不支持`PUT`、`PATCH`或`DELETE`行为。所以当需要从 HTML 表单中直接调用定义了`PUT`、`PATCH`或`DELETE`的路由时,需要在表单中增加隐藏的`_method`输入标签,使用`_method`字段的值作为 HTTP 的请求方法。 4 | 5 | > 当然,如果使用 JavaScript 来调用的话,就不会有这个问题了。 6 | 7 | ```html 8 |
9 | 10 | ... 11 |
12 | ``` 13 | 14 | 也可以使用辅助函数`method_field()`来生成隐藏的`_method`标签: 15 | 16 | ```html 17 | {{ method_field('PUT') }} 18 | ``` 19 | 20 | ### CSRF 保护 21 | 22 | 指向 web 路由文件中定义的`POST`、`PUT`或`DELETE`路由的任何 HTML 表单都应该包含一个 CSRF 令牌字段,否则这个请求将会被拒绝: 23 | 24 | ```html 25 |
26 | 27 |
28 | ``` 29 | 30 | 或者使用`csfr_field()`方法来生成: 31 | 32 | ```html 33 |
34 | {{ csrf_field() }} 35 |
36 | ``` 37 | 38 | -------------------------------------------------------------------------------- /PHP/Laravel/问题/Laravel 数据库返回的整型数据被转换成了字符串类型.md: -------------------------------------------------------------------------------- 1 | Laravel 从 MySQL 获取的整型数据被转换成了 String 类型,而这经常会造成奇怪的结果。但是这个现象并不是在所有机器上都能出现,只有在服务器上才会。 2 | 3 | 如,在测试机器上,返回如下: 4 | 5 | ```json 6 | { 7 | "id": 1, 8 | "level": 1 9 | } 10 | ``` 11 | 12 | 但是在服务器上,返回如下的结果: 13 | 14 | ```json 15 | { 16 | "id": "1", 17 | "level": "1" 18 | } 19 | ``` 20 | 21 | 可以看到,本来是整型数据,变成了字符串数据。确认了表结构没有问题,说明问题出在了数据被取出来的过程中。 22 | 23 | 问题出在了 PHP 的 MySQL 驱动上: 24 | 25 | * [MySQL integer field is returned as string in PHP](http://stackoverflow.com/questions/5323146/mysql-integer-field-is-returned-as-string-in-php) 26 | * [laravel eloquent integers returned as strings in mssql](http://stackoverflow.com/questions/26974914/laravel-eloquent-integers-returned-as-strings-in-mssql) 27 | 28 | 检查服务器端的 MySQL 驱动,发现装的是`php71w-mysql`,改成对应的`php71w-mysqlnd`驱动之后,重启 PHP-FPM 就 OK 了。 29 | 30 | > 转摘:[数据库返回的整型数据被偷换成了字符串类型](https://www.sunzhongwei.com/php-mysqlnd) 31 | 32 | -------------------------------------------------------------------------------- /Python/Python 内置模块 — hashlib.md: -------------------------------------------------------------------------------- 1 | Python 中内置了一个`hashlib`模块,提供了很多摘要算法,如 MD5、SHA1 等。 2 | 3 | > 摘要算法又称哈希算法、散列算法。它通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常用 16 进制的字符串表示)。 4 | 5 | ### 一般的使用方式 6 | 7 | ```py 8 | import hashlib 9 | 10 | data = 'This is a md5 test!' 11 | print(hashlib.md5(data.encode('utf-8')).hexdigest()) 12 | 13 | data = 'This is a sha1 test!' 14 | print(hashlib.sha1(data.encode('utf-8')).hexdigest()) 15 | ``` 16 | 17 | 这样就会输出如下内容: 18 | 19 | ``` 20 | 0a2c0b988863f08471067903d8737962 21 | 63d8242da8214b3028624397be3ee20f3f8e3372 22 | ``` 23 | 24 | ### 处理大数据量 25 | 26 | 如果要处理的数据量很大,那么直接使用上面的方式就会造成内存紧张了。这时就需要分块多次调用`update()`,最后计算的结果是一样的: 27 | 28 | ```py 29 | import hashlib 30 | 31 | md5 = hashlib.md5() 32 | md5.update('This is a '.encode('utf-8')) 33 | md5.update('md5 test!'.encode('utf-8')) 34 | print(md5.hexdigest()) 35 | ``` 36 | 37 | 输出的内容也是`0a2c0b988863f08471067903d8737962`。 38 | 39 | 对于`sha1`也是同样的使用方式。 40 | 41 | 42 | -------------------------------------------------------------------------------- /DB/Redis/数据结构/Redis ziplist 压缩列表.md: -------------------------------------------------------------------------------- 1 | 压缩列表(ziplist)是 list 和 hash 的底层实现之一。如果 list 的每个都是小整数值,或者是比较短的字符串,压缩列表(ziplist)就会作为 list 的底层实现。 2 | 3 | 压缩列表(ziplist)是 Redis 为了节约内存而开发的,是由一系列的特殊编码的连续内存块组成的顺序性数据结构。 4 | 5 | ### 1. 列表结构 6 | 7 | 压缩列表结构图例如下: 8 | 9 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1558873859484.png) 10 | 11 | 属性值有: 12 | 13 | * `zlbytes`: 长度为 4 字节,记录整个压缩数组的内存字节数。 14 | * `zltail`: 长度为 4 字节,记录压缩队列表尾节点距离压缩队列的起始地址有多少字节,通过该属性可以直接确定尾节点的地址。 15 | * `zllen`: 长度为 2 字节,包含的节点数。当属性值小于 INT16_MAX 时,该值就是节点总数,否则需要遍历整个队列才能确定总数。 16 | * `zlend`: 长度为 1 字节,特殊值,用于标记压缩队列的末端。 17 | 18 | **压缩列表从表尾节点倒序遍历**,首先指针通过`zltail`偏移量指向表尾节点,然后通过指向节点记录的前一个节点的长度依次向前遍历访问整个压缩列表。 19 | 20 | ### 2. 节点结构 21 | 22 | 压缩列表中,每个节点的结构图如下: 23 | 24 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1558873910012.png) 25 | 26 | 属性值有: 27 | 28 | * `previous_entry_length`: 压缩列表中前一个节点的长度,和当前的地址进行指针运算,计算出前一个节点的起始地址。 29 | * `encoding`: 节点保存数据的类型和长度 30 | * `content`: 节点值,可以为一个字节数组或者整数。 31 | 32 | -------------------------------------------------------------------------------- /Git/配置/Git 设置 commit 默认模板.md: -------------------------------------------------------------------------------- 1 | > 转摘:[一日一技:为 git commit 设置默认模板](https://mp.weixin.qq.com/s/Nn2PeMHML4jnBIoC-6EUaw) 2 | 3 | 在提交 commit 的时候,如果提交信息都随意写,那就没办法快速的知道每个提交修改的是什么——是修复了什么 bug?是增强了什么功能?或者是添加了新的模块?等时间久了,需要找以前的某一个提交检查问题的时候,就无从下手了。 4 | 5 | 如果要求 commit 信息都按照一定的模板来编写,那么后续的查看、交流会很方便了。这可以通过为 Git 配置 commit 模板来实现。 6 | 7 | 1. 创建一个 commit message 模板文件,比如`~/.gitmessage`: 8 | 9 | ```ini 10 | [#id] title 11 | 12 | [问题描述] 13 | 1. ... 14 | 2. ... 15 | 3. ... 16 | 17 | [问题原因] 18 | 1. ... 19 | 2. ... 20 | 3. ... 21 | 22 | [解决方案] 23 | 1. ... 24 | 2. ... 25 | 3. ... 26 | ``` 27 | 28 | 其中,第一行首先是编号,后面是对这一次提交的总结性标题。从第三行开始,就是本次提交的详细信息,指明问题信息、原因及解决方案。 29 | 30 | 2. 然后为 Git 配置提交信息模板,打开配置文件`~/.gitconfig`,在`[commit]`模块中增加两行内容: 31 | 32 | ```ini 33 | [commit] 34 | template = ~/.gitmessage 35 | ``` 36 | 37 | 配置好之后,再执行`git commit`命令的时候,这个模板就会自动的弹出来了。 38 | 39 | 40 | -------------------------------------------------------------------------------- /DB/Redis/数据结构/Redis List 链表.md: -------------------------------------------------------------------------------- 1 | ### 1. 数据结构 2 | 3 | Redis 中使用 list 数据结构来表示链表: 4 | 5 | ```c 6 | typedef struct list{ 7 | // 表头结点 8 | listNode *head; 9 | 10 | // 表尾节点 11 | listNode *tail; 12 | 13 | // 链表长度 14 | unsigned long len; 15 | 16 | // 节点值复制函数 17 | void *(*dup) (void *ptr); 18 | 19 | // 节点值释放函数 20 | void (*free) (void *ptr); 21 | 22 | // 节点值对比函数 23 | int (*match) (void *ptr, void *key); 24 | } list; 25 | ``` 26 | 27 | 而每个节点使用 listNode 结构来表示: 28 | 29 | ```c 30 | typedef strcut listNode{ 31 | // 前置节点 32 | strcut listNode *pre; 33 | 34 | // 后置节点 35 | strcut listNode *next; 36 | 37 | // 节点的值 38 | void *value; 39 | } listNode; 40 | ``` 41 | 42 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1558864804133.png) 43 | 44 | ### 2. 特点 45 | 46 | Redis 的链表有以下特性: 47 | 48 | 1. 无环双向链表; 49 | 2. 获取表头指针、表尾指针、链表节点长度的时间复杂度均为`O(1)`; 50 | 3. 链表使用`void *`指针来保存节点值,可以保存各种不同类型的值。 51 | 52 | -------------------------------------------------------------------------------- /Linux/CentOS/CentOS 更新 wget.md: -------------------------------------------------------------------------------- 1 | Wget 有一个缓冲区溢出漏洞,需要更新到 1.19 版本以上来修复这个漏洞。更新步骤如下: 2 | 3 | ### 1. 下载 wget 压缩包 4 | 5 | 从 [http://mirrors.ustc.edu.cn/gnu/wget/](http://mirrors.ustc.edu.cn/gnu/wget/) 中获取到 Wget 1.19 版本的 tar 包: 6 | 7 | ```shell 8 | wget http://mirrors.ustc.edu.cn/gnu/wget/wget-1.19.tar.gz 9 | ``` 10 | 11 | ### 2. 解压 12 | 13 | ```shell 14 | tar -zxvf wget-1.19.tar.gz 15 | ``` 16 | 17 | ### 3. 编译 18 | 19 | 进入解压缩之后的文件夹,进行编译: 20 | 21 | ```shell 22 | cd wget-1.19 23 | ./configure --prefix=/usr --sysconfdir=/etc --with-ssl=openssl 24 | ``` 25 | 26 | 在这个过程中可能会提示检查失败,缺少某些包,例如 openssl。使用`yum install`命令安装之后**重新编译**。 27 | 28 | 需要**注意**的是:openssl 安装之后,编译是如果还是提示未安装,则需要安装`openssl-devel`包。 29 | 30 | ### 4. 安装 31 | 32 | 编译通过之后,就可以进行安装了: 33 | 34 | ```shell 35 | make && make install 36 | ``` 37 | 38 | 安装完成之后,用`wget -V`就可以看到 Wget 版本已经更新了。 39 | 40 | ### 5. 转摘 41 | 42 | [centos中wget更新到1.18版本以上](https://blog.csdn.net/rczrj/article/details/78931007) 43 | 44 | -------------------------------------------------------------------------------- /Python/方法函数/range.md: -------------------------------------------------------------------------------- 1 | `range()`方法用于生成一个数字序列,可以设置该序列的起始和终止数值,还可以设置递增的幅度(步长)。 2 | 3 | ### 1. 语法 4 | 5 | `range()`方法的使用语法有两种,分别如下: 6 | 7 | ``` 8 | range(stop) 9 | range(start, stop[, step]) 10 | ``` 11 | 12 | 对于第一种用法,只需要一个`stop`参数,表示生成从 0 开始的自然数序列,直到`stop`数值为止,不包含`stop`数值。比如: 13 | 14 | ```Python 15 | for x in range(5): 16 | print(x) 17 | 18 | # 输出: 19 | # 0 20 | # 1 21 | # 2 22 | # 3 23 | # 4 24 | ``` 25 | 26 | 对于第二种用法,则可以有两个或者三个参数,分别表示序列的起始数值、结束数值和步长,其中步长参数是可选的。该种方式生成的序列包含起始数值,但不包含结束数值。比如: 27 | 28 | ```Python 29 | range(5, 10) 30 | # 结果:5, 6, 7, 8, 9 31 | 32 | range(0, 10, 3) 33 | # 结果:0, 3, 6, 9 34 | 35 | range(-10, -100, -30) 36 | # 结果:-10, -40, -70 37 | ``` 38 | 39 | ### 2. 可迭代对象 40 | 41 | `range()`方法所返回的对象在许多方面表现得像一个列表,但实际上却并不是。此对象会在被迭代时基于所希望的序列返回连续的项,但它没有真正生成列表,这样就能节省空间。 42 | 43 | 这样的对象是*可迭代的*,也就是说,适合作为函数和结构体的参数,这些函数和结构体期望在迭代结束之前可以从中获取连续的元素。这些对象可以用在`for`结构或者`list()`方法中,从而完成对其的遍历。 44 | 45 | 所以,在需要迭代数值序列时,建议使用`range()`方法来生成。 46 | 47 | 48 | -------------------------------------------------------------------------------- /DB/Redis/数据结构/Redis String 字符串.md: -------------------------------------------------------------------------------- 1 | ### 1. 数据结构 2 | 3 | Redis 使用动态字符串 SDS 来表示字符串值,使用`sdshdr`数据结构: 4 | 5 | ```c 6 | struct sdshdr{ 7 | 8 | // 字节数组,用于保存字符串 9 | char buf[]; 10 | 11 | // 记录 buf 数组中已使用的字节数量,也是字符串的长度 12 | int len; 13 | 14 | // 记录 buf 数组未使用的字节数量 15 | int free; 16 | } sdshdr; 17 | ``` 18 | 19 | 示意图: 20 | 21 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1558799609988.png) 22 | 23 | ### 2. 特点 24 | 25 | SDS 的好处如下: 26 | 27 | 1. `sdshdr`数据结构中用`len`属性记录了字符串的长度。获取字符串的长度时,时间复杂度为`O(1)`。 28 | 2. SDS **不会发生溢出**的问题,如果修改 SDS 时空间不足,先会扩展空间,再进行修改(内部实现了**动态扩展**机制)。 29 | 3. SDS 可以**减少内存分配的次数** (空间预分配机制)。在扩展空间时,除了分配修改时所必要的空间,还会分配额外的空闲空间(free 属性)。 30 | 4. SDS 是**二进制安全**的 ,所有 SDS API 都会以处理二进制的方式来处理 SDS 存放在 buf 数组里的数据。 31 | 32 | SDS 的动态扩展和预分配内存机制如下: 33 | 34 | * 如果修改后,SDS 的长度(也就是`len`属性的值)将小于 1MB,那么 Redis 预分配和`len`属性相同大小的未使用空间。 35 | * 如果修改后,SDS 的长度将大于 1MB ,那么 Redis 会分配 1MB 的未使用空间。
 36 | 类似的,当 SDS 缩短其保存的字符串长度时,并不会立即释放多出来的字节,而是等待之后使用。 37 | 38 | 39 | -------------------------------------------------------------------------------- /PHP/Laravel/Laravel 杂项知识点.md: -------------------------------------------------------------------------------- 1 | ## 启动内置服务器 2 | 3 | 默认情况下,PHP 已经提供了一个内置的 web server,可以通过如下的命令来启动: 4 | 5 | ```shell 6 | # 启动一个服务器在 localhost:8000 上 7 | # 并设置根目录为当前目录下的 public 文件夹 8 | php -S localhost:8000 -t public 9 | ``` 10 | 11 | 另外,Laravel 对这个命令做了一些封装,从而能更方便的使用这个服务器: 12 | 13 | ```shell 14 | php artisan serve 15 | ``` 16 | 17 | ## tinker 18 | 19 | Laravel artisan 中提供了一个和 php 命令行交互界面类似的工具 tinker,不过他能更方便的我们在命令行中查看 PHP 代码的效果。比如,在命令行中,我们不再需要每次输出变量的值的时候都要使用`echo`等方法,只需要在命令行中输入这个变量即可。和 Chrome 开发者调试工具类似。 20 | 21 | 进入方式: 22 | 23 | ```shell 24 | php artisan tinker 25 | ``` 26 | 27 | 在 tinker 命令工具中,可以使用 Laravel 应用中的所有的代码和模块。比如,我们直接通过一个完成的命名空间来实例化一个类:`$article = new App\Article();` 28 | 29 | ## 路由缓存 30 | 31 | 在 L5 之前对于 100 个以上路由的情况很尴尬,效率确实是个问题。在 L5 中,果断添加了缓存来提高效率,对于一些稍微大点的项目来说,收益不小。 32 | 33 | ```shell 34 | php artisan route:cache 35 | ``` 36 | 37 | ## 调试 38 | 39 | 如果需要在页面中输出对应变量的内容,可以使用`dd()`方法来输出。比如,`dd($article)`将会在页面上显示变量`$article`的值。调用了`dd()`方法之后,后面的操作都不会再执行了。 40 | 41 | -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 下载远程图片.md: -------------------------------------------------------------------------------- 1 | PHP 下载远程图片简单思路就是通过`curl()`函数来请求图片的 URL,然后将请求成功后的结果写入到本地的文件中。 2 | 3 | ```PHP 4 | class Spider { 5 | 6 | public function downloadImage($url, $path = 'images/') 7 | { 8 | $ch = curl_init(); 9 | curl_setopt($ch, CURLOPT_URL, $url); 10 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); 11 | curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); 12 | $file = curl_exec($ch); 13 | curl_close($ch); 14 | 15 | $this->saveAsImage($url, $file, $path); 16 | } 17 | 18 | private function saveAsImage($url, $file, $path) 19 | { 20 | $filename = pathinfo($url, PATHINFO_BASENAME); 21 | $resource = fopen($path . $filename, 'a'); 22 | fwrite($resource, $file); 23 | fclose($resource); 24 | } 25 | } 26 | ``` 27 | 28 | 之后就可以这样调用代码来下载图片: 29 | 30 | ```PHP 31 | $spider = new Spider(); 32 | 33 | foreach ( $images as $url ) { 34 | $spider->downloadImage($url); 35 | } 36 | ``` -------------------------------------------------------------------------------- /Python/知识点/Python 3.8 仅位置参数.md: -------------------------------------------------------------------------------- 1 | Python 函数传递参数的方式有很多:位置参数、默认参数、可变参数、命名关键字参数等。比如: 2 | 3 | ```Python 4 | def add(x, y, *args, **kwargs): 5 | print(f"x={x}, y={y}") 6 | ``` 7 | 8 | 这个函数中 x 和 y 就是两个位置参数,为这两个参数传递值时,需要按照顺序传递,也可以将它们作为命名关键字参数进行传递,这样就可以改变参数的顺序了,比如: 9 | 10 | ```Python 11 | # 按照位置传递,此时输出:x=1, y=2 12 | add(1, 2) 13 | 14 | # 按照明明关键字参数传递,此时输出:x=2, y=1 15 | ad(y=1, x=2) 16 | ``` 17 | 18 | 使用命名关键字方式传递参数,虽然很方便,但是也增加了出错的机会,特别是多人合作的项目中。 19 | 20 | Python 3.8 中引入仅位置参数语法来限制命名关键字参数传递的使用。在函数定义时,参数之间可以指定一个斜杠(`/`),在斜杠之前的参数严格遵守仅位置参数的定义。 21 | 22 | 例如: 23 | 24 | ```Python 25 | def add(x, y, /, * args, **kwargs): 26 | print(f"x={x}, y={y}") 27 | 28 | add(1, 2) # 输出:x=1, y=2 29 | ``` 30 | 31 | `/`告诉解释器,x 和 y 是两个严格的位置参数,不能当做命名关键字参数进行传递。如果把它当作命名关键字参数进行传递参数时,就会引发错误: 32 | 33 | ```Python 34 | add(y=2, x=1) 35 | # Traceback (most recent call last): 36 | # File "", line 1, in 37 | # TypeError: add() missing 2 required positional arguments: 'x' and 'y' 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /Linux/CentOS/CentOS 8 安装 PHP 7.4.md: -------------------------------------------------------------------------------- 1 | > 转摘:[How to Install PHP 7.4 on CentOS 8](https://www.tecmint.com/install-php-on-centos-8/) 2 | 3 | ### 1. 添加仓库 4 | 5 | 在 CentOS 8 中安装 PHP 7.4 需要先添加对应的 EPEL & Remi 仓库。 6 | 7 | 首先,安装 EPEL 仓库: 8 | 9 | ```shell 10 | dnf install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm 11 | ``` 12 | 13 | 安装好之后,可以通过如下的命令来确认: 14 | 15 | ```shell 16 | > rpm -qa | grep epel 17 | # epel-release-8-7.el8.noarch 18 | ``` 19 | 20 | 然后,安装 Remi 仓库: 21 | 22 | ```shell 23 | dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm 24 | ``` 25 | 26 | 安装好之后,可以通过如下的命令来确认: 27 | 28 | ```shell 29 | > rpm -qa | grep remi 30 | # remi-release-8.0-4.el8.noarch 31 | ``` 32 | 33 | ### 2. 安装 PHP 7.4 34 | 35 | ```shell 36 | # 查看当前可用的 PHP 37 | dnf module list php 38 | 39 | # 开启 Remi 仓库的 PHP 7.4 模块 40 | dnf module enable php:remi-7.4 41 | 42 | # 安装 PHP 相关组件 43 | dnf install php php-cli php-common 44 | 45 | # 查看已安装的 PHP 版本 46 | php -v 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript Debouncing 防抖动.md: -------------------------------------------------------------------------------- 1 | Debouncing 是限制下次函数调用之前必须等待的时间间隔。正确实现 debouncing 的方法是将若干个函数调用 合成 一次,并在给定时间过去之后仅被调用一次。下面是一个原生 JavaScript 的实现,用到了作用域、闭包、this 和计时事件: 2 | 3 | ```JavaScript 4 | // 将会包装事件的 debounce 函数 5 | function debounce(fn, delay) { 6 | // 维护一个 timer 7 | let timer = null; 8 | // 能访问 timer 的闭包 9 | return function() { 10 | // 通过 ‘this’ 和 ‘arguments’ 获取函数的作用域和变量 11 | let context = this; 12 | let args = arguments; 13 | // 如果事件被调用,清除 timer 然后重新设置 timer 14 | clearTimeout(timer); 15 | timer = setTimeout(function() { 16 | fn.apply(context, args); 17 | }, delay); 18 | } 19 | } 20 | ``` 21 | 22 | 这个函数当传入一个事件(fn)时 — 会在经过给定的时间(delay)后执行。类似如下的方式使用: 23 | 24 | ```JavaScript 25 | // 当用户滚动时被调用的函数 26 | function foo() { 27 | console.log('You are scrolling!'); 28 | } 29 | 30 | // 在 debounce 中包装我们的函数,过 2 秒触发一次 31 | let elem = document.getElementById('container'); 32 | elem.addEventListener('scroll', debounce(foo, 2000)); 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /PHP/Lumen/Lumen 问题笔记.md: -------------------------------------------------------------------------------- 1 | ### Request 2 | 3 | Version:5.7、5.8 4 | 5 | 从 5.7 开始,Lumen 定义了一个`\Laravel\Lumen\Http\Request`类,这是对`\Illuminate\Http\Request`进行封装得到的,其重新定义了`routeIs()`等几个方法,以便更好的适应 Lumen 的路由上的变化。 6 | 7 | 在 Application 启动的时候,实例化的 Request 对象就是`\Laravel\Lumen\Http\Request`实例,而不是`\Illuminate\Http\Request`实例了,但是注册在 Application 中的键依旧是`\Illuminate\Http\Request::class`,也就是如果在路由闭包或者控制器中使用解析参数的话,还是需要将参数中的`$request`定义为`\Illuminate\Http\Request`类型。如果定义为`\Laravel\Lumen\Http\Request`类型,那么 Application 将会重新生成一个该类的实例,而不是使用已解析好的 Request 实例。 8 | 9 | 这就导致一个问题:在应用启动生成 Request 实例的时候,已经将客户端提交的数据都读取了。此时如果重新解析得到一个`\Laravel\Lumen\Http\Request`实例,那么它将无法获得客户端提供的数据。所以**在路由闭包和控制器方法中,还是要将`$request`参数定义为`\Illuminate\Http\Request`类型。** 10 | 11 | 有个例外:在 Middleware 的`handle()`方法中的第一个参数可以定义为`\Laravel\Lumen\Http\Request`类型。这是由于 Middleware 的第一个参数是由 Application 在调用中间件时直接传入`$app->make('request')`的结果得到的,而不是由 Application 解析生产的。所以这个参数无论是被定义为`\Laravel\Lumen\Http\Request`类型,还是`\Illuminate\Http\Request`,都不会有问题。 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /杂项/钉钉/钉钉网页分享设置.md: -------------------------------------------------------------------------------- 1 | 在钉钉中可以将网页分享成卡片形式,并支持自主设置标题、描述和小图等,类似如下: 2 | 3 | 4 | 5 | 钉钉这种卡片配置不需要调用 api,只需在 HTML 写上些许代码便可。 6 | 7 | 钉钉的卡片信息的识别获取逻辑为: 8 | 9 | 1. 首先基于 [Open Graph Data](https://moz.com/blog/meta-data-templates-123) 协议来获取相关信息; 10 | 2. 如果该网页不支持 OGP,那么基于默认规则提取网页标题、主图、正文摘要来生成卡片信息。 11 | 12 | > 注:这些信息都必须静态写在 HTML 代码中,不支持通过 JavaScript 动态插入。 13 | 14 | 比如,基于 OGP 协议,可以为网页的``标签中添加如下的``标签来设置如上图中所示的卡片信息: 15 | 16 | ```HTML 17 | 18 | 19 | 20 | 21 | 22 | 23 | ``` 24 | 25 | 其中,前三个标签是最主要的,分别用于设置卡片的标题、图片和描述信息。 26 | 27 | -------------------------------------------------------------------------------- /DB/PostgreSQL/模块-插件/@安装插件准备和问题.md: -------------------------------------------------------------------------------- 1 | ### 有多个版本的 PostgreSQL 2 | 3 | 如果服务器上有多个版本的 PostgreSQL,如果需要将插件安装到指定版本而非默认版本的 PostgreSQL 目录中,则需要修改服务器的系统环境变量。 4 | 5 | 比如,如果系统上先安装了 PostgreSQL 9.5,然后又安装了 9.6 版本,那么服务器的系统环境变量中,默认的是使用 9.5 版本的。此时,修改`/etc/profile`中的环境变量设置即可: 6 | 7 | ```shell 8 | vim /etc/profile 9 | 10 | # 找到类似如下的语句 11 | PATH=$PATH:/usr/pgsql-9.5/bin 12 | 13 | # 修改成下面的语句 14 | PATH=$PATH:/usr/pgsql-9.6/bin 15 | ``` 16 | 17 | > 如果 PostgreSQL 的安装路径不同,则需要设定成正常的安装路径。 18 | 19 | 修改之后,应用修改,并重新登录即可: 20 | 21 | ```shell 22 | source /etc/profile 23 | logout 24 | ``` 25 | 26 | ### 提示缺少`pgxs.mk` 27 | 28 | 安装插件时,提示类似如下错误: 29 | 30 | ``` 31 | [root@backup zhparser-master]# SCWS_HOME=/usr/local make && make install 32 | Makefile:18: /usr/pgsql-9.6/lib/pgxs/src/makefiles/pgxs.mk: 没有那个文件或目录 33 | make: *** 没有规则可以创建目标“/usr/pgsql-9.6/lib/pgxs/src/makefiles/pgxs.mk”。 停止。 34 | ``` 35 | 36 | 这是缺少 PostgreSQL 的 devel 程序导致的,安装相应版本的程序之后即可,如下: 37 | 38 | ```shell 39 | yum -y install postgresql96-devel.x86_64 40 | ``` 41 | 42 | 43 | -------------------------------------------------------------------------------- /Git/技巧/Git 从其他分支合并个别文件或文件夹.md: -------------------------------------------------------------------------------- 1 | ### 需求 2 | 3 | 有两个分支 A、B,需要将 B 分支中的部分文件合并到 A 分支中。 4 | 5 | ### 实现 6 | 7 | 使用`git merge`命令进行分支合并是通用的做法,但是`git merge`合并的时候会将两个分支的内容完全合并,如果想合并一部分肯定是不行的。 8 | 9 | 这时候`git checkout`是个合适的工具:`git checkout source_branch ...`。 10 | 11 | 示例如下: 12 | 13 | ```shell 14 | $ git branch 15 | * A 16 | B 17 | 18 | $ git checkout B message.html message.css message.js other.js 19 | 20 | $ git status 21 | # On branch A 22 | # Changes to be committed: 23 | # (use "git reset HEAD ..." to unstage) 24 | # 25 | # new file: message.css 26 | # new file: message.html 27 | # new file: message.js 28 | # modified: other.js 29 | # 30 | ``` 31 | 32 | 这样就合并完成了。 33 | 34 | **注意:在使用`git checkout`某文件到当前分支时,会将当前分支的对应文件强行覆盖** 35 | 36 | 如果 A 分支上需要合并的文件有过更新,直接这样合并的话就会被覆盖丢失了。此时可以考虑先从 A 分支上新建一个分支 C,然后将 B 分支和 C 分支通过`git merge`合并,然后再将 A 分支和 C 分支使用这种方式来合并就行了。 37 | 38 | > 转摘:[git小技巧--如何从其他分支merge个别文件或文件夹](https://segmentfault.com/a/1190000008360855) 39 | 40 | 41 | -------------------------------------------------------------------------------- /PHP/Laravel/实用技巧/Laravel 5.6 生产环境优化.md: -------------------------------------------------------------------------------- 1 | ## 一、生产环境配置 2 | 3 | ### 1.1 composer 4 | 5 | 首先使用`composer install --optimize-autoloader`安装依赖。 6 | 7 | ### 1.2 设置目录权限 8 | 9 | 配置项目目录中的`storage/`和`bootstrap/cache/`两个目录可以被 PHP-FPM 读写: 10 | 11 | ```shell 12 | chown -R apache:apache storeage 13 | chown -R apache:apache bootstrap/cache 14 | ``` 15 | 16 | > 如果 PHP-FPM 的用户和属组不是 apache,则需要改成正确的用户和属组。 17 | 18 | ### 1.3 设置密钥 19 | 20 | 拷贝`.env.example`为一个新的文件`.env`,并根据实际情况进行配置。配置好之后,还需要生成应用密钥,用于保护加密信息: 21 | 22 | ```shell 23 | php artisan key:generate 24 | ``` 25 | 26 | > 项目运行之后,应将`.env`做一个备份,避免加密密钥发生变化,否则可能会造成一些数据无法解析。 27 | 28 | 29 | ## 二、优化 30 | 31 | ### 2.1 配置优化 32 | 33 | 将应用部署到生产环境时,记得在部署过程中运行 Artisan 命令`config:cache`: 34 | 35 | ```shell 36 | php artisan config:cache 37 | ``` 38 | 39 | 这个命令可以将所有 Laravel 的配置文件合并到单个文件中缓存,此举能大大减少框架在加载配置值时必须执行的系统文件的数量。 40 | 41 | ### 2.2 路由优化 42 | 43 | 通过下面的命令,可以将所有路由注册减少为缓存文件中的单个方法调用,以达到当应用程序在注册数百条路由时,提高路由注册的性能: 44 | 45 | ```shell 46 | php artisan route:cache 47 | ``` 48 | 49 | -------------------------------------------------------------------------------- /DB/Redis/数据结构/Redis IntSet 整数集合.md: -------------------------------------------------------------------------------- 1 | 整数集合是 Set(集合)的底层数据结构之一:当一个 Set(集合)只包含整数值元素,并且元素的数量不多时,Redis 就会采用整数集合(intset)作为 Set(集合)的底层实现。 2 | 3 | ### 1. 数据结构 4 | 5 | 整数集合(intset)保证了元素是不会出现重复的,并且是有序的(从小到大排序),intset 的结构是这样子的: 6 | 7 | ```c 8 | typeof struct intset { 9 | // 编码方式 10 | unit32_t encoding; 11 | 12 | // 集合包含的元素数量 13 | unit32_t length; 14 | 15 | // 保存元素的数组 16 | int8_t contents[]; 17 | } 18 | ``` 19 | 20 | 示意图如下: 21 | 22 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1558873467813.png) 23 | 24 | ### 编码类型 25 | 26 | 虽然 intset 结构将`contents`属性声明为`int8_t`类型的数组,但实际上`contents`数组并不保存任何`int8_t`类型的值,`contents`数组的真正类型取决于`encoding`属性的值: 27 | 28 | * INTSET_ENC_INT16 29 | * INTSET_ENC_INT32 30 | * INTSET_ENC_INT64 31 | 32 | 如果本来是`INTSET_ENC_INT16`的编码,想要存放大于`INTSET_ENC_INT16`编码能存放的整数值,此时就得编码**升级**(从 16 升级成 32 或者 64)。步骤如下: 33 | 34 | 1. 根据新元素类型拓展整数集合底层数组的空间并为新元素分配空间。 35 | 2. 将底层数组现有的所有元素都转换成与新元素相同的类型,并将类型转换后的元素放到正确的位上,需要维持底层数组的有序性质不变。 36 | 3. 将新元素添加到底层数组。 37 | 38 | 另外,IntSet **只支持升级操作,并不支持降级操作。** 39 | 40 | 41 | -------------------------------------------------------------------------------- /JavaScript/实例/JavaScript 实现质数算法.md: -------------------------------------------------------------------------------- 1 | ### 需求 2 | 写一个`isPrime()`函数,当其为质数时返回`true`,否则返回`false`。 3 | 4 | ### 分析 5 | 首先,因为 JavaScript 是弱类型语言,因此你不能信任传递来的数据类型。如果没有明确地要求,严格上说,应该对函数的输入进行检查。 6 | 7 | 然后,质数 不是 负数。同样的,1 和 0 也不是,因此,首先测试这些数字。 8 | 9 | 此外,2 是质数中唯一的偶数。没有必要再检查其他的偶数。 10 | 11 | 当然,还有其他的一些优化方法,比如,如果一个数字不能被5整除,它也不会被5的倍数整除。所以,没有必要检测10,15,20等等。 12 | 13 | 最后一点,你不需要检查比输入数字的开方还要大的数字。 14 | 15 | ### 答案 16 | 17 | ```JavaScript 18 | function isPrime (number) { 19 | // Alternatively you can throw an error. 20 | if (typeof number !== 'number' || number <= 1) return false; 21 | 22 | if (number <= 3) return true; 23 | 24 | if (number % 2 === 0 || number % 3 === 0) return false; 25 | 26 | var square = Math.sqrt(number); 27 | for (var i = 5; i < square; i + 6) { 28 | if (number % i == 0 || number % (i + 2) === 0) return false; 29 | } 30 | 31 | return true; 32 | } 33 | ``` 34 | 35 | ### 算法 36 | 相关说明:[Primality test - Wikipedia](https://en.wikipedia.org/wiki/Primality_test) 37 | 38 | -------------------------------------------------------------------------------- /JavaScript/内置对象/JavaScript Boolean.md: -------------------------------------------------------------------------------- 1 | Boolean 是与布尔值对应的引用类型。 2 | 3 | ### 1. 基本 4 | 5 | 创建 Boolean 对象可以使用 new 关键词,并传入 true 或 false 值。 6 | 7 | 需要注意的是,Boolean 对象也是一个对象,所以转换成基本类型的布尔值时,总是 true,这和创建 Boolean 对象时传入的是 true 还是 false 无关。 8 | 9 | 比如: 10 | 11 | ```JavaScript 12 | var falseBoolean = new Boolean(false); 13 | if (falseBoolean) { 14 | console.log('falseBoolean 转换成布尔值是 true') 15 | } else { 16 | console.log('falseBoolean 转换成布尔值是 false') 17 | } 18 | // falseBoolean 转换成布尔值是 true 19 | ``` 20 | 21 | 而且,基本类型的布尔值不是 Boolean 的实例,而且它们的`typeof`结果也不同: 22 | 23 | ```JavaScript 24 | var falseObject = new Boolean(false); 25 | var falseValue = false; 26 | 27 | console.log(typeof falseObject); // "object" 28 | console.log(typeof falseValue); // "boolean" 29 | console.log(falseObject instanceof Boolean); // true 30 | console.log(falseValue instanceof Boolean); // false 31 | ``` 32 | 33 | ### 2. 方法 34 | 35 | * `valueOf()` Boolean 类型的实例重写了该方法,返回基本类型值 true 或 false。 36 | * `toString()` 返回字符串`"true"`或`"false"`。 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Go/数据类型/Go Array.md: -------------------------------------------------------------------------------- 1 | > 转摘:[Go切片与技巧(附图解)](https://mp.weixin.qq.com/s/IQRHWNUnxiaCDleayNVRVg) 2 | 3 | ### 1. 定义 4 | 5 | Go 中 Array **数组的定义包含类型和长度**,这两者同时组成了一个特定的数组类型: 6 | 7 | ```go 8 | // 数组类型:定义指定长度和元素类型 9 | var a [4]int 10 | 11 | // 数组中数据的存取 12 | a[0] = 1 13 | i := a[0] 14 | 15 | fmt.Println(i) // 1 16 | fmt.Println(a[1]) // 0 (数组不需要显式的初始化,其元素默认被设置为零值) 17 | fmt.Println(a[4]) // panic: invalid array index 4 (out of bounds for 4-element array) 18 | ``` 19 | 20 | ### 2. 值类型 21 | 22 | **Go 的数组是值类型**,不像 C 语言数组变量是指向第一个元素的指针。所以当把数组变量传递或者赋值的时候,其实是做 copy 操作。 23 | 24 | 比如,下面的例子 a 赋值给 b,修改 a 中的元素并不会影响 b 中的元素: 25 | 26 | ```go 27 | a := [2]string{"johnny", "太白技术"} 28 | b := a 29 | a[0] = "xujiajun" 30 | fmt.Println(a) // 输出:[xujiajun 太白技术] 31 | fmt.Println(b) // 输出:[johnny 太白技术] 32 | ``` 33 | 34 | 为了避免复制,可以传递一个指向数组的指针,例如: 35 | 36 | ```go 37 | func double(arr *[3]int) { 38 | for i, num := range *arr { 39 | (*arr)[i] = num * 2 40 | } 41 | } 42 | 43 | a := [3]int{1, 2, 3} 44 | double(&a) 45 | fmt.Println(a) // [2 4 6] 46 | ``` 47 | 48 | -------------------------------------------------------------------------------- /Go/杂项/Go 杂项.md: -------------------------------------------------------------------------------- 1 | ## 一、常规事项 2 | 3 | ### 1.1 package 不支持循环导入 4 | 5 | Go 中包是不支持循环导入的,这会对 Go 的构建性能和依赖关系造成非常不利的影响。而且在 Go2 中官方也明确拒绝了循环导入的提案。 6 | 7 | Go 语言之父 Rob Pike 对该问题有专门的回答: 8 | 9 | * 不支持循环引用,目的是迫使 Go 程序员更多地考虑程序的依赖关系。 10 | 11 | - 保持依赖关系图的简洁,是一个 DAG(Directed acyclic graph,有向无环图); 12 | - 快速的程序构建。 13 | 14 | * 如果支持循环引用,容易造成懒惰、不良的依赖性管理和缓慢的构建。 15 | 16 | - 混乱的依赖关系; 17 | - 缓慢的程序构建。 18 | 19 | ## Go 调试工具 20 | 21 | ### gdb/cgdb 22 | 23 | ```shell 24 | go build -gcflags "-N -l" -o main 25 | gdb main 26 | ``` 27 | 28 | 常用 [gdb](https://linuxtools-rst.readthedocs.io/zh_CN/latest/tool/gdb.html) 的调试命令: 29 | 30 | * run 31 | * continue 32 | * break 33 | * backtrace / frame 34 | * info break / locals 35 | * list 36 | * print / ptype 37 | * disass 38 | 39 | [cgdb](https://cgdb.github.io/) 是 gdb 的增强调试命令,其视窗分为两个部分,上面显示源代码,下面是具体的命令行调试界面(跟 gdb 一样)。 40 | 41 | ### delve 42 | 43 | [delve](https://github.com/go-delve/delve) 是使用 go 语言开发的,功能是十分强大,打印结果可以显示 gdb 支持不了的东西。 44 | 45 | [dlv](https://github.com/aarzilli/gdlv) 则带图形化界面。 46 | 47 | 48 | -------------------------------------------------------------------------------- /CSS/属性/user-select.md: -------------------------------------------------------------------------------- 1 | 有时候需要保护页面上的内容,不被随意的复制,可以使用 CSS 中的`user-select`属性来做简单的防护。 2 | 3 | > 当然,在前端页面上做防护,永远不能彻底的保护内容。因为总会有方法内容获取到,在此只是做一个最基础的防护功能。 4 | 5 | 可取值如下: 6 | 7 | - `none` 禁止选择 8 | - `auto` 浏览器来决定是否允许选择 9 | - `all` 可以选择任何内容 10 | - `text` 只能选择文本 11 | - element 指定一个元素,使得可以选择这个元素以内的内容 12 | 13 | `user-select`是一个 CSS 2 中的属性,但是并没有被各浏览器以标准的行为来实现,所以使用中还要加上各种前缀: 14 | 15 | ```css 16 | .no-select { 17 | -moz-user-select: none; 18 | -ms-user-select: none; 19 | -webkit-user-select: none; 20 | user-select:none; 21 | } 22 | ``` 23 | 24 | > IE8 及更早的 IE 不支持。 25 | 26 | 另外,还可以使用 JavaScript 来禁止选择,这样就能兼容到低版本的 IE 浏览器了: 27 | 28 | ```js 29 | // 禁用选择 30 | function disabledSelection () { 31 | // IE 浏览器 32 | document.onselectstart = function () { return false } 33 | // 其他浏览器 34 | document.onmousedown = function () { return false } 35 | } 36 | // 启用选择 37 | function enableSelection () { 38 | // IE 浏览器 39 | document.onselectstart = null; 40 | // 其他浏览器 41 | document.onmousedown = null; 42 | } 43 | ``` 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /Git/Git 父提交.md: -------------------------------------------------------------------------------- 1 | 在 Git 的版本管理中,每一次提交 Git 会保存一个提交对象(commit object),而每一次提交产生的提交对象都有一个父对象,即本次提交的上次提交。这是 Git 的数据存储方式。 2 | 3 | Git 中有一个特殊的指针`HEAD`,它指向当前所在的本地分支(也可以认为是本地当前分支的别名),但是 HEAD 并不是那么简单的指向最后一次提交那么简单。 4 | 5 | ### 没有分支 6 | 7 | 如果所有的提交都在同一个分支(假设是 master)产生,`HEAD`应该指向该分支的最后一次提交,如图所示: 8 | 9 | ![HEAD 无分支](http://cnd.qiniu.lin07ux.cn/markdown/1473486415408.png) 10 | 11 | 在这样的一个仓库中,因为没有合并产生,任何一次提交都是没有第二父提交的。自然,在这样的仓库中,`HEAD^`或`HEAD~1`指向的是倒数第二次提交,`HEAD^^`或`HEAD~2`指向的是倒数第三次提交,依次类推,都是正确的。 12 | 13 | ### 有分支 14 | 15 | 如果有分支合并情况,假设目前的分支状态如下: 16 | 17 | ![HEAD 有分支](http://cnd.qiniu.lin07ux.cn/markdown/1473486625039.png) 18 | 19 | 在`qwq3`的时候有分支`test`产生,分支`test`于`db56`提交后,合并入`master`分支并产生提交`ad0b`。 20 | 21 | 此时,`HEAD`指向的就是最后一次提交`ad0b`,但是*`HEAD^`和`HEAD~1`是指向`20af`还是`db56`呢?* 22 | 23 | 根据 Git Pro 中的说明,`HEAD`目前指向`master`分支,其第一父提交应为合并前的`20af`,第二父提交为`db56`。在这种情况下,`HEAD^`和`HEAD~1`只会拿第一父提交往前追溯,那么基于这样的机制,使用`git show HEAD^^`显示的就是当前分支上的倒数第三次提交,而不会计入合并机进来的分支上的提交情况。 24 | 25 | 那么,如果想要显示最近的 10 次提交(包含合并进来的提交),怎么办呢? 26 | 27 | `git log -10` 28 | 29 | 这样就可行了。 30 | 31 | 32 | -------------------------------------------------------------------------------- /Mac/问题/Mac Brew.md: -------------------------------------------------------------------------------- 1 | ### 1. Mac Updating Homebrew... 长时间不动 2 | 3 | 由于 Homebrew 默认使用的 git 仓库在国内访问较慢,所以会造成在使用 brew 的时候,经常会提示`Updating Homebrew...`并卡住不动。可以通过修改 Homebrew 的安装源来解决这个问题。 4 | 5 | ```shell 6 | # 替换 brew.git 7 | cd "$(brew --repo)" 8 | git remote set-url origin https://mirrors.ustc.edu.cn/brew.git 9 | 10 | # 替换 homebrew-core.git: 11 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-core" 12 | git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-core.git 13 | 14 | # 如果使用了 homebrew-cask 还需要替换 Homebrew Cask 的地址 15 | cd "$(brew --repo)/Library/Taps/homebrew/homebrew-cask" 16 | git remote set-url origin https://mirrors.ustc.edu.cn/homebrew-cask.git 17 | ``` 18 | 19 | > 转摘:[Mac 解决brew一直卡在Updating Homebrew](https://www.jianshu.com/p/7cb05a2b39a5) 20 | 21 | ### 2. Error: php@7.3 has been disabled because it is a versioned formula 22 | 23 | 安装旧版本 PHP 提示错误,无法安装,可以通过`shivammathur/php`来安装。 24 | 25 | 1. `brew tap shivammathur/php` 仅需执行一次,表示安装这个包。 26 | 2. `brew install shivammathur/php/php@7.4` 安装指定版本的 PHP 27 | 3. `brew link php@7.4` 连接指定的版本 -------------------------------------------------------------------------------- /杂项/Sublime Text/Sublime Text 3 常用插件.md: -------------------------------------------------------------------------------- 1 | ## HTML 2 | 3 | * `Emmet` 可以快速编写 HTML、CSS 代码。是以前的 Zen Coding。 4 | 5 | [参考 1](http://www.qianduan.net/zen-coding-a-new-way-to-write-html-code/) 6 | [参考 2](http://caibaojian.com/emmet.html) 7 | 8 | ## JavaScript 9 | 10 | * `jQuery` 11 | * `JSFormat` JS 代码格式化 12 | * `JSMinifier` JS 代码压缩 13 | * [`Minify`](https://github.com/tssajo/minify) 压缩或美化 JS、JSON、CSS、HTML、SVG 等多种文件 14 | 15 | > Minify 需要借助 Node 和相关的插件来实现具体格式的文件的压缩和美化,常见的插件如下:`npm install -g clean-css-cli uglifycss js-beautify html-minifier uglify-js minjson svgo`。不需要的可以不安装。 16 | 17 | ## CSS 18 | 19 | * `Autoprefixer` CSS 前缀自动补全 20 | 21 | ## PHP 22 | 23 | * PHP Companion 24 | 25 | [PHP Companion](https://github.com/erichard/SublimePHPCompanion) 包含很多实用的功能,但是默认没有 keymapping,可以参照 [Learn more about how to set up PHPCompanion keymapping here](http://huangzhiqun.com/external/https://github.com/erichard/SublimePHPCompanion/blob/master/messages/1.0.0.txt) 进行配置。 26 | 27 | 28 | ## 其他 29 | 30 | * `Clipboard History` 粘贴板历史 31 | 32 | 33 | -------------------------------------------------------------------------------- /DB/PostgreSQL/设置/PostgreSQL 定时备份.md: -------------------------------------------------------------------------------- 1 | 通过 Linux 系统的 Crontab 服务可以定时对 PostgreSQL 数据进行备份,而备份使用的命令是`pg_dumpall`。该命令会将全部的数据库和数据都备份下来。备份下来之后,还可以对其进行压缩,以便节约存储空间。 2 | 3 | 1. 首先,创建自动备份脚本 4 | 5 | 创建脚本`backup.sh`,内容如下: 6 | 7 | ```shell 8 | #!/bin/bash 9 | 10 | cur_date=$(date '+%Y-%m-%d') 11 | before_date=$(date -d -10days '+%Y-%m-%d') 12 | su - postgres < "$cur_date.dmp" 17 | 18 | echo "Compressing..." 19 | tar zcvf "./$cur_date.tar.gz" *.dmp 20 | chmod 0600 $cur_date.tar.gz 21 | 22 | echo "Remove temp file ..." 23 | rm -rf *.dmp 24 | echo "Finish Backup ..." 25 | exit 26 | ! 27 | ``` 28 | 29 | 2. 设置 crontab 计划 30 | 31 | 运行`crontab -e`命令,来将上面创建的脚本定时执行: 32 | 33 | ```shell 34 | 0 2 * * * /var/lib/pgsql/backup.sh 35 | ``` 36 | 37 | > 参考:[PostgreSQL定时自动备份](https://blog.csdn.net/sunbocong/article/details/77936601) 38 | 39 | -------------------------------------------------------------------------------- /Linux/CentOS/CentOS user 用户操作.md: -------------------------------------------------------------------------------- 1 | ## useradd 添加用户 2 | 3 | 添加用户使用`useradd `。 4 | 5 | ## usermod 修改用户信息 6 | 7 | 8 | ### 问题 9 | 在修改用户的信息的时候(如主目录)的时候,可能会出现*当前用户正在使用中*错误: 10 | 11 | ```shell 12 | $ usermod -d /home/user502home user502 13 | > usermod: user502 is currently used by process 4220 14 | ``` 15 | 16 | 这是由于有其他应用是以该用户的身份和权限在运行的。可以通过`ps -fp `来查看是什么程序,然后关闭程序或者直接`kill `结束进程: 17 | 18 | ```shell 19 | $ ps -fp 4220 20 | > UID PID PPID C STIME TTY TIME CMD 21 | > www 742 800 0 5月24 ? 00:00:03 php-fpm: pool www 22 | ``` 23 | 24 | 这里显示是被 php-fpm 程序使用的,可以停止这个程序,然后重新修改用户的主目录即可。 25 | 26 | ## userdel 删除用户 27 | 28 | 删除用户使用如下的命令: 29 | 30 | ```shell 31 | userdel 32 | userdel -f tmp_name # 连同用户目录一并删除 33 | ``` 34 | 35 | > 注意:如果用户还在登陆的话,删除时会提示,用户正在登陆无法删除。此时可能需要先强制用户退出。 36 | 37 | ## passwd 修改密码 38 | 39 | 修改用户的登录密码使用`passwd `命令,然后就会提示你输入用户的新密码并需要确认重输一遍。 40 | 41 | ## 强制退出登录 42 | 43 | * 首先查看当前已经登录的用户:`w`。 44 | * 然后退出指定用户:`pkill -kill -t [TTY]`。 45 | 46 | > TTY 根据`w`的查看结果中得到。 47 | 48 | -------------------------------------------------------------------------------- /JavaScript/杂项/jQuery 笔记.md: -------------------------------------------------------------------------------- 1 | ## 一、DOM 相关 2 | 3 | ### 1.1 删除元素 4 | 5 | * `remove()` - 删除被选元素(及其子元素) 6 | * `empty()` - 从被选元素中删除子元素 7 | 8 | ### 1.2 添加元素 9 | 10 | * `before()` - 在元素前面添加元素 11 | * `after()` - 在元素后面添加元素 12 | 13 | ### 1.3 获取标签名(tagName) 14 | 15 | 如果是为了取到 tagName 后再进行判断,那直接用下面的代码会更方便:`$(element).is('input')`。 16 | 17 | 如果是要取到标签用作到别的地方,可以使用以下代码: 18 | 19 | * `$(element)[0].tagName` 20 | * `$(element).get(0).tagName` 21 | * `$(element).prop("tagName")` 22 | 23 | ## 二、技巧 24 | 25 | ### 2.1 点击 text 的 input 后,直接选中其中的所有文字: 26 | 27 | ```js 28 | $("input:text").click(function () { 29 | $(this).select(); 30 | }); 31 | ``` 32 | 33 | ### 2.2 获取 select 标签的文本和值 34 | 35 | ```js 36 | jQuery("#select1 option:selected").text(); // 获取选中的值的文本 37 | jQuery("#select1").val(); // 获取选中的值的 value 属性值 38 | ``` 39 | 40 | ### 2.3 滚动到指定位置 41 | 42 | 43 | ```js 44 | var container = $('div'), 45 | scrollTo = $('#row_8'); 46 | 47 | container.scrollTop( 48 | scrollTo.offset().top - container.offset().top + container.scrollTop() 49 | ); 50 | ``` 51 | 52 | 53 | -------------------------------------------------------------------------------- /Nginx/问题/Nginx 无法上传文件.md: -------------------------------------------------------------------------------- 1 | 2 | ### 问题 3 | Nginx 搭建的 PHP 服务器,无法上传文件,准确的说,是无法上传常规大小的文件。对于很小的文件则可以正常上传。 4 | 5 | ### 排查 6 | php.ini 中已经开启了文件上传功能,大小限制在 2M。已经开启 PHP 的日志记录,但是并没有相应的错误日志出现。php-fpm 的错误日志中也没有找到对应的错误日志。 7 | 8 | Nginx 的错误日志(/var/log/nginx/error.log)中则出现相应的错误信息: 9 | 10 | ``` 11 | [crit] 796#0: *2397 open() "/var/lib/nginx/client_body/0000000003" failed (13: Permission denied) 12 | ``` 13 | 14 | 很明显,这里指明了是权限问题。 15 | 16 | ### 解决 17 | 这里说明的是不能读取`/var/lib/nginx/client_body/`中的文件。查看`/var/lib/nginx/`文件夹的权限: 18 | 19 | ``` 20 | ls -l /var/lib/ | grep nginx 21 | ``` 22 | 23 | 和运行 nginx 服务的用户-组并不相同,所以导致出现问题。 24 | 25 | 修改`/var/lib/nginx/`文件夹的权限,使其和运行 nginx 服务的用户-组一致: 26 | 27 | ``` 28 | chown -R www:www /var/lib/nginx/ 29 | ``` 30 | 31 | ### 备注 32 | 参考:[nginx cannot upload regular sized files permission denied](https://blog.lysender.com/2015/05/nginx-cannot-upload-regular-sized-files-permission-denied/) 33 | 34 | 前面提到过,在不能上传常规大小文件的时候,小文件还是能够正常上传的。这可能是因为,Nginx 在文件很小(至少小于 200K,具体界限不清楚)的情况下,Nginx 并不将文件写入到临时目录中,所以不会遇到权限问题。而对于大文件,则必须要写入到临时目录中才可以,则必然要权限正常。 35 | 36 | -------------------------------------------------------------------------------- /PHP/知识点/SCRIPT_FILENAME 与 __FILE__ 的区别.md: -------------------------------------------------------------------------------- 1 | `$_SERVER['SCRIPT_FILENAME']`是客户端请求的资源文件的路径;`__FILE__`是当前运行脚本所在的资源文件路径。 2 | 3 | 初看它们好像应该是同一个文件。确实,一般情况下,它们会是同一个文件,但是当有文件引用(`include`或`require`)的时候,它们就有区别了。看下面的例子。 4 | 5 | 文件 a.php: 6 | 7 | ```php 8 | ', f; 20 | ``` 21 | 22 | 1. 此时,访问 a.php 的时候,会显示类似如下的输出: 23 | 24 | /usr/share/nginx/html/a.php; 25 | /usr/share/nginx/html/b.php; 26 | 27 | 也即是说,访问 a.php 的时候,在 b.php 文件中`$_SERVER['SCRIPT_FILENAME']`和`__FILE__`分别是 a.php 和 b.php 文件的绝对路径。 28 | 29 | 2. 再看直接访问 b.php 的时候,会显示类似如下的输出: 30 | 31 | /usr/share/nginx/html/b.php; 32 | /usr/share/nginx/html/b.php; 33 | 34 | 也即是说,直接访问 b.php 的时候,`$_SERVER['SCRIPT_FILENAME']`和`__FILE__`都是 b.php 文件的绝对路径。 35 | 36 | 综上,我们的结论是: 37 | 38 | - 共同点:这两者返回的都是 php 文件的绝对路径,在没有引用包含的情况下,他们是相同的。 39 | - 不同点:如果有包含关系的时候,`$_SERVER['SCRIPT_FILENAME']`永远指向的是当前请求资源的绝对路径及文件名,而`__FILE__`则是指向原始文件(被包含文件)的绝对路径和文件名。 40 | 41 | 42 | -------------------------------------------------------------------------------- /Python/安装/Python pip.md: -------------------------------------------------------------------------------- 1 | pip 是 Python 包管理工具,该工具提供了对Python 包的查找、下载、安装、卸载的功能。 2 | 3 | [pip 官网](https://pypi.org/project/pip/) 4 | 5 | ### 安装 6 | 7 | 如果未安装过 pip,则可以通过如下的命令来安装: 8 | 9 | ```shell 10 | curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py 11 | sudo python get-pip.py 12 | ``` 13 | 14 | 如果同时安装了 Python 2.x 和 Python 3.x,那么就会有两个 pip:pip2(或 pip) 和 pip3。一般情况下,pip 就表示 pip2。 15 | 16 | > 不论是 pip2 还是 pip3,都只需要通过这种方式安装一次即可。 17 | 18 | ### 升级 19 | 20 | 可以通过如下命令来查看是否需要升级: 21 | 22 | ```shell 23 | pip show pip 24 | ``` 25 | 26 | 如果需要升级,会有类似如下的输出: 27 | 28 | ```shell 29 | ou are using pip version 9.0.1, however version 18.1 is available. 30 | You should consider upgrading via the 'pip install --upgrade pip' command. 31 | ``` 32 | 33 | 如果需要进行更新,则可以通过如下方式进行升级: 34 | 35 | ```shell 36 | pip install --upgrade pip 37 | # 或 38 | pip3 install --upgrade pip 39 | ``` 40 | 41 | > 如果同时安装了 Python 2.x 和 Python 3.x,那么只需要更新一个即可。 42 | 43 | 44 | 这种方式也可以用来安装和升级 Python 包: 45 | 46 | ```shell 47 | pip install 48 | pip install --upgrade 49 | ``` 50 | 51 | -------------------------------------------------------------------------------- /杂项/Markdown/Markdown 高级用法.md: -------------------------------------------------------------------------------- 1 | ### 1. 字符 2 | 3 | 字符 | 描述 | 实体名称 | 实体编号 4 | :--------------|:-------|:---------|:-------- 5 | | 空格 | ` ` | ` ` 6 | `<` | 小于号 | `<` | `<` 7 | `>` | 大于号 | `>` | `>` 8 | `&` | 与号 | `&` | `&` 9 | `"` | 双引号 | `"` | `"` 10 | `'` | 单引号 | `'` | `'`; 11 | `|` | 竖线 | | `|` 12 | 13 | 由于表格是用`|`符号来分隔的,所以如果在单元格中需要输入这个符号,就要用实体符号`|`替代。 14 | 15 | > 更多实体字符可以参考:[HTML特殊字符编码对照表](https://www.jb51.net/onlineread/htmlchar.htm) 16 | 17 | ### 2. 标记 18 | 19 | Markdown 文档也支持 HTML 标记,常用的标记有: 20 | 21 | * `` 键盘符号,如:Ctrl + Alt + Del 22 | * `` 上标,展示的更靠上且更小,如:xy 23 | * `` 下标,展示的更靠下且更小,如:a1 24 | 25 | ### 3. 图示 26 | 27 | 不同的平台对 Markdown 的图示支持不尽相同,主要有以下几种图示语法: 28 | 29 | * mermaid:[mermaid 语法](https://cloud.tencent.com/developer/article/1334691)、[Markdown 高级技巧](https://www.runoob.com/markdown/md-advance.html) 30 | * flow 31 | * sequence 32 | 33 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript 使用 HTML5 Blob 实现文本信息文件下载.md: -------------------------------------------------------------------------------- 1 | 原理其实很简单,可以将文本或者 JS 字符串信息借助 Blob 转换成二进制,然后,作为``元素的`href`属性,配合`download`属性,实现下载。 2 | 3 | 代码也比较简单,如下示意(兼容 Chrome 和 Firefox): 4 | 5 | ```javascript 6 | var funDownload = function (content, filename) { 7 | // 创建隐藏的可下载链接 8 | var eleLink = document.createElement('a'); 9 | eleLink.download = filename; 10 | eleLink.style.display = 'none'; 11 | // 字符内容转变成blob地址 12 | var blob = new Blob([content]); 13 | eleLink.href = URL.createObjectURL(blob); 14 | // 触发点击 15 | document.body.appendChild(eleLink); 16 | eleLink.click(); 17 | // 然后移除 18 | document.body.removeChild(eleLink); 19 | }; 20 | ``` 21 | 22 | 其中,`content`指需要下载的文本或字符串内容,`filename`指下载到系统中的文件名称。 23 | 24 | 不止是 .html 文件, .txt , .json 等只要内容是文本的文件,都是可以利用这种小技巧实现下载的。 25 | 26 | 在 Chrome 浏览器下,模拟点击创建的``元素即使不 append 到页面中,也是可以触发下载的,但是在 Firefox 浏览器中却不行,因此,上面的`funDownload()`方法有一个`appendChild`和`removeChild`的处理,就是为了兼容 Firefox 浏览器。 27 | 28 | > `download`属性从 Edge13 开始支持,理论上,Edge 也应该支持直接 JS 触发的浏览器文件下载,但是没有测过。 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /杂项/微信/微信小程序.md: -------------------------------------------------------------------------------- 1 | ### iOS 上当前激活的 tab 的文字不显示 2 | 3 | 在`app.json`中,`tabBar`里面的`selectedColor`用来配置 tab 激活时文字的颜色,虽然可以使用颜色的英文名称,但是这样会导致在 iOS 里面出现激活时文字不显示的情况,此时需把颜色名称改成对应的十六进制。 4 | 5 | 如:需要将`"selectedColor": "green"`改成`"selectedColor": "#00ff00"`。 6 | 7 | ### 提示:Do not have handler in component 8 | 9 | WXML 端采用`model:`来双向绑定: 10 | 11 | ```html 12 | 13 | ``` 14 | 15 | 控制台会有`warning:“Do not have handler in component XXXXXX”`的错误: 16 | 17 | ![](https://cnd.qiniu.lin07ux.cn/markdown/1666276150) 18 | 19 | 报这个 Warning 的原因是没有绑定对应的`input`事件。、 20 | 21 | 在不影响最终结果的情况下可以无视报错,如果看着难受可以`bind`一个空函数。 22 | 23 | WXML 部分: 24 | 25 | ```html 26 | 27 | ``` 28 | 29 | WXS 部分: 30 | 31 | ```js 32 | // 空方法 33 | nop(){} 34 | ``` 35 | 36 | ### button border 无法去掉 37 | 38 | button 在小程序中边框无法去掉,这是因为它在伪元素中设置边框的。去除方式如下: 39 | 40 | ```css 41 | button::after { 42 | border: none; 43 | } 44 | ``` 45 | 46 | 47 | -------------------------------------------------------------------------------- /JavaScript/Vue/vue-cli/Vue-cli 问题.md: -------------------------------------------------------------------------------- 1 | ### 资源路径 2 | 3 | 在项目中,默认会生成两个存放资源素材的文件夹:`static/`和`src/assets`。其中,前者是真正的静态文件目录,该目录下的所有文件在 build 的时候都会直接拷贝到 dist 目录中;后者则是需要先在项目中被引用,build 的时候才会处理到 dist 目录中。 4 | 5 | 在引用`static/`中的资源的时候,直接使用`/static/filename.ext`这种格式即可,而引用`src/asstes/`中的资源的时候则需要有一定的设置。 6 | 7 | > 可以先查看官方文档:[Handing Static Assets](http://vuejs-templates.github.io/webpack/static.html)。 8 | 9 | 如果想通过`~assets/filename.ext`的方式进行访问,则先需要在 Webpack 的配置文件中设置对应的`resolve`项。比如,在 Vue-cli 2.8 版本中,需要在`build/webpack.base.conf.js`文件中,找到`resolve.alias`设置处,默认情况下,其配置如下: 10 | 11 | ```JavaScript 12 | resolve: { 13 | extensions: ['.js', '.vue', '.json'], 14 | alias: { 15 | '@': resolve('src') 16 | } 17 | } 18 | ``` 19 | 20 | 可以看到,默认已经设置了一个`@`作为`src`文件的别名(所以我们可以在项目中使用`@`表示`src/`目录)。为了能够使 webpack 自动解析`~assets/`开头的资源,我们需要添加`'assets': resolve('src/assets')`到这个`alias`对象中,修改后如下: 21 | 22 | 23 | ```JavaScript 24 | resolve: { 25 | extensions: ['.js', '.vue', '.json'], 26 | alias: { 27 | '@': resolve('src'), 28 | 'assets': resolve('src/assets') 29 | } 30 | } 31 | ``` 32 | 33 | 34 | -------------------------------------------------------------------------------- /Python/技巧/从 String 中提取 bytes.md: -------------------------------------------------------------------------------- 1 | 由于未设置好编码或其他问题,导致写入到文件中的内容是一些 utf-8 编码,而不是正常的文字(中文),这时就需要想办法将其中的编码转换成文字。 2 | 3 | 可以考虑使用如下的方法: 4 | 5 | 1. 先从字符串中截取对应的编码; 6 | 2. 将其构造成类似 bytes 格式的字符串; 7 | 3. 将该字符串解析成 bytes 格式的内容; 8 | 4. 从 bytes 中获取到真实的字符。 9 | 10 | 具体操作如下: 11 | 12 | ```py 13 | import ast 14 | 15 | file = open('/path/to/file', 'r') 16 | 17 | # 从文件中获取一行,并截取其中的 utf-8 编码字符串 18 | string = file.readline()[:20] 19 | # 将编码字符串构造成类似 bytes 格式的字符串 20 | string = r"b'" + string + "'" 21 | # 使用 ast 将字符串解析成 bytes 对象 22 | bytes = ast.literal_eval(string) 23 | # 将 bytes 对象解码成对应的文字 24 | word = bytes.decode('utf-8') 25 | print(word) 26 | ``` 27 | 28 | 上面就是对应的实现方式,虽然可以使用 Python 自带的`eval()`函数来完成字符串到 bytes 对象的解析,但是其并不安全,建议使用 ast 库。 29 | 30 | 另外,对于直接将 utf-8 编码(或其他编码也行)的字符串进行解析的情况下,可以直接使用如下的方式: 31 | 32 | ```py 33 | string = '\xe4\xb8\xad\xe6\x96\x87' 34 | word = string.encode('raw_unicode_escape').decode() 35 | ``` 36 | 37 | 这是因为直接赋值和从文件中读取时,Python 对其的处理不同(具体是什么样的我也不清楚),直接赋值可以直接被当做编码过的 unicode 字符串来处理。 38 | 39 | > 参考:[python3.x 如何从str中提取bytes?](https://www.zhihu.com/question/43161731) 40 | 41 | 42 | -------------------------------------------------------------------------------- /PHP/问题/PHP 无法开启 session.md: -------------------------------------------------------------------------------- 1 | 2 | ## 问题 3 | 4 | PHP 环境搭建好了,但是后台无法登陆,分析数据都是正常的,最后分析,很有可能是 session 没有开启导致的。 5 | 6 | 检查配置文件,均正常,而且程序已经开启了 session,但仍旧无法保存 session 数据。 7 | 8 | ## 验证 9 | 10 | 写一个`session_test.php`文件,看看能否每次刷新数值都增加: 11 | 12 | ```php 13 | 'a11', 13 | 'b' => 'b11', 14 | 'c' => 'c11', 15 | ); 16 | 17 | foreach ($arr as $k => &$v) { 18 | var_dump($v); 19 | } 20 | 21 | echo "
"; 22 | 23 | var_dump($v); 24 | 25 | echo "
"; 26 | 27 | foreach ($arr as $k => $v) { 28 | var_dump($v); 29 | } 30 | ``` 31 | 32 | 上面的代码中,第一个输出为: 33 | 34 | ``` 35 | string(3) "a11" 36 | string(3) "b11" 37 | string(3) "c11" 38 | ``` 39 | 40 | 第二个输出: 41 | 42 | ``` 43 | string(3) "c11" 44 | ``` 45 | 46 | 第三个输出为: 47 | 48 | ``` 49 | string(3) "a11" 50 | string(3) "b11" 51 | string(3) "b11" 52 | ``` 53 | 54 | ### 解释 55 | 56 | 因为 PHP foreach 循环中,使用引用的时候,在循环结束时,引用不会取消,所以第一次循环结束后,`$v`仍然指向的是`$arr['c']`。 57 | 58 | 于是,第二个输出就是 "c11"。 59 | 60 | 在第二次循环中,每一次都要将`$arr`数组的元素值赋值给`$v`变量,也即是赋值给`$arr['c']`,也就是说,随着第二次循环的进行,`$arr['c']`依次从`"c11"`变成了`"a11"`,再变成了`"b11"`。所以在循环到`$arr['c']`时,其值已经变成了`"b11"`,最后输出的就是`"b11"`而不是`"c11"`。 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /DB/MySQL/查询指令/GROUP BY 数据分组.md: -------------------------------------------------------------------------------- 1 | ## 一、简介 2 | 3 | `GROUP BY`子句能够将查询到的数据进行分组,再进行处理。一般用于数据的统计、过滤中。 4 | 5 | ## 二、使用 6 | 7 | ### 2.1 过滤重复值 8 | 9 | GROUP BY 子句可以根据某个字段来过滤重复值。这个字段比 DISTINCT 更方便,而且速度上也略胜一筹: 10 | 11 | ```sql 12 | SELECT id, COUNT(1) AS total FROM fruits GROUP BY id; 13 | ``` 14 | 15 | ### 2.2 合并重复记录的某个字段的全部值 16 | 17 | 在使用 GROUP BY 子句的时候,还可以使用`GROUP_CONCAT()`方法,来将那些重复记录的中的某个字段的值都合并起来,并使用`,`分割: 18 | 19 | ```sql 20 | SELECT id, GROUP_CONCAT(name) AS NAMES FROM fruits GROUP BY id; 21 | ``` 22 | 23 | 这样会根据 id 来过滤重复值,并将相同的 id 的记录中的 name 字段的值合并起来,每两个值之间使用英文逗号`,`分割。 24 | 25 | ### 2.3 分组后统计总数 26 | 27 | 还可以使用`WITH ROLLUP`关键字,用来在分组的统计数据的基础上再进行相同的统计(SUM,AVG,COUNT…): 28 | 29 | ```sql 30 | SELECT id, COUNT(1) AS total FROM fruits GROUP BY id WITH ROLLUP; 31 | ``` 32 | 33 | 上面的这个语句会在分组统计的基础上,对结果中的 total 字段也使用一次 COUNT 方法,来计算总的数目。所以,结果可能会类似如下: 34 | 35 | ``` 36 | id total 37 | 1001 1 38 | 1002 3 39 | 1003 2 40 | NULL 6 41 | ``` 42 | 43 | 其中,最后一行 id 为 NULL 的记录中,total 为 6,就是对前面的结果中的 total 进行统计之后得出的。 44 | 45 | > 注意:当使用`WITH ROLLUP`时,不能同时使用`ORDER BY`子句进行结果排序,即`WITH ROLLUP`和`ORDER BY`是互相排斥的! 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /Go/问题/Go 值为 nil 能调用函数吗.md: -------------------------------------------------------------------------------- 1 | > [Go 读者提问:值为 nil 能调用函数吗?](https://mp.weixin.qq.com/s/mH51UmolTqCAb7E0LxEjDA) 2 | 3 | ### 1. 问题 4 | 5 | 下面的程序能否正常执行: 6 | 7 | ```go 8 | type T struct{} 9 | 10 | func (t *T) Hello() string { 11 | if t == nil { 12 | fmt.Println("脑子进煎鱼了") 13 | return "" 14 | } 15 | return "煎鱼进脑子了" 16 | } 17 | 18 | func main() { 19 | var t *T 20 | t.Hello() 21 | } 22 | ``` 23 | 24 | ### 2. 答案 25 | 26 | 可以正常运行,且运行结果为: 27 | 28 | ``` 29 | 脑子进煎鱼了 30 | ``` 31 | 32 | ### 3. 解释 33 | 34 | Go 中结构体的方法只是一种书写上的语法糖,在调用时,结构体实例会作为方法的第一个参数(接收者)传入。因为方法是允许接收一个值为 nil 的参数的,所以结构体实例的值为 nil 依旧可以调用该结构体类型的方法。 35 | 36 | 实际上,在 Go 表达式中,`Expression.Method()`的语法所调用的方法完全由`Expression`的类型决定。其调用函数的指向不是由该表达式的特定运行时的值来决定。 37 | 38 | 也就是说: 39 | 40 | ```go 41 | func (p *SomeType) SomeMethod(firstArg int) { 42 | // TODO 43 | } 44 | ``` 45 | 46 | 本质上是: 47 | 48 | ```go 49 | func SomeTypeSomeMethod(p *SomeType, firstArg int) { 50 | // TODO 51 | } 52 | ``` 53 | 54 | 由于参数`p *SomeType`是有具体上下文累心的,自然也就能调用到相应的方法。如果没有任何上下文类型,例如`nil.SomeMethod()`,那肯定就是无法运行的。 55 | 56 | 所以,调用类型的方法与实例的值是不是 nil 没有太多直接影响,只要有预期的上下文类型就可以了。 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Go/packages/Go fmt.md: -------------------------------------------------------------------------------- 1 | `fmt`包是 Go 中用于格式化输出的标准包。 2 | 3 | ## 一、格式化输出 4 | 5 | `fmt.Printf()`和`fmt.Sprintf()`方法可以按照设定的格式对参数进行适当的格式化后进行输出或返回。 6 | 7 | ### 1.1 转换动词 8 | 9 | `fmt.Printf()`和`fmt.Sprintf()`方法的第一个参数都支持多种转换动词来对参数进行输出格式化: 10 | 11 | 12 | verb | description 13 | ------- | ------------- 14 | `%d` | 十进制整数 15 | `%x` | 十六进制 16 | `%o` | 八进制 17 | `%b` | 二进制 18 | `%f` | 浮点数 3.141593 19 | `%g` | 双精度浮点数 3.141592653589793 20 | `%e` | 科学计数浮点数 3.141593e+00 21 | `%t` | 布尔值(true 或 false) 22 | `%c` | 字符(runne)(Unicode 码点) 23 | `%s` | 字符串 24 | `%q` | 带双引号的字符串(`"abc"`)或带单引号的字符(`'c'`) 25 | `%v` | 变量的自然形式(natural format) 26 | `%T` | 变量的类型 27 | `%%` | 字面上的百分号符号(无操作数) 28 | 29 | ### 1.3 使用技巧 30 | 31 | 1. 默认情况下,`Printf`和`Sprintf`方法在,第一个参数中的`%`出现多少次(不包含`%%`),则后续就需要提供多少个操作数,但是`%`后面可以添加`[n]`符号来表示这个要再次使用第 n 个操作数。 32 | 2. `%`后面的`#`副词表示在输出八进制、十六进制时生成相关的`0`、`0x`、`0X`前缀。 33 | 34 | 例如: 35 | 36 | ```go 37 | o := 0666 38 | fmt.Printf("%d %[1]o %#[1]o\n", o) // "438 666 0666" 39 | 40 | x := int64(0xdeadbeef) 41 | fmt.Printf("%d %[1]x %#[1]x %#[1]X\n", x) // 3735928559 deadbeef 0xdeadbeef 0XDEADBEEF 42 | ``` 43 | 44 | 45 | -------------------------------------------------------------------------------- /JavaScript/实例/JavaScript 移动端判断横屏还是竖屏.md: -------------------------------------------------------------------------------- 1 | ## 横竖屏判断 2 | ### window.orientation 3 | 移动端的浏览器一般都支持`window.orientation`这个参数,通过这个参数可以判断出手机是处在横屏还是竖屏状态。从而根据实际需求而执行相应的程序。这个参数的值为只能为 0、90、-90、180 中的一个,但在不同设备上,每个值对应的状态可能不同。 4 | 5 | 屏幕方向对应的`window.orientation`值: 6 | 7 | - ipad: 90 或 -90 横屏 8 | - ipad: 0 或180 竖屏 9 | - Andriod:0 或180 横屏 10 | - Andriod: 90 或 -90 竖屏 11 | 12 | ### screen.orientation.angle 13 | 由于`window.orientation`在部分浏览器上并不被支持,所以还可以使用`screen.orientation.angle`的值来进行判断。 14 | 15 | 16 | ## 横竖屏切换事件 17 | 一般可以通过`orientationchange`来监听横竖屏状态的切换事件。不过,这个事件也有一定的兼容性问题,可以通过监听`resize`事件来补充。因为在移动端,一般横竖屏切换的时候,会自动触发 window 对象的 resize 事件。 18 | 19 | ```javascript 20 | // 判断手机横竖屏状态: 21 | function orientation () { 22 | if (window.orientation == 180 || window.orientation == 0){ 23 | alert("竖屏状态!") 24 | } 25 | else if (window.orientation == 90 || window.orientation == -90) { 26 | alert("横屏状态!") 27 | } 28 | } 29 | window.addEventListener("onorientationchange" in window ? "orientationchange" : "resize", orientation, false); 30 | ``` 31 | 32 | 33 | ## 转摘 34 | [更靠谱的横竖屏检测方法](http://www.cnblogs.com/zhansingsong/p/5866692.html) 35 | 36 | -------------------------------------------------------------------------------- /PHP/知识点/PHP 权限笔记.md: -------------------------------------------------------------------------------- 1 | ## private 2 | 3 | 父类中定义为 private 的属性,子类是无法直接访问的,但是如果父类中定义了非 private 权限的访问方法,那么子类就可以调用这个方法来获取到这个属性了。 4 | 5 | ```php 6 | 7 | class A 8 | { 9 | private $data; 10 | 11 | public function __construct($data) 12 | { 13 | $this->data = $data; 14 | } 15 | 16 | public function getData() 17 | { 18 | return $this->data; 19 | } 20 | } 21 | 22 | class B extends A 23 | { 24 | public function plus($num) 25 | { 26 | return $this->getData() + $num; 27 | } 28 | } 29 | 30 | class C extends A 31 | { 32 | public function sub($num) 33 | { 34 | return $this->data - $num; 35 | } 36 | } 37 | 38 | // 这里父类 A 中定义了一个 private 属性 $data 39 | // 还定义了一个 public 的 getDate() 方法来访问这个属性 40 | // 那么子类中虽然不能直接访问这个 $data 属性, 41 | // 但是能够通过 getData() 来获取到其值 42 | 43 | // B 子类中的 plus() 方法能正常执行 44 | $b = new B(1); 45 | echo $b->getData(); // 1 46 | echo $b->plus(1); // 2 47 | 48 | // C 子类中的 sub() 方法由于是直接调用 $data 属性 49 | // 所以会有错误提示信息出现 50 | $c = new C(1); 51 | echo $c->getData(); // 1 52 | echo $c->sub(1); // -1 PHP Notice: Undefined property: C::$data 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /JavaScript/Node/Node Express 知识点记录.md: -------------------------------------------------------------------------------- 1 | ### 1. 全局 404 响应 2 | 3 | 在 Express 中,404 响应不是错误的结果,所以错误处理程序中间件不会将其捕获。此行为是因为 404 响应只是表明缺少要执行的其他工作;换言之,Express 执行了所有中间件函数和路由,且发现它们都没有响应。 4 | 5 | 需要做的只是在堆栈的最底部(在其他所有函数之下)添加一个中间件函数来处理 404 响应: 6 | 7 | ```JavaScript 8 | app.use(function(req, res, next) { 9 | res.status(404).send('Sorry cant find that!'); 10 | }); 11 | ``` 12 | 13 | 需要注意的是,这个中间件需要放在**最底部**,否则会造成在其下方的路由和中间件不被处理。 14 | 15 | ### 2. res.sendfile() 出现 Forbidden 错误 16 | 17 | 当在 Express 的路由中使用相对路径(`../`)输出文件内容的时候,由于这可能存在被攻击的风险(恶意访问者通过构造特定的相对路径使得可以获取到服务器的私密文件),所以 Express 是禁止在`sendfile()`方法中使用相对路径的。 18 | 19 | 要解决这个问题有三个方法: 20 | 21 | 1. 对于较多的文件直接输出,可以考虑使用`express.static()`方法将文件的路径设置为静态路径,这样就可以直接访问了: 22 | 23 | ```JavaScript 24 | app.use(express.static(dir); 25 | ``` 26 | 27 | 2. 先使用`path.resolve()`得到对应的文件路径,然后再调用`sendfile()`方法: 28 | 29 | ```JavaScript 30 | const path = require('path'); 31 | res.sendfile(path.resolve(__dirname + '/../' + path)); 32 | ``` 33 | 34 | 3. 调用`sendfile()`方法时,传入`root`选项,避免构造相对路径: 35 | 36 | ```JavaScript 37 | res.sendfile(path, {'root': '/path/to/root/directory'}); 38 | ``` 39 | 40 | -------------------------------------------------------------------------------- /PHP/问题/PHP strtotime 的一些计算问题.md: -------------------------------------------------------------------------------- 1 | > 转摘:[PHP 获取周一,上个月的正确做法](https://www.tuicool.com/articles/vEbuIvQ) 2 | 3 | ### 日期不存在的问题 4 | 5 | `strtotime()`方法可以对一个基础日期进行处理,从而得到另一个日期,但是计算时可能得到的结果并非预期。 6 | 7 | 如下: 8 | 9 | ```php 10 | $now = strtotime('2018-01-31'); 11 | echo date('Y-m-d', strtotime('+1 month', $now)); 12 | ``` 13 | 14 | 这是计算 2018-01-31 下一个月的日期,本应该是 2 月某一天,但会得到 2018-03-03。 15 | 16 | 这是由于,增加一个月时会得到 2018-02-31 这个结果,但是由于 2018 年 2 月只有 28 天,所以这个结果是不存在的日期,会被自动修正为对应的 2018-03-03。 17 | 18 | ### 周一问题 19 | 20 | `strtotime()`在计算星期的时候,认为周日是一周的开始,而不是按照 ISO-8601 标准认为,周一才是一周的开始。所以在使用`strtotime()`计算下周、上周等情况的时候,结果会不是预期的结果。 21 | 22 | 比如: 23 | 24 | ```php 25 | $now = strtotime('2018-05-20'); // 这一天是周日 26 | echo date('Y-m-d', strtotime('this monday', $now)); 27 | ``` 28 | 29 | 2018-05-20 这一天是周日,预期得到的结果应该 2018-05-14,但得到的却是 2018-05-21,也就是下一个周一。 30 | 31 | 获取本周一的正确方式应该是: 32 | 33 | ```php 34 | $now = strtotime('2018-05-20'); 35 | // 先计算当前是周几,再减去相应的天数,就得到对应的本周一的时间戳了 36 | $time = $now - 86400 * (date('N', $now) - 1); 37 | echo date('Y-m-d', $time) . "\n"; // 2018-05-14 38 | 39 | // 以本周一为基础,求出 3 周以前的那个周一 40 | strtotime('-3 week', $time); 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /Web/HTML/HTML a 元素打开新窗口或刷新已打开窗口.md: -------------------------------------------------------------------------------- 1 | > 转摘:[实现a元素href URL链接自动刷新或新窗口打开](https://www.zhangxinxu.com/wordpress/2019/10/a-href-target-window-blank-refresh/) 2 | 3 | ### 1. 需求 4 | 5 | 希望实现这样一个功能:点击一个链接,如果这个链接浏览器已经打开过,则刷新已经打开的那个窗口;如果这个链接没有打开过,则使用新窗口打开这个链接页面。 6 | 7 | 这个功能并不需要 JS 的参与,使用 HTML a 元素的`target`特性就可以实现这样的需求。 8 | 9 | ### 2. target 特性值 10 | 11 | 无论是`
`链接元素还是`
`表单元素都有一个名叫`target`的属性,支持的值包括下面这些: 12 | 13 | * `_self` 默认值。当前浏览器上下文。 14 | * `_blank` 通常是一个新的标签页,但是用户可以配置浏览器,是否在新窗口打开。 15 | * `_parent` 当前浏览器上下文的的父级上下文,如果没有父级,则行为类似`_self`。 16 | * `_top` 最顶级的浏览器上下文。如果没有祖先上下文环境,则行为类似`_self`。 17 | 18 | 实际上,`target`还有一个隐藏特性,那就是可以指定为具体的 URL 地址。例如: 19 | 20 | ```html 21 | 空白页 22 | ``` 23 | 24 | 此时,如果浏览器已经有标签页的地址是`blank.html`,则点击上面的链接并不会打开新窗口,是直接刷新已经打开的`blank.html`;如果浏览器中没有地址是`blank.html`的标签页,则此时`target`属性的行为表现类似`_blank`。 25 | 26 | 也就是说,要想实现链接地址自动刷新和新窗口打开的这个需求,直接设置链接元素和表单元素的`target`属性值为目标 URL 地址值就好了。 27 | 28 | 需要注意的是,URL 的查询参数不同也会被作为不同的目标,例如:`target="blank.html?s=1"`和`target="blank.html?s=2"`会认为是两个独立的页面,不会互相刷新。 29 | 30 | [查看示例](https://www.zhangxinxu.com/study/201910/new-window-or-refresh-demo.php) 31 | 32 | -------------------------------------------------------------------------------- /Python/包库/psycopg.md: -------------------------------------------------------------------------------- 1 | ## 一、错误 2 | 3 | ### 1.1 undefined symbol 4 | 5 | > 转摘:[ImportError _psycopg.so: undefined symbol: lo_truncate64](http://www.leeladharan.com/importerror-psycopg-so:-undefined-symbol:-lo-truncate64) 6 | 7 | 在引入 psycopg 依赖之后,会提示类似如下的符号不存在错误: 8 | 9 | ``` 10 | ImportError _psycopg.so: undefined symbol: lo_truncate64 11 | ``` 12 | 13 | 可能提示的是`lo_truncate64`不存在,也可能提示的是其他的符号不存在。但是这类问题基本都是由于使用了不正确的`libpq.so`文件导致的。解决方法如下: 14 | 15 | 1. 查看引用的`libpq.so`的位置: 16 | 17 | ```shell 18 | # 这里假设提示错误的 _psycopg.so 的位置如下 19 | > ldd /path/to/venv/lib/python2.6/site-packages/psycopg2/_psycopg.so | grep libpq 20 | libpq.so.5 => /usr/lib64/libpq.so.5 (0x00007f0d6c027000) 21 | ``` 22 | 23 | 2. 查找下系统中其他的`libpq.so`文件: 24 | 25 | ```shell 26 | find / -name libpq.so 27 | ``` 28 | 29 | 3. 对比第一步中`libpq.so.5`文件与找到的其他的`libpg.so`文件的日期。 30 | 31 | 一般情况下会发现第一步中的`libpq.so.5`文件比其他找到的文件的版本更低,此时可以对其他位置的`libpg.so`文件重新做软连到第一步中指定的位置。 32 | 33 | ```shell 34 | cd /usr/lib64 35 | rm libpq.so.5 36 | # 假设找到的其他的 libpq.so 的文件的路径为 /usr/pgsql-9.4/lib/libpq.so.5 37 | ln -s /usr/pgsql-9.4/lib/libpq.so.5 libpq.so.5 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /杂项/Sublime Text/Sublime Text 3 配置.md: -------------------------------------------------------------------------------- 1 | 下面是我的 ST3 的配置文件模板: 2 | 3 | ``` 4 | { 5 | "color_scheme": "Packages/User/SublimeLinter/Monokai Extended (SL).tmTheme", 6 | "font_face": "Courier", 7 | "font_size": 16, 8 | "highlight_line": true, 9 | "ignored_packages": 10 | [ 11 | "phpfmt", 12 | "Vintage" 13 | ], 14 | "line_padding_bottom": 4, 15 | "line_padding_top": 4, 16 | "predawn_findreplace_small": false, 17 | "predawn_quick_panel_small": false, 18 | "predawn_sidebar_arrows": true, 19 | "predawn_sidebar_large": false, 20 | "predawn_sidebar_medium": false, 21 | "predawn_sidebar_narrow": false, 22 | "predawn_sidebar_small": false, 23 | "predawn_sidebar_xlarge": false, 24 | "predawn_sidebar_xsmall": false, 25 | "predawn_tabs_active_underline": true, 26 | "predawn_tabs_large": false, 27 | "predawn_tabs_medium": false, 28 | "predawn_tabs_small": true, 29 | "tab_size": 4, 30 | "theme": "predawn-DEV.sublime-theme", 31 | "ensure_newline_at_eof_on_save": true, // 末尾添加空行 32 | "translate_tabs_to_spaces": true, 33 | "word_separators": "./\\()\"':,.;<>~!@#%^&*|+=[]{}`~?", // 分隔符删除$和-,方便 PHP 和 CSS 选择 34 | } 35 | 36 | ``` 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /PHP/问题/PHP Windows 生成文本文件乱码.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | 在 Window 中使用 PHP 的生成文件的时候,可能会遇到不论是使用`fwrite`还是`file_put_contents`写入,生成的文件总是会乱码的情况。 4 | 5 | ### 原因 6 | 7 | 可能会先尝试从编码入手尝试解决,但最终的结果往往是不理想的,尽管我们都将其转换为了 UTF-8 编码了。那么究其根本原因是什么呢? 8 | 9 | 一句话:**缺少头部 BOM**(当然,这里指的肯定不是浏览器 JavaScript 的 BOM)。 10 | 11 | > BOM —— Byte Order Mark,中文名译作“字节顺序标记”。 12 | > 13 | > UTF-8 不需要 BOM 来表明字节顺序,但可以用 BOM 来表明编码方式。字符 "Zero Width No-Break Space" 的 UTF-8 编码是`EF BB BF`。所以如果接收者收到以`EF BB BF`开头的字节流,就知道这是 UTF-8 编码了。Windows 就是使用 BOM 来标记文本文件的编码方式的。 14 | > 15 | > 类似 WINDOWS 自带的记事本等软件,在保存一个以 UTF-8 编码的文件时,会在文件开始的地方插入三个不可见的字符(`0xEF 0xBB 0xBF`,即 BOM)。它是一串隐藏的字符,用于让记事本等编辑器识别这个文件是否以 UTF-8 编码。对于一般的文件,这样并不会产生什么麻烦。 16 | > 17 | > 但对于 PHP 来说,BOM 是个大麻烦。PHP 并不会忽略 BOM,所以在读取、包含或者引用这些文件时,会把 BOM 作为该文件开头正文的一部分。根据嵌入式语言的特点,这串字符将被直接执行(显示)出来。由此造成即使页面的 top padding 设置为 0,也无法让整个网页紧贴浏览器顶部,因为在 html 一开头有这 3 个字符! 18 | 19 | ### 解决方法 20 | 21 | 那么如何在 PHP 中输出 BOM 呢?答案是在所有内容输出之前输出如下的内容: 22 | 23 | ```php 24 | print(chr(0xEF).chr(0xBB).chr(0xBF)); 25 | ``` 26 | 27 | 当然,如果是在生成文件,可能是下面两种: 28 | 29 | ```php 30 | fwrite($file, chr(0xEF).chr(0xBB).chr(0xBF)); 31 | 32 | file_put_contents($file, chr(0xEF).chr(0xBB).chr(0xBF)); 33 | ``` 34 | 35 | -------------------------------------------------------------------------------- /Python/装饰器/dataclass.md: -------------------------------------------------------------------------------- 1 | Python 3.7 引入了`dataclass`装饰器,用于装饰类,可以用来减少对样板代码的使用,因为该装饰器会自动生成诸如`__init__()`和`__repr__()`这样的特殊方法。在官方的文档中,它们被描述为「带有缺省值的可变命名元组」。 2 | 3 | > `dataclass`装饰器属于`dataclasses`标准库,使用前需要先引入。 4 | 5 | 对于一般的类: 6 | 7 | ```Python 8 | class Armor: 9 | 10 | def __init__(self, armor: float, description: str, level: int = 1): 11 | self.armor = armor 12 | self.level = level 13 | self.description = description 14 | 15 | def power(self) -> float: 16 | return self.armor * self.level 17 | 18 | armor = Armor(5.2, "Common armor.", 2) 19 | armor.power() 20 | # 10.4 21 | 22 | print(armor) 23 | # <__main__.Armor object at 0x7fc4800e2cf8> 24 | ``` 25 | 26 | 使用`dataclass`装饰器修饰`Armor`类之后,可以简写成如下方式: 27 | 28 | ```Python 29 | from dataclasses import dataclass 30 | 31 | @dataclass 32 | class Armor: 33 | armor: float 34 | description: str 35 | level: int = 1 36 | 37 | def power(self) -> float: 38 | return self.armor * self.level 39 | 40 | armor = Armor(5.2, "Common armor.", 2) 41 | armor.power() 42 | # 10.4 43 | 44 | print(armor) 45 | # Armor(armor=5.2, description='Common armor.', level=2) 46 | ``` 47 | 48 | 49 | -------------------------------------------------------------------------------- /JavaScript/Node/Yarn.md: -------------------------------------------------------------------------------- 1 | Yarn 是用来代替 npm 客户端的命令行工具,它更快,更可靠,更安全。用 Yarn 后可以继续使用你所有的包。 2 | 3 | Yarn 有如下的特点: 4 | 5 | * **性能**:没人喜欢等着依赖包安装的过程,特别当你只需要更新一两样小东西时。 Yarn 重度缓存了依赖包,并且优化安装过程,这样安装时间比以往大大加快。 6 | * **安全**:当你依赖的是从网上安装的包,你会希望下载下来的代码是你想要的代码。你不希望有人拦截你的请求然后更改里面的内容。用 Yarn,你可以存一个包的 checksum 来保证代码在每次安装时都是一样的。 7 | * **离线**:Yarn 允许你从离线镜像里安装包。这可以用于命令行环境,阻止它向互联网提出请求(对安全来说也很重要)。 8 | 9 | [中文官网](https://yarnpkg.com/zh-Hans/) 10 | 11 | ### 安装 12 | Mac 上可以使用 Homebrew 进行安装: 13 | 14 | ``` 15 | brew update 16 | brew install yarn 17 | ``` 18 | 19 | ### 配置 20 | **1. 镜像** 21 | 22 | 在用 Yarn 时你可以继续用 npm registry 或者任何 npm 镜像。下面就是使用淘宝的镜像: 23 | 24 | ```shell 25 | yarn config set registry https://registry.npm.taobao.org 26 | 27 | # 或 28 | yarn install --registry https://registry.npm.taobao.org 29 | ``` 30 | 31 | ### 常用命令 32 | 开始新项目: 33 | 34 | ```shell 35 | yarn init 36 | ``` 37 | 38 | 添加依赖包: 39 | 40 | ```shell 41 | yarn add [package] 42 | yarn add [package]@[version] 43 | yarn add [package]@[tag] 44 | ``` 45 | 46 | 移除依赖包: 47 | 48 | ```shell 49 | yarn remove [package] 50 | ``` 51 | 52 | 安装项目的全部依赖: 53 | 54 | ```shell 55 | yarn 56 | 57 | # 或 58 | yarn install 59 | ``` 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /Go/工具调试/Go test 禁用缓存.md: -------------------------------------------------------------------------------- 1 | > 转摘:[go test 的一个小技巧:禁用缓存](https://mp.weixin.qq.com/s/4DljJ8FlbmaEvdFi4V1oTw) 2 | 3 | ### 1. 问题 4 | 5 | 在执行单元测试时,如果代码没有任何变动(包括可能读取的配置文件),那么后续的测试执行会直接读取缓存中的测试结果,同时会有一个`cached`标记: 6 | 7 | ```shell 8 | > go test -run ^TestPrint$ test/hello 9 | ok test/hello 0.113s 10 | 11 | > go test -run ^TestPrint$ test/hello 12 | ok test/hello (cached) 13 | ``` 14 | 15 | 有时候可能希望执行实际的测试,比如看日志输出。此时需要禁用缓存,需要怎么做呢? 16 | 17 | ### 2. 解决 18 | 19 | 查看 go test 的文档,里面有如下的一段说明: 20 | 21 | ``` 22 | When 'go test' runs in package list mode, 'go test' caches successful 23 | package test results to avoid unnecessary repeated running of tests. To 24 | disable test caching, use any test flag or argument other than the 25 | cacheable flags. The idiomatic way to disable test caching explicitly 26 | is to use -count=1. 27 | ``` 28 | 29 | 也就是说,在`go test`命令中加上`-count=1`选项即可禁用缓存。 30 | 31 | 在 [issues #24573](https://github.com/golang/go/issues/24573) 中有人提到,在 Go 1.10 及以前,可以通过`GOCACHE=off`的方式来禁用测试缓存;在 Go 1.11 及以上版本中则使用`-count=1`来禁用。这是因为 Go 1.11 开始,`GOCACHE=off`会影响`go.mod`。 32 | 33 | 另外,在 VSCode 中,可以加上如下的配置来禁用缓存: 34 | 35 | ``` 36 | "go.testFlags": ["-count=1"] 37 | ``` 38 | 39 | 40 | -------------------------------------------------------------------------------- /PHP/Lumen/Lumen 缓存 Redis.md: -------------------------------------------------------------------------------- 1 | 默认情况下,Lumen 使用的是 Memcached 缓存,在确保已经安装好 Memcached PECL 扩展之后,就可以使用了,如果需要特别的配置,则在`.env`文件中设置即可。 2 | 3 | ### 使用 Redis 缓存 4 | 5 | 如果要换用 Redis 缓存,则需要先做好如下的配置: 6 | 7 | 1. 安装`predis/predis`扩展:`composer require predis/predis`; 8 | 2. 安装`illuminate/redis(5.5.*)`扩展:`composer require illuminate/redis`; 9 | 3. 注册 rerids 服务提供者:在`bootstrap/app.php`文件中添加`$app->register(Illuminate\Redis\RedisServiceProvider::class);`; 10 | 4. 调用配置:如果没有在`bootstrap/app.php`文件中调用`$app->withEloquent()`,那么应该在`bootstrap/app.php`文件中调用`$app->configure('database');`,这样才能保证 Redis 数据库配置的正确加载。 11 | 12 | ### 使用 PHPRedis 代替 Predis 13 | 14 | predis 是使用 php 写的,phpredis 则是 C 语言写的原生模块,所以后者的速度相对就更快一些。但 Laravel/Lumen 原生的并不支持 phpredis,可以通过如下的改写来使 Lumen 支持 phpredis。 15 | 16 | 1. 安装 phpredis:具体可以参见[phpredis/phpredis](https://github.com/phpredis/phpredis); 17 | 2. 注册单例:在`bootstrap/app.php`中加入如下语句: 18 | 19 | ```php 20 | $app->singleton('redis', function(){ 21 | $redis = new Redis; 22 | $redis->pconnect('127.0.0.1'); // 可以用 config 或者 env 来获取 host 23 | return $redis; 24 | }); 25 | unset($app->availableBindings['redis']); // Lumen 5.6 之后不需要 26 | ``` 27 | 28 | 29 | -------------------------------------------------------------------------------- /Linux/Shell/Shell 获取当前正在执行脚本的绝对路径.md: -------------------------------------------------------------------------------- 1 | 在 Shell 脚本中获取当前脚本的绝对路径,常见的一种误区,是使用`pwd`命令,该命令的作用是“print name of current/working directory”,显示当前的工作目录,这里没有任何意思说明,这个目录就是脚本存放的目录。所以,这是不对的。 2 | 3 | 另一个误人子弟的答案是`$0`,这个`$0`是 Bash 环境下的特殊变量,其真实含义是: 4 | 5 | > Expands to the name of the shell or shell script. This is set at shell initialization.  If bash is invoked with a file of commands, `$0` is set to the name of that file. If bash is started with the -c option, then `$0` is set to the first argument after the string to be executed, if one is present. Otherwise, it is set to the file name used to invoke bash, as given by argument zero. 6 | 7 | 这个`$0`有可能是好几种值,跟调用的方式有关系: 8 | 9 | * 使用一个文件调用 bash,那`$0`的值,是那个文件的名字(没说是绝对路径噢) 10 | * 使用`-c`选项启动 bash 的话,真正执行的命令会从一个字符串中读取,字符串后面如果还有别的参数的话,使用从`$0`开始的特殊变量引用(跟路径无关了) 11 | * 除此以外,`$0`会被设置成调用 bash 的那个文件的名字(没说是绝对路径)
 12 | 真正的正确答案应该是: 13 | 14 | ```shell 15 | basepath = $(cd `dirname $0`; pwd) 16 | ``` 17 | 18 | 解释如下: 19 | 20 | * `dirname $0`,取得当前执行的脚本文件的父目录 21 | * ``cd `dirname $0` ``,进入这个目录(切换当前工作目录) 22 | * `pwd`,显示当前工作目录(cd 执行后的) 23 | 24 | 由此,我们获得了当前正在执行的脚本的存放路径。 25 | 26 | > 参考:[linux shell 获取当前正在执行脚本的绝对路径](http://www.cnblogs.com/FlyFive/p/3640267.html) 27 | 28 | 29 | -------------------------------------------------------------------------------- /JavaScript/小技巧/JavaScript 快速排序算法.md: -------------------------------------------------------------------------------- 1 | ### 方法一:尽可能不用 js 数组方法 2 | 3 | ```javascript 4 | function quickSort(arr){ 5 | qSort(arr,0,arr.length - 1); 6 | } 7 | function qSort(arr,low,high){ 8 | if(low < high){ 9 | var partKey = partition(arr,low,high); 10 | qSort(arr,low, partKey - 1); 11 | qSort(arr,partKey + 1,high); 12 | } 13 | } 14 | function partition(arr,low,high){ 15 | var key = arr[low]; // 使用第一个元素作为分类依据 16 | while(low < high){ 17 | while(low < high && arr[high] >= arr[key]) 18 | high--; 19 | arr[low] = arr[high]; 20 | while(low < high && arr[low] <= arr[key]) 21 | low++; 22 | arr[high] = arr[low]; 23 | } 24 | arr[low] = key; 25 | return low; 26 | } 27 | ``` 28 | 29 | ### 方法二:使用 js 数组方法 30 | 31 | ```javascript 32 | function quickSort(arr){ 33 | if(arr.length <= 1) return arr; 34 | var index = Math.floor(arr.length/2); 35 | var key = arr.splice(index,1)[0]; 36 | var left = [],right = []; 37 | arr.forEach(function(v){ 38 | v <= key ? left.push(v) : right.push(v); 39 | }); 40 | return quickSort(left).concat([key],quickSort(right)); 41 | } 42 | ``` 43 | 44 | -------------------------------------------------------------------------------- /JavaScript/问题/try...catch...finally 语句中 return 的问题.md: -------------------------------------------------------------------------------- 1 | > 转摘:[重学前端学习笔记(二十)--try里面放return,finally还会执行吗?](https://segmentfault.com/a/1190000019224768) 2 | 3 | ### try 中有 return,finally 还会执行吗 4 | 5 | **对于`try...catch...finally`语句,不论什么情况,`finally`中的语句都是会执行的**,这也是其存在的意义。 6 | 7 | 所以,即便`try`语句块中使用`return`返回了值,`finally`依旧会执行,只是`try`语句块中使用`return`后,并不立即返回值,而是在执行完`finally`语句块之后再返回。 8 | 9 | 同样的,即便`catch`语句抛出了错误,也是要在`finally`语句块执行完之后再抛出。 10 | 11 | `try`语句块中的`break`和`continue`语句也和`return`语句一样被处理。 12 | 13 | ```JavaScript 14 | function kaimo(){ 15 | try{ 16 | return 0; 17 | } catch(err) { 18 | console.log(err) 19 | } finally { 20 | console.log("a") 21 | } 22 | } 23 | 24 | console.log(kaimo()); 25 | // a 26 | // 0 27 | ``` 28 | 29 | ### try 和 finally 都有 return 语句会怎么样 30 | 31 | 前面说了,`finally`语句永远会被执行,而如果在**`finally`语句块中出现`return`语句,那么它就会覆盖`try`语句块中的`return`的结果**。 32 | 33 | 相应的,**如果抛出了错误,而`finally`语句块中有`return`语句,那么该错误就会被吞没**,而是返回`finally`中返回的值。 34 | 35 | ```JavaScript 36 | function kaimo(){ 37 | try{ 38 | return 0; 39 | } catch(err) { 40 | console.log(err) 41 | } finally { 42 | return 1; 43 | } 44 | } 45 | 46 | console.log(kaimo()); 47 | // 1 48 | ``` 49 | 50 | 51 | -------------------------------------------------------------------------------- /Python/装饰器/lru_cache.md: -------------------------------------------------------------------------------- 1 | 目前,几乎所有层面上的软件和硬件中都需要缓存。Python 3 将 LRU(最近最少使用算法)缓存作为一个名为`lru_cache`的装饰器,使得对缓存的使用非常简单。这种优化技术被称为`memoization`。 2 | 3 | 使用`lru_cache`装饰器修饰一个方法后,Python 会自动缓存该方法最近的执行结果,并在下次相同调用的时候直接返回缓存值,而不需要再次计算。该装饰器可以指定最多缓存的数量,超过数量之后,会使用 LRU 算法进行淘汰。 4 | 5 | > `lru_cache`装饰器属于`functools`标准模块,使用前需要先引入,且 Python 版本至少要为 3.2。 6 | 7 | 比如,对于一个计算斐波那契数列的方法,一般实现和调用如下: 8 | 9 | ```Python 10 | import time 11 | 12 | def fib(number: int) -> int: 13 | if number == 0: return 0 14 | if number == 1: return 1 15 | 16 | return fib(number-1) + fib(number-2) 17 | 18 | start = time.time() 19 | fib(40) 20 | print(f'Duration: {time.time() - start}s') 21 | # Duration: 30.684099674224854s 22 | ``` 23 | 24 | 现在,可以使用`lru_cache`来优化斐波那契函数,将执行时间从几秒降低到了几纳秒: 25 | 26 | ```python 27 | import time 28 | from functools import lru_cache 29 | 30 | @lru_cache(maxsize=512) 31 | def fib_memoization(number: int) -> int: 32 | if number == 0: return 0 33 | if number == 1: return 1 34 | 35 | return fib_memoization(number-1) + fib_memoization(number-2) 36 | 37 | start = time.time() 38 | fib_memoization(40) 39 | print(f'Duration: {time.time() - start}s') 40 | # Duration: 6.866455078125e-05s 41 | ``` 42 | 43 | -------------------------------------------------------------------------------- /Nginx/实例/Nginx Nodejs.md: -------------------------------------------------------------------------------- 1 | 使用 Nginx 反向代理 NodeJS 而不是直接使用 NodeJS 服务器,可以降低对静态文件的处理负担,并实现多机负载均衡。 2 | 3 | 配置参考如下: 4 | 5 | ```conf 6 | location @nodejs { 7 | proxy_http_version 1.1; 8 | proxy_set_header Host $host; # 为反向设置原请求头 9 | proxy_set_header X-Real-IP $remote_addr; 10 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 11 | proxy_set_header Upgrade $http_upgrade; # 设置 WebSocket Upgrade 12 | proxy_set_header Connection "upgrade"; 13 | proxy_pass http://localhost:3000; 14 | } 15 | 16 | location / { 17 | try_files $uri $uri/ @nodejs; 18 | } 19 | 20 | location ~ \.(gif|png|jpg|css|js)$ { 21 | root /srv/http/www; # 静态文件的位置,例如 express 中的 public 目录 22 | try_files $uri @nodejs; 23 | expires 7d; # 设置静态文件 7 天过期 24 | } 25 | ``` 26 | 27 | 这里需要注意:静态文件的`location`作用域中也使用了`try_files $uri @nodejs;`指令。因为如果使用了 Socket.IO 之类的 Node 库,那么它的 js/css 文件就需要从 Node 中获取,所以要判断如果找不到静态文件时就尝试去 Node 中获取。 28 | 29 | 另外,对于`location /`区块,由于`try_files`中使用了`$uri/`,所以会先在目录中查找对应的默认文件(由`index`指令设置,一般是`index.html`一类的),如果找不到会再到代理中查找。但是当使用 Socket.IO 时,由于默认情况 Socket.IO 会使用`POST`来请求一个目录,如果刚好这个目录有默认的静态文件(如`index.html`),那么 Nginx 会因 POST 请求静态文件而产生 405 错误,此时就不可用在`try_files`指令中使用`$uri/`了。 30 | 31 | -------------------------------------------------------------------------------- /DB/MySQL/内置方法/条件判断方法.md: -------------------------------------------------------------------------------- 1 | ### IF 2 | 3 | 根据条件返回不同的值。 4 | 5 | 语法:`IF(expr1, expr2, expr3) ` 6 | 7 | 参数:`expr1`一个表达式,`expr2`表达式为真时的返回值,`expr3`表达式为假时的返回值。 8 | 9 | 效果:如果 expr1 是 TRUE(`expr1<>0`且`expr1<>NULL`),那么`IF()`返回 expr2,否则它返回 expr3。 10 | 11 | > 注意:expr1 作为整数值被计算,它意味着如果你正在测试浮点或字符串值,你应该使用一个比较操作来做。  12 | 13 | ```sql 14 | SELECT IF(1>2, 2, 3); 15 | ``` 16 | 17 | ![IF](http://cnd.qiniu.lin07ux.cn/markdown/1472301305841.png) 18 | 19 | 更多示例: 20 | 21 | ```sql 22 | SELECT IF(1>2, 2, 3); # 3 23 | SELECT IF(1<2, 'yes', 'no'); # 'yes' 24 | SELECT IF(strcmp('test','test1'), 'yes', 'no'); # 'no' 25 | SELECT IF(0.1, 1, 0); # 0 因为 0.1 被变换到整数值变成测试 IF(0) 26 | SELECT IF(0.1<>0, 1, 0); # 1 27 | ``` 28 | 29 | ### IFNULL 30 | 31 | 判断是否为 NULL。 32 | 33 | 语法:`IFNULL(expr1, expr2) ` 34 | 35 | 参数:`expr1`与 NULL 进行比较的值,`expr2`为 NULL 时的返回值。 36 | 37 | 效果:如果 expr1 不是 NULL,`IFNULL()`返回 expr1,否则它返回 expr2。 38 | 39 | > 注意:expr1 是与 NULL 来比较的,不会做类型转换。也即是 0、false 并不是 NULL。 40 | 41 | 效果:假如 v1 不为 NULL,则返回值为 v1;否则其返回值为 v2。IFNULL() 的返回值是数字或是字符串,具体情况视语境而定。 42 | 43 | 示例: 44 | 45 | ```sql 46 | SELECT IFNULL(1, 2), IFNULL(NULL, 10); 47 | ``` 48 | 49 | ![IFNULL](http://cnd.qiniu.lin07ux.cn/markdown/1472301445855.png) 50 | 51 | 52 | -------------------------------------------------------------------------------- /Mac/杂项/Mac Chrome 将非官方扩展程序加入白名单.md: -------------------------------------------------------------------------------- 1 | 在 Chrome 中手动添加非官方扩展时,会出现重启浏览器以后无法启用扩展的情况。如图所示: 2 | 3 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486534798807.png) 4 | 5 | 最近群友提供了一个方法,特此弄一个中文教程; 6 | 7 | > 原文地址:[https://hencolle.com/2016/10/16/baidu_exporter/](https://hencolle.com/2016/10/16/baidu_exporter/) 8 | 9 | **注意:该方法只适用于 通过 crx 文件安装的扩展(将crx文件拖入chrome扩展程序界面)** 10 | 11 | 1. 首先下载一个描述文件: 12 | [Github 地址](https://gist.github.com/Explorare/be3dd598289252698cd37bca04abd0fe#file-com-google-chrome-mobileconfig) 13 | 14 | [百度网盘](https://pan.baidu.com/s/1qYERRac) 密码:`mt25` 15 | 16 | 2. 打开 chrome 的扩展程序界面,复制扩展的 ID。 17 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486534971110.png) 18 | 19 | 3. 用文本编辑器打开下载好的`com.google.Chrome.mobileconfig`找到如图所示位置: 20 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486535009246.png) 21 | 22 | 这里的三个``中分别对应单个扩展的 ID,如果只需要一个的话,可以吧多余的两个删掉,将其中的一个标签中的值替换为第二步复制过来的 ID。编辑完后保存。如图: 23 | 24 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486535052632.png) 25 | 26 | 4. 双击打开第三步编辑好的描述文件,按照弹出的提示点击`继续` - `安装`(输入电脑密码),安装结束后重启浏览器,就可以勾选这个扩展了,并且以后重启浏览器也不会有停用的提示了! 27 | 28 | > 转摘:[将非官方扩展程序加入 Chrome 的白名单](http://xclient.info/a/1ddd2a3a-d34b-b568-c0d0-c31a95f0b309.html) 29 | 30 | -------------------------------------------------------------------------------- /杂项/localhost 与 127.0.0.1 原理简介.md: -------------------------------------------------------------------------------- 1 | 在开始之前,先来了解下一个叫 loopback 的概念。 2 | 3 | `loopback`顾名思义,就是转一圈就回来,把一个东西,例如电子信号、数据流不加修改和处理的返回到它的来源地。具体到现在的计算机软件系统,我们的网络协议栈软件会实现一个虚拟的网络接口(可以简单的理解为虚拟的网卡),专门用于 loopback。 4 | 5 | 在 Unix 和 Linux 系统中,通常把 loopback 接口命名为 lo 或者 lo0(注意第一个字母是 L 的小写字母,不是数字一) 6 | 7 | IPv4 的网络标准把从 127.0.0.1 到 127.255.255.254 的 IP 地址块都用作 loopback。所有的发到这些地址的数据包都会被毫发无损的返回去(looped back),这一千六百多万个个地址中,最知名的、最常用的就是 127.0.0.1 。 8 | 9 | 对于 IPv6 来说,它只把一个地址用作 loopback,就是 ::1 (0000:0000:0000:0000:0000:0000:0000:0001)。 10 | 11 | 有了loopback 地址,同一个计算机上的进程通信都很方便了,根本不用走实际的物理网卡。 12 | 13 | 比如说你在本机建立了一个 Web 服务器,然后通过浏览器用 http://127.0.0.1:8080 去访问, 操作系统内的网络协议栈会把这个 HTTP GET 请求封装到一个 TCP 包中,写上目的端口号 8080,然后再封装到一个 IP 包中,写上目的地址 127.0.0.1。 14 | 15 | 但是这个 IP 数据包并不会发送到物理的网卡那里去,更不会通过数据链路层发送到局域网乃至互联网中,实际上它发给了虚拟的网络接口, 然后立刻被 looped back 到 IP 层的输入队列中。IP 层收到数据包,交付给 TCP 层,TCP 层发现目的端口是 8080,就会把 GET 请求取出来,交付给绑定8080 端口的 Web 服务器。 16 | 17 | 至于 localhost,这就是个本机的主机名,在大多数机器上,这个主机名都会被计算机操作系统映射到 127.0.0.1 (ipv4) 或者 ::1 (ipv6),那使用 localhost 和 ip 实际上一样了。 18 | 19 | 但是有个有意思的例外就是 mysql,在 Linux 上,当你使用 localhost 来连接数据库的时候, Mysql 会使用 Unix domain socket 来传输数据,这种方式会快一些,因为这是一种进程内通信(IPC)机制,不走网络协议栈,不需要打包拆包,计算校验和,维护序号等操作。当你使用 127.0.0.1的时候,mysql 还是会使用 TCP/IP 协议栈来进行数据传输。 20 | 21 | -------------------------------------------------------------------------------- /PHP/Laravel/src/Container/train.php: -------------------------------------------------------------------------------- 1 | trafficTool = $trafficTool; 50 | } 51 | 52 | /** 53 | * 去西藏旅行 54 | */ 55 | public function visitTibet() 56 | { 57 | $this->trafficTool->go(); 58 | } 59 | } 60 | 61 | $app = new Container(); 62 | 63 | $app->bind('TrafficTool', 'Train'); 64 | $app->bind('travellerA', 'Traveller'); 65 | 66 | $traveller = $app->make('travellerA'); 67 | $traveller->visitTibet(); 68 | -------------------------------------------------------------------------------- /PHP/内置函数/get_class()、get_called_class() 和 __CLASS__ 获取类名称.md: -------------------------------------------------------------------------------- 1 | ### `__CLASS__` 2 | 3 | PHP 中`__CLASS__`可以用来获取当前类的名称,但是`__CLASS__`是静态绑定的,如果不在子类里进行重载的话,继承父类方法所得到的依旧是父类的名称,而不是子类的名称。 4 | 5 | 比如: 6 | 7 | ```php 8 | class A 9 | { 10 | public function __construct() 11 | { 12 | echo __CLASS__; 13 | } 14 | 15 | static public function name() 16 | { 17 | echo __CLASS__; 18 | } 19 | } 20 | 21 | class B extends A 22 | { 23 | } 24 | 25 | $objB = new B(); // A 26 | B::name(); // A 27 | ``` 28 | 29 | 由于 B 类没有重载父类 A 中的构造方法和`name()`方法,所以在调用的时候,`__CLASS__`指向的就是定义时的类的名称,所以输出就是`A`。 30 | 31 | ### get_class()/get_called_class() 32 | 33 | 如果想要在不重载父类的方法就得到当前类的名称,可以使用 PHP 内置的`get_class()`和`get_called_class()`方法。其中,`get_class()`方法用于实例调用,`get_called_class()`用于静态方法调用。 34 | 35 | > `get_called_class()`需要 PHP >= 5.3.0 才支持 36 | 37 | 对于上面的例子,修改如下: 38 | 39 | ```php 40 | class A 41 | { 42 | public function __construct() 43 | { 44 | echo get_class($this); 45 | } 46 | 47 | static public function name() 48 | { 49 | echo get_called_class(); 50 | } 51 | } 52 | 53 | class B extends A 54 | { 55 | } 56 | 57 | $objB = new B(); // B 58 | B::name(); // B 59 | ``` 60 | 61 | 62 | -------------------------------------------------------------------------------- /PHP/实用技巧/不使用 mb 系列函数分隔字符串.md: -------------------------------------------------------------------------------- 1 | 如果需要将可能含有中文的字符串进行拆分成数组,可以使用 mb 系列的扩展方法很容易的解决: 2 | 3 | ```PHP 4 | $str = "周梦康"; 5 | 6 | $array = []; 7 | for ($i=0, $l = mb_strlen($str, "utf-8"); $i < $l; $i++) { 8 | array_push($array, mb_substr($str, $i, 1)); 9 | } 10 | 11 | var_export($array, true); 12 | ``` 13 | 14 | 如果没有安装`mb`扩展时,可以使用如下的方式来处理: 15 | 16 | ```PHP 17 | function str_split_utf8($str) 18 | { 19 | $split = 1; 20 | $array = array(); 21 | 22 | for ($i = 0; $i < strlen($str);) { 23 | $value = ord($str[$i]); 24 | 25 | if ($value > 127) { 26 | if ($value >= 192 && $value <= 223) { 27 | $split = 2; 28 | } elseif ($value >= 224 && $value <= 239) { 29 | $split = 3; 30 | } elseif ($value >= 240 && $value <= 247) { 31 | $split = 4; 32 | } 33 | } else { 34 | $split = 1; 35 | } 36 | 37 | $key = null; 38 | for ($j = 0; $j < $split; $j++, $i++) { 39 | $key .= $str[$i]; 40 | } 41 | 42 | array_push($array, $key); 43 | } 44 | 45 | return $array; 46 | } 47 | ``` 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /Git/命令/switch.md: -------------------------------------------------------------------------------- 1 | `switch`命令是 Git 2.23.0 中引入的新命令,用于承担`checkout`命令的分支切换操作。 2 | 3 | ### 1. 原有分支操作 4 | 5 | Git 中原本有两个命令用来操作分支: 6 | 7 | * `branch` 管理分支,如分支的增删改查管理; 8 | * `checkout` 切换分支,也可以新建分支。 9 | 10 | > 由于 Git 中分支仅仅是一个 commit id 的别名,所以`checkout`命令也可以切换到一个 commit id 上。 11 | 12 | ```shell 13 | $ git branch # 查看当前所在分支 14 | $ git branch aaa # 新建分支 aaa 15 | $ git branch -d aaa # 删除分支 aaa 16 | 17 | $ git checkout aaa # 切换到 aaa 分支 18 | $ git checkout -b aaa # 创建 aaa,然后切换到 aaa 分支 19 | $ git checkout commitid # 切换到某个 commit id 20 | ``` 21 | 22 | ### 2. 新版分支操作 23 | 24 | `switch`命令虽然是用来接替`checkout`的功能,但是`switch`只能切换到分支,不能切换到 commit id。 25 | 26 | ```shell 27 | $ git switch aaa # 切换到 aaa 分支 28 | $ git switch -c aaa # 创建 aaa 分支,然后切换到 aaa 分支 29 | ``` 30 | 31 | 对比如下: 32 | 33 | 操作 | 2.23- | 2.23+ 34 | -----------------|-------------------|-------------- 35 | 管理分支 | `git branch` | `git branch` 36 | 切换分支 | `git checkout` | `git switch` 37 | 新建+切换分支 | `git checkout -b` | `git switch -c` 38 | 切换到 commit id | `git checkout` | `git checkout` 39 | 40 | ### 3. 转摘 41 | 42 | [Git 新命令 switch 和 restore](https://mp.weixin.qq.com/s/xhr-rkrd-kRQvG3vYruTTA) 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /JavaScript/问题/JavaScript 0.._ 为什么等于 undefined.md: -------------------------------------------------------------------------------- 1 | > 转摘:[为什么 0.._ 等于 undefined](http://www.hongweipeng.com/index.php/archives/1873/) 2 | 3 | JavaScript 中,`0.._`的结果是`undefined`,这是 JavaScript 中对数字的解析特性造成的。 4 | 5 | ### 1. `0.._`的隐式转换 6 | 7 | 在 JavaScript 的词法分析中,对于 10 进制数字来说,后面接`.`操作符时,JavaScript 引擎并不知道该`.`是小数点还是属性访问符,因此有如下规定: 8 | 9 | **`.`前面的数字为十进制数字时,如果这个数字已带小数点,则该`.`符号是访问数组的属性,否则即表示该数字的小数点;如果`.`前面不是十进制数字,则它表示属性访问符。** 10 | 11 | 比如: 12 | 13 | ```JavaScript 14 | 00._ // . 前面是八进制数字,所以其表示属性访问符 15 | true._ // . 前面不是十进制数字,所以其表示属性访问符 16 | 0._ // 语法错误,此时 . 表示小数点,其后不可以是 . 和非数字字符 17 | 0.0._ // 输出 undefined,相当于 (0.0)._ 18 | 0.._ // 相当于(0.)._ 19 | ``` 20 | 21 | 所以,对于`0.._`来说,相当于先定义了一个值为 0 的数字,然后访问这个数字的`_`属性(访问会将数字转换成 Number 对象),所以也就等同于`0['_']`了。由于 Number 对象中并没有`_`属性,所以自然其值就是 undefined 了。 22 | 23 | ### 2. 为何不用`0.._`代替`void 0` 24 | 25 | 由于 JavaScript 中,`undefined`并非关键字,所以它是可以被重定义为其他值的,所以一般情况下会会用`void 0`来代替`undefined`,而且这种写法也会更短。 26 | 27 | 而`0.._`更短,为什么不用这个来代替`void 0`呢?原因主要有如下两个: 28 | 29 | * 首先是因为可读性:`0.._`的可读性远不如`void 0`。 30 | * 其次是正确性问题:`void`是 JavaScript 中的关键字,不会被外部改变,因此`void 0`的值永远是`undefined`;但对于`0.._`来说,由于会被转成 Number 对象后再访问`_`属性值,那么就可以在 Number 或 Object 的原型链中定义`_`属性,从而改变其值。 31 | 32 | 综上可以看到,`0.._`结果不是固定的,因此不能用于替换`void 0`。 33 | 34 | 35 | -------------------------------------------------------------------------------- /JavaScript/问题/JavaScript (a == 1 && a == 2 && a == 3) 可能为 true 吗?.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | JavaScript (a == 1 && a == 2 && a == 3) 可能为 true 吗? 4 | 5 | ### 分析 6 | 7 | 这个问题初看起来,是不可能的:一个变量,不可能即等于 1,又等于 2,还等 3。JavaScript 中最奇特的数应该是`NaN`但是也不符合这个特征。 8 | 9 | 但是需要注意的是,这里进行判断使用的是`==`符号,也就是说,在判断中,会允许进行隐式变换,而就是这一点,可以使得该等式成立。 10 | 11 | 当使用`==`时,如果两个参数的类型不一样,那么 JS 会尝试将其中一个的类型转换为和另一个相同。在这里左边对象,右边数字的情况下,会首先尝试调用`valueOf`如果可以调用的话)来将对象转换为数字,如果失败,再调用`toString`。 12 | 13 | ### 解决 14 | 15 | 自定义变量 a 的`toString`或`valueOf`方法,每次将变量 a 变成字符串或数值的时候,改变一次返回值,从而就能满足判断条件: 16 | 17 | ```js 18 | const a = { 19 | i: 1, 20 | toString: function () { 21 | return this.i++ 22 | } 23 | } 24 | 25 | if(a == 1 && a == 2 && a == 3) { 26 | console.log('Hello World!'); 27 | } 28 | ``` 29 | 30 | 当然,还有其他的方法可以实现,比如将使用如下的方式: 31 | 32 | ```js 33 | with({ 34 | get a() { 35 | return Math.floor(Math.random()*4); 36 | } 37 | }){ 38 | for(var i=0;i<1000;i++){ 39 | if (a == 1 && a == 2 && a == 3){ 40 | console.log("after "+(i+1)+" trials, it becomes true finally!!!"); 41 | break; 42 | } 43 | } 44 | } 45 | ``` 46 | 47 | ### 转摘 48 | 49 | [JavaScript (a == 1 && a == 2 && a == 3) 可能为 true 吗?](https://www.tuicool.com/articles/3uEnIzv) 50 | 51 | 52 | -------------------------------------------------------------------------------- /CSS/CSS 效果片段 - 动画.md: -------------------------------------------------------------------------------- 1 | ### 1. 脉冲动画 2 | 3 | > 效果:[CSS 脉冲动画](https://www.jq22.com/code4371) 4 | 5 | 让元素周边不断出现并扩展,类似波纹荡漾开的效。其核心逻辑是为元素和元素的`before`、`after`元素设置`box-shadow`动画,让`box-shadow`不断的扩展并变淡,而且每个元素的动画延迟时间不同,从而形成层叠的脉冲动画。 6 | 7 | ```html 8 |
9 |
10 |
11 | ``` 12 | 13 | ```css 14 | .ripple { 15 | width: 1rem; /* control the size */ 16 | background: #ff0; /* control the color here */ 17 | } 18 | .ripple, 19 | .ripple::before, 20 | .ripple::after { 21 | content: ""; 22 | display: grid; 23 | grid-area: 1/1; 24 | aspect-ratio: 1; 25 | border-radius: 50%; 26 | box-shadow: 0 0 0 0 #ff03; /* and here, 3 is the transparency */ 27 | animation: r 3s linear infinite var(--s,0s); 28 | } 29 | .ripple::before {--s: 1s} 30 | .ripple::after {--s: 2s} 31 | 32 | @keyframes r { 33 | to {box-shadow: 0 0 0 6rem #0000} 34 | } 35 | 36 | body { 37 | margin: 0; 38 | height: 100vh; 39 | display: flex; 40 | justify-content: center; 41 | align-items: center; 42 | gap: 11rem; 43 | background: #000; 44 | } 45 | ``` 46 | 47 | ![](https://cnd.qiniu.lin07ux.cn/markdown/f6f168e97dd386b252e33fd266abffbe.jpg) 48 | -------------------------------------------------------------------------------- /DB/PostgreSQL/设置/PostgreSQL 更改数据存储路径.md: -------------------------------------------------------------------------------- 1 | 数据路径迁移方法有两种: 2 | 3 | * 重新初始化 PostgreSQL 数据库,初始化时指定新的数据路径`--PGDATA`,然后在新的环境下将原有的数据库备份恢复一下; 4 | * 直接将现有的数据库文件全部拷贝到新的数据库路径下,然后重启数据库服务。 5 | 6 | ## 直接迁移 7 | 8 | 直接迁移方式相对简单,但是前提是 PostgreSQL 已经作为服务添加到了 systemctl 服务中。 9 | 10 | 1. PostgreSQL 安装后,默认的数据库路径是`/var/lib/pgsql/9.x/data`; 11 | 12 | 2. 新建一个路径作为新的数据库数据路径,假如是`/home/data` 13 | 14 | ```shell 15 | sudo mkdir /home/data 16 | sudo chown -R postgres:postgres data 17 | sudo chmod 700 data 18 | ``` 19 | 20 | 最后这个赋权命令是必须的,不然数据库启动会有问题的 21 | 22 | 3. 拷贝之前的数据文件 23 | 24 | ```shell 25 | # 首先要停止 PostgreSQL 服务 26 | sudo systemctl stop postgresql 27 | sudo su - postgres 28 | cp -rf /var/lib/pgsql/9.x/data/* /home/data 29 | ``` 30 | 31 | 4. 修改 service 文件 32 | 33 | ```shell 34 | vim /usr/lib/systemd/system/postgresql*.service 35 | 36 | # 修改这个文件中的 37 | Environment=PGDATA=/var/lib/pgsql/9.4/data/ 38 | # 将其修改为自己的新的数据路径: 39 | Environment=PGDATA=/home/data/ 40 | ``` 41 | 42 | 5. 重新加载 service,并重启 PostgreSQL。 43 | 44 | ```shell 45 | # 更改 service 文件之后需要重新加载 46 | systemctl daemon-reload 47 | # 重启 PostgreSQL 服务 48 | systemctl restart postgresql-9.5 49 | ``` 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Linux/Shell/Linux Shell $* 和 $@ 的区别.md: -------------------------------------------------------------------------------- 1 | `$*`和`$@`都表示传递给函数或脚本的所有参数,而且不包含脚本参数中的文件名(`$0`),但是在被双引号包裹时,两者之间有些区别: 2 | 3 | **`"$*"`会将所有的参数作为一个整体,以`"$1 $2 … $n"`的形式输出所有参数;`"$@"`会将各个参数分开,以`"$1" "$2" … "$n"`的形式输出所有参数**。 4 | 5 | 6 | 下面通过示例展示两者的不同: 7 | 8 | ```shell 9 | #!/bin/bash 10 | echo "\$*=" $* 11 | echo "\"\$*\"=" "$*" 12 | 13 | echo "\$@=" $@ 14 | echo "\"\$@\"=" "$@" 15 | 16 | echo "print each param from \$*" 17 | for var in $* 18 | do 19 | echo "$var" 20 | done 21 | 22 | echo "print each param from \$@" 23 | for var in $@ 24 | do 25 | echo "$var" 26 | done 27 | 28 | echo "print each param from \"\$*\"" 29 | for var in "$*" 30 | do 31 | echo "$var" 32 | done 33 | 34 | echo "print each param from \"\$@\"" 35 | for var in "$@" 36 | do 37 | echo "$var" 38 | done 39 | ``` 40 | 41 | 在命令行中通过`./test.sh "a" "b" "c" "d"`,看到下面的结果: 42 | 43 | ``` 44 | $*= a b c d 45 | "$*"= a b c d 46 | 47 | $@= a b c d 48 | "$@"= a b c d 49 | 50 | print each param from $* 51 | a 52 | b 53 | c 54 | d 55 | 56 | print each param from $@ 57 | a 58 | b 59 | c 60 | d 61 | 62 | print each param from "$*" 63 | a b c d 64 | 65 | print each param from "$@" 66 | a 67 | b 68 | c 69 | d 70 | ``` 71 | 72 | 重点查看最后两段代码的输出,可以看到,`$*`和`#@`基本相同,只是后者在双引号包裹时会将各个参数当做单独的变量进行输出。 73 | 74 | 75 | -------------------------------------------------------------------------------- /DB/MySQL/问题/MySQL Authentication plugin.md: -------------------------------------------------------------------------------- 1 | > 转摘:[解决MAC+ MySQL 8 错误:Authentication plugin 'caching_sha2_password' cannot be loaded](https://www.jianshu.com/p/9a645c473676) 2 | 3 | ### 1. 问题描述 4 | 5 | 在 Mac 中的 Navicat 中连接 MySQL 8.0 的时候,出现如下连接错误提示: 6 | 7 | ``` 8 | Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(/usr/local/mysql/lib/plugin/caching_sha2_password.so, 2): image not found 9 | ``` 10 | 11 | ### 2. 问题原因 12 | 13 | 这不是客户端 Navicat 的原因,而是 MySQL 的版本兼容问题: 14 | 15 | * MySQL 8.0 默认的认证方式是`caching_sha2_password`; 16 | * MySQL 5.* 默认的认证方式是`mysql_native_password`。 17 | 18 | ### 3. 解决方案 19 | 20 | 解决这个问题只需要修改数据库的认证方式即可,有如下多种方式: 21 | 22 | * 用终端连接 MySQL,修改如下指令进行修改相关用户的登录密码: 23 | 24 | ```sql 25 | ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'yourpassword'; 26 | ``` 27 | 28 | * 修改`my.cnf`文件中的认证方式,然后重启 MySQL 29 | 30 | ```ini 31 | [mysqld] 32 | default_authentication_plugin=mysql_native_password 33 | ``` 34 | 35 | * Docker 中,修改 MySQL 镜像命令的启动配置项: 36 | 37 | ```yaml 38 | db: 39 | image: mysql:8.0.18 40 | command: --default-authentication-plugin=mysql_native_password 41 | ``` 42 | 43 | > [mysql_native_password - Docker Hub](https://hub.docker.com/_/mysql) 44 | 45 | -------------------------------------------------------------------------------- /Git/技巧/Git 从仓库中永久删除文件或目录.md: -------------------------------------------------------------------------------- 1 | 我们常用的`git rm`仅对`Working Tree`构成影响,如果想永久的删除仓库中的文件或目录,那么就要用到`git filter-branch`命令了。`git filter-branch`会检索整个 Commit 历史,逐一改写 Commit Object,重构整个 Tree。 2 | 3 | ```shell 4 | git filter-branch --tree-filter 'rm -rf path/folder' HEAD 5 | git filter-branch --tree-filter 'rm -f path/file' HEAD 6 | ``` 7 | 8 | 也可以指定检索的 Commit 历史的范围: 9 | 10 | ```shell 11 | git filter-branch --tree-filter 'rm -rf path/folder' 347ae59..HEAD 12 | ``` 13 | 14 | 最后,不要忘了向仓库强制推送所有的变化: 15 | 16 | ```shell 17 | git push origin master --force 18 | ``` 19 | 20 | 执行`git filter-branch`命令后,已经标记为删除的 Object 在本地仓库中要到过期后才会解除关联和进行垃圾回收。如果想立即解除关联,执行垃圾回收,可以这么做: 21 | 22 | ```shell 23 | # 先检查哪些 tags 和 branch 引用了这些 Object,并根据结果更新引用 24 | git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin 25 | # 然后使这些引用立即过期,并立即执行垃圾回收 26 | git reflog expire --expire=now --all 27 | git gc --prune=now 28 | # 之后就可以推送到远程仓库了 29 | git push origin --force --all 30 | git push origin --force --tags 31 | ``` 32 | 33 | > 不到迫不得已,不要轻易使用`git filter-branch`,因为它重构了整个 Tree,所以每个开发人员都需要重新克隆仓库到本地,对于有很多开发者参与的大型项目来说,这么做会给很多人带来麻烦,与其事后对仓库内容进行修正,不如伊始就对每个 Commit 慎之又慎。 34 | 35 | 转摘:[从 Git 仓库中永久删除文件或目录](http://www.jmlog.com/permanently-remove-files-and-folders-from-git-repository/) 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Nginx/实例/Nginx 合并多个 X-Forwarded-For.md: -------------------------------------------------------------------------------- 1 | 在使用 HAProxy 做负载均衡服务的时候,HAProxy 不处理已有的`X-Forwarded-For`,只是简单地在 header 末尾加入一个新的`X-Forwarded-For`。但是其他后端语言可能不会正确处理多个同名的 header。比如 php-fpm 对 header 的处理方式是同名的 header 只保留最后一个,这样就会导致无法取得正确的用户 IP。 2 | 3 | HAProxy 的这种处理方式是正确的,根据 RFC2616 ,多个同名的 header 和单个逗号分隔列表构成的 header 是等价的: 4 | 5 | > Multiple message-header fields with the same field-name MAY be present in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one "field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded. 6 | 7 | 这个问题可以通过让 Nginx 来合并多个`X-Forwarded-For`记录来解决。在 Nginx 配置中加入以下选项(一般在`location ~ \.php$`部分或者在`fastcgi_params`配置文件里): 8 | 9 | ```conf 10 | fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for if_not_empty; 11 | ``` 12 | 13 | 配置好之后 Nginx 服务器就会预先合并多个`X-Forwarded-For`请求 header 记录为逗号分隔格式,然后再传给 php-fpm。 -------------------------------------------------------------------------------- /Web/HTML/HTML 知识点.md: -------------------------------------------------------------------------------- 1 | ## 一般元素 2 | 3 | ### a 4 | 5 | `target`属性设置为`_blank`值时,会在新的浏览器标签页中打开相应页面。这样可能会有一些隐性问题存在: 6 | 7 | * 新页面和原始页面占用同一个进程。这也意味着,如果这个新页面有任何性能上的问题,比如有一个很高的加载时间,这也将会影响到原始页面的表现。 8 | * 如果打开的是一个同域的页面,那么将可以在新页面访问到原始页面的所有内容,包括`document`对象(`window.opener.document`)。 9 | 10 | 可以给`a`元素增加`rel="noopener"`来阻止这种特性。在老浏览器中,可以使用`rel="noreferrer"`属性达到同样的效果,但是,这样也会阻止 Referer header 被发送到新页面。如下所示: 11 | 12 | ```html 13 | 14 | ``` 15 | 16 | > 如果是通过 js 来打开新的页面的话,可以使用如下方式避免这种情况: 17 | > 18 | > ```js 19 | > var newWindow = window.open(); 20 | > newWindow.opener = null; 21 | > ``` 22 | 23 | ## FORM 24 | 25 | * 用户单击提交按钮或图像按钮时,就会提交表单,使用 input 或者 button 都可以提交表单,只需将 type 设置为 submit 或者 image 即可。 26 | * 同样,将 input 或者 button 的 type 设置为 reset 就能重置表单。 27 | * 访问表单字段:使用dom节点来访问;通过表单元素的 elements 属性。 28 | 29 | 每个表单都有`elements`属性,该属性: 30 | 31 | * 是表单中所有表单元素集合; 32 | * 是个有序列表; 33 | * 包含着所有字段,比如有`input`、`textarea`、`button`、`fieldset`等; 34 | * 可以通过索引次序或者表单元素的`name`属性值来访问相应的元素。 35 | 比如:`formId.elements[0]`可以获取表单中的第一个表单元素; 36 | `formId.elements['select1']`可以获取到表单中名称为`select1`的表单元素。 37 | 如果一个表单中,有多个`name`相同的属性,那么取得数据是一个集合。 38 | 39 | ## Table 40 | 41 | ### td 42 | 43 | `colspan`是横向合并;`rowspan`是纵向合并。 44 | 45 | -------------------------------------------------------------------------------- /Python/Python 3 新特性.md: -------------------------------------------------------------------------------- 1 | ### 1. 类型提示 Type hinting 2 | 3 | > 类型提示最低需要 Python 3.5。 4 | 5 | ```Python 6 | def sentence_has_animal(sentence: str) -> bool: 7 | return "animal" in sentence 8 | 9 | sentence_has_animal("Donald had a farm without animals") 10 | # True 11 | ``` 12 | 13 | ### 2. 枚举 14 | 15 | > 枚举最低要求 Python 3.4。 16 | 17 | Python 3 支持通过`Enum`类编写枚举的简单方法。枚举是一种封装常量列表的便捷方法,因此这些列表不会在结构性不强的情况下随机分布在代码中。 18 | 19 | ```Python 20 | from enum import Enum, auto 21 | 22 | class Monster(Enum): 23 | ZOMBIE = auto() 24 | WARRIOR = auto() 25 | BEAR = auto() 26 | 27 | print(Monster.ZOMBIE) 28 | # Monster.ZOMBIE 29 | ``` 30 | 31 | 枚举是符号名称(成员)的集合,这些符号名称与唯一的常量值绑定在一起。在枚举中,可以通过标识对成员进行比较操作,枚举本身也可以被遍历。 32 | 33 | ```Python 34 | for monster in Monster: 35 | print(monster) 36 | 37 | # Monster.ZOMBIE 38 | # Monster.WARRIOR 39 | # Monster.BEAR 40 | ``` 41 | 42 | ### 3. 扩展的可迭代对象解包 43 | 44 | ```Python 45 | head, *body, tail = range(5) 46 | print(head, body, tail) 47 | # 0 [1, 2, 3] 4 48 | 49 | py, filename, *cmds = "python3.7 script.py -n 5 -l 15".split() 50 | print(py) 51 | print(filename) 52 | print(cmds) 53 | # python3.7 54 | # script.py 55 | # ['-n', '5', '-l', '15'] 56 | 57 | first, _, third, *_ = range(10) 58 | print(first, third) 59 | # 0 2 60 | ``` 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /Linux/CentOS/CentOS 安装中文字体.md: -------------------------------------------------------------------------------- 1 | > 转摘:[Centos7 安装字体库&中文字体](http://www.mamicode.com/info-detail-2190315.html) 2 | 3 | ### 1. 查看当前已安装字体 4 | 5 | 使用`fc-list`可以查看当前系统中已经安装了的字体。如果提示没有该命令,则需要先安装该工具: 6 | 7 | ```shell 8 | yum -y install fontconfig 9 | ``` 10 | 11 | ### 2. 添加中文字体文件 12 | 13 | 在安装字体之前,需要先将中文字体文件拷贝到系统中: 14 | 15 | ```shell 16 | # 创建一个专门存放中文字体的文件夹,当然,放在其他文件夹中也是可以的 17 | mkdir /usr/share/fonts/chinese 18 | # 移动字体文件到该文件夹中 19 | mv simhei.ttf /usr/share/fonts/chinese/ 20 | # 修改文件夹权限,确保该文件夹可被查看和执行 21 | chmod -R 755 /usr/share/fonts/chinese/ 22 | ``` 23 | 24 | ### 3. 安装及配置 25 | 26 | 做好准备工作后,就可以使用 ttmkfdir 工具来搜索目录中所有的字体信息,并汇总生成`fonts.scale`文件。配置好之后该字体就会被安装到系统中了。 27 | 28 | ```shell 29 | # 如果没有安装 ttmkfdir 则需要先进行安装 30 | yum -y install ttmkfdir 31 | # 执行 ttmkfdir 命令 32 | ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir 33 | # 修改字体配置文件,确保存放改字体文件的路径在配置文件中 34 | vim /etc/fonts/fonts.conf 35 | ``` 36 | 37 | 在`fonts.conf`文件中,可以看到已经列出了一些字体文件的目录。如果在前面第 2 步中新创建的字体文件存放路径不在这里,则需要将其添加进入。如下图中的倒数第二行: 38 | 39 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1584939037218.png) 40 | 41 | ### 4. 刷新字体缓存 42 | 43 | 执行完上面的操作后,不需要重启系统,只需要刷新系统的字体缓存即可: 44 | 45 | ```shell 46 | # 刷新缓存 47 | fc-cache 48 | # 查看当前系统的字体列表 49 | fc-list 50 | ``` 51 | 52 | 这样在系统中就可以使用该字体了。需要注意的是,使用字体的时候,其名称与字体文件的名称并不一定是相同的。 53 | 54 | 55 | -------------------------------------------------------------------------------- /Web/FireFox 浏览器内置的网页截屏功能.md: -------------------------------------------------------------------------------- 1 | 国内的一些浏览器,基本都实现了一个网页截屏的功能。而在`FireFox`浏览器中,也能够通过一个命令进行截图。 2 | 3 | 首先,使用快捷键`Shift + F2`来打开`Developer Toolbar`,然后在浏览器窗口底部出现一个深蓝色的命令行窗口。 4 | 5 | 然后,我们就能再这个命令行中输入命令,进行网页截屏: 6 | 7 | ``` 8 | screenshot name [optional] 9 | ``` 10 | 11 | 保存下来的文件是`png`格式,所以只需要指定文件的名称,不需要指定其格式后缀。 12 | 13 | 后面的`optional`是可选参数,用来控制截屏的效果(范围),有五个可选值: 14 | 15 | * **--fullpage** 16 | 截取全屏。会将整个网页内容都截取下来,包含为没有显示在当前浏览器窗口中的内容。 17 | 18 | * **--selector** 19 | 需要指定一个`CSS`选择符,然后浏览器将会找到这个选择符指定的元素,将其包含的内容截取下来。最后的那个`CSS`选择器,可以是一个`HTML元素`,可以是一个`id`,也可以是一个`class`,但是需要保证这个选择器只会选中一个元素。 20 | 21 | ``` 22 | screenshot ff-ss-selector.png --selector #myid 23 | ``` 24 | 25 | * **--clipboard** 26 | 这个参数会指定将当前浏览器窗口中展示出来的网页内容截取到粘贴板中,而不是保存为文件。这个参数能和其他的四个参数配合使用。 27 | 28 | * **--chrome** 29 | 这个参数会指定将整个 FireFox 浏览器窗口给截取下来,而不仅仅是网页内容。 30 | 31 | * **--delay** 32 | 延迟一定时间之后在截取浏览器内显示的网页内容。使用这个参数时,在其后面还需要指定一个正整数,来表示延迟的时间,单位是`s(秒)`。 33 | 34 | 这个参数能够和上面的四个参数组合起来使用,如,下面的命令表示延迟1s之后将浏览器窗口内的网页内容截取到粘贴板中: 35 | 36 | ``` 37 | screenshot clipboard-delay --clipboard --delay 1 38 | ``` 39 | 40 | 当`screenshot`这个命令执行完成之后,截取的图片会出现在火狐浏览器的缺省下载目录里。 41 | 42 | 如果你不喜欢命令行,有一个选项可以将这个命令也按钮的形式出现,就是下面图中这个选项: 43 | ![设置截屏按钮](http://cnd.qiniu.lin07ux.cn/2015-08-03设置截屏按钮.jpg) 44 | 45 | 46 | -------------------------------------------------------------------------------- /Mac/杂项/Mac 百度云加速下载.md: -------------------------------------------------------------------------------- 1 | ### 命令行安装法 2 | 具体方法请移步 [百度云加速下载](http://zwpaper.github.io/2015/07/19/baiduyun-fastdown/)。 3 | 4 | 如果安装方法文章中的 安装包下载地址 打不开,可以从这里 [下载安装包](http://pan.baidu.com/s/1bqUUzO) 密码:`ymsg`。 5 | 6 | 7 | ### 傻瓜安装法(更适合小白同学) 8 | 如果不喜欢命令行的同学可以参照 以下方法(更简单哦~): 9 | 10 | 1. Aria2GUI dmg 下载传送门 [https://github.com/yangshun1029/aria2gui/releases](https://github.com/yangshun1029/aria2gui/releases)(下载页面中的 dmg 包); 11 | 12 | > 下载好后安装:每次下载东西的时候都需要打开这个Aria2GUI客户端 13 | 14 | 2. 安装 浏览器百度云插件 15 | 16 | > 插件目前只有 Chrome 版本在一直维护,所以只适用于 Chrome 浏览器,按照以下方法,安装完了以后,在百度云的下载界面会多出来一个“导出下载”的按钮,点击这个里面的"ARIA2 RPC",下载任务会自动在 Aria2GUI 客户端中开始。 17 | 18 | 目前百度云插件已停止打包,使用最新版本方法如下: 19 | 20 | * [下载百度云插件源代码](https://github.com/acgotaku/BaiduExporter) 并解压,如图: 21 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486533803024.png) 22 | 23 | * 方法一(直接安装crx文件):直接将下载好的文件夹中的`chrome.crx`文件拖动到浏览器的`扩展程序`界面进行安装。 24 | 25 | > 安装完毕后请参考:[将非官方扩展程序加入 Chrome 的白名单](http://xclient.info/a/1ddd2a3a-d34b-b568-c0d0-c31a95f0b309.html) 解决扩展程序失效停用的问题。 26 | 27 | * 方法二(开发者模式加载) 28 | - 打开 Chrome 的扩展程序界面,勾选 开发者模式 并点击刚显示出来的 加载已解压的扩展程序 按钮。如图: 29 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486534009968.png) 30 | 31 | - 选择解压好的源码中的 Chrome 文件夹,如图: 32 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1486534064157.png) 33 | 34 | 35 | -------------------------------------------------------------------------------- /Go/数据类型/struct/Go struct 特例 - DoNotCompare.md: -------------------------------------------------------------------------------- 1 | > 转摘:[Gopher 需要知道的几个结构体骚操作](https://mp.weixin.qq.com/s/A4m1xlFwh9pD0qy3p7ItSA) 2 | 3 | ### 1. struct 的比较 4 | 5 | 在 Go 语言中,对于 struct 来说,只有所有字段全部都是可比较的(不限大小写是否导出),那么结构体才是可比较的。同时只比较 non-blank 的字段。 6 | 7 | 示例如下: 8 | 9 | ```go 10 | type T struct { 11 | name string 12 | age int 13 | _ float64 14 | } 15 | 16 | func main() { 17 | x := [1]T{{"foo", 1, 0}} 18 | y := [1]T{{"foo", 1, 1}} 19 | fmt.Println(x == y) // true 20 | } 21 | ``` 22 | 23 | 运行的结果为 true。虽然变量`x`和`y`的最后一个字段的值不同,但是这并不影响两者的比较结果。因为`T`类型的最后一个字段是空白字段。 24 | 25 | ### 2. DoNotCampare 26 | 27 | 因为 slice、map、function 类型是不可比较的,只能判断是否为 nil。所以,如果要让一个 struct 不能比较,那么就可以为其添加一个这三种类型的字段即可。 28 | 29 | 如下,定义了一个不可比较类型: 30 | 31 | ```go 32 | // DoNotCompare can be embedded in a struct to prevent comparability. 33 | type DoNotCompare [0]func() 34 | ``` 35 | 36 | 这个不可比较类型是一个包含 0 个 function 元素的数组,所以占用空间为 0,而且是不可比较的。 37 | 38 | 将这个类型嵌入到其他的 struct,那么被嵌入的 struct 就是不可比较的: 39 | 40 | ```go 41 | type DoNotCompare [0]func() 42 | 43 | type T struct { 44 |     name string 45 |     age int 46 |     DoNotCompare 47 | } 48 | func main() { 49 | // ./cmp.go:13:21: invalid operation: T{} == T{} (struct containing 50 | // DoNotCompare cannot be compared) 51 |     fmt.Println(T{} == T{}) 52 | } 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /DB/MySQL/问题/MySQL 问答—分区.md: -------------------------------------------------------------------------------- 1 | ### 1. 表分区与分表的区别是什么? 2 | 3 | * 表分区:是指根据一定规则,将数据库中的一张表分解成多个更小的、更容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。 4 | * 分表:指的是通过一定规则,将一张表分解成多张不同的表,比如将用户订单记录根据时间成多个表。 5 | 6 | 分表与分区的区别在于:**表分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表**。 7 | 8 | > 可以通过`show variables like '%partition%';`查看是否支持分区,支持的话,`have_partintioning`的值为`YES`。 9 | 10 | ### 2. 表分区有什么好处? 11 | 12 | 1. **存储更多数据**:分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据。 13 | 2. **优化查询**:在`where`语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及`sum`和`count`语句时,也可以在多个分区上并行处理,最后汇总结果。 14 | 3. **分区表更容易维护**:例如,想批量删除大量数据可以清除整个分区。 15 | 4. **避免某些特殊的瓶颈**:例如 InnoDB 的单个索引的互斥访问,ext3 文件系统的 inode 锁竞争等。 16 | 17 | ### 3. 表分区的限制因素有哪些? 18 | 19 | 1. 一个表最多只能有 1024 个分区。 20 | 2. MySQL 5.1 中,分区表达式必须是整数,或者返回整数的表达式。在 MySQL 5.5 中提供了非整数表达式分区的支持。 21 | 3. 如果分区字段中有主键或者唯一索引的列,那么多有主键列和唯一索引列都必须包含进来。即:分区字段要么不包含主键或者索引列,要么包含全部主键和索引列。 22 | 4. 分区表中无法使用外键约束。 23 | 5. MySQL 的分区适用于一个表的所有数据和索引,不能只对表数据分区而不对索引分区,也不能只对索引分区而不对表分区,也不能只对表的一部分数据分区。 24 | 25 | ### 4. MySQL 支持的分区类型有哪些? 26 | 27 | 1. RANGE 分区:这种模式允许将数据划分不同范围。例如可以将一个表通过年份划分成若干个分区。 28 | 2. LIST 分区:这种模式允许系统通过预定义的列表的值来对数据进行分割。与 RANGE 的区别是,RANGE 分区的区间范围值是连续的,而 LIST 分区可以任意指定分割方式。 29 | 3. HASH 分区:这中模式允许通过对表的一个或多个列的 Hash Key 进行计算,最后通过这个 Hash 码不同数值对应的数据区域进行分区。例如可以建立一个对表主键进行分区的表。 30 | 4. KEY 分区:是 Hash 模式的一种延伸,这里的 Hash Key 是 MySQL 系统产生的。
 31 | 32 | 33 | -------------------------------------------------------------------------------- /PHP/问题/PHP 文件上传问题.md: -------------------------------------------------------------------------------- 1 | ### 问题 2 | 3 | 进行文件上传时,可能会出现稍大的文件无法上传的错误,有两种情况: 4 | 5 | 1. 返回 413 错误,提示 POST 请求体太长; 6 | 2. 无法获取到上传的文件及文件信息。 7 | 8 | ### 原因 9 | 10 | 这两种错误一般都是由于设置不当导致的,不仅仅是 PHP 相关的设置,可能还需要调整 Nginx 的设置(或其他 Web 服务器的设置)。 11 | 12 | Nginx 和 PHP 都会有文件上传相关的限制,默认情况下,都比较小,如果需要上传较大的文件,那么就需要更改这些设置。 13 | 14 | ### 解决 15 | 16 | 首先,检查 Nginx 的`client_max_body_size`配置。默认情况下,Nginx 该指令的值为 2M,所以对于有上传大文件的情况,需要显式的更改配置。 17 | 18 | ```conf 19 | client_max_body_size 20M; 20 | ``` 21 | 22 | > 该指令可以用于 Nginx 的 http、server 模块。 23 | 24 | 然后,需要配置 PHP 的配置文件`php.ini`,更改如下的几个指令: 25 | 26 | ```ini 27 | ; 是否允许通过 HTTP 上传文件的开关。默认为 ON 即是开 28 | file_uploads = on 29 | 30 | ; 文件上传至服务器上存储临时文件的地方,如果没指定就会用系统默认的临时文件夹 31 | ; 如果配置了,则需要确保 PHP 对该路径有读写操作 32 | upload_tmp_dir = [path] 33 | 34 | ; 允许上传文件大小的最大值。默认为 2M,如要改成你期望的值 35 | upload_max_filesize = 20M 36 | 37 | ; 指通过表单 POST 给 PHP 的所能接收的最大值,包括表单里的所有值。默认为 8M 38 | ; 如果没有修改这个值,那么上传大文件的时候,是不能获取到文件信息的 39 | post_max_size = 20M 40 | ``` 41 | 42 | 另外,上传较大的文件的时候,还需要考虑网络因素引起的 PHP 执行时间问题,否则可能会因为上传文件较长时间造成 PHP 运行超时,提前结束掉请求了。可以在`php.ini`中设置如下的几个配置: 43 | 44 | ```ini 45 | ; 每个 PHP 页面运行的最大时间值(秒),默认 30 秒 46 | ; 不建议设置过大,否则会造成服务器负载过重 47 | max_execution_time = 300 48 | 49 | ; 每个 PHP 页面接收数据所需的最大时间,默认 60 秒 50 | max_input_time = 600 51 | 52 | ; 每个 PHP 页面所吃掉的最大内存,默认 8M 53 | memory_limit = 8M 54 | ``` 55 | 56 | -------------------------------------------------------------------------------- /JavaScript/原生方法/encodeURI:decodeURI:encodeURIComponent:decodeURIComponent.md: -------------------------------------------------------------------------------- 1 | JavaScript 内置了四个 URI 编码和解码方法,这些方法能够对 URI 中的特殊字符进行编码和解码,以便浏览器和 JavaScript 代码操作。 2 | 3 | ### 1. encodeRUI()/encodeURIComponent() 4 | 5 | 有效的 URI 中不能包含某些字符,而通过这两个方法可以将这些无效字符用特殊的 UTF-8 编码替换,从而让浏览器能够接受和理解。其中: 6 | 7 | * `encodeURI()` 主要用于整个 URI(包含协议头、域名、端口等)的编码,它不会对本身属于 URI 的特殊字符(如`:/?#`)进行编码,而只会将空格替换成`%20`。 8 | * `encodeURIComponent()` 主要用于对 URI 中的某一段(如查询参数)进行编码,对任何非字母数字字符都会进行编码。 9 | 10 | 比如: 11 | 12 | ```JavaScript 13 | var uri = 'http://www.wrox.com/illegal value.html#start'; 14 | 15 | encodeURI(uri); // "http://www.wrox.com/illegal%20value.html#start" 16 | encodeURIComponent(uri); // "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start" 17 | ``` 18 | 19 | ### 2. decodeURI()/decodeURIComponent() 20 | 21 | 这两个方法是前面两个方法的匿方法,他们可以对已经编码过的 URI 进行解码,得到原始的 URI 字符串。其中: 22 | 23 | * `decodeURI()` 只能对使用`encodeURI()`后替换的字符进行解码,也就是只会将`%20`替换成空格,但对`%23`就不会替换成`#`了。 24 | * `decodeURIComponent()` 对使用`decodeURIComponent()`编码所有的字符都会解码,即它可以解码任何特殊字符的编码。 25 | 26 | 比如: 27 | 28 | ```JavaScript 29 | var uri = 'http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.html%23start' 30 | 31 | decodeURI(uri); // http%3A%2F%2Fwww.wrox.com%2Fillegal value.html%23start 32 | decodeURIComponent(uri); // http://www.wrox.com/illegal value.html#start 33 | ``` 34 | 35 | 36 | -------------------------------------------------------------------------------- /DB/MySQL/内置方法/其他方法.md: -------------------------------------------------------------------------------- 1 | ### IP地址与数字相互转换 2 | 3 | * `SELEC`给出一个作为字符串的网络地址的点地址表示,返回一个代表该地址数值的整数。地址可以是 4 或 8 比特地址。 4 | * `INET_NTOA(expr)`给定一个数字网络地址(4 或 8 比特),返回作为字符串的该地址的点地址表示。 5 | 6 | ### 加锁和解锁 7 | 8 | * `GET_LOCK(str,timeout)`设法使用字符串 str 给定的名字得到一个锁,超时为 timeout 秒。 9 | * `RELEASE_LOCK(str)`解开被 GET_LOCK() 获取的、用字符串 str 所命名的锁。 10 | * `IS_FREE_LOCK(str)`检查名为 str 的锁是否可以使用 11 | * `IS_USED_LOCK(str)`检查名为 str 的锁是否正在被使用 12 | 13 | ### 重复执行指定操作 14 | 15 | `BENCHMARK(count,expr)`函数重复 count 次执行表达式 expr。他可以用于计算 MYSQL 处理表达式的速度。结果值通常为 0(0 只是表示处理过程很快,并不是没有花费时间) 16 | 17 | 另一个作用是他可以在MYSQL客户端内部报告语句执行的时间。 18 | 19 | BENCHMARK 报告的时间是客户端经过的时间,而不是在服务器端的 CPU 时间,每次执行后报告的时间并不一定是相同的。 20 | 21 | ### CONVERT 改变字符集 22 | 23 | `CONVERT(str USING charset)`带有 USING 的 CONVERT() 函数被用来在不同的字符集之间转化数据。 24 | 25 | ```sql 26 | SELECT CHARSET('string'), CHARSET(CONVERT('string' USING latin1)); 27 | ``` 28 | 29 | ![CONVERT](http://cnd.qiniu.lin07ux.cn/markdown/1472347465763.png) 30 | 31 | ### 改变数据类型 32 | 33 | `CAST(x AS type)`和`CONVERT(x, type)`函数将一个类型的值转换为另一个类型的值,可转换的 type 有:`BINARY`、`CHAR(n)`、`DATE`、`TIME`、`DATETIME`、`DECIMAL`、`SIGNED`、`UNSIGNED`。 34 | 35 | ```sql 36 | SELECT CAST(100 AS CHAR(2)), CONVERT('2013-8-9 12:12:12', TIME); 37 | ``` 38 | 39 | ![CAST/CONVERT](http://cnd.qiniu.lin07ux.cn/markdown/1472347577888.png) 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /Git/命令/revert.md: -------------------------------------------------------------------------------- 1 | git revert 命令可以用来对指定的提交进行回退。 2 | 3 | ### revert merge commit 4 | 5 | > 转摘:[当你决定去 revert 一个merge commit](https://juejin.cn/post/6844903590545506312) 6 | 7 | 一些情况下,因为不能`fast-forward`合并而导致合并点有两个父级,如下图所示: 8 | 9 | ![](https://cnd.qiniu.lin07ux.cn/markdown/da629ba58369f611f4164a9f300b191b.jpg) 10 | 11 | 此时要对这个合并进行 revert,以取消 feature 分支的提交。如果直接执行 revert 命令,会得到如下的错误: 12 | 13 | ```shell 14 | $ git revert cae5381 15 | error: commit cae5381823aad7c285d017e5cf7e8bc4b7b12240 is a merge but no -m option was given. 16 | fatal: revert failed 17 | ``` 18 | 19 | 提交错误提示,查看 revert 命令的`-m`选项的[官方文档](https://git-scm.com/docs/git-revert#git-revert--mparent-number),可知: 20 | 21 | > 通常情况下,无法 revert 一个 Merge,因为 Git 并不知道 Merge 的哪一条线应该被视为主线。而选项`-m`就是用来指定主线的 parent 的代号(从 1 开始),并允许以相对于指定的 parent 进行 revert。 22 | 23 | 可以使用`git show`命令来查看当前的 commit 的祖先有哪些: 24 | 25 | ```shell 26 | $ git show cae5381 27 | commit cae5381823aad7c285d017e5cf7e8bc4b7b12240 28 | Merge: edf99ca 125cfdd 29 | Author: ULIVZ <472590061@qq.com> 30 | Date: Thu Apr 12 18:27:21 2018 +0800 31 | 32 | Merge tag 'thumbup-feature' 33 | ``` 34 | 35 | 输出中的`Merge`行就指明了当前的 parent 有哪些。parent 的顺序是有一定规则的:当前在 B 分支上,要把 A 分之合并到 B 分支,则 B 即为 parent1,A 则为 parent2。 36 | 37 | 因此,要 revert 掉合并进来的 feature 分支,就要使用`-m`来指定主线分支: 38 | 39 | ```shell 40 | git revert cae5381 -m 1 41 | ``` -------------------------------------------------------------------------------- /PHP/实用技巧/PHP 文件操作.md: -------------------------------------------------------------------------------- 1 | 2 | ### file_get_contents 3 | 4 | 该函数读取一个文件的内容,然后赋值给一个变量。也就是说,这个函数读取的文件内容都存放在内存中的。可以使用这个函数来打开任意类型的文件。 5 | 6 | 比如,打开一个远程图片,保存到本地: 7 | 8 | ```php 9 | $image = file_get_contents('http://www.url.com/image.jpg');  10 | file_put_contents('/images/image.jpg', $image);  11 | ``` 12 | 13 | 再比如,打开一个图片[PHP 小技巧](media/PHP%20%E5%B0%8F%E6%8A%80%E5%B7%A7.md),并输出给用户: 14 | 15 | ```php 16 | header('Content-type: image/jpeg'); 17 | $image = file_get_contents('/temp/a.jpg'); 18 | echo $image; 19 | ``` 20 | 21 | > 虽然 fopen 能够用文件流的方式打开文件,可以节省内容占用,但是如果是想打开文件并上传到远程服务器的时候,fopen 可能会造成上传的文件有问题。而 file_get_contents 则不会。 22 | 23 | 24 | ### file_put_contents 25 | 26 | 将一个字符串写入文件,有4个参数。其中前两个分别表示要被写入数据的文件名和要写入的数据。其余两个使用的较少。 27 | 28 | 由于写入的数据是一个字符串,所以处理一维或者多维数组时,建议使用 json 格式封装数组数据,读取的时候解析 json 即可。 29 | 30 | ```php 31 | 44 | ``` 45 | 46 | 47 | -------------------------------------------------------------------------------- /杂项/MQ 消息队列的优劣势.md: -------------------------------------------------------------------------------- 1 | > 转摘:[天天用消息队列 MQ,却不知道为啥要用,尴尬不?](https://mp.weixin.qq.com/s/zC2LGdy1DZ2_WE-2lx34ZQ) 2 | 3 | ## 一、 使用 MQ 的好处 4 | 5 | 使用消息队列的好处主要有三个:解耦、异步、削峰。 6 | 7 | ### 1.1 解耦 8 | 9 | 对于由不同模块组合完成一个功能的需求,传统方式上是直接使用一个模块调用另一个模块的方式。如下图所示: 10 | 11 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1569549126431.png) 12 | 13 | 这种方式下,各个模块之间的耦合性很高,当需要修改、替换或者增加被调用模块时,调用方也需要修改代码。 14 | 15 | 使用消息中间件之后,调用方和被调用方之间通过中间件作为数据传递和沟通渠道,调用方只需要将消息数据存入到中间件,而被调用方通过监听中间件的消息数据变动来自动执行,从而将调用方和被调用方完成解耦,互不干涉。 16 | 17 | ### 1.2 异步 18 | 19 | 在传统模式下,当一个模块需要通过另一个模块来完成非必要的任务时,需要同步的等待其调用完成才能返回响应给用户,时间浪费在了等待非必要任务的完成上。如下图所示: 20 | 21 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1569549465658.png) 22 | 23 | 而使用消息中间件之后,调用方将数据存入到中间件之后即可立即返回响应,非必要的业务逻辑以异步的方式运行,可以大大减少请求响应时间。如下图所示: 24 | 25 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1569549549965.png) 26 | 27 | ### 1.3 削峰 28 | 29 | 在传统模式下,当并发量比较大的时候,容易造成单点资源(如数据库)无法正常响应,出现异常,从而影响用户的使用。 30 | 31 | 加入消息中间件之后,可以按照单点资源的最大并发量从中间件中提取消息进行处理,避免出现异常情况。此时,这个短暂的高峰期积压是可以接受的。 32 | 33 | ## 二、使用消息中间件的缺点 34 | 35 | 在原本的系统上增加了中间件系统,必然会增加整个系统的复杂性、降低可用性。 36 | 37 | ### 2.1 增加复杂性 38 | 39 | 引入消息中间件之后,需要从多个方面确保消息数据的安全,如一致性问题、重复消费问题、消息可靠传输问题、中间件异常时消息数据丢失问题等。 40 | 41 | 因此,需要考虑的东西更多,系统复杂性增大。 42 | 43 | ### 2.2 降低可用性 44 | 45 | 向系统中每新增加一个模块,都会由于该模块也会出现问题而降低整个系统的可用性。 46 | 47 | 加入消息中间件也一样,需要保证消息中间件的可用性问题,要避免数据在消息中间件丢失,从而降低了整个系统的可用性。 48 | 49 | -------------------------------------------------------------------------------- /Nginx/指令/Nginx add_header.md: -------------------------------------------------------------------------------- 1 | `add_header`指令用于设置用户自定义的响应头,比如,设置 HSTS 响应头: 2 | 3 | ```conf 4 | add_header Strict-Transport-Security "max-age=63072000; preload"; 5 | add_header X-Frame-Options SAMEORIGIN; 6 | add_header X-Content-Type-Options nosniff; 7 | add_header X-XSS-Protection "1; mode=block"; 8 | ``` 9 | 10 | ### 继承性 11 | 12 | > 转摘:[小心Nginx的add_header指令](https://www.tlanyan.me/be-careful-with-nginx-add_header-directive/) 13 | 14 | `add_header`指令的继承性有点特殊,官网上关于`add_header`有如下的说明: 15 | 16 | > There could be several add_header directives. **These directives are inherited from the previous level if and only if there are no add_header directives defined on the current level**. 17 | 18 | 这段话中,重要的就是**仅当当前层级中没有`add_header`指令才会继承父级设置**。 19 | 20 | 也就是说:如果`location`块中有`add_header`指令,那么`server`和更上层级的`http`块中的`add_header`都会失效。 21 | 22 | 这是 Nginx 的故意行为,说不上是 bug 或坑。但深入体会这句话,会发现更有意思的现象:仅最近一处的`add_header`起作用。`http`、`server`和`location`三处均可配置`add_header`,但起作用的是最接近的配置,往上的配置都会失效。 23 | 24 | 即便是同级的`location`之间进行的`rewrite`操作,也仅仅会在最后一次出现`add_header`处的`location`块中的有效,其他的都失效。 25 | 26 | 示例如下: 27 | 28 | ```conf 29 | location /foo1 { 30 | add_header foo1 1; 31 | rewrite / /foo2; 32 | } 33 | 34 | location /foo2 { 35 | add_header foo2 1; 36 | return 200 "OK"; 37 | } 38 | ``` 39 | 40 | 不管请求`/foo1`还是`/foo2`,最终`header`只有`foo2`。 41 | 42 | -------------------------------------------------------------------------------- /Python/技巧/namedtuple 和 dataclass 定义简单功能类.md: -------------------------------------------------------------------------------- 1 | dataclass 在 Python 3.7 中引入到标准库,用于解决具名元组(namedtuple)的属性必须预先定义的缺点。 2 | 3 | ### 1. namedtuple 4 | 5 | namedtuple 是 Python 标准库 collections 里的一个模块,可以实现一个类似类的一个功能。具名元组类虽然定义和使用比较简单,但是所有属性都需要提前定义好才能用,如果要为其添加属性,则必须修改具名元组类的定义,否则会引发错误。 6 | 7 | 比如: 8 | 9 | ```Python 10 | from collections import namedtuple 11 | 12 | # 定义一个 Car 具名元组类,并设置 color 和 mileage 两个属性 13 | Car = namedtuple('Car', 'color mileage') 14 | 15 | my_car = Car('red', 3812.4) 16 | 17 | print(my_car.color) # 'red' 18 | print(my_car) # Car(color='red', mileage=3812.4) 19 | 20 | # 添加新的属性引发错误 21 | my_car.name = 'Benz' 22 | # Traceback (most recent call last): 23 | # File "", line 1, in 24 | # AttributeError: 'Car' object has no attribute 'name' 25 | ``` 26 | 27 | ### 2. dataclass 28 | 29 | 在 Python 3.7 中引入的标准库 dataclass 可以更方便的实现简单功能类的定义。 30 | 31 | 比如,对于上面的示例,使用 dataclass 可以有如下实现: 32 | 33 | ```Python 34 | from dataclasses import dataclass 35 | 36 | @dataclass 37 | class Car: 38 | color: str 39 | mileage: float 40 | 41 | my_car = Car('red', 3812.4) 42 | print(my_car) # Car(color='red', mileage=3812.4) 43 | 44 | my_car.name = 'Benz' 45 | print(my_car) # Car(color='red', mileage=3812.4) 46 | print(my_car.name) # 'Benz' 47 | ``` 48 | 49 | 可以看到,使用 dataclass 可以定义简单的功能类,并能为其添加未定义的属性。 50 | 51 | -------------------------------------------------------------------------------- /Linux/Service/firewall.md: -------------------------------------------------------------------------------- 1 | > 转摘:[Linux CentOS7 开通端口外网端口访问权限](https://www.cnblogs.com/gz666666/p/12710457.html) 2 | 3 | Linux 的多个发行版本都默认安装了 firewall 服务作为防火墙,其可以控制 Liunx 系统的端口开放情况和网络数据连通等。 4 | 5 | ### 1. 服务状态 6 | 7 | ```shell 8 | systemctl status firewall # 查看服务状态 9 | systemctl start firewall # 开启服务 10 | systemctl stop firewall # 停止服务 11 | systemctl disable firewall # 禁止开机自启动 12 | systemctl enable firewall # 启用开机自启动 13 | ``` 14 | 15 | ### 2. 基本参数 16 | 17 | * `--version` 查看版本; 18 | * `--state` 查看状态; 19 | * `--reload` 重新启动以更新防火墙规则; 20 | * `--list-port` 查看打开的端口; 21 | * `--zone` 指定访问区域,一般使用`--zone=public`来指定配置外网访问; 22 | * `--get-active-zones` 查看区域信息; 23 | 24 | ### 3. 开启端口外网 TCP 访问 25 | 26 | ```shell 27 | # 开启 TCP 80 端口的外网访问 28 | firewall-cmd --zone=public --add-port=80/tcp --permanent 29 | 30 | # 开启 TCP 443 端口的外网访问 31 | firewall-cmd --zone=public --add-port=443/tcp --permanent 32 | 33 | # 开放多个端口的 TCP 外网访问 34 | firewall-cmd --zone=public --add-port=80-85/tcp --permanent 35 | ``` 36 | 37 | > `--permanent`表示永久生效,不指定此参数的话,重启 firewall 服务后该配置就会失效。 38 | 39 | ### 4. 其他常用命令 40 | 41 | ```shell 42 | # 查看所有打开外网访问的端口 43 | firewall-cmd --zone=public --list-ports 44 | 45 | # 查看指定接口所属区域 46 | firewall-cmd --get-zone-of-interface=eth0 47 | 48 | # 拒绝所有包 49 | firewall-cmd --panic-on 50 | 51 | # 查看是否拒绝 52 | firewall-cmd --query-panic 53 | ``` 54 | 55 | -------------------------------------------------------------------------------- /PHP/Laravel/Laravel env.md: -------------------------------------------------------------------------------- 1 | ### env 函数的误区 2 | 3 | 当执行`config:cache`之后,在代码中使用的`env()`方法返回的值就都是 null 了,而使用`config:clear`之后就正常了。 4 | 5 | Laravel 5.2 的升级日志中有如下的说明: 6 | 7 | > If you are using the config:cache command during deployment, you must make sure that you are only calling the env function from within your configuration files, and not from anywhere else in your application. 8 | > 9 | > If you are calling env from within your application, it is strongly recommended you add proper configuration values to your configuration files and call env from that location instead, allowing you to convert your env calls to config calls. 10 | 11 | 这里明确说明了这个问题,并指出应该在配置文件中使用`env`方法,而在代码中则使用`config`方法来作为替代。 12 | 13 | 从代码角度来说,这是由于 Laravel 5.2 升级之后代码运行的逻辑决定的,在框架的核心启动类`Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables`中的`bootstrap()`方法中有如下的处理: 14 | 15 | ```PHP 16 | public function bootstrap(Application $app)
{
 if ($app->configurationIsCached()) {
 return;
 }

 $this->checkForSpecificEnvironmentFile($app);

 try {
 (new Dotenv($app->environmentPath(), $app->environmentFile()))->load();
 } catch (InvalidPathException $e) {
 //
 }
} 17 | ``` 18 | 19 | 在函数中的起始部分我们可以发现,一旦缓存了配置以后,就不会再从`.env`文件加载内容了,所以你在业务代码中使用`env`函数时已经无法读取`.env`中设定的内容了,但是其它环境变量不影响。那为什么配置文件的可以呢?因为配置文件缓存的时候会加载`.env`然后读取值缓存配置内容。 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /PHP/内置函数/trim 逐字符匹配.md: -------------------------------------------------------------------------------- 1 | ### 1. 处理原理 2 | 3 | `trim()`方法可以去除字符串两端的指定字符,类似的方法还有`ltrim()`去除字符串左侧的指定字符、`rtrim()`去除字符串右侧的指定字符。他们的实现原理基本一样,都是**逐字符匹配**。 4 | 5 | **逐字符匹配**的意思就是说,从字符串的某一侧的第一个的字符开始,依次查找该字符是否在指定的要去除的字符列表中,如果存在则去除,直到找到第一个不在指定的要去除的字符列表中为止。而`trim()`则需要分别从左侧和右侧进行上述操作。下面用实例来进行说明: 6 | 7 | ```php 8 | $str = 'abc66646abc666'; 9 | echo trim($str, 'abc666'); 10 | ``` 11 | 12 | 输出结果是`4`而不是`46`,下面进行分析: 13 | 14 | 1. 从左往右开始匹配取出第一个字符`a`,字符`a`在需要去除的'abc666'里面,所以`a`被去除; 15 | 2. 然后取出第二个字符`b`,字符`b`也在需要去除的'abc666'里面,所以`b`也被去除了; 16 | 3. 重复进行匹配和去除操作,直到字符`4`,字符`4`不在需要去除的'abc666'里面,所以从左往右匹配停止,这个时候剩下'46abc666'; 17 | 4. 然后从右往左匹配,匹配过程同从左往右,最后一直匹配到`4`,所以最后结果为`4`。 18 | 19 | 实际上,将需要去除的字符列表`abc666`改成`abc6`也可以得到一样的结果。 20 | 21 | ### 2. .. 符号 22 | 23 | 去除列表还可以使用`..`符号,表示两个字符之间的全部字符都需要去除。 24 | 25 | 比如`trim('abcdefg','a..f')`,在执行的时候会被当做`trim('abcdefg','abcdef')`来执行,所以结果就是`g`。 26 | 27 | 当然,如果要去除`a`、`.`、`f`三个字符,就不能使用上述的方法,而是使用一个`.`符号,如`trim('abcdefg','a.f')`。 28 | 29 | ### 3. 多字节 30 | 31 | 由于`trim()`方法的底层是通过十六进制数据进行匹配和去除的,在多字节处理的时候就会出现问题了,这也就是为什么`trim()`处理中文时会产生乱码。 32 | 33 | 比如,对于`trim('品、' , '、')`,`品`的十六进制表示为`e5 93 81`,字符`、`的十六进制表示`e3 80 81`。在`trim()`中,按字节计算,utf8 中文编码 3 个字节表示一个汉字。因此相当于`trim()`去掉内容是三个字符。这三个字符的十六进制表示为`e3 80 81`。所以最终返回字符串的十六进制表示为`e5 93`,因为`81`已经被去除了。 34 | 35 | 而`trim('的、', '、')`就能返回正确结果,因为`的`的十六进制表示`e7 9a 84`,与`、`的十六进制没有相同的部分。 36 | 37 | 38 | -------------------------------------------------------------------------------- /PHP/杂项/编译安装 PHP 7.1 pdo_mysql 扩展.md: -------------------------------------------------------------------------------- 1 | > 参考:[php7 编译安装pdo_mysql扩展](https://my.oschina.net/u/2399303/blog/1512320) 2 | 3 | ### 1. 下载源码 4 | 5 | 如果在编译安装 PHP 7.1 时没有开启 pdo mysql 扩展,那么需要先下载 pdo_mysql 扩展包源码:[pecl.php.net](http://pecl.php.net/package/PDO_MYSQL)。 6 | 7 | ```shell 8 | wget http://pecl.php.net/get/PDO_MYSQL-1.0.2.tgz 9 | tar -zxvf PDO_MYSQL-1.0.2.tgz 10 | cd PDO_MYSQL-1.0.2 11 | ``` 12 | 13 | 如果编译安装的 PHP 源码还存在,则不需要单独下载,直接使用 PHP 源码中的代码: 14 | 15 | ```shell 16 | cd php-7.1.25/ext/pdo_mysql/ 17 | ``` 18 | 19 | ### 2. 安装 20 | 21 | 进入源码目录之后,需要先对其进行相关处理,没问题即可安装: 22 | 23 | ```shell 24 | /usr/local/php71/bin/phpize 25 | 26 | ./configure --with-php-config=/usr/local/php71/bin/php-config --with-pdo-mysql=mysqlnd 27 | 28 | make && make install 29 | ``` 30 | 31 | 这里有两个地方需要注意: 32 | 33 | * 这里使用`mysqlnd`而不是`/usr/local/mysql`,因为 PHP7 正式移除了 mysql 扩展; 34 | * 如果有多个版本的 PHP,`phpize`和`php-config`都需要使用相应 PHP 版本的程序。 35 | 36 | ### 3. 修改配置 37 | 38 | 编译安装完成之后,还需要在`php.ini`文件中引入该扩展,否则不会自动加载: 39 | 40 | ```ini 41 | extension=pdo_mysql.so 42 | ``` 43 | 44 | ### 4. 问题 45 | 46 | 使用 pdo_mysql 扩展包的源码安装时,可能会提示`can not find mysql under the "mysqlnd" that you specified`,即便已经安装了`mysqlnd`,依旧不行。这需要安装 MySQL 的开发包: 47 | 48 | ```shell 49 | yum install libmysqlclient-dev 50 | ``` 51 | 52 | 如果依旧不能正常安装,建议使用 PHP 的源码中的扩展来安装,注意 PHP 源码需要和编译安装的 PHP 版本一致。 53 | 54 | 55 | -------------------------------------------------------------------------------- /DB/MySQL/实用技巧/MySQL 一个字段包含多个数据的关联查询.md: -------------------------------------------------------------------------------- 1 | 在实际业务中,经常会遇到一个模型(记录)有多个其他的关联模型(记录),也就是常见的一对多关系。可以考虑用一个中间表存储这个关联关系,而简便的方法就是直接在父记录中用一个字段存储所有的关联字段的 ID,这时候在进行关联查找的时候就需要一定的技巧了。 2 | 3 | 加入有一个`users`表和一个`places`表,表结构分别如下: 4 | 5 | ```sql 6 | 7 | CREATE TABLE shao_places ( 8 | `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', 9 | `name` varchar(100) NOT NULL COMMENT '地点名称', 10 | PRIMARY KEY (`id`) 11 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='来自与去往地点数据表'; 12 | 13 | CREATE TABLE shao_users ( 14 | `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 'ID', 15 | `name` varchar(50) NOT NULL COMMENT '姓名', 16 | `from` int(11) UNSIGNED NOT NULL COMMENT '来自地点 ID', 17 | `to` varchar(20) NOT NULL COMMENT '销往地点 ID 列表(, 分隔)', 18 | PRIMARY KEY (`id`), 19 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci COMMENT='用户表'; 20 | ``` 21 | 22 | 可以看到,每个`users`记录都有一个`from`键表示来自地区,还有一个`to`表示去往地区,其中,来自只能是一个地方,而去往则可以有多个地方。 23 | 24 | 现在需要查询每个用户的来往地点,和要去往的地点。由于去往地点是多个,则需要进行一点的处理,可以考虑使用`FIND_IN_SET()`函数来实现: 25 | 26 | ```sql 27 | select u.id, u.name, f.name as `from`, group_concat(t.name SEPARATOR " ") as `to` from users as u 28 | join places as f on u.from = f.id 29 | join places as t on find_in_set(t.id, u.to) 30 | where phone not like '100%' 31 | group by u.id 32 | order by u.id 33 | ``` 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /JavaScript/实例/JavaScript 获取文件扩展名.md: -------------------------------------------------------------------------------- 1 | ## 方案一 正则表达式 2 | ```js 3 | function getFileExtension1 (filename) { 4 | return (/[.]/.exec(filename)) ? /[^.]+$/.exec(filename)[0] : undefined; 5 | } 6 | ``` 7 | 8 | ## 方案二 String.split() 方法 9 | ```js 10 | function getFileExtension2 (filename) { 11 | return filename.split('.').pop(); 12 | } 13 | ``` 14 | 15 | ## 方案三 String.slice() 和 String.lastIndexOf() 结合 16 | ```js 17 | function getFileExtension3 (filename) { 18 | return filename.slice((filename.lastIndexOf('.') - 1 >>> 0) + 2); 19 | } 20 | ``` 21 | 工作原理是: 22 | 23 | - 首先用 String.lastIndexOf() 找到文件名中最后一个'.'的位置(从 0 开始计数)。如果返回 -1 表示文件名中没有'.'存在。 24 | - 然后将上一步的结果减 1 之后,进行无符号右移 0(就是为了转成无符号数)。这是为了对如`filename`、`.hiddenfile`这类文件名能正确处理。这类文件均没有扩展名,进行这一步操作之后,起始位置就会变成 4294967295 和 4294967294,也就是远大于文件名的长度。 25 | - 用 String.slice() 方法将字符串从上一步处理后得到的位置开始截取到文件名结尾。截取不到字符的就返回空。 26 | - 然后返回最终截取到的结果作为扩展名。 27 | 28 | 29 | ## 测试 30 | 前两种方法无法覆盖到一些极端的情况,第三个方案会更稳健一些。 31 | 32 | ```js 33 | console.log(getFileExtension3('')); // '' 34 | console.log(getFileExtension3('filename')); // '' 35 | console.log(getFileExtension3('filename.txt')); // 'txt' 36 | console.log(getFileExtension3('.hiddenfile')); // '' 37 | console.log(getFileExtension3('filename.with.many.dots.ext')); // 'ext' 38 | ``` 39 | 40 | 41 | -------------------------------------------------------------------------------- /Linux/Command/wc.md: -------------------------------------------------------------------------------- 1 | `wc`是 Linux 系统中的一个统计工具,可以用于统计每个输入文件内容的行数、词数、字符数、Bytes 数。 2 | 3 | ### 1. 语法 4 | 5 | 语法如下: 6 | 7 | ```shell 8 | wc [-clmw][--help][--version][文件...] 9 | ``` 10 | 11 | ### 2. 选项 12 | 13 | * `-c` 统计字节数,如果还指定了`-m`参数,则该参数不起作用。 14 | * `-l` 统计行数。 15 | * `-m` 统计字符数。这个标志不能与`-c`标志一起使用。非 ASCII 字符会被当做多个字符。 16 | * `-w` 统计字词数。一个字词被定义为由空白、跳格或换行字符分隔的字符串。 17 | 18 | 需要注意的是,`-w`统计的字词并非常见意义中的词,必须要通过这三种空白符号分隔才会被作为不同的字词,而且对于非 ASCII 内容进行字词统计常会有不符合预期的情况。比如,中文的`你好`会被作为两个词,而`你好吗`依旧是两个词。 19 | 20 | ### 3. 参数 21 | 22 | `wc`命令可以一次提供零个或多个文件进行统计。如果没有提供文件,则默认统计标准输入中的内容。 23 | 24 | ### 4. 使用 25 | 26 | 有一个名为`test.txt`的文本文件,内容如下: 27 | 28 | ``` 29 | hnlinux 30 | peida.cnblogs.com 31 | ubuntu 32 | ubuntu linux 33 | redhat 34 | Redhat 35 | linuxmint 36 | 你好! 37 | ``` 38 | 39 | 分别执行如下的命令: 40 | 41 | ```shell 42 | wc -c test.txt # 输出: 81 test.txt 43 | wc -l test.txt # 输出: 8 test.txt 44 | wc -m test.txt # 输出: 74 test.txt 45 | wc -w test.txt # 输出: 10 test.txt 46 | ``` 47 | 48 | 这里由于有中文字符存在,所以统计结果会有点不太准确,如果没有最后一行中文,则统计结果依次为:70、7、70、8。 49 | 50 | ### 5. 技巧 51 | 52 | **只输出统计数字不输出文件名** 53 | 54 | 使用 wc 命令对一个文件做统计的时候,会同时输出文件的名称,而直接从标准输入中进行统计则不会输出文件名。所以可以考虑使用管道来达成这个需求: 55 | 56 | ```shell 57 | wc -l test.txt  # 输出: 8 test.txt 58 | cat test.txt | wc -l # 输出: 8 59 | ``` 60 | 61 | **统计当前目录下的文件数** 62 | 63 | ```shell 64 | ls -l | wc -l 65 | ``` 66 | 67 | 68 | -------------------------------------------------------------------------------- /Nginx/知识点/Nginx root 与 alias 的区别.md: -------------------------------------------------------------------------------- 1 | root 和 alias 都可以定义在 location 模块中,用来指定请求资源的真实路径。不同点在于: 2 | 3 | 1. `alias`指令只能作用在 location 中,而`root`指令可以存在 server、http 和 location 中。 4 | 2. `alias`指令的参数后面必须要用`/`结束,否则会找不到文件,而`root`指令的参数则对`/`可有可无。 5 | 3. 对于请求资源的真实路径: 6 | * `alias`:用配置值**替换** location 中的值之后的路径; 7 | * `root`:用配置的值**拼接** location 中的值之后的路径。 8 | 9 | `root`指令,对应的请求资源的**真实的路径是 root 指定的值加上 location 指定的值**。比如: 10 | 11 | ```conf 12 | location /i/ { 13 | root /data/w3; 14 | } 15 | ``` 16 | 17 | 请求`http://foofish.net/i/top.gif`这个地址时,在服务器里面对应的真正的资源是`/data/w3/i/top.gif`文件。。 18 | 19 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1476061025524.png) 20 | 21 | `alias`指令指定的路径是 location 的别名,不管 location 的值怎么写,资源的**真实路径都是 alias 指定的路径替换 location 的路径后得到的结果**。比如: 22 | 23 | ```nginx 24 | location /i/ { 25 | alias /data/w3/; 26 | } 27 | ``` 28 | 29 | 同样请求`http://foofish.net/i/top.gif`时,在服务器查找的资源路径是:`/data/w3/top.gif`。 30 | 31 | ![](http://cnd.qiniu.lin07ux.cn/markdown/1476061099215.png) 32 | 33 | 如果在 location 中使用了正则表达式,那么其中的`alias`必须要使用正则变量: 34 | 35 | ```conf 36 | // if alias is used inside a location defined with a regular expression 37 | // then such regular expression should contain captures and alias should 38 | // refer to these captures, for example: 39 | 40 | location ~ ^/users/(.+\.(?:gif|jpe?g|png))$ { 41 | alias /data/w3/images/$s; 42 | } 43 | ``` -------------------------------------------------------------------------------- /Linux/Command/grep.md: -------------------------------------------------------------------------------- 1 | > 转摘:[都说Linux很重要,你会几个Linux命令?来看看这道面试题目。](https://mp.weixin.qq.com/s/BGh4eQ6zf8NNem29ou4kqg) 2 | 3 | `grep`可以用于文件内容的搜索器,从文件中搜索出符合指定规则的内容,语法如下: 4 | 5 | ```shell 6 | grep [-abcdDEFGHhIiJLlmnOopqRSsUVvwxZ] [-A num] [-B num] [-C[num]] 7 | [-e pattern] [-f file] [--binary-files=value] [--color[=when]] 8 | [--colour[=when]] [--context[=num]] [--label] [--line-buffered] 9 | [--null] [pattern] [file ...] 10 | ``` 11 | 12 | ### 1. 选项 13 | 14 | * `-r` 递归查找 15 | * `-n` 显示匹配到的内容在文件中的行号 16 | * `-R` 查找所有文件,包含子目录 17 | * `-i` 匹配时忽略大小写,默认情况下会区分大小写 18 | * `-l` 只列出匹配的文件名 19 | * `-L` 列出不匹配的文件名 20 | * `-w` 只匹配整个单词,而不是字符串中的一部分 21 | * `-A ` 显示每个匹配的行及其之后的 num 行内容 22 | * `-B ` 显示每个匹配的行及其之前的 num 行内容 23 | * `-C ` 显示每个匹配的行及其之前的 num 行和之后的 num 行的内容 24 | * ` | ` 显示匹配 pattern1 或 pattern2 的行 25 | 26 | 如果要显示同时包含 pattern1 和 pattern2 的行,可以使用级联的 grep 命令: 27 | 28 | ```shell 29 | grep pattern1 files | grep pattern2 30 | ``` 31 | 32 | ### 2. pattern 的特殊字符 33 | 34 | 用于搜索的 pattern 中,可以使用一些特殊的符号,来达到部分正则表达式的功能: 35 | 36 | * `\<` 标注单词的开始 37 | * `\>` 标注单词的结尾 38 | * `^` 标注匹配行首 39 | * `$` 标注匹配行尾 40 | 41 | 例如: 42 | 43 | ```shell 44 | grep yuan* files # 匹配 chenyuan、yuannic、yuan 等 45 | grep '\' files # 只匹配 yuan,而不匹配 chenyuan、yuanic 等其他的字符串 47 | ``` 48 | 49 | 50 | -------------------------------------------------------------------------------- /Nginx/实例/Nginx 防盗链.md: -------------------------------------------------------------------------------- 1 | ## 通过 referer 判断 2 | 3 | 防盗链主要是通过 referer 指令来过滤图片请求的。如果请求图片的 referer 不是指定的网站域名,或者没有 referer,那么就不能访问图片,也不能下载了。 4 | 5 | ```conf 6 | location ~* \.(gif|jpg|jpeg|png)$ { 7 | expires 30d; 8 | valid_referers *.lin07ux.dev *.baidu.com; 9 | 10 | if ($invalid_referer) { 11 | return 404; 12 | } 13 | } 14 | ``` 15 | 16 | 参考:[nginx实现图片防盗链(referer指令)](http://www.ttlsa.com/nginx/nginx-referer/) 17 | 18 | 延伸:[nginx secure_link下载防盗链](http://www.ttlsa.com/nginx/nginx-modules-secure_link/) 19 | 20 | ## 语法 21 | 22 | 语法:`valid_referers none | blocked | server_names | string ...;` 23 | 24 | 默认值:`—` 25 | 26 | 配置段:`server`, `location` 27 | 28 | 作用:指定合法的来源的 referer,决定了内置变量`$invalid_referer`的值,如果 referer 头部包含在这个合法网址里面,这个变量被设置为 0,否则设置为 1。记住,不区分大小写。 29 | 30 | 可能的值: 31 | 32 | - `none` Referer 来源头部为空的情况 33 | - `blocked` Referer 来源头部不为空,但是里面的值被代理或者防火墙删除了,这些值都不以`http://`或者`https://`开头。 34 | - `server_names` Referer 来源头部包含当前的`server_names`(当前域名) 35 | - `arbitrary string` 任意字符串,定义服务器名或者可选的 URI 前缀。主机名可以使用`*`开头或者结尾,在检测来源头部这个过程中,来源域名中的主机端口将会被忽略掉。 36 | - `regular expression` 正则表达式,`~`表示排除`https://`或`http://`开头的字符串。 37 | 38 | 这些值可以混合使用,比如,下面的配置表示允许 referer 为空,或者被代理删除,或者是从当前域名过来的,还可以是在`test.com`的子域名中过来的: 39 | 40 | ```conf 41 | valid_referers none blocked server_names *.test.com http://IP; 42 | ``` 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /Web/Unicode 字符在 HTML、CSS、JavaScript 中的不同处理.md: -------------------------------------------------------------------------------- 1 | Unicode 字符在 HTML、CSS 和 JavaScript 中的表示方法均不相同: 2 | 3 | ### CSS 中的表示 4 | CSS 中一般会在伪元素中使用 Unicode 字符,用于显示一个特殊的字符或 icon。 5 | 6 | 语法:`'\ + 16进制的unicode编码'` 7 | 8 | 比如,一段很常见的 bootstrap 的字体图标代码: 9 | 10 | ```css 11 | .glyphicon-home:before { 12 | content: "\e021"; 13 | } 14 | ``` 15 | 16 | 上面代码中的`e021`就是这个字符的 Unicode 码,是 16 进制。 17 | 18 | ### JavaScript 中的表示 19 | JavaScript 和 CSS 中的语法很像,只是多了一个字母`u`。 20 | 21 | 语法:`'\u + 16进制的unicode编码'` 22 | 23 | ```javascript 24 | // 如:'\u5b89'表示汉字“安” 25 | console.log('\u5b89'); // 输出“安” 26 | ``` 27 | 28 | JavaScript 中,可以使用`charCodeAt()`或者`codePointAt()`方法来获取字符的 Unicode 码,结果用十进制表示: 29 | 30 | ```javascript 31 | '安'.charCodeAt(); // 23433 32 | '安'.codePointAt(); // 23433 33 | ``` 34 | 35 | 由于获取到的是十进制数,所有如果想在 js 和 css 里面用的话,就需要用`toString(16)`转 16 进制,然后再做进一步处理了: 36 | 37 | ```javascript 38 | // 输出字符串:"\u8317" 39 | var unicode = '\\u' + '茗'.charCodeAt().toString(16); 40 | // 输出汉字:"茗" 41 | JSON.parse('"' + unicode + '"'); 42 | // 或者使用eval解析也可以 43 | eval('"' + unicode + '"'); 44 | ``` 45 | 46 | ### HTML 中的表示 47 | HTML 特殊一点,使用的是 10 进制,而且格式也不太一样。 48 | 49 | 语法:`'&# + 10 进制的 unicode 编码 + 英文分号;'` 50 | 51 | 比如,`安`表示中文中的“安”。 52 | 53 | 另外,HTML 一些特殊字符还有其它表示,也就是常说的 HTML 转义字符,如:`$nbsp;`表示` `,也就是空格。 54 | 55 | 完整的 HTML 转义字符可以看这里:[站长工具](http://tool.oschina.net/commons?type=2)。 56 | 57 | -------------------------------------------------------------------------------- /Docker/Docker 命令.md: -------------------------------------------------------------------------------- 1 | * `docker save` 将镜像保存为一个归档文件 2 | 3 | ```shell 4 | # 这里的 filename 可以为任意名称甚至任意后缀名,但文件的本质都是归档文件 5 | docker save alpine -o filename 6 | # 使用 gzip 压缩 7 | docker save alpine | gzip > alpine-latest.tar.gz 8 | ``` 9 | 10 | * `docker load` 从文件加载镜像 11 | 12 | ```shell 13 | docker load -i alpine-latest.tar.gz 14 | ``` 15 | 16 | * `docker login` 登录 Docker Hub 17 | 18 | * `docker logout` 退出登录 19 | 20 | * `docker search` 搜索官方仓库中的镜像 21 | 22 | - 可以指定镜像名称进行搜索,如:`docker search centos`,表示搜索 centos 镜像; 23 | - 可以指定仓库名称进行搜索,如:`docker search tianon/`,表示搜索用户`tianon`提供的镜像; 24 | - 可以使用过滤条件进行过滤,如:`docker search nginx --filter=stars=1000`,表示搜索收藏数量为 1000 以上的镜像。 25 | 26 | * `docker push` 推送镜像到自己的 Docker Hub 账户下 27 | 28 | ```shell 29 | $ docker tag ubuntu:18.04 username/ubuntu:18.04 30 | 31 | $ docker image ls 32 | REPOSITORY TAG IMAGE ID CREATED SIZE 33 | ubuntu 18.04 275d79972a86 6 days ago 94.6MB 34 | username/ubuntu 18.04 275d79972a86 6 days ago 94.6MB 35 | 36 | $ docker push username/ubuntu:18.04 37 | 38 | $ docker search username 39 | NAME DESCRIPTION STARS OFFICIAL AUTOMATED 40 | username/ubuntu 41 | ``` 42 | 43 | 44 | -------------------------------------------------------------------------------- /Go/packages/encoding/json/Go JSON.md: -------------------------------------------------------------------------------- 1 | ### 1. 忽略某个字段 2 | 3 | 如果想在 json 序列化/反序列化的时候忽略掉结构体中的某个字段,可以在字段的 tag 中使用`json:"-"`来忽略该字段。如: 4 | 5 | ```go 6 | type Person struct { 7 | Name string `json:"name"` 8 | Age int64 9 | Weight float64 `json:"-"` // Weight 字段在序列化/反序列化时将会被忽略 10 | } 11 | ``` 12 | 13 | ### 2. 忽略空值字段 14 | 15 | 当 struct 中年的字段没有有效值时,可以使用`json:"name,omitempty"`tag 来将其忽略掉。 16 | 17 | 其含义是:当字段值为其所属类型的零值时,在进行 JSON 序列化和反序列化的时候会忽略该字段。 18 | 19 | 所以,当字段是指针类型的时候,字段值为 nil 就会被忽略;当字段是 int 类型时,字段值为 0 就会被忽略。以此类推。 20 | 21 | 示例: 22 | 23 | ```go 24 | type User struct { 25 | Name string `json:"name"` 26 | Email string `json:"email,omitempty"` 27 | Hobby []string `json:"hobby,omitempty"` 28 | } 29 | ``` 30 | 31 | ### 3. 处理字符串格式的数字 32 | 33 | 有些时候,数据传输过程中会使用字符串类型的数值,可以使用`json:"name,string"`的方式来从字符串中解析相应的值,或者将数值序列化为字符串格式。 34 | 35 | 例如: 36 | 37 | ```go 38 | // ID 和 Score 字段指定使用 string 类型序列化和反序列化 39 | type Card struct { 40 | ID int64 `json:"id,string"` 41 | Score float64 `json:"score,string"` 42 | } 43 | 44 | func intAndStringDemo() { 45 | jsonStr := `{"id": "1234567","score": "88.50"}` 46 | var c1 Card 47 | if err := json.Unmarshal([]byte(jsonStr), &c1); err != nil { 48 | fmt.Printf("json.Unmarshal jsonStr failed, err: %v\n", err) 49 | return 50 | } 51 | fmt.Printf("c1: %#v\n", c1) // c1:main.Card{ID:1234567, Score:88.5} 52 | } 53 | ``` -------------------------------------------------------------------------------- /Linux/网络/连接不存在的 IP 地址或端口的处理.md: -------------------------------------------------------------------------------- 1 | ### 1. 用 TCP 连接一个不存在的 IP 地址会发生什么? 2 | 3 | 这里需要区分两种情况:发起 TCP 连接的客户端 IP 地址和被连接的 IP 地址是否属于同一个局域网。 4 | 5 | **同一个局域网** 6 | 7 | 在同一个局域网的时候,客户端将无法发出 SYN 报文,主要卡在数据链路层。 8 | 9 | 在局域网下,客户端的内核在发起 TCP 连接之前是需要通过 ARP 请求来寻找这个目标 IP 地址对应的 MAC 地址。但是由于这个目标 IP 不存在,所以将无法得到对端的响应,也就无法拿到目标设备的 MAC 地址,这样就没有办法组装 MAC 头信息,所以 SYN 报文无法发送出去。 10 | 11 | **不在一个局域网** 12 | 13 | 目标 IP 地址和客户端 IP 地址不在同一个局域网(网络号不同)的时候,会发生 SYN 超时重传,最终出现连接超时。 14 | 15 | 因为不在客户端 IP 和目标 IP 不在同一个局域网,所以客户端会通过其路由表判断出,下一步是要将网络报文发送给它的网关设备,所以此时客户端的 SYN 报文就已经发出去了。 16 | 17 | > 这个过程中会通过 ARP 请求获取到网关(路由器)设备的 MAC 地址,然后数据链路层将 SYN 报文组装上网关设备的 MAC 地址发送给网关。 18 | 19 | 网关设备接收到客户端的 SYN 报文后,会继续通过路由表判断,发送给下一个网关,直到最终的目标网络和目标设备。 20 | 21 | 但是由于目标 IP 不存在,所以没有目标设备会最终接收该 SYN 报文并对其进行确认。客户端在等待一段时间后,一直没有收到 SYN 报文的确认报文,就会触发超时重发,直到达到最大的重发次数,触发连接超时,最终释放该连接。 22 | 23 | ### 2. 用 TCP 连接一个 IP 存在但不存在的端口会发生什么? 24 | 25 | 目标 IP 地址存在的时候,就会有对应的设备接收并处理 SYN 报文,所以此时客户端是能正常的发出 SYN 报文的。 26 | 27 | 但是由于目标设备收到 SYN 报文后,发现并没有进程监听这个端口号,目标设备的内核就会发回 RST 报文关闭该连接。 28 | 29 | 客户端收到对应的 RST 报文后也会释放连接。 30 | 31 | ### 3. 用 UDP 连接一个 IP 存在但不存在的端口会发生什么? 32 | 33 | 在目标设备上,内核在发现端口没有进程在监听的时候,数据包将不会进入到传输层(UDP/TCP)就被丢弃了。而且网络层在没有进程监听 UDP 这个端口的时候,会向客户端发回一个目标端口不可达的 ICMP 报文,该报文中会包含原数据包的前 8 个字节的内容。 34 | 35 | 也就是说,UPD 不会像 TCP 那样通过目标设备发送 RST 报文来关闭连接,而是通过 ICMP 报文来通知客户端端口不可达。 36 | 37 | > 转摘:[字节面试:连接一个不存在的 IP 地址,会发生什么?](https://mp.weixin.qq.com/s/yLp6Z_00TsAwagbx_lEPXA) 38 | 39 | --------------------------------------------------------------------------------