lniwn 7 years ago
commit
5b2f7279ea
  1. 3
      .gitmodules
  2. 6
      archetypes/default.md
  3. 89
      config.toml
  4. 17
      content/about.md
  5. 142
      content/posts/CMake学习笔记.md
  6. 77
      content/posts/CMake项目添加预编译头.md
  7. 42
      content/posts/Cef-Bug-Fix-List.md
  8. 67
      content/posts/Python模块timezone学习笔记.md
  9. 79
      content/posts/SQLAlchemy学习笔记.md
  10. 135
      content/posts/Vim快捷键备忘录.md
  11. 572
      content/posts/Win32汇编学习.md
  12. 169
      content/posts/office2016激活步骤.md
  13. 67
      content/posts/一句话Windows.md
  14. 43
      content/posts/为Hexo博客Next主题添加Schnack评论.md
  15. 101
      content/posts/为Hexo博客Next主题添加Wildfire评论系统.md
  16. 190
      content/posts/为Ubuntu启用Swap分区.md
  17. 58
      content/posts/加快Visual-Studio编译速度.md
  18. 93
      content/posts/动态获取当前模块的HMODULE-HINSTANCE值.md
  19. 46
      content/posts/在vps上搭建hexo.md
  20. 362
      content/posts/注释大全.md
  21. 478
      content/posts/流畅的Python学习笔记.md
  22. 36
      content/posts/解决chromium警告C4819.md
  23. 2
      resources/_gen/assets/js/bundle.js_3d041b08546090308b2e5d3a88088713.content
  24. 1
      resources/_gen/assets/js/bundle.js_3d041b08546090308b2e5d3a88088713.json
  25. 9
      resources/_gen/assets/js/js/main.js_d11fe7b62c27961c87ecd0f2490357b9.content
  26. 1
      resources/_gen/assets/js/js/main.js_d11fe7b62c27961c87ecd0f2490357b9.json
  27. 1
      resources/_gen/assets/scss/scss/main.scss_39fa5fe97be74115670eace810202c56.content
  28. 1
      resources/_gen/assets/scss/scss/main.scss_39fa5fe97be74115670eace810202c56.json
  29. 5
      resources/_gen/assets/scss/scss/style.scss_c16d144eee185fbddd582cd5e25a4fae.content
  30. 1
      resources/_gen/assets/scss/scss/style.scss_c16d144eee185fbddd582cd5e25a4fae.json
  31. BIN
      static/android-chrome-192x192.png
  32. BIN
      static/android-chrome-384x384.png
  33. BIN
      static/android-chrome-512x512.png
  34. BIN
      static/apple-touch-icon.png
  35. 9
      static/browserconfig.xml
  36. BIN
      static/favicon-16x16.png
  37. BIN
      static/favicon-32x32.png
  38. BIN
      static/favicon.ico
  39. BIN
      static/mstile-150x150.png
  40. 1
      static/safari-pinned-tab.svg
  41. 19
      static/site.webmanifest
  42. 1
      themes/hermit

3
.gitmodules vendored

@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
[submodule "themes/hermit"]
path = themes/hermit
url = https://github.com/Track3/hermit.git

6
archetypes/default.md

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
---
title: "{{ replace .Name "-" " " | title }}"
date: {{ .Date }}
draft: true
---

89
config.toml

@ -0,0 +1,89 @@ @@ -0,0 +1,89 @@
baseURL = "https://oaoa.me"
languageCode = "en-us"
defaultContentLanguage = "en"
title = "个人博客"
theme = "hermit"
# enableGitInfo = true
pygmentsCodefences = true
pygmentsUseClasses = true
hasCJKLanguage = true # If Chinese/Japanese/Korean is your main content language, enable this to make wordCount works right.
rssLimit = 10 # Maximum number of items in the RSS feed.
copyright = "This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License." # This message is only used by the RSS template.
enableEmoji = true # Shorthand emojis in content files - https://gohugo.io/functions/emojify/
# googleAnalytics = "UA-123-45"
# disqusShortname = "yourdiscussshortname"
[author]
name = "lniwn"
[blackfriday]
# hrefTargetBlank = true
# noreferrerLinks = true
# nofollowLinks = true
[taxonomies]
tag = "tags"
category = "categories"
# Categories are disabled by default.
[params]
dateform = "Jan 2, 2006"
dateformShort = "Jan 2"
dateformNum = "2006-01-02"
dateformNumTime = "2006-01-02 15:04 -0700"
# Metadata mostly used in document's head
# description = ""
# images = [""]
themeColor = "#494f5c"
homeSubtitle = "记录读书笔记和心得体会"
footerCopyright = ' &#183; <a href="https://creativecommons.org/licenses/by-nc/4.0/" target="_blank" rel="noopener">CC BY-NC 4.0</a>'
# bgImg = "" # Homepage background-image URL
# Prefix of link to the git commit detail page. GitInfo must be enabled.
# gitUrl = "https://github.com/username/repository/commit/"
# Toggling this option needs to rebuild SCSS, requires Hugo extended version
justifyContent = false # Set "text-align: justify" to `.content`.
relatedPosts = false # Add a related content section to all single posts page
# Add custom css
# customCSS = ["css/foo.css", "css/bar.css"]
# Social Icons
# Check https://github.com/Track3/hermit#social-icons for more info.
[[params.social]]
name = "twitter"
url = "https://twitter.com/sglshdo"
[[params.social]]
name = "telegram"
url = "https://t.me/lniwn"
[[params.social]]
name = "github"
url = "https://github.com/lniwn"
[menu]
[[menu.main]]
name = "Posts"
url = "posts/"
weight = 1
[[menu.main]]
name = "Categories"
url = "categories/"
weight = 2
[[menu.main]]
name = "Tags"
url = "tags/"
weight = 3
[[menu.main]]
name = "About"
url = "about/"
weight = 4

17
content/about.md

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
+++
title = "About Hugo"
date = "2014-04-09"
+++
Hugo is the **world’s fastest framework for building websites**. It is written in Go.
It makes use of a variety of open source projects including:
* https://github.com/russross/blackfriday
* https://github.com/alecthomas/chroma
* https://github.com/muesli/smartcrop
* https://github.com/spf13/cobra
* https://github.com/spf13/viper
Learn more and contribute on [GitHub](https://github.com/gohugoio).

142
content/posts/CMake学习笔记.md

@ -0,0 +1,142 @@ @@ -0,0 +1,142 @@
---
title: CMake学习笔记
date: 2017-12-27 13:54:05
tags: [cmake, visual studio]
categories: cmake
---
本文主要记录CMake学习过程的一些笔记。
<!-- more -->
## 基本文件结构
编写CMakeLists.txt
```
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo1)
# 指定生成目标
add_executable(Demo main.cc)
```
## 常用命令
### 项目类型命令
- `add_executable`可执行文件
- `add_library` 静态库
### 文件依赖命令
- `aux_source_directory(<dir> <variable>)`
查找指定目录下的所有源文件,然后将结果保存进指定的变量名。
```
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo2)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
```
这样,CMake 会将当前目录所有源文件的文件名赋值给变量`DIR_SRCS`,再指示变量`DIR_SRCS` 中的源文件需要编译成一个名称为 Demo 的可执行文件。
- `add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])`
添加子文件夹到构建系统中。
`source_dir`子文件夹路径
`binary_dir` 输出路径
`EXCLUDE_FROM_ALL` 从Build All项目中排除
### 编译选项命令
- Visual Studio to CMake Mapping
{% asset_img VS-to-CMake-Mapping.png VS-to-CMake-Mapping %}
{% asset_img CMake-Projects.png CMake-Projects %}
> ZERO_CHECK will rerun cmake. You can/should execute this after changing something on your CMake files.
> ALL_BUILD is simply a target which builds all and everything project in the active solution, I guess one can compare it to "make all".
> 可以通过`set(CMAKE_SUPPRESS_REGENERATION true)`不生成`ZERO_CHECK`工程。
### 链接命令
- `target_link_libraries`指明链接库
`target_link_libraries(<target> [lib1 [lib2 [...]]] [[debug|optimized|general] <lib>] ...)`
`general`可选字段,表示所有模式都链接的库
`debug`表示debug模式才链接的库
`optimized`表示非debug模式才链接的库
```cmake
target_link_libraries(${PROJECT_NAME}
delayimp.lib libcef.lib
debug cef_module_d.lib
debug libcef_dll_wrapper_d.lib
optimized cef_module.lib
optimized libcef_dll_wrapper.lib)
```
## 项目实例
### 自定义编译选项
顶层CMakeLists.txt文件
```
# CMake 最低版本号要求
cmake_minimum_required (VERSION 2.8)
# 项目信息
project (Demo4)
# 加入一个配置头文件,用于处理 CMake 对源码的设置
configure_file (
"${PROJECT_SOURCE_DIR}/config.h.in"
"${PROJECT_BINARY_DIR}/config.h"
)
# 是否使用自己的 MathFunctions 库
option (USE_MYMATH
"Use provided math implementation" ON)
# 是否加入 MathFunctions 库
if (USE_MYMATH)
include_directories ("${PROJECT_SOURCE_DIR}/math")
add_subdirectory (math)
set (EXTRA_LIBS ${EXTRA_LIBS} MathFunctions)
endif (USE_MYMATH)
# 查找当前目录下的所有源文件
# 并将名称保存到 DIR_SRCS 变量
aux_source_directory(. DIR_SRCS)
# 指定生成目标
add_executable(Demo ${DIR_SRCS})
target_link_libraries (Demo ${EXTRA_LIBS})
```
编写`config.h.in`文件 `#cmakedefine USE_MYMATH`
### 设置编译模式
```
set(CMAKE_BUILD_TYPE "Debug")
set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")
```
### 环境检查
首先在顶层 CMakeLists 文件中添加 CheckFunctionExists.cmake 宏,并调用 `check_function_exists` 命令测试链接器是否能够在链接阶段找到 pow 函数。
```
# 检查系统是否支持 pow 函数
include (${CMAKE_ROOT}/Modules/CheckFunctionExists.cmake)
check_function_exists (pow HAVE_POW)
```
### 设置libcurl运行时环境
```cmake
if(USE_ALLMT_)
target_compile_definitions(libcurl PRIVATE -DRTLIBCFG=static)
set_property(TARGET libcurl APPEND_STRING PROPERTY COMPILE_OPTIONS $<IF:$<CONFIG:Debug>,/MTd,/MT>)
else()
target_compile_definitions(libcurl PRIVATE -DRTLIBCFG=shared)
set_property(TARGET libcurl APPEND_STRING PROPERTY COMPILE_OPTIONS $<IF:$<CONFIG:Debug>,/MDd,/MD>)
endif()
```
## 参考链接
- [<i class="icon-gittip"></i>cmake-and-visual-studio](https://cognitivewaves.wordpress.com/cmake-and-visual-studio/)
- [<i class="icon-gittip"></i>CMake手册](https://www.zybuluo.com/khan-lau/note/254724)
- [<i class="icon-gittip"></i>CMakeLists.txt](http://wiki.ros.org/catkin/CMakeLists.txt)

77
content/posts/CMake项目添加预编译头.md

@ -0,0 +1,77 @@ @@ -0,0 +1,77 @@
---
title: CMake项目添加预编译头
date: 2017-12-28 11:46:13 +08:00
tags: [cmake, visual studio]
images: ["apple-touch-icon.png"]
categories: cmake
---
本文主要记录为CMake项目添加预编译头支持,以及过程中遇到的坑,比如`set_target_properties`连续调用两次失效的问题。
<!-- more -->
各个编译器支持预编译头指令不同,这里仅以Visual Studio为例进行说明。
## 操作步骤
- 创建cmake宏文件`PrecompiledHeader.cmake`
```cmake PrecompiledHeader.cmake
#-------------------------------------------------------
# Support macro to use a precompiled header
# Usage:
# use_precompiled_header(TARGET HEADER_FILE SRC_FILE)
#-------------------------------------------------------
macro(use_precompiled_header TARGET HEADER_FILE SRC_FILE)
get_filename_component(HEADER ${HEADER_FILE} NAME)
# Use MSVC_IDE to exclude NMake from using PCHs
if (MSVC AND NOT NMAKE AND NOT OGRE_UNITY_BUILD)
set_property(TARGET ${TARGET} APPEND_STRING PROPERTY
COMPILE_FLAGS " /Yu\"${HEADER}\"")
set_property(TARGET ${TARGET} APPEND_STRING PROPERTY
COMPILE_FLAGS " /FI\"${HEADER}\"")
set_source_files_properties(${SRC_FILE}
PPROPERTIES COMPILE_FLAGS /Yc"${HEADER}")
elseif (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX)
endif ()
endmacro(use_precompiled_header)
```
- 在主工程的`CMakeLists.txt`中添加依赖
```cmake
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Tools/CMake)
include(PrecompiledHeader)
```
- 在需要使用预编译头的项目中调用`use_precompiled_header`宏函数
```cmake
use_precompiled_header(${PROJECT_NAME}
"${CMAKE_CURRENT_SOURCE_DIR}/stdafx.h"
"${CMAKE_CURRENT_SOURCE_DIR}/stdafx.cpp")
```
## 踩坑记录
- set_target_properties连续调用两次,导致前一次调用无效
在`PrecompiledHeader.cmake`文件中,最开始使用了如下的代码
{% note danger %}
{% codeblock lang:cmake %}
if (MSVC AND NOT NMAKE AND NOT OGRE_UNITY_BUILD)
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS /Yu"${HEADER}")
set_target_properties(${TARGET} PROPERTIES COMPILE_FLAGS /FI"${HEADER}")
set_source_files_properties(${SRC_FILE}
PPROPERTIES COMPILE_FLAGS /Yc"${HEADER}"
)
{% endcodeblock %}
{% endnote %}
可是发现永远只有/FI生效,后来查找了大量资料,替换为了`set_property APPEND`的形式,才最终解决。

42
content/posts/Cef-Bug-Fix-List.md

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
---
title: Cef Bug Fix List
date: 2017-12-20 16:59:50
tags: [cef, cplusplus]
categories: cplusplus
---
本文主要记录在cef开发过程中发现的bug及解决方法。
<!-- more -->
## 解决CEF中html页面不显示鼠标tips的bug
在预编译头文件`stdafx.h`最下方加入:
```c
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_IA64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif
```
> VS2015自动生成的manifest如下,去掉了ia64选项:
```c
#ifdef _UNICODE
#if defined _M_IX86
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"")
#elif defined _M_X64
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"")
#else
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
#endif
#endif
```

67
content/posts/Python模块timezone学习笔记.md

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
---
title: Python模块timezone学习笔记
date: 2018-08-06 18:19:30
tags: [python]
categories: python
---
本文基于python3,记录了datetime包中的timezone用法。
<!-- more -->
使用第三方扩展包pytz,构造指定时区。
> **astimezone**
`datetime.datetime.astimezone`是将原始输入解释为本地时区,然后再转换为目标时区,而pytz包的`localize`方法,是将原始输入直接解释为目标时区,例如:
```python
tz = pytz.timezone('Asia/Shanghai')
target_dt = datetime.datetime(2018, 8, 5, 0, 0, 0, 0)
print(repr(target_dt.astimezone(tz)))
print(repr(tz.localize(target_dt)))
# Output
# > datetime.datetime(2018, 8, 5, 8, 0, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)
# > datetime.datetime(2018, 8, 5, 0, 0, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>)
```
> **timetuple**
由于`datetime.datetime.timetuple`方法不存储时区,所以如果需要构造不同时区的timestamp,需要使用`datetime.datetime.utctimetuple`方法。
```python
target_dt = datetime.datetime(2018, 8, 5, 0, 0, 0, 0)
print(repr(target_dt.utctimetuple()))
print(repr(target_dt.timetuple()))
# Output
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=5, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=217, tm_isdst=0)
# > time.struct_time(tm_year=2018, tm_mon=8, tm_mday=5, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=6, tm_yday=217, tm_isdst=-1)
```
> `datetime.``timetuple`()[¶](https://docs.python.org/3/library/datetime.html#datetime.datetime.timetuple)
>
> Return a [`time.struct_time`](https://docs.python.org/3/library/time.html#time.struct_time) such as returned by [`time.localtime()`](https://docs.python.org/3/library/time.html#time.localtime). `d.timetuple()` is equivalent to `time.struct_time((d.year, d.month, d.day, d.hour, d.minute, d.second, d.weekday(), yday, dst))`, where `yday = d.toordinal() - date(d.year, 1, 1).toordinal() + 1` is the day number within the current year starting with `1` for January 1st. The `tm_isdst` flag of the result is set according to the [`dst()`](https://docs.python.org/3/library/datetime.html#datetime.datetime.dst) method: [`tzinfo`](https://docs.python.org/3/library/datetime.html#datetime.datetime.tzinfo) is `None` or [`dst()`](https://docs.python.org/3/library/datetime.html#datetime.datetime.dst) returns `None`, `tm_isdst` is set to `-1`; else if [`dst()`](https://docs.python.org/3/library/datetime.html#datetime.datetime.dst) returns a non-zero value, `tm_isdst`is set to `1`; else `tm_isdst` is set to `0`.
> `datetime.``utctimetuple`()[¶](https://docs.python.org/3/library/datetime.html#datetime.datetime.utctimetuple)
>
> If [`datetime`](https://docs.python.org/3/library/datetime.html#datetime.datetime) instance *d* is naive, this is the same as `d.timetuple()` except that `tm_isdst` is forced to 0 regardless of what `d.dst()` returns. DST is never in effect for a UTC time.
>
> If *d* is aware, *d* is normalized to UTC time, by subtracting `d.utcoffset()`, and a [`time.struct_time`](https://docs.python.org/3/library/time.html#time.struct_time) for the normalized time is returned. `tm_isdst` is forced to 0. Note that an [`OverflowError`](https://docs.python.org/3/library/exceptions.html#OverflowError) may be raised if *d*.year was`MINYEAR` or `MAXYEAR` and UTC adjustment spills over a year boundary.
目标需求,将东8区(+8)的`2018-08-05 00:00:00`转换为unix timestamp:
```python
tz = pytz.timezone('Asia/Shanghai')
target_dt = datetime.datetime(2018, 8, 5, 0, 0, 0, 0)
target_dt = tz.localize(target_dt)
print(time.mktime(target_dt.utctimetuple()))
print(target_dt.timestamp())
# Output
# > 1533398400.0
# > 1533398400.0
```
参考文档:
https://kkc.github.io/2015/07/08/dealing-with-datetime-and-timezone-in-python/

79
content/posts/SQLAlchemy学习笔记.md

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
---
title: SQLAlchemy学习笔记
date: 2018-08-02 16:28:45
tags: [sql, python]
categories: python
---
本文记录SQLAlchemy学习及使用笔记。
<!-- more -->
- **如何替换一个已有主键的记录?**
使用`session.merge()`方法替换`session.add()`,其实就是`SELECT + UPDATE`。
- **插入大量数据**
- ORM方式
```python
s = Session()
objects = [
User(name="u1"),
User(name="u2"),
User(name="u3")
]
s.bulk_save_objects(objects)
```
如果插入字典形式的数据,可以使用 [`Session.bulk_insert_mappings()`](http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html#sqlalchemy.orm.session.Session.bulk_insert_mappings), 和 [`Session.bulk_update_mappings()`](http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html#sqlalchemy.orm.session.Session.bulk_update_mappings)
```python
s.bulk_insert_mappings(User,
[dict(name="u1"), dict(name="u2"), dict(name="u3")]
)
```
- 非ORM方式
```python
session.execute(
User.__table__.insert(),
[{'name': `randint(1, 100)`,'age': randint(1, 100)} for i in xrange(10000)]
)
session.commit()
```
- **获取大量数据**
- 使用stream方式
```python
def test_core_fetchmany_w_streaming(n):
"""Load Core result rows using fetchmany/streaming."""
with engine.connect() as conn:
result = conn.execution_options(stream_results=True).\
execute(Customer.__table__.select().limit(n))
while True:
chunk = result.fetchmany(10000)
if not chunk:
break
for row in chunk:
data = row['id'], row['name'], row['description']
```
- 使用yield_per方式
```python
def test_orm_full_objects_chunks(n):
"""Load fully tracked ORM objects a chunk at a time using yield_per()."""
sess = Session(engine)
for obj in sess.query(Customer).yield_per(1000).enable_eagerloads(False).limit(n):
pass
```

135
content/posts/Vim快捷键备忘录.md

@ -0,0 +1,135 @@ @@ -0,0 +1,135 @@
---
title: Vim快捷键备忘录
date: 2018-10-17 10:17:49
tags: [vim]
categories: daily
---
Vim快捷键查询。
<!-- more -->
## 光标移动
| 命令 | 作用 |
| ----------------- | ------------------------------------------ |
| h,j,k,l | h表示往左,j表示往下,k表示往上,l表示往右 |
| ctrl+f | 上一页 |
| ctrl+b | 下一页 |
| w,e,W,E | 跳到单词的后面,小写包括标点 |
| b,B | 跳到单词的前面,小写包括标点 |
| 0 | 跳到本行的头部 |
| ^ | 跳到一行的开始 |
| $ | 跳到一行的结尾 |
| gg | 文档的第一行 |
| [N]G | 文档的第N行(G是最后一行),如:27G |
| f`space`,F`space` | 移动到右边的空格,大写移动到左边的空格 |
## 插入
| 命令 | 作用 |
| ---- | -------------------------- |
| i | 插入到光标前面 |
| I | 插入到行的开始位置 |
| a | 插入到光标的后面 |
| A | 插入到行的最后位置 |
| o | 在当前光标的下方插入新一行 |
| O | 在当前光标的上方插入新一行 |
| Esc | 关闭插入模式 |
| | |
| | |
| | |
| | |
## 编辑
| 命令 | 作用 |
| ------ | -------------------------------------- |
| r | 替换光标所在的一个字符 |
| J | 合并下一行到当前行 |
| s | 删除光标所在的一个字符,光标还在当前行 |
| S | 删除光标所在行的内容,光标还在当前行 |
| u | 撤销上一步操作 |
| U | 撤销当前行的更改 |
| ctrl+r | 恢复上一步操作 |
| . | 重复最后一个命令 |
| ~ | 变换为大写 |
| [N]>> | 一行或N行往右移动一个tab |
| [N]<< | 一行或N行往左移动一个tab |
| | |
## 退出
| 命令 | 作用 |
| ------ | ---------------- |
| :w | 保存 |
| :wq,:x | 保存并关闭 |
| :q | 关闭(已保存) |
| :q! | 强制关闭,不保存 |
| | |
## 查找和搜索
| 命令 | 作用 |
| -------------------- | ------------------------------------------------------------ |
| /pattern | 搜索(非插入模式),支持正则 |
| ?pattern | 往后搜索 |
| n | 当前搜索结果的下一个目标 |
| N | 当前搜索结果的上一个目标 |
| rp | 将光标之后的字符替换为字母p |
| :s/word/replace | 光标所在行的第一个word替换为replace |
| :%s/word/replace | 全文查找word并替换为replace |
| :1,50s/word/replace | 在第1行和第50行之间(含)进行搜索和替换 |
| :45s/word/replace/ | 表示仅仅在第45行进行搜索和替换。而 1,$ 行号范围和 % 是等价的 |
| :%s/^/要插入的字符串 | 每行开头插入字符串 |
| :%s/$/要插入的字符串 | 每行结尾插入字符串 |
## 剪切、复制和粘贴
| 命令 | 作用 |
| ----- | ------------------------------------------------------------ |
| dd | 删除一行,同时被删除内容存于剪贴板上 |
| de | 删除光标后的单词内容,同时被删除内容存于剪贴板上 |
| dG | 删除当前位置到文件结尾内容 |
| dw | 删除光标后的单词内容以及之后的空格,同时被删除内容存于剪贴板上 |
| [N]dd | 删除以当前行开始的n行 |
| x | 删除后一个字符 |
| X | 删除前一个字符 |
| D | 删除当前位置到行末的内容 |
| [N]yy | 复制一行或者N行 |
| yw | 复制一个单词 |
| p | 粘贴 |
## 窗口操作
| 命令 | 作用 |
| ------- | ------------------------------------------------------------ |
| :split | 水平方向分割出一个窗口 |
| :vsplit | 垂直方向分割出一个窗口 |
| :close | 关闭窗口 |
| ctrl+w | 切换窗口, h到左边窗口,j到下方窗口,k到上方窗口,l到右边窗口 |
## 常用操作
| 命令 | 作用 |
| ------- | --------------------------------- |
| gg + dG | 清空文件内容 |
| viw,vaw | 选中光标所在单词(vaw包括前后空格) |
| | |
## 在线文档
- [VIM QUICK REFERENCE CARD](http://tnerual.eriogerg.free.fr/vimqrc.pdf)
- {% asset_img morden1.png 增强版 %}
- {% asset_img text1.png 文字版 %}

572
content/posts/Win32汇编学习.md

@ -0,0 +1,572 @@ @@ -0,0 +1,572 @@
---
title: Win32汇编学习
date: 2018-02-12 17:48:00
tags: [win32, 汇编]
categories: windows
---
本文记录了C函数调用过程,以及常用的汇编函数指令集。
<!-- more -->
## 函数调用过程
栈帧,即stack frame,其本质就是一种栈,只是这种栈专门用于保存函数调用过程中的各种信息,栈帧有栈顶(TOS)和栈底之分,其中栈顶的地址最低,栈底的地址最高,增长方向为高地址向低地址方向。在x86-32bit中,用esp(extended stack pointer)一直指向栈顶,ebp(extended base pointer)指向栈底。
{% asset_img stackframe.png 栈帧方向 %}
一般来说,ebp和esp之间的区域叫做栈帧,每调用一个函数,就会生成一个新的栈帧。在函数调用过程中,我们将调用函数称为“调用者(caller)”,将被调用的函数称为“被调用者(callee)”。
函数调用过程如下:
```asm
push ebp ; 保存ebp的值
mov ebp,esp ; 将esp的值赋给ebp,使新的ebp指向栈顶
sub esp,0d8h ; 分配额外的空间给局部变量,对于大内存,使用call __alloca_probe (010FD4EAh) 的方式来分配
```
windows平台,返回值保存在eax中。
## x86汇编指令
### 寄存器
{% asset_img x86-registers.png x86寄存器 %}
X86处理器中有8个32位的通用寄存器。由于历史的原因,EAX通常用于计算,ECX通常用于循环变量计数。ESP和EBP有专门用途,ESP指示栈指针(用于指示栈顶位置),而EBP则是基址指针(用于指示子程序或函数调用的基址指针)。如图中所示,EAX、EBX、ECX和EDX的前两个高位字节和后两个低位字节可以独立使用,其中两位低字节又被独立分为H和L部分,这样做的原因主要是考虑兼容16位的程序,具体兼容匹配细节请查阅相关文献。
应用寄存器时,其名称大小写是不敏感的,如EAX和eax没有区别。
### 内存和寻址模式
#### 声明静态数据区
可以在X86汇编语言中用汇编指令.DATA声明静态数据区(类似于全局变量),数据以单字节、双字节、或双字(4字节)的方式存放,分别用DB,DW, DD指令表示声明内存的长度。在汇编语言中,相邻定义的标签在内存中是连续存放的。
| .DATA | | |
| ----- | -------- | ------------------------------------- |
| var | DB 64 | ;声明一个字节,并将数值64放入此字节中 |
| var2 | DB ? | ; 声明一个未初始化的字节. |
| | DB 10 | ; 声明一个没有label的字节,其值为10. |
| X | DW ? | ; 声明一个双字节,未初始化. |
| Y | DD 30000 | ; 声明一个4字节,其值为30000. |
还可以声明连续的数据和数组,声明数组时使用DUP关键字。
| .DATA | | |
| ----- | ------------- | ------------------------------------------------------------ |
| Z | DD 1, 2, 3 | ; Declare three 4-byte values, initialized to 1, 2, and 3. The value of location Z + 8 will be 3. |
| bytes | DB 10 DUP(?) | ; Declare 10 uninitialized bytes starting at location *bytes*. |
| arr | DD 100 DUP(0) | ; Declare 100 4-byte words starting at location arr, all initialized to 0 |
| str | DB 'hello',0 | ; Declare 6 bytes starting at the address str, initialized to the ASCII character values for hello and the null (0) byte. |
#### 寻址模式
现代X86处理器具有232字节的寻址空间。在上面的例子中,我们用标签(label)表示内存区域,这些标签在实际汇编时,均被32位的实际地址代替。除了支持这种直接的内存区域描述,X86还提供了一种灵活的内存寻址方式,即利用最多两个32位的寄存器和一个32位的有符号常数相加计算一个内存地址,其中一个寄存器可以左移1、2或3位以表述更大的空间。下面例子是汇编程序中常见的方式。
| 指令 | 说明 |
| -------------------- | ----------------------------------------------- |
| mov eax, [ebx] | ; 将ebx值指示的内存地址中的4个字节传送到eax中 |
| mov [var], ebx | ; 将ebx的内容传送到var的值指示的内存地址中. |
| mov eax, [esi-4] | ; 将esi-4值指示的内存地址中的4个字节传送到eax中 |
| mov [esi+eax], cl | ; 将cl的值传送到esi+eax的值指示的内存地址中 |
| mov edx, [esi+4*ebx] | ; 将esi+4*ebx值指示的内存中的4个字节传送到edx |
#### 长度规定
在声明内存大小时,在汇编语言中,一般用DB,DW,DD均可声明的内存空间大小,这种现实声明能够很好地指导汇编器分配内存空间,但是,对于`mov [ebx], 2`,如果没有特殊的标识,则不确定常数2是单字节、双字节,还是双字。对于这种情况,X86提供了三个指示规则标记,分别为`BYTE PTR`, `WORD PTR`, and `DWORD PTR`,如上面例子写成:`mov BYTE PTR [ebx], 2`, `mov WORD PTR [ebx], 2``mov DWORD PTR [ebx], 2`,则意思非常清晰。
### 汇编指令
汇编指令通常可以分为数据传送指令、逻辑计算指令和控制流指令。本节将讲述其中最重要的指令,以下标记分别表示寄存器、内存和常数。
| 标识 | 描述 |
| ------- | --------------------------------------------------------- |
| <reg32> | 32位寄存器 (EAX, EBX, ECX, EDX, ESI, EDI, ESP, or EBP) |
| <reg16> | 16位寄存器 (AX, BX, CX, or DX) |
| <reg8> | 8位寄存器(AH, BH, CH, DH, AL, BL, CL, or DL) |
| <reg> | 任何寄存器 |
| <mem> | 内存地址 (e.g., [eax], [var + 4], or dword ptr [eax+ebx]) |
| <con32> | 32为常数 |
| <con16> | 16位常数 |
| <con8> | 8位常数 |
| <con> | 任何8位、16位或32位常数 |
#### 数据传送指令
- **mov** — Move (Opcodes: 88, 89, 8A, 8B, 8C, 8E, ...)
mov指令将第二个操作数(可以是寄存器的内容、内存中的内容或值)复制到第一个操作数(寄存器或内存)。mov不能用于直接从内存复制到内存,其语法如下所示:
``` asm
mov <reg>,<reg>
mov <reg>,<mem>
mov <mem>,<reg>
mov <reg>,<const>
mov <mem>,<const>
```
*Examples*
`mov eax, ebx — 将ebx的值拷贝到eax`
`mov byte ptr [var], 5 — 将5保存找var指示内存中的一个字节中`
- **push**— Push stack (Opcodes: FF, 89, 8A, 8B, 8C, 8E, ...)
push指令将操作数压入内存的栈中,栈是程序设计中一种非常重要的数据结构,其主要用于函数调用过程中,其中ESP只是栈顶。在压栈前,首先将ESP值减4(X86栈增长方向与内存地址编号增长方向相反),然后将操作数内容压入ESP指示的位置。其语法如下所示:
```asm
push <reg32>
push <mem>
push <con32>
```
*Examples*
`push eax — 将eax内容压栈`
`push [var] — 将var指示的4直接内容压栈`
- **pop**— Pop stack
pop指令与push指令相反,它执行的是出栈的工作。它首先将ESP指示的地址中的内容出栈,然后将ESP值加4. 其语法如下所示:
```asm
pop <reg32>
pop <mem>
```
*Examples*
`pop edi — pop the top element of the stack into EDI.`
`pop [ebx] — pop the top element of the stack into memory at the four bytes starting at location EBX.`
- **lea**— Load effective address
lea实际上是一个载入有效地址指令,将第二个操作数表示的地址载入到第一个操作数(寄存器)中。其语法如下所示:
*Syntax*
`lea <reg32>,<mem>`
*Examples*
`lea eax, [var] — var指示的地址载入eax中.`
`lea edi, [ebx+4*esi] — ebx+4*esi表示的地址载入到edi中,这实际是上面所说的寻址模式的一种表示方式.`
#### 算术和逻辑指令
- **add**— Integer Addition
add指令将两个操作数相加,且将相加后的结果保存到第一个操作数中。其语法如下所示:
```asm
add <reg>,<reg>
add <reg>,<mem>
add <mem>,<reg>
add <reg>,<con>
add <mem>,<con>
```
*Examples*
`add eax, 10 — EAX ← EAX + 10`
`add BYTE PTR [var], 10 — 10与var指示的内存中的一个byte的值相加,并将结果保存在var指示的内存中`
- **sub**— Integer Subtraction
sub指令指示第一个操作数减去第二个操作数,并将相减后的值保存在第一个操作数,其语法如下所示:
```asm
sub <reg>,<reg>
sub <reg>,<mem>
sub <mem>,<reg>
sub <reg>,<con>
sub <mem>,<con>
```
*Examples*
`sub al, ah — AL ← AL - AH`
`sub eax, 216 — eax中的值减26,并将计算值保存在eax中`
- **inc, dec**— Increment, Decrement
inc,dec分别表示将操作数自加1,自减1,其语法如下所示:
```asm
inc <reg>
inc <mem>
dec <reg>
dec <mem>
```
*Examples*
`dec eax — eax中的值自减1.`
`inc DWORD PTR [var] — *var指示内存中的一个4-byte值自加1`*
- **imul**— Integer Multiplication
整数相乘指令,它有两种指令格式,一种为两个操作数,将两个操作数的值相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器;第二种格式为三个操作数,其语义为:将第二个和第三个操作数相乘,并将结果保存在第一个操作数中,第一个操作数必须为寄存器。其语法如下所示:
```asm
imul <reg32>,<reg32>
imul <reg32>,<mem>
imul <reg32>,<reg32>,<con>
imul <reg32>,<mem>,<con>
```
*Examples*
`imul eax, [var] — eax→ eax * [var]`
`imul esi, edi, 25 — ESI → EDI * 25`
- **idiv**— Integer Division
idiv指令完成整数除法操作,idiv只有一个操作数,此操作数为除数,而被除数则为EDX:EAX中的内容(一个64位的整数),操作的结果有两部分:商和余数,其中商放在eax寄存器中,而余数则放在edx寄存器中。其语法如下所示:
*Syntax*
`idiv <reg32>`
`idiv <mem>`
*Examples*
`idiv ebx`
`idiv DWORD PTR [var]`
- **and, or, xor**— Bitwise logical and, or and exclusive or
逻辑与、逻辑或、逻辑异或操作指令,用于操作数的位操作,操作结果放在第一个操作数中。其语法如下所示:
```asm
and <reg>,<reg>
and <reg>,<mem>
and <mem>,<reg>
and <reg>,<con>
and <mem>,<con>
or <reg>,<reg>
or <reg>,<mem>
or <mem>,<reg>
or <reg>,<con>
or <mem>,<con>
xor <reg>,<reg>
xor <reg>,<mem>
xor <mem>,<reg>
xor <reg>,<con>
xor <mem>,<con>
```
*Examples*
`and eax, 0fH — 将eax中的钱28位全部置为0,最后4位保持不变.`
`xor edx, edx — 设置edx中的内容为0.`
- **not**— Bitwise Logical Not
位翻转指令,将操作数中的每一位翻转,即0->1, 1->0。其语法如下所示:
`not <reg>`
`not <mem>`
*Example*
`not BYTE PTR [var] — *将var指示的一个字节中的所有位翻转*.`
- **neg**— Negate
取负指令。语法为:
`neg <reg>`
`neg <mem>`
*Example*
`neg eax — EAX → - EAX`
- **shl, shr**— Shift Left, Shift Right
位移指令,有两个操作数,第一个操作数表示被操作数,第二个操作数指示位移的数量。其语法如下所示:
```asm
shl <reg>,<con8>
shl <mem>,<con8>
shl <reg>,<cl>
shl <mem>,<cl>
shr <reg>,<con8>
shr <mem>,<con8>
shr <reg>,<cl>
shr <mem>,<cl>
```
*Examples*
`shl eax, 1 — Multiply the value of EAX by 2 (if the most significant bit is 0),左移1位,相当于乘以2`
`shr ebx, cl — Store in EBX the floor of result of dividing the value of EBX by 2*n* where *n* is the value in CL.`
#### 控制转移指令
X86处理器维持着一个指示当前执行指令的指令指针(IP),当一条指令执行后,此指针自动指向下一条指令。IP寄存器不能直接操作,但是可以用控制流指令更新。
> ```
> mov esi, [ebp+8]
> begin: xor ecx, ecx
> mov eax, [esi]
>
> ```
如第二条指令用begin指示,这种标签的方法在某种程度上简化了汇编程序设计,控制流指令通过标签实现程序指令跳转。
- **jmp** — Jump
控制转移到label所指示的地址,(从label中取出执行执行),如下所示:
`jmp <label>`
*Example*
`jmp begin — Jump to the instruction labeled begin.`
- **jcondition**— Conditional Jump
条件转移指令,条件转移指令依据机器状态字中的一些列条件状态转移。机器状态字中包括指示最后一个算数运算结果是否为0,运算结果是否为负数等。机器状态字具体解释请见微机原理、计算机组成等课程。语法如下所示:
```asm
je <label> (jump when equal)
jne <label> (jump when not equal)
jz <label> (jump when last result was zero)
jg <label> (jump when greater than)
jge <label> (jump when greater than or equal to)
jl <label> (jump when less than)
jle <label>(jump when less than or equal to)
```
*Example*
`cmp eax, ebx`
`jle done , 如果eax中的值小于ebx中的值,跳转到done指示的区域执行,否则,执行下一条指令。`
- **cmp**— Compare
cmp指令比较两个操作数的值,并根据比较结果设置机器状态字中的条件码。此指令与sub指令类似,但是cmp不用将计算结果保存在操作数中。其语法如下所示:
```asm
cmp <reg>,<reg>
cmp <reg>,<mem>
cmp <mem>,<reg>
cmp <reg>,<con>
```
*Example*
`cmp DWORD PTR [var], 10`
`jeq loop, `
比较var指示的4字节内容是否为10,如果不是,则继续执行下一条指令,否则,跳转到loop指示的指令开始执行
- **call**, **ret**— Subroutine call and return
这两条指令实现子程序(过程、函数等意思)的调用及返回。call指令首先将当前执行指令地址入栈,然后无条件转移到由标签指示的指令。与其它简单的跳转指令不同,call指令保存调用之前的地址信息(当call指令结束后,返回到调用之前的地址)。
ret指令实现子程序的返回机制,ret指令弹出栈中保存的指令地址,然后无条件转移到保存的指令地址执行。
call,ret是函数调用中最关键的两条指令。具体细节见下面一部分的讲解。语法为:
`call <label>`
`ret`
### 调用规则
调用规则分为两个方面,及调用者规则和被调用者规则,如一个函数A调用一个函数B,则A被称为调用者(Caller),B被称为被调用者(Callee)。
下图显示一个调用过程中的内存中的栈布局:
{% asset_img stack-convention.png 调用栈 %}
在X86中,栈增长方向与内存编号增长方向相反。
#### Caller Rules
调用者规则包括一系列操作,描述如下:
1)在调用子程序之前,调用者应该保存一系列被设计为调用者保存的寄存器的值。调用者保存寄存器有eax,ecx,edx。由于被调用的子程序会修改这些寄存器,所以为了在调用子程序完成之后能正确执行,调用者必须在调用子程序之前将这些寄存器的值入栈。
2)在调用子程序之前,将参数入栈。参数入栈的顺序应该是从最后一个参数开始,如上图中parameter3先入栈。
3)利用call指令调用子程序。这条指令将返回地址放置在参数的上面,并进入子程序的指令执行。(子程序的执行将按照被调用者的规则执行)
当子程序返回时,调用者期望找到子程序保存在eax中的返回地址。为了恢复调用子程序执行之前的状态,调用者应该执行以下操作:
1)清除栈中的参数;
2)将栈中保存的eax值、ecx值以及edx值出栈,恢复eax、ecx、edx的值(当然,如果其它寄存器在调用之前需要保存,也需要完成类似入栈和出栈操作)
**Example**
如下代码展示了一个调用子程序的调用者应该执行的操作。此汇编程序调用一个具有三个参数的函数_myFunc,其中第一个参数为eax,第二个参数为常数216,第三个参数为var指示的内存中的值。
```asm
push [var] ; Push last parameter first
push 216 ; Push the second parameter
push eax ; Push first parameter last
call _myFunc ; Call the function (assume C naming)
add esp, 12
```
在调用返回时,调用者必须清除栈中的相应内容,在上例中,参数占有12个字节,为了消除这些参数,只需将ESP加12即可。
_myFunc的值保存在eax中,ecx和edx中的值也许已经被改变,调用者还必须在调用之前保存在栈中,并在调用结束之后,出栈恢复ecx和edx的值。
#### 被调用者规则
被调用者应该遵循如下规则:
1)将ebp入栈,并将esp中的值拷贝到ebp中,其汇编代码如下:
```asm
push ebp
mov ebp, esp
```
上述代码的目的是保存调用子程序之前的基址指针,基址指针用于寻找栈上的参数和局部变量。当一个子程序开始执行时,基址指针保存栈指针指示子程序的执行。为了在子程序完成之后调用者能正确定位调用者的参数和局部变量,ebp的值需要返回。
2)在栈上为局部变量分配空间。
3)保存callee-saved寄存器的值,callee-saved寄存器包括ebx,edi和esi,将ebx,edi和esi压栈。
4)在上述三个步骤完成之后,子程序开始执行,当子程序返回时,必须完成如下工作:
  4.1)将返回的执行结果保存在eax中
  4.2)弹出栈中保存的callee-saved寄存器值,恢复callee-saved寄存器的值(ESI和EDI)
  4.3)收回局部变量的内存空间。实际处理时,通过改变EBP的值即可:mov esp, ebp。
  4.4)通过弹出栈中保存的ebp值恢复调用者的基址寄存器值。
  4.5)执行ret指令返回到调用者程序。
After these three actions are performed, the body of the subroutine may proceed. When the subroutine is returns, it must follow these steps:
1. Leave the return value in EAX.
**Example**
```asm
.486
.MODEL FLAT
.CODE
PUBLIC _myFunc
_myFunc PROC
; Subroutine Prologue
push ebp ; Save the old base pointer value.
mov ebp, esp ; Set the new base pointer value.
sub esp, 4 ; Make room for one 4-byte local variable.
push edi ; Save the values of registers that the function
push esi ; will modify. This function uses EDI and ESI.
; (no need to save EBX, EBP, or ESP)
; Subroutine Body
mov eax, [ebp+8] ; Move value of parameter 1 into EAX
mov esi, [ebp+12] ; Move value of parameter 2 into ESI
mov edi, [ebp+16] ; Move value of parameter 3 into EDI
mov [ebp-4], edi ; Move EDI into the local variable
add [ebp-4], esi ; Add ESI into the local variable
add eax, [ebp-4] ; Add the contents of the local variable
; into EAX (final result)
; Subroutine Epilogue
pop esi ; Recover register values
pop edi
mov esp, ebp ; Deallocate local variables
pop ebp ; Restore the caller's base pointer value
ret
_myFunc ENDP
END
```
子程序首先通过入栈的手段保存ebp,分配局部变量,保存寄存器的值。
在子程序体中,参数和局部变量均是通过ebp进行计算。由于参数传递在子程序被调用之前,所以参数总是在ebp指示的地址的下方(在栈中),因此,上例中的第一个参数的地址是ebp+8,第二个参数的地址是ebp+12,第三个参数的地址是ebp+16;而局部变量在ebp指示的地址的上方,所有第一个局部变量的地址是ebp-4,而第二个这是ebp-8.
## AT&T 和 Intel 汇编语法的主要区别
- 首先,两者最让人纠结的区别就是源操作数、目标操作数的顺序。AT&T 语法先写源操作数,再写目标操作数;Intel 语法先写目标操作数,再写源操作数:
AT&T
```asm
movl %esp, %ebp
```
Intel
```asm
MOV EBP, ESP
```
- 然后,另一个明显的区别就是指令的命名(或者说,操作数大小的指定方式)。AT&T 语法将操作数的大小表示在指令的后缀中(b、w、l);Intel 语法将操作数的大小表示在操作数的前缀中(BYTE PTR、WORD PTR、DWORD PTR):
AT&T
```asm
decw (%eax)
```
Intel
```asm
DEC WORD PTR [EBX]
```
- 再者,各种取址方式的表示。AT&T 语法总体上是`offset(base, index, width)`的格式;Intel 语法总体上是`[INDEX * WIDTH + BASE + OFFSET]`的格式:
AT&T
```asm
movl 0x0100, %eax
movl (%esi), %eax
movl -8(%ebp), %eax
movl 0x0100(,%ebx,4), %eax
movl 0x8(%edx,%ebx,4), %eax
```
Intel
```asm
MOV EAX, [0100]
MOV EAX, [ESI]
MOV EAX, [EBP-8]
MOV EAX, [EBX*4+0100]
MOV EAX, [EDX+EBX*4+8]
```
- 另外,各种非十进制数制下数字的表示方法。AT&T 语法用前缀表示数制(0x、0、0b);Intel 语法用后缀表示数制(h、o、b):
AT&T
```asm
movl 0x8 , %eax
movl 010 , %eax
movl 0b1000, %eax
```
Intel
```asm
MOV EAX, 8h
MOV EAX, 10o
MOV EAX, 1000b
```
- 最后就是零碎的东西的表示方法了。AT&T 语法要在常数前加 $、在寄存器名前加 % 符号;Intel 语法没有相应的东西要加:
AT&T
```asm
subl $0x30, %eax
```
Intel
```asm
SUB EAX, 30
```
## 参考文档
- <https://segmentfault.com/a/1190000007977460>
- <http://www.cnblogs.com/YukiJohnson/archive/2012/10/27/2741836.html>
- <http://timothyqiu.com/archives/difference-between-att-and-intel-asm-syntax/>

169
content/posts/office2016激活步骤.md

@ -0,0 +1,169 @@ @@ -0,0 +1,169 @@
---
title: office2016激活步骤
date: 2018-09-28 20:32:30
tags: [教程]
categories: windows
---
office2016激活方法。
<!-- more -->
## 1. Retail版本转VOL版本
```bat
cd /d "C:\Program Files (x86)\Microsoft Office\Office16"
cscript ospp.vbs /dstatus
```
Retail版显示`LICENSE DESCRIPTION: Office 15, RETAIL(Grace) channel`,VOL版显示`LICENSE DESCRIPTION: Office 15, VOLUME_KMSCLIENT channel`
- 32位版本Office转换代码
```bat
@echo off
:ADMIN
openfiles >nul 2>nul ||(
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs" >nul 2>&1
goto:eof
)
del /f /q "%temp%\getadmin.vbs" >nul 2>nul
for /f "tokens=6 delims=[]. " %%G in ('ver') do set win=%%G
pushd "%~dp0"
Title Office 2016 Retail to Volume License Converter
echo Press Enter to start VL-Conversion...
echo.
pause
echo.
cd /D "%SystemRoot%\System32"
if %win% GEQ 9200 (
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-bridge-office.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-root.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-root-bridge-test.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-stil.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-ul.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-ul-oob.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\pkeyconfig-office.xrm-ms
)
if %win% LSS 9200 (
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-bridge-office.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-root.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-root-bridge-test.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-stil.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-ul.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\client-issuance-ul-oob.xrm-ms
cscript "%ProgramFiles(x86)%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles(x86)%\Microsoft Office\root\Licenses16\pkeyconfig-office.xrm-ms
)
echo.
echo Retail to Volume License conversion finished.
echo.
pause
```
- 64位版本office转换代码
```bat
@echo off
:ADMIN
openfiles >nul 2>nul ||(
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs" >nul 2>&1
goto:eof
)
del /f /q "%temp%\getadmin.vbs" >nul 2>nul
for /f "tokens=6 delims=[]. " %%G in ('ver') do set win=%%G
pushd "%~dp0"
Title Office 2016 Retail to Volume License Converter
echo Press Enter to start VL-Conversion...
echo.
pause
echo.
cd /D "%SystemRoot%\System32"
if %win% GEQ 9200 (
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ppd.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul-oob.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul.xrm-ms"
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-bridge-office.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-root.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-root-bridge-test.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-stil.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-ul.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-ul-oob.xrm-ms
cscript slmgr.vbs /ilc "%ProgramFiles%\Microsoft Office\root\Licenses16\pkeyconfig-office.xrm-ms
)
if %win% LSS 9200 (
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProPlusVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\ProjectProVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ppd.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul-oob.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\VisioProVL_KMS_Client-ul.xrm-ms"
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-bridge-office.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-root.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-root-bridge-test.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-stil.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-ul.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\client-issuance-ul-oob.xrm-ms
cscript "%ProgramFiles%\Microsoft Office\Office16\ospp.vbs" /inslic:"%ProgramFiles%\Microsoft Office\root\Licenses16\pkeyconfig-office.xrm-ms
)
echo.
echo Retail to Volume License conversion finished.
echo.
pause
```
## 2. 一键激活
```bat
cd /d "C:\Program Files (x86)\Microsoft Office\Office16"
cscript ospp.vbs /inpkey:XQNVK-8JYDB-WJ9W3-YJ8YR-WFG99
cscript ospp.vbs /sethst:kms.library.hk
cscript ospp.vbs /act
```
> 参考页面:
> - https://kms.library.hk/archives/kms.html
> - https://0w0.pw/216.html

67
content/posts/一句话Windows.md

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
---
title: 一句话Windows
date: 2017-12-20 20:54:38
tags: [windows, cplusplus]
categories: windows
---
本文主要记录windows开发中遇到的一句话技巧和知识点。
<!-- more -->
---
## 为VC++ 2008添加application compatibility段
使用visual studio为应用程序添加manifest方法很简单,下面为常用的一个manifest文件
```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly manifestversion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<trustinfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedprivileges>
<requestedexecutionlevel level="asInvoker" uiaccess="false">
</requestedexecutionlevel>
</requestedprivileges>
</security>
</trustinfo>
<dependency>
<dependentassembly>
<assemblyidentity name="Microsoft.VC90.CRT" processorarchitecture="x86" publickeytoken="1fc8b3b9a1e18e3b" type="win32" version="9.0.21022.8">
</assemblyidentity>
</dependentassembly>
</dependency>
<dependency>
<dependentassembly>
<assemblyidentity language="*" name="Microsoft.Windows.Common-Controls" processorarchitecture="x86" publickeytoken="6595b64144ccf1df" type="win32" version="6.0.0.0">
</assemblyidentity>
</dependentassembly>
</dependency>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<supportedos id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}">
</supportedos>
<!-- Windows 8.1 -->
<supportedos id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}">
</supportedos>
<!-- Windows Vista -->
<supportedos id="{e2011457-1546-43c5-a5fe-008deee3d3f0}">
</supportedos>
<!-- Windows 7 -->
<supportedos id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}">
</supportedos>
<!-- Windows 8 -->
<supportedos id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}">
</supportedos>
</application>
</compatibility>
</assembly>
```
但是由于visual Studio2008不支持compatibility字段,直接这样添加会报错,所以需要先正常生成文件,然后再使用新版的mt.exe手动嵌入manifest文件。
使用mt.exe为程序添加manifest文件的命令很简单:
``mt.exe -nologo -manifest "r:\shared\hl.exe.manifest" -outputresource:"r:\shared\hl33m.exe;#1"``
[参考页面](https://blogs.msdn.microsoft.com/yvesdolc/2009/09/26/how-to-add-the-application-compatibility-section-with-visual-c-2008/)

43
content/posts/为Hexo博客Next主题添加Schnack评论.md

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
---
title: 为Hexo博客Next主题添加Schnack评论
date: 2017-12-21 17:11:31
tags: [vps, hexo]
categories: vps
---
本文主要记录schnack评论搭建步骤(服务端搭建未完成)。
<!-- more -->
> **Step 1**
在`%BLOG_PATH%\themes\next\layout\_third-party\comments`路径下创建`schnack.swig`文件
```swig
{% if theme.schnack and theme.schnack.enable %}
<script src="//blog.oaoa.me/embed.js"
data-schnack-slug="post-slug"
data-schnack-target=".comments">
</script>
{% endif %}
```
> **Step 2**
在`%BLOG_PATH%\themes\next\layout\_third-party\comments\index.swig`文件中添加`schnack.swig`的引用
```swig
{% include 'schnack.swig' %}
```
> **Step 3**
在`%BLOG_PATH%\themes\next\layout\_partials\comments.swig`文件中,添加一个elseif代码块:
```swig
{% elseif theme.schnack and schnack.enable %}
<div class="comments" id="comments">
</div>
```
> **Step 4**
**TODO: 服务端配置**

101
content/posts/为Hexo博客Next主题添加Wildfire评论系统.md

@ -0,0 +1,101 @@ @@ -0,0 +1,101 @@
---
title: 为Hexo博客Next主题添加Wildfire评论系统
date: 2017-12-26 14:18:11
tags: [vps, hexo]
categories: vps
---
本文主要记录[Wildfire](https://github.com/cheng-kang/wildfire)评论系统搭建的过程。
<!-- more -->
## Hexo配置步骤
{% note primary %} Step 1 {% endnote %}
关于wildfire的设置,请直接参考{% link 官方帮助文档 https://wildfire.js.org/#/zh-cn/usage?id=%e4%bd%bf%e7%94%a8%e8%af%b4%e6%98%8e %}。
{% note primary %} Step 2 {% endnote %}
在`%BLOG_PATH%\themes\next\layout\_third-party\comments`路径下创建`wildfire.swig`文件
```swig
{% if page.comments and theme.wildfire.enable %}
<script type="text/javascript">
var wildfireConfig = () => ({
databaseProvider: '{{ theme.wildfire.database_provider }}',
databaseConfig: {
{% if (theme.wildfire.database_provider) === 'wilddog' %}
siteId: '{{ theme.wildfire.site_id }}'
{% elseif (theme.wildfire.database_provider) === 'firebase' %}
apiKey: '{{ theme.wildfire.api_key }}',
authDomain: '{{ theme.wildfire.auth_domain }}',
databaseURL: '{{ theme.wildfire.database_url }}',
projectId: '{{ theme.wildfire.project_id }}',
storageBucket: '{{theme.wildfire.storage_bucket}}',
messagingSenderId: '{{theme.wildfire.messaging_sender_id}}'
{% endif %}
},
theme: '{{theme.wildfire.theme}}',
locale: '{{theme.wildfire.locale}}'
})
</script>
<script type="text/javascript" src='//unpkg.com/wildfire/dist/wildfire.auto.js'></script>
{% endif %}
```
{% note primary %} Step 3 {% endnote %}
在{% quote %}%BLOG_PATH%\themes\next\layout\_third-party\comments\index.swig{% endquote %}文件中添加wildfire.swig的引用:
{% code lang:swig %}
{% raw %}{% include 'wildfire.swig' %}{% endraw %}
{% endcode%}
{% note primary %} Step 4 {% endnote %}
在`%BLOG_PATH%\themes\next\layout\_partials\comments.swig`文件中,添加一个elseif代码块:
```swig
{% elseif theme.wildfire.enable %}
<div class="comments" id="comments">
<div class="wildfire_thread"></div>
</div>
```
## 遇到的坑
- [x] 由于之前配置过valine的评论系统,后来添加了wildfire后死活不生效,重试了好多遍,最后无意中发现valine的bug,原代码如下:
```swig
{% elseif theme.valine.appid and theme.valine.appkey %}
<div class="comments" id="comments">
</div>
{% elseif theme.wildfire.enable %}
<div class="comments" id="comments">
<div class="wildfire_thread"></div>
</div>
```
修改后如下:
```swig
{% elseif theme.valine.enable and theme.valine.appid and theme.valine.appkey %}
<div class="comments" id="comments">
</div>
{% elseif theme.wildfire.enable %}
<div class="comments" id="comments">
<div class="wildfire_thread"></div>
</div>
```
因为我禁用valine的时候只是把_config.yml里面的enable改为了false,valine的appid和appkey都是有效值,所以导致这里的判断进入了valine分支。
- [x] ~~页面会有报错 `GET https://api.ipify.org/?format=json net::ERR_BLOCKED_BY_CLIENT`,暂时未解决,等待原作者处理。~~
- [x] ~~页面url不能有中文,否则Edge浏览器会一直处于`正在启动 Wildfire……`中。~~
- [x] ~~`pageURL`字段必须经过url编码,否则会报错,临时解决方案为:{% quote %}
{% raw %}pageURL: '{{page.permalink|url_encode}}'{% endraw %}
{% endquote%}~~
## 参考文章
[在Hexo.NexT主题中部署Wildfire评论系统](http://mrliao.cn/2017/12/25/%E5%9C%A8Hexo.NexT%E4%B8%BB%E9%A2%98%E4%B8%AD%E9%83%A8%E7%BD%B2Wildfire%E8%AF%84%E8%AE%BA%E7%B3%BB%E7%BB%9F/)

190
content/posts/为Ubuntu启用Swap分区.md

@ -0,0 +1,190 @@ @@ -0,0 +1,190 @@
---
title: 为Ubuntu启用Swap分区
date: 2018-07-07 10:43:23
tags: [Linux]
categories: vps
---
## 简介
保护应用程序远离`out-of-memeory`错误的一种最简单方式,就是为服务器增加交换区。本文将介绍如何为Ubuntu Server添加交换区。
> 警告:在SSD磁盘上启用swap分区,可能导致系统不稳定。
<!-- more -->
## 什么是Swap分区
Swap分区是磁盘上的一块区域,当RAM空间不够使用时,系统会根据调度算法,将一部分内存数据存储到Swap分区中,从而保证应用正常执行。
## Step1-检查系统的Swap信息
检测是否有swap分区:
```shell
root@oaoa:~# swapon --show
```
如果系统没有交换区,则不会有任何输出。
可以使用`free`命令检测是否有正在使用的swap空间:
```shell
root@oaoa:~# free -h
total used free shared buff/cache available
Mem: 989M 135M 109M 11M 744M 661M
Swap: 0B 0B 0B
```
## Step2-检查磁盘可用空间
在创建swap分区之前,先检查磁盘空间是否足够:
```shell
root@oaoa:~# df -h
Filesystem Size Used Avail Use% Mounted on
udev 473M 0 473M 0% /dev
tmpfs 99M 11M 89M 11% /run
/dev/vda1 25G 2.7G 21G 12% /
tmpfs 495M 0 495M 0% /dev/shm
tmpfs 5.0M 0 5.0M 0% /run/lock
tmpfs 495M 0 495M 0% /sys/fs/cgroup
tmpfs 99M 0 99M 0% /run/user/0
```
## Step3-创建Swap文件
接下来,使用`fallocate`命令,创建一个名为`swap`的交换分区,由于我需要搭建gitlab, 所以交换分区大小设置为3G:
```shell
root@oaoa:~# fallocate -l 3G /swap
```
检测交换分区文件是否创建成功:
```shell
root@oaoa:~# ls -lh /swap
-rw-r--r-- 1 root root 3.0G Jul 7 10:29 /swap
```
## Step4-启用Swap文件
经过上面的步骤,已经在磁盘上预留了指定大小的磁盘空间,现在需要激活交换分区。
首先,需要禁用其他用户的读取权限,否则,会产生重大安全隐患。
使文件只有root用户可访问:
```shell
sudo chmod 600 /swap
```
```shell
root@oaoa:~# ls -lh /swap
-rw------- 1 root root 3.0G Jul 7 10:29 /swap
```
激活swap分区:
```shell
sudo mkswap /swap
sudo swapon /swap
```
检测交换分区是否可用:
```shell
root@oaoa:~# swapon --show
NAME TYPE SIZE USED PRIO
/swap file 3G 0B -1
```
## Step5-使Swap文件持久化
上面的改动已经使swap分区生效,但是重启之后就没有了,所以需要在`/etc/fstab`文件中主动挂在swap分区。
备份fstab文件:
```shell
sudo cp /etc/fstab /etc/fstab.bak
```
添加swap文件信息到`/etc/fstab`文件末尾:
```shell
echo '/swap none swap sw 0 0' | sudo tee -a /etc/fstab
```
截至到这里,已经完成了swap分区的创建和使用,下面是一些优化设置,可根据实际情况进行取舍。
## Step6-调整交换分区设置
- **调整Swappiness属性**
`swappiness` 参数用于配置系统将RAM数据交换到磁盘的优先级,值为0到100。
- 值接近于0时,除非绝对必要,否则内核不会将数据交换到磁盘。
- 值接近于100时,内核会尽可能将数据放入交换区,从而保证更多的RAM空间
一般默认大小为60,可以通过下面命令查看
```shell
cat /proc/sys/vm/swappiness
```
对于桌面系统,设置为60问题不大,但是对于服务器,最好设置为接近于0,因为与磁盘交互的速度远远慢于与RAM交互的速度。
可以通过`sysctl`命令修改参数值:
```shell
sudo sysctl vm.swappiness=10
```
添加到`/etc/sysctl.conf`文件,使重启之后仍然生效:
```shell
sudo vim /etc/sysctl.conf
```
在文件末尾添加一行:
```shell /etc/sysctl.conf
vm.swappiness=10
```
- **调整Cache Pressure设置**
另一个相关的参数是`vfs_cache_pressure`,表示系统将选择多少缓存*inode*和*dentry*。基本上,这是关于文件系统的访问数据,一般是非常耗时又请求频繁的,所以缓存会增加性能。
查看系统默认值:
```shell
cat /proc/sys/vm/vfs_cache_pressure
```
一般默认值为100,系统会很快从缓存中删除inode信息,需要设置一个更加保守的数字,比如50:
```shell
sudo sysctl vm.vfs_cache_pressure=50
```
添加到`/etc/sysctl.conf`文件,使重启之后仍然生效:
```shell
sudo vim /etc/sysctl.conf
```
在文件末尾添加一行:
```shell /etc/sysctl.conf
vm.vfs_cache_pressure=50
```
*参考文档:<https://www.digitalocean.com/community/tutorials/how-to-add-swap-space-on-ubuntu-18-04>*

58
content/posts/加快Visual-Studio编译速度.md

@ -0,0 +1,58 @@ @@ -0,0 +1,58 @@
---
title: 加快Visual Studio编译速度
date: 2018-01-05 12:08:32
tags: [visual studio, cplusplus]
categories: windows
---
为Visual Studio开启多核编译支持,Visual Studio 2010及以上版本,直接可以在界面配置,而Visual Studio 2008则需要手动增加编译命令。
<!--more-->
## Build with Multiple Processes
Visual Studio并行编译选项命令为/MP,具体语法为:
> `/MP[processMax]`
`processMax` 为可选参数,范围为`1-65536`,表示可以创建的并行进程数,如果省略该参数,默认为[有效内核数](https://msdn.microsoft.com/en-us/library/bb385193.aspx#effective_processors),计算方法为:` (8 effective processors) = (2 physical processors) x (2 cores per physical processor) x (2 effective processors per core because of hyperthreading)`。
`/MP`选项会与下表中的选项冲突,所以如果需要开启`/MP`,需要关闭下表中其他选项,Visual Studio默认配置下debug模式会启用`/Gm`选项,需要手动关闭。
| Option or Language Feature | Description |
| ---------------------------------------- | ---------------------------------------- |
| [#import](https://msdn.microsoft.com/en-us/library/8etzzkb6.aspx) preprocessor directive | Converts the types in a type library into C++ classes, and then writes those classes to a header file. |
| [/E](https://msdn.microsoft.com/en-us/library/3xkfswhy.aspx), [/EP](https://msdn.microsoft.com/en-us/library/becb7sys.aspx) | Copies preprocessor output to the standard output (**stdout**). |
| [/Gm](https://msdn.microsoft.com/en-us/library/kfz8ad09.aspx) | Enables an incremental rebuild. |
| [/showIncludes](https://msdn.microsoft.com/en-us/library/hdkef6tk.aspx) | Writes a list of include files to the standard error (**stderr**). |
| [/Yc](https://msdn.microsoft.com/en-us/library/7zc28563.aspx) | Writes a precompiled header file. |
## 为Visual Studio 2010开启多核并行编译
- 属性 -> 配置属性 -> C/C++ -> 常规 -> 多处理器编译,设为`是`。[^1]
- 属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用最小重新生成,设为`否`。[^2]
- 工具 -> 选项 -> 项目和解决方案 -> 生成并运行,设置`最大并行项目生成数`为8(*可以自定义合理值*)。
## 为Visual Studio 2008开启多核并行编译
- 属性 -> 配置属性 -> C/C++ -> 命令行 -> 附加选项,添加`/MP`。[^1]
- 属性 -> 配置属性 -> C/C++ -> 代码生成 -> 启用最小重新生成,设为`否`。[^2]
- 工具 -> 选项 -> 项目和解决方案 -> 生成并运行,设置`最大并行项目生成数`为8(*可以自定义合理值*)。
## 实例说明
以我自己的项目为例,不开启`/MP`选项,完整编译一次时间为48秒,开启之后完整编译一次时间为26秒。
{% asset_img before.png 不开启/MP选项 %}
{% asset_img after.png 开启/MP选项 %}
[^1]: 启用`/MP`编译选项
[^2]: 禁用`/Gm`编译选项

93
content/posts/动态获取当前模块的HMODULE-HINSTANCE值.md

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
---
title: 动态获取当前模块的HMODULE/HINSTANCE值
date: 2018-05-14 18:38:45
tags: [win32]
categories: windows
---
如何动态获取当前代码运行时所在的模块句柄?这里介绍三种方法。
<!-- more -->
## 1. 使用GetModuleHandle
这是标准方案,可以动态获取exe或者dll模块句柄。
```c++
HMODULE WINAPI GetModuleHandle(
_In_opt_ LPCTSTR lpModuleName
);
```
其中`lpModuleName`为dll或者exe名,如果扩展名被省略,默认会追加.dll后缀。如果结尾为`.`,则表示模块没有后缀名。一般来说,只需要执行模块名就可以了,如果指定了完整路径,分隔符必须使用`\`,不能使用`/`,如果使用`NULL`,则返回创建当前进程的exe句柄。另外,如果dll文件是以资源文件形式被加载,即指定了`LOAD_LIBRARY_AS_DATAFILE`,是无法使用该函数获取到句柄的。
## 2. 使用VirtualQuery
函数原型为
```c++
SIZE_T WINAPI VirtualQuery(
_In_opt_ LPCVOID lpAddress,
_Out_ PMEMORY_BASIC_INFORMATION lpBuffer,
_In_ SIZE_T dwLength
);
```
其中,`MEMORY_BASIC_INFORMATION `结构体中的`AllocationBase `就是模块基址,可以转换成模块句柄。
```c++
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
```
## 3. 使用伪变量__ImageBase
```c++
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
#define HINST_THISCOMPONENT ((HINSTANCE)&__ImageBase)
```
如果使用Microsoft链接器,就可以使用上面的方法来获取当前代码所在模块的句柄。伪变量`__ImageBase `表示模块的DOS头,即这个模块的起始地址。
一般使用场景为,编写了一个静态库,提供给其他人调用,需要动态获取运行时所在模块的句柄。
```c++
#if _MSC_VER >= 1300 // for VC 7.0
// from ATL 7.0 sources
extern "C" IMAGE_DOS_HEADER __ImageBase;
#endif
HMODULE GetCurrentModule()
{
#if _MSC_VER < 1300 // earlier than .NET compiler (VC 6.0)
// Here's a trick that will get you the handle of the module
// you're running in without any a-priori knowledge:
// http://www.dotnet247.com/247reference/msgs/13/65259.aspx
MEMORY_BASIC_INFORMATION mbi;
static int dummy;
VirtualQuery(&dummy, &mbi, sizeof(mbi));
return reinterpret_cast<HMODULE>(mbi.AllocationBase);
#else // VC 7.0
// from ATL 7.0 sources
return reinterpret_cast<HMODULE>(&__ImageBase);
#endif
}
```
---
参考链接:
- https://blogs.msdn.microsoft.com/oldnewthing/20041025-00/?p=37483/
- http://www.codeguru.com/Cpp/W-P/dll/tips/article.php/c3635/

46
content/posts/在vps上搭建hexo.md

@ -0,0 +1,46 @@ @@ -0,0 +1,46 @@
---
title: 在vps上搭建hexo
date: 2017-12-20 21:25:57
tags: [vps, hexo]
categories: vps
---
本文记录在[vps](https://www.vultr.com/?ref=7276933)上搭建hexo的过程。
<!-- more -->
在vps上搭建hexo,网络上已经有不少教程了,但是全部套路都是一样,大致流程如下:
> 本地搭建hexo环境 -> 配置hexo主题等 -> 本地编写md文件 -> 通过hexo d进行远程部署
这样的流程,有个最大的问题是,远程服务器只保存了最终渲染完成的html文件,每次更换电脑都需要重新部署环境,所以我就把hexo部署到了远程vps上,本地编写md,然后提交到远程git,由git的hook功能触发hexo进行渲染和部署,大致流程如下:
> 本地编写md -> 提交到vps上的git-repo -> post-receive -> hexo generate -> hexo deploy -> nginx
在远程仓库的hooks目录,创建post-receive文件,在这里进行hexo的渲染和部署:
```shell
#! /bin/bash
git --work-tree=/home/lniwn/hexo/source/ --git-dir=/home/git/repo/blog.git/ checkout -f
hexo --cwd /home/lniwn/hexo/ clean
hexo --cwd /home/lniwn/hexo/ g -d
cp -Rf /home/lniwnxxx/hexo/public/* /var/www/oaoa.me/
```
这样可以在任何地方编写md文件,写完之后通过git提交即可看到自动部署的信息
{% asset_img TortoiseGit-message.png TortoiseGit打印的远程部署信息 %}
由于我创建了一个git用户,仅用于git相关操作,而我的登陆用户是lniwn,部署时经常会遇到权限问题,所以需要进行一些权限分配:
- 将lniwn添加到git组 `$ sudo usermod -a -G git lniwn`
- 修改hexo文件夹所属组 `$ sudo chgrp git -R /home/lniwn/hexo/`
- 修改hexo文件夹组权限 `$ sudo chmod g+rw -R /home/lniwn/hexo/`
虽然每次git的push操作都会触发post-receive,从而进行自动部署,但是有时候还是希望手动部署下,所以写了个部署脚本auto-deploy-hexo,脚本很简单,就是以git用户执行post-receive文件:
```shell
#! /bin/bash
sudo -H -u git bash -c '/home/git/repo/blog.git/hooks/post-receive'
```

362
content/posts/注释大全.md

@ -0,0 +1,362 @@ @@ -0,0 +1,362 @@
---
title: 注释大全
date: 2017-12-27 15:48:55
tags: [收藏]
categories: daily
---
各种神奇注释,顺便推荐个在线生成ascii码注释的网站<http://www.network-science.de/ascii/>
<!-- more -->
## 佛祖保佑
```c++
//
// _oo0oo_
// o8888888o
// 88" . "88
// (| -_- |)
// 0\ = /0
// ___/`---'\___
// .' \\| |// '.
// / \\||| : |||// \
// / _||||| -:- |||||- \
// | | \\\ - /// | |
// | \_| ''\---/'' |_/ |
// \ .-\__ '-' ___/-. /
// ___'. .' /--.--\ `. .'___
// ."" '< `.___\_<|>_/___.' >' "".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `_. \_ __\ /__ _/ .-` / /
// =====`-.____`.___ \_____/___.-`___.-'=====
// `=---='
//
//
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// 佛祖保佑 永无BUG
//
//
//
```
## 神兽保佑1
```c++
/*code is far away from bug with the animal protecting
* ┏┓   ┏┓
*┏┛┻━━━┛┻┓
*┃        
*┃      
*┃ ┳┛ ┗┳ 
*┃       
*┃      
*┃       
*┗━┓   ┏━┛
*     ┃神兽保佑
*     ┃代码无BUG!
*     ┗━━━┓
*         ┣┓
*         ┏┛
*  ┗┓┓┏━┳┓┏┛
*   ┃┫┫ ┃┫┫
*   ┗┻┛ ┗┻┛
*   
*/
```
## 神兽保佑2
```c++
/**
*        ┏┓   ┏┓+ +
*       ┏┛┻━━━┛┻┓ + +
*               
*             ┃ ++ + + +
*       ████━████ ┃+
*              ┃ +
*             
*              ┃ + +
*       ┗━┓   ┏━┛
*                       
*            ┃ + + + +
*                Code is far away from bug with the animal protecting       
*            ┃ +     神兽保佑,代码无bug  
*            
*              +         
*             ┗━━━┓ + +
*                ┣┓
*                ┏┛
*         ┗┓┓┏━┳┓┏┛ + + + +
*          ┃┫┫ ┃┫┫
*          ┗┻┛ ┗┻┛+ + + +
*/
```
## FUCK BUG
```c++
//
// █████▒█ ██ ▄████▄ ██ ▄█▀ ██████╗ ██╗ ██╗ ██████╗
// ▓██ ▒ ██ ▓██▒▒██▀ ▀█ ██▄█▒ ██╔══██╗██║ ██║██╔════╝
// ▒████ ░▓██ ▒██░▒▓█ ▄ ▓███▄░ ██████╔╝██║ ██║██║ ███╗
// ░▓█▒ ░▓▓█ ░██░▒▓▓▄ ▄██▒▓██ █▄ ██╔══██╗██║ ██║██║ ██║
// ░▒█░ ▒▒█████▓ ▒ ▓███▀ ░▒██▒ █▄ ██████╔╝╚██████╔╝╚██████╔╝
// ▒ ░ ░▒▓▒ ▒ ▒ ░ ░▒ ▒ ░▒ ▒▒ ▓▒ ╚═════╝ ╚═════╝ ╚═════╝
// ░ ░░▒░ ░ ░ ░ ▒ ░ ░▒ ▒░
// ░ ░ ░░░ ░ ░ ░ ░ ░░ ░
// ░ ░ ░ ░ ░
//
```
## LOL
```c++
/**
88 88
88 88
88 88
88 ,adPPYba, 88
88 a8" "8a 88
88 8b d8 88
88 "8a, ,a8" 88
88 `"YbbdP"' 88
**/
```
## 剪刀手
```python
# d*##$.
# zP"""""$e. $" $o
#4$ '$ $" $
#'$ '$ J$ $F
# 'b $k $> $
# $k $r J$ d$
# '$ $ $" $~
# '$ "$ '$E $
# $ $L $" $F ...
# $. 4B $ $$$*"""*b
# '$ $. $$ $$ $F
# "$ R$ $F $" $
# $k ?$ u* dF .$
# ^$. $$" z$ u$$$$e
# #$b $E.dW@e$" ?$
# #$ .o$$# d$$$$c ?F
# $ .d$$#" . zo$> #$r .uF
# $L .u$*" $&$$$k .$$d$$F
# $$" ""^"$$$P"$P9$
# JP .o$$$$u:$P $$
# $ ..ue$" "" $"
# d$ $F $
# $$ ....udE 4B
# #$ """"` $r @$
# ^$L '$ $F
# RN 4N $
# *$b d$
# $$k $F
# $$b $F
# $"" $F
# '$ $
# $L $
# '$ $
# $ $
```
## 书
```python
# .-~~~~~~~~~-._ _.-~~~~~~~~~-.
# __.' ~. .~ `.__
# .'// \./ \\`.
# .'// | \\`.
# .'// .-~"""""""~~~~-._ | _,-~~~~"""""""~-. \\`.
# .'//.-" `-. | .-' "-.\\`.
# .'//______.============-.. \ | / ..-============.______\\`.
# .'______________________________\|/______________________________`.
```
## 十字架
```c++
// |~~~~~~~|
// | |
// | |
// | |
// | |
// | |
// |~.\\\_\~~~~~~~~~~~~~~xx~~~ ~~~~~~~~~~~~~~~~~~~~~/_//;~|
// | \ o \_ ,XXXXX), _..-~ o / |
// | ~~\ ~-. XXXXX`)))), _.--~~ .-~~~ |
// ~~~~~~~`\ ~\~~~XXX' _/ ';)) |~~~~~~..-~ _.-~ ~~~~~~~
// `\ ~~--`_\~\, ;;;\)__.---.~~~ _.-~
// ~-. `:;;/;; \ _..-~~
// ~-._ `'' /-~-~
// `\ / /
// | , | |
// | ' / |
// \/; |
// ;; |
// `; . |
// |~~~-----.....|
// | \ \
// | /\~~--...__ |
// (| `\ __-\|
// || \_ /~ |
// |) \~-' |
// | | \ '
// | | \ :
// \ | | |
// | ) ( )
// \ /; /\ |
// | |/ |
// | | |
// \ .' ||
// | | | |
// ( | | |
// | \ \ |
// || o `.)|
// |`\\\\) |
// | |
// | |
```
## 恶龙
```python
# ___====-_ _-====___
# _--^^^#####// \\#####^^^--_
# _-^##########// ( ) \\##########^-_
# -############// |\^^/| \\############-
# _/############// (@::@) \\############\_
# /#############(( \\// ))#############\
# -###############\\ (oo) //###############-
# -#################\\ / VV \ //#################-
# -###################\\/ \//###################-
# _#/|##########/\######( /\ )######/\##########|\#_
# |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \|
# ` |/ V V ` V \#\| | | |/#/ V ' V V \| '
# ` ` ` ` / | | | | \ ' ' ' '
# ( | | | | )
# __\ | | | | /__
# (vvv(VVV)(VVV)vvv)
# 神兽保佑
# 代码无BUG!
# __----~~~~~~~~~~~------___
# . . ~~//====...... __--~ ~~
# -. \_|// |||\\ ~~~~~~::::... /~
# ___-==_ _-~o~ \/ ||| \\ _/~~-
# __---~~~.==~||\=_ -_--~/_-~|- |\\ \\ _/~
# _-~~ .=~ | \\-_ '-~7 /- / || \ /
# .~ .~ | \\ -_ / /- / || \ /
# / ____ / | \\ ~-_/ /|- _/ .|| \ /
# |~~ ~~|--~~~~--_ \ ~==-/ | \~--===~~ .\
# ' ~-| /| |-~\~~ __--~~
# |-~~-_/ | | ~\_ _-~ /\
# / \ \__ \/~ \__
# _--~ _/ | .-~~____--~-/ ~~==.
# ((->/~ '.|||' -_| ~~-/ , . _||
# -_ ~\ ~~---l__i__i__i--~~_/
# _-~-__ ~) \--______________--~~
# //.-~~~-~_--~- |-------~~~~~~~~
# //.-~~~--\
```
## 葱官赐福
```c++
/*
_______________########_______________________
______________##########_______________________
______________############_____________________
______________#############____________________
_____________##__###########___________________
____________###__######_#####__________________
____________###_#######___####_________________
___________###__##########_####________________
__________####__###########_####_______________
________#####___###########__#####_____________
_______######___###_########___#####___________
_______#####___###___########___######_________
______######___###__###########___######_______
_____######___####_##############__######______
____#######__#####################_#######_____
____#######__##############################____
___#######__######_#################_#######___
___#######__######_######_#########___######___
___#######____##__######___######_____######___
___#######________######____#####_____#####____
____######________#####_____#####_____####_____
_____#####________####______#####_____###______
______#####______;###________###______#________
________##_______####________####______________
葱官赐福 百无禁忌
*/
```
## 龙图腾
```c++
/*
11111111111111111111111111111111111111001111111111111111111111111
11111111111111111111111111111111111100011111111111111111111111111
11111111111111111111111111111111100001111111111111111111111111111
11111111111111111111111111111110000111111111111111111111111111111
11111111111111111111111111111000000111111111111111111111111111111
11111111111111111111111111100000011110001100000000000000011111111
11111111111111111100000000000000000000000000000000011111111111111
11111111111111110111000000000000000000000000000011111111111111111
11111111111111111111111000000000000000000000000000000000111111111
11111111111111111110000000000000000000000000000000111111111111111
11111111111111111100011100000000000000000000000000000111111111111
11111111111111100000110000000000011000000000000000000011111111111
11111111111111000000000000000100111100000000000001100000111111111
11111111110000000000000000001110111110000000000000111000011111111
11111111000000000000000000011111111100000000000000011110001111111
11111110000000011111111111111111111100000000000000001111100111111
11111111000001111111111111111111110000000000000000001111111111111
11111111110111111111111111111100000000000000000000000111111111111
11111111111111110000000000000000000000000000000000000111111111111
11111111111111111100000000000000000000000000001100000111111111111
11111111111111000000000000000000000000000000111100000111111111111
11111111111000000000000000000000000000000001111110000111111111111
11111111100000000000000000000000000000001111111110000111111111111
11111110000000000000000000000000000000111111111110000111111111111
11111100000000000000000001110000001111111111111110001111111111111
11111000000000000000011111111111111111111111111110011111111111111
11110000000000000001111111111111111100111111111111111111111111111
11100000000000000011111111111111111111100001111111111111111111111
11100000000001000111111111111111111111111000001111111111111111111
11000000000001100111111111111111111111111110000000111111111111111
11000000000000111011111111111100011111000011100000001111111111111
11000000000000011111111111111111000111110000000000000011111111111
11000000000000000011111111111111000000000000000000000000111111111
11001000000000000000001111111110000000000000000000000000001111111
11100110000000000001111111110000000000000000111000000000000111111
11110110000000000000000000000000000000000111111111110000000011111
11111110000000000000000000000000000000001111111111111100000001111
11111110000010000000000000000001100000000111011111111110000001111
11111111000111110000000000000111110000000000111111111110110000111
11111110001111111100010000000001111100000111111111111111110000111
11111110001111111111111110000000111111100000000111111111111000111
11111111001111111111111111111000000111111111111111111111111100011
11111111101111111111111111111110000111111111111111111111111001111
11111111111111111111111111111110001111111111111111111111100111111
11111111111111111111111111111111001111111111111111111111001111111
11111111111111111111111111111111100111111111111111111111111111111
11111111111111111111111111111111110111111111111111111111111111111
*/
```
**版权说明:**
此贴内容来源于互联网,仅列出部分来源站点。
- <https://yq.aliyun.com/articles/103033#>
- <https://gist.github.com/edokeh/7580064>

478
content/posts/流畅的Python学习笔记.md

@ -0,0 +1,478 @@ @@ -0,0 +1,478 @@
---
title: 《流畅的Python》学习笔记
date: 2018-10-09 19:48:53
tags: [python]
categories: python
---
《流畅的Python》学习笔记,备忘录形式。
<!-- more -->
## 第1章 Python数据模型
## 第2章 序列构成的数组
### 一个关于+=的谜题
`+=`对应的方法为`__iadd__`,对应的指令为`INPLACE_ADD`,表示`inplace add`。对应实现了`__iadd__`的对象,解释器会直接调用该方法,否则退化为调用`__add__`,然后再赋值。
```python
>>> t=(1,2,[30,50])
>>> t[2] += [50,60]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> t
(1, 2, [30, 50, 50, 60])
```
通过上面的代码,我们发现:`t[2] += [50,60]`抛出异常,但是`t`的值仍然被改变了,通过字节码来分析执行过程:
```python
>>> t=(1,2,[30,50])
>>> dis.dis('t[2] += [50,60]')
1 0 LOAD_NAME 0 (t)
2 LOAD_CONST 0 (2)
4 DUP_TOP_TWO
6 BINARY_SUBSCR
8 LOAD_CONST 1 (50)
10 LOAD_CONST 2 (60)
12 BUILD_LIST 2
14 INPLACE_ADD
16 ROT_THREE
18 STORE_SUBSCR
20 LOAD_CONST 3 (None)
22 RETURN_VALUE
```
`18 STORE_SUBSCR`执行失败,因为`t`是个不可变对象。
三个点:
- 不要把可变对象(列表)放在不可变对象(元组)中;
- 增量赋值不是原子操作;
- 多查看Python的字节码,来分析背后的运行机制。
## 第3章 字典和集合
### 子类化UserDict
创造自定义映射类型,优先使用`collections.UserDict`为基类,而不是以`dict`为基类。`UserDict`有个属性叫做`data`,是`dict`的实例,这个属性实际上是`UserDict`最终存储数据的地方。
### 不可变映射类型
标准库里所有的映射类型都是可变的,如果希望构造一个不可变的映射,可以使用[`MappingProxyType`](https://docs.python.org/3/library/types.html#types.MappingProxyType),给这个类一个映射,它会返回一个只读的映射视图。
### 集合字面量
构造空集合,需要写成`set()`的形式,`{}`表示构造空字典。使用字面量构造集合比使用构造函数的形式要快,因为从字面量构造时,Python会利用一个专门的字节码`BUILD_SET`来创建集合。
```python
>>> dis.dis('{1}')
1 0 LOAD_CONST 0 (1)
2 BUILD_SET 1
4 RETURN_VALUE
>>> dis.dis('set([1])')
1 0 LOAD_NAME 0 (set)
2 LOAD_CONST 0 (1)
4 BUILD_LIST 1
6 CALL_FUNCTION 1
8 RETURN_VALUE
```
## 第4章 文本和字节序列
### 默认编码值
- 如果打开文件时没有指定`encoding`参数,默认值由`locale.getpreferredencoding()`提供。
- 如果设定了`PYTHONIOENCODING`环境变量,`sys.stdout/stdin.stderr`的编码使用设定的值,否则继承自所在控制台,如果输入/输出重定向到文件,则由`locale.getpreferredencoding()`定义。
*在Python3.6以后,Windows平台下,指定`PYTHONIOENCODING`的同时还需要指定[`PYTHONLEGACYWINDOWSSTDIO`](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONLEGACYWINDOWSSTDIO)才能让`sys.stdout/stdin/stderr`使用指定编码*
- Python在二进制数据和字符串之间转换时,内部使用`sys.getdefaultencoding()`获得的编码(在Python3中无法被修改)。
- `sys.getfilesystemencoding()`用于编解码文件名(不是文件内容)。把字符串参数作为文件名传给`open()`函数时就会使用它,如果传入的文件名参数是字节序列,那就不经改动直接传给OS API。可参考[Unicode filenames](https://docs.python.org/3/howto/unicode.html#unicode-filenames)一文。
## 第5章 一等函数
### 高阶函数
接受函数为参数,或者把函数作为结果返回的函数是`高阶函数(higher-order function)`。
### 可调用对象
如果想判断对象能否调用,可以使用内置的`callable()`函数。Python数据模型文档列出了7中可调用对象。
- 用户定义的函数
使用def语句或lambda表达式创建。
- 内置函数
使用C语言(CPython)实现的函数,如`len`或`time.strftime`。
- 内置方法
使用C语言实现的方法,如`dict.get`。
- 方法
在类的定义体中定义的函数。
- 类
调用类时会运行类的`__new__`方法创建一个实例,然后运行`__init__`方法,初始化实例,最后把实例返回给调用方。因为Python没有new运算符,所以调用类相当于调用函数。
- 类的实例
如果类定义了`__call__`方法,那么它的实例可以作为函数调用。
- 生成器函数
使用`yield`关键字的函数或方法。调用生成器函数返回的是生成器对象。
### 获取关于参数的信息
函数对象有个`__defaults__`属性,它的值是一个元组,里面保存着定位参数和关键字参数的默认值。仅限关键字参数的默认值在`__kwdefaults__`属性中。然而,参数的名称在`__code__`属性中,它的值是一个`code`对象引用,自身也有很多属性。
使用`inspect`模块提取函数签名,`inspect.Parameter.kind`值有以下5中:
- `POSITIONAL_OR_KEYWORD`
可以通过定位参数和关键字传入的形参(多数Python函数的参数属于此类)。
- `VAR_POSITIONAL`
定位参数元组。
- `VAR_KEYWORD`
关键字参数字典。
- `KEYWORD_ONLY`
仅限关键字参数(Python3新增)。
- `POSITIONAL_ONLY`
仅限定位参数。目前,Python声明函数的语法不支持,但是有些使用C语言实现且不接受关键字参数的函数(如divmod)支持。
### 函数注解
Python3提供了一种句法,用于为函数声明中的参数和返回值附加元数据。
```python
def clip(text: str, max_len: 'int > 0'=80) -> str:
"""
在max_len前面或后面的第一个空格处截断文本
"""
return text
```
函数声明中的各个参数可以在`:`之后附加注解表达式。如果参数有默认值,注解放在参数名和`=`之间。如果想注解返回值,在`)`和函数声明末尾的`:`之间添加`->`和一个表达式。那个表达式可以是任何类型。
注解不会做任何处理,只是存储在函数的`__annotations__`属性中。
Python对注解所做的唯一的事情是,把它们存储在函数的`__annotations__`属性里,解释器不会对注解做任何处理或验证。注解只是元数据,可供IDE、框架和装饰器等工具使用。可以使用`inspect.signature()`函数提取注解。
## 第6章 使用一等函数实现设计模式
### 案例分析:重构“策略”模式
在Python中,模块也是一等对象,而且标准库提供了几个处理模块的函数。
`globals()`返回一个字典,表示当前的全局符号表。这个符号表始终针对当前模块(对函数或方法来说,是指定义他们的模块,而不是调用他们的模块)。
`inspect.getmembers`函数用于获取对象的属性。
## 第7章 函数装饰器和闭包
### 装饰器基础知识
装饰器是可调用对象,其参数是另一个函数(被装饰的函数)。装饰器可能会处理被装饰的函数,然后把它返回,或者将其替换成另一个函数或者可调用对象。
假如有个名为`decorate`的装饰器
```python
@decorate
def target():
print('running target()')
```
上述代码的效果与下述写法一致:
```python
def target():
print('running target()')
target = decorate(target)
```
装饰器只是语法糖,有两大特性:
- 能把被装饰的函数替换成其他函数。
- 装饰器在加载模块时立即执行。
### Python何时执行装饰器
函数装饰器在**导入**模块时(被装饰函数定义时)立即执行,而被装饰的函数只在明确**调用**时运行。
### 变量作用域规则
```python
b = 6
def f2(a):
print(a)
print(b)
b = 9
f2(3)
```
上述代码,执行会报错:
> Traceback (most recent call last):
>
> File "<stdin>", line 1, in <module>
>
> File "<stdin>", line 3, in f2
>
> UnboundLocalError: local variable 'b' referenced before assignment
Python在编译函数的定义体时,它判断`b`是局部变量,因为在函数中给它赋值了。
这不是缺陷,而是设计选择:**Python不要求声明变量,但是假定在函数定义体中赋值的变量是局部变量**。如果在函数中赋值时想让解释器把`b`当成全局变量,要使用`global`声明。
### 闭包
闭包指延伸了作用域的函数,其中包含函数定义体中引用、但是不在定义体中定义的非全局变量。函数是不是匿名的没有关系,关键是它能访问定义体之外定义的非全局变量。
示例 average_oo.py:
计算移动平均值的类
```python
class Averager():
def __init__(self):
self.series = []
def __call__(self, new_value):
self.series.append(new_value)
total = sum(self.series)
return total/len(self.series)
avg = Averager()
avg(10)
avg(11)
```
计算移动平均值的高阶函数
```python
def make_averager():
series = []
def averager(new_value):
series.append(new_value)
total = sum(self.series)
return total/len(self.series)
return averager
avg = make_averager()
avg(10)
avg(11)
```
在`averager`函数中,`series`是**自由变量(free variable)**。这是一个技术术语,指未在本地作用域中绑定的变量。
{% asset_img frame7-1.png 自由变量 %}
综上,闭包是一种函数,它会保留定义函数时存在的自由变量的绑定,这样调用函数时,虽然定义作用域不可用了,但是仍然能使用那些绑定。
### nonlocal声明
用于在闭包中声明变量作用域。
### 标准库中的装饰器
`functools.lru_cache`实现了备忘(memorization)功能。这是一项优化技术,它把耗时的函数的结果保存起来,避免传入相同的参数时重复计算。可用来优化递归调用。因为`lru_cache`使用字典存储结果,而且键根据调用时传入的定位参数和关键字参数创建,所以被`lru_cache`装饰的函数,它的所有参数都必须是**可散列的**。
`functools.singledispatch`可以使普通的函数变为泛函数(generic function):根据第一个参数的类型,以不同方式执行相同操作的一组函数。`singledispatch`机制的一个显著特征是,你可以在系统的任何地方和任何模块中注册专门函数。如果后来在新的模块中定义了新的类型,可以轻松地添加一个新的专门函数来处理那个类型。此外,你还可以为不是自己编写的或者不能修改的类添加自定义函数。
### 参数化装饰器
创建一个装饰器工厂函数,把参数传给它,返回一个装饰器,然后再把它应用到要装饰的函数上。
```python
from inspect import signature
from functools import wraps
def typeassert(*ty_args, **ty_kwargs):
def decorate(func):
# If in optimized mode, disable type checking
if not __debug__:
return func
# Map function argument names to supplied types
sig = signature(func)
bound_types = sig.bind_partial(*ty_args, **ty_kwargs).arguments
@wraps(func)
def wrapper(*args, **kwargs):
bound_values = sig.bind(*args, **kwargs)
# Enforce type assertions across supplied arguments
for name, value in bound_values.arguments.items():
if name in bound_types:
if not isinstance(value, bound_types[name]):
raise TypeError(
'Argument {} must be {}'.format(name, bound_types[name])
)
return func(*args, **kwargs)
return wrapper
return decorate
```
```python
import types
from functools import wraps
class Profiled:
def __init__(self, func):
wraps(func)(self)
self.ncalls = 0
def __call__(self, *args, **kwargs):
self.ncalls += 1
return self.__wrapped__(*args, **kwargs)
def __get__(self, instance, cls):
if instance is None:
return self
else:
return types.MethodType(self, instance)
```
{% cq %} *示例来自[python3-cookbook](https://python3-cookbook.readthedocs.io/zh_CN/latest/chapters/p09_meta_programming.html)*{% endcq %}
## 第8章 对象引用、可变性和垃圾回收
### 在`==`和`is`之间选择
`==`比较是两个变量的值是否相等,`is`比较两个变量是否同一个对象,即对象标识是否相等。
`is`运算符比`==`速度快,因为它不能重载,所以Python不用寻找并调用特殊方法,而是直接比较两个整数ID。
### 默认做浅复制
```python
l1 = [3, [66, 55, 44], (7, 8, 9)]
l2 = list(l1) # l2是l1的浅复制副本
l1.append(100) # 把100追加到l1中,对l2没有影响
l1[1].remove(55) # 对l2有影响,因为l2[1]绑定的列表与l1[1]是同一个
print('l1:', l1) # l1: [3, [66, 44], (7, 8, 9), 100]
print('l2:', l2) # l2: [3, [66, 44], (7, 8, 9)]
l2[1] += [33, 22] # 对可变对象来说,如l2[1]引用的列表,+=运算符就地修改列表。这次修改在l1[1]中也有提现
l2[2] += (10, 11) # 对元组来说,+=运算符创建一个新元组,然后新绑定给变量l2[2]。现在l2和l1最后位置上的元组不是同一个对象。
print('l1:', l1) # l1: [3, [66, 44, 33, 22], (7, 8, 9), 100]
print('l2:', l2) # l2: [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]
```
### 函数的参数作为引用时
函数可选参数的默认值在定义函数时计算(通常在加载模块时),因此默认值变成了函数对象的属性。因此,如果默认值是可变对象,而且修改了它的值,那么后续的函数调用都会受到影响。
### del和垃圾回收
CPython主要使用引用计数进行内存管理,CPython2.0增加了分代垃圾回收算法,用于检测循环引用的问题。
del不会删除对象,但是执行del后,可能会导致对象不可获取,从而被GC删除。
### 弱引用
`weakref`模块的[文档](https://docs.python.org/3/library/weakref.html)指出,`weakref.ref`类其实是底层接口,供高级用途使用,多数程序最好使用`weakref`集合和`finalize`。也就是说,应该使用`WeakKeyDictonary`、`WeakValueDictionary`、`WeakSet`和`finalize`,不要自己动手创建并处理`weakref.ref`实例。
## 第9章 符合Python风格的对象
### Python的私有属性和“受保护的”属性
以两个前导下划线开头,尾部没有或最多有一个下划线的实例属性,Python会把属性名存入实例的`__dict__`属性中,而且会在前面加上一个下划线和类名,这个语言特性叫做**名称改写**(name mangling)。
以单个下划线开头的实例属性,表示“受保护的”属性,但是仍然可以直接访问到。
### 使用`__slots__`类属性节省空间
默认情况下,Python在各个实例中名为`__dict__`的字典里存储实例属性。为了使用底层的散列表提升访问速度,字典会消耗大量内存。如果要处理数百万个属性不多的实例,通过`__slots__`类属性,能节省大量内存,方法是让解释器在元组中存储实例属性,而不用字典。
继承自超类的`__slots__`属性没有效果。Python只会使用各个类中定义的`__slots__`属性。
定义`__slots__`的方式是,创建一个类属性,使用`__slots__`这个名字,并把它的值设为一个字符串构成的可迭代对象,其中各个元素表示各个实例属性。
不要在`__slots__`中添加`__dict__`,这样做违背了设计初衷。
为了让对象支持弱引用,必须有`__weakref__`属性。用户定义的类默认就有`__weakref__`属性,可是,如果类中定义了`__slots__`属性,而且想把实例作为弱引用的目标,那么要手动把`__weakref__`添加到`__slots__`中。
几个注意点:
- 每个子类都要定义`__slots__`属性,因为解释器会忽略继承的`__slots__`属性。
- 实例只能拥有`__slots__`中列出的属性,除非把`__dict__`加入`__slots__`中(这样做就失去了节省内存的功效)。
- 如果不把`__weakref__`加入`__slots__`,实例就不能作为弱引用的目标。
## 第10章 序列的修改、散列和切片
### 协议和鸭子类型
Python的序列协议只需要`__len__`和`__getitem__`两个方法。任何类,只要使用标准的签名和语义实现了这两个方法,就能用在任何期待序列的地方。人们称其为**鸭子类型**(duck typing)。
### 切片原理
`slice.indices(len) -> (start, stop, stride)`
`all`, `functools.reduce`, `zip`, `reprlib`
## 第11章 接口:从协议到抽象基类
协议是接口,但不是正式的(只由文档和约定定义),因此协议不能像正式接口那样施加限制。
### 标准库中的抽象基类
[Collections Abstract Base Classes](https://docs.python.org/3/library/collections.abc.html#collections-abstract-base-classes)
- `abc`
- `collections.abc`
- `numbers`
### 定义并使用一个抽象基类
在Python 3.4及以上版本,可以直接继承自`abc.ABC`,在旧版本中,需要在class语句中使用`metaclass`关键字,把值设为`abc.ABCMeta`。
```python python3的写法
class Tombola(metaclass=abc.ABCMeta): # python3
pass
```
```python python2的写法
class Tombola(object): # python2
__metaclass__ = abc.ABCMeta
```
[`@abc.abstractmethod`](https://docs.python.org/3/library/abc.html#abc.abstractmethod)装饰器可以堆叠,但是与其他装饰器合用时,该装饰器必须位于最里层。
白鹅类型的一个基本特性:即便不继承,也有办法把一个类注册为抽象基类的**虚拟子类**。注册虚拟子类的方式是在抽象基类上调用`register`方法。这么做之后,注册的类会变成抽象基类的虚拟子类,而且`issubclass`和`isinstance`等函数都能识别,但是注册的类不会从抽象基类中继承任何方法或属性。Python不会对注册类的实现做检查,如果有接口未实现,只能通过运行时错误发现。Python3.3之后的版本,`register`方法可以当做装饰器使用。
类的继承关系在一个特殊的类属性中指定`__mro__`,即方法解析顺序(Method Resolution Order)。这个属性的作用很简单,按顺序列出类及其超类,Python会按照这个顺序搜索方法。通过`register`方法注册的类,不在`__mro__`列表中。
### 鹅的行为有可能像鸭子
`__subclasshook__`在白鹅类型中添加了一些鸭子类型的踪迹。我们可以使用抽象基类定义正式接口,可以始终使用`isinstance`检查,也可以完全使用不相关的类,只要实现特定的方法即可。只有提供`__subclasshook__`方法的抽象基类才能这么做。
## 第12章 继承的优缺点
### 子类化内置类型很麻烦
直接子类化内置类型(如`dict`, `list`或`str`)容易出错,因为内置类型的方法通常会忽略用户覆盖的方法。不要子类化内置类型,用户自定义的类应该继承`collections`模块中的类,例如`UserDict`、`UserList`和`UserString`,这些类做了特殊处理,因此易于扩展。
### 处理多重继承
1. 把接口继承和实现继承区分开
使用多重继承时,一定要明确一开始为什么创建子类。主要原因可能有:
- 继承接口,创建子类型,实现“是什么”关系
- 继承实现,通过重用避免代码重复
2. 使用抽象基类显示表示接口
现代的Python中,如果类的作用是定义接口,应该明确把它定义为抽象基类,创建`abc.ABC`或其他抽象基类的子类
3. 通过混入重用代码
如果一个类的作用是为多个不相关的子类提供方法实现,从而实现方法重用,但不体现“是什么”关系,应该把那个类明确定义为**混入类(mixin class)**
4. 在名称中明确指明混入
因为在Python中没有把类声明为混入的正规方式,所以强烈推荐名称中加入...Mixin后缀
5. 抽象基类可以作为混入,反过来则不成立
抽象基类可以实现具体方法,因此可以作为混入使用。不过,抽象基类会定义类型,而混入做不到。
6. 不要子类化多个具体类
具体类可以没有,或最多只有一个具体超类。也就是说,具体类的超类中除了这一个具体超类之外,其余的都是抽象基类或混入。
7. 为用户提供聚合类
如果抽象基类或混入的组合对客户代码非常有用,那就提供一个类,使用易于理解的方式把它们组合起来。这种类叫做**聚合类(aggregate class)**
8. 优先使用对象组合,而不是类继承
## 第13章 正确重载运算符
### 运算符重载基础
- 不能重载内置类型的运算符
- 不能新建运算符,只能重载现有的
- 某些运算符不能重载--`is`、`and`、`or`和`not`(不过位运算符`&|~`可以)
### 重载向量加法运算符+
实现一元运算符和中缀运算符的特殊方法一定不能修改操作数。使用这些运算符的表达式期待结果是新对象。
`__add__`, `__radd__`, `__iadd__`
{% asset_img frame13-1.png %}
### 众多比较运算符
- 正向和反向调用使用的是同一系列方法。
- 对`==`和`!=`来说,如果反向调用失败,Python会比较对象的ID,而不抛出`TypeError`。

36
content/posts/解决chromium警告C4819.md

@ -0,0 +1,36 @@ @@ -0,0 +1,36 @@
---
title: 解决chromium警告C4819
date: 2018-04-26 20:57:04
tags: [chromium]
categories: chromium
---
初次构建chromium的时候,可能会遇到错误
> : warning C4819: The file contains a character that cannot be represented in the current code page (936). Save the file in Unicode format to prevent data loss
>
> : error C2220: warning treated as error - no 'object' file generated
<!-- more -->
尤其是在Windows上构建的时候,更容易遇到,网络上的方法,基本都是修改系统区域为英国(美国):
> 控制面板--区域--管理--更改系统区域设置
> 在页面中选择英语区域即可
~~这样修改系统设置,我不太喜欢,尤其是在工作机上,这样修改可能会引起其他未知问题,所以直接修改了[gn配置文件](https://chromium.googlesource.com/chromium/src.git/+/master/build/config/compiler/BUILD.gn#1161)中的`default_warnings`字段,添加一项`"/wd4819"`即可。~~
---
**Update:**
上面方法会导致部分文件无法正常解析,产生各种奇怪的语法错误。
新版chromium已经修复了此问题,提交详情见[这里](https://chromium.googlesource.com/chromium/src.git/+/663994ebf90ac57f5cc56a9639a16e29aee1ff2b%5E%21/#F0),最新的BUILD.gn文件见[这里](https://chromium.googlesource.com/chromium/src.git/+/663994ebf90ac57f5cc56a9639a16e29aee1ff2b/build/config/compiler/BUILD.gn#842),其基本原理就是VS2015支持的新特性[/utf-8](https://msdn.microsoft.com/en-us/library/mt708821.aspx),所以最终只需要在`build/config/compiler/BUILD.gn`文件中添加该编译选项即可:
```gn
cflags += [
# Assume UTF-8 by default to avoid code page dependencies.
"/utf-8",
]
```

2
resources/_gen/assets/js/bundle.js_3d041b08546090308b2e5d3a88088713.content

File diff suppressed because one or more lines are too long

1
resources/_gen/assets/js/bundle.js_3d041b08546090308b2e5d3a88088713.json

@ -0,0 +1 @@ @@ -0,0 +1 @@
{"Target":"bundle.min.9e52e68b082cf2a30a7fead88260edb8818fbd7f7831e39674917d4539ec75df41ba88eaddfbd916594ab4fb2a31913b46cf2d6094cf80381edb8c632512a8ca.js","MediaType":"application/javascript","Data":{"Integrity":"sha512-nlLmiwgs8qMKf+rYgmDtuIGPvX94MeOWdJF9RTnsdd9Buojq3fvZFllKtPsqMZE7Rs8tYJTPgDge24xjJRKoyg=="}}

9
resources/_gen/assets/js/js/main.js_d11fe7b62c27961c87ecd0f2490357b9.content

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
const throttle=(callback,limit)=>{let timeoutHandler=null;return()=>{if(timeoutHandler==null){timeoutHandler=setTimeout(()=>{callback();timeoutHandler=null;},limit);}};};const listen=(ele,e,callback)=>{if(document.querySelector(ele)!==null){document.querySelector(ele).addEventListener(e,callback);}}
let header=document.getElementById('site-header');let lastScrollPosition=window.pageYOffset;const autoHideHeader=()=>{let currentScrollPosition=Math.max(window.pageYOffset,0);if(currentScrollPosition>lastScrollPosition){header.classList.remove('slideInUp');header.classList.add('slideOutDown');}else{header.classList.remove('slideOutDown');header.classList.add('slideInUp');}
lastScrollPosition=currentScrollPosition;}
let mobileMenuVisible=false;const toggleMobileMenu=()=>{let mobileMenu=document.getElementById('mobile-menu');if(mobileMenuVisible==false){mobileMenu.style.animationName='bounceInRight';mobileMenu.style.webkitAnimationName='bounceInRight';mobileMenu.style.display='block';mobileMenuVisible=true;}else{mobileMenu.style.animationName='bounceOutRight';mobileMenu.style.webkitAnimationName='bounceOutRight'
mobileMenuVisible=false;}}
const showImg=()=>{document.querySelector('.bg-img').classList.add('show-bg-img');}
const hideImg=()=>{document.querySelector('.bg-img').classList.remove('show-bg-img');}
const toggleToc=()=>{document.getElementById('toc').classList.toggle('show-toc');}
if(header!==null){listen('#menu-btn',"click",toggleMobileMenu);listen('#toc-btn',"click",toggleToc);listen('#img-btn',"click",showImg);listen('.bg-img',"click",hideImg);document.querySelectorAll('.post-year').forEach((ele)=>{ele.addEventListener('click',()=>{window.location.hash='#'+ele.id;});});window.addEventListener('scroll',throttle(()=>{autoHideHeader();if(mobileMenuVisible==true){toggleMobileMenu();}},250));}

1
resources/_gen/assets/js/js/main.js_d11fe7b62c27961c87ecd0f2490357b9.json

@ -0,0 +1 @@ @@ -0,0 +1 @@
{"Target":"js/main.min.35ccbf1cdceb91e4c64c06b5d009d6e2977fafe56beda7762febd4e67528d2ac.js","MediaType":"application/javascript","Data":{"Integrity":"sha256-Ncy/HNzrkeTGTAa10AnW4pd/r+Vr7ad2L+vU5nUo0qw="}}

1
resources/_gen/assets/scss/scss/main.scss_39fa5fe97be74115670eace810202c56.content

File diff suppressed because one or more lines are too long

1
resources/_gen/assets/scss/scss/main.scss_39fa5fe97be74115670eace810202c56.json

@ -0,0 +1 @@ @@ -0,0 +1 @@
{"Target":"main.min.0d47b4686e972122bd29f0c1e3dd024a2d541cd8b1b543622520822ea6f4238a.css","MediaType":"text/css","Data":{"Integrity":"sha256-DUe0aG6XISK9KfDB490CSi1UHNixtUNiJSCCLqb0I4o="}}

5
resources/_gen/assets/scss/scss/style.scss_c16d144eee185fbddd582cd5e25a4fae.content

File diff suppressed because one or more lines are too long

1
resources/_gen/assets/scss/scss/style.scss_c16d144eee185fbddd582cd5e25a4fae.json

@ -0,0 +1 @@ @@ -0,0 +1 @@
{"Target":"css/style.min.568c54a56780af2a70c45272522247710b69dbfc080b315211fb98381e3796f8.css","MediaType":"text/css","Data":{"Integrity":"sha256-VoxUpWeArypwxFJyUiJHcQtp2/wICzFSEfuYOB43lvg="}}

BIN
static/android-chrome-192x192.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
static/android-chrome-384x384.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

BIN
static/android-chrome-512x512.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

BIN
static/apple-touch-icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

9
static/browserconfig.xml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig>
<msapplication>
<tile>
<square150x150logo src="/mstile-150x150.png"/>
<TileColor>#da532c</TileColor>
</tile>
</msapplication>
</browserconfig>

BIN
static/favicon-16x16.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
static/favicon-32x32.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

BIN
static/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/mstile-150x150.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

1
static/safari-pinned-tab.svg

@ -0,0 +1 @@ @@ -0,0 +1 @@
<svg version="1" xmlns="http://www.w3.org/2000/svg" width="666.667" height="666.667" viewBox="0 0 500.000000 500.000000"><path d="M0 250v250h500V0H0v250zm203.2-55l-.5 43H297v-86h29.9l-.1 107.5V367H297V263h-94v104h-29V152h29.8l-.6 43z"/></svg>

After

Width:  |  Height:  |  Size: 242 B

19
static/site.webmanifest

@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
{
"name": "",
"short_name": "",
"icons": [
{
"src": "/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

1
themes/hermit

@ -0,0 +1 @@ @@ -0,0 +1 @@
Subproject commit 00dbd49a94f092b591bf7326c9005a97117836d9
Loading…
Cancel
Save