diff --git a/2020/01/19/King Back/1.jpg b/2020/01/19/King Back/1.jpg new file mode 100644 index 00000000..f4ad9346 Binary files /dev/null and b/2020/01/19/King Back/1.jpg differ diff --git a/2020/01/19/King Back/2.jpg b/2020/01/19/King Back/2.jpg new file mode 100644 index 00000000..745d8f8b Binary files /dev/null and b/2020/01/19/King Back/2.jpg differ diff --git a/2020/01/19/King Back/index.html b/2020/01/19/King Back/index.html new file mode 100644 index 00000000..7d4f46a3 --- /dev/null +++ b/2020/01/19/King Back/index.html @@ -0,0 +1,802 @@ + + + + + + + + + King Back | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/03/15/\347\274\226\347\240\201/1.jpg" "b/2020/03/15/\347\274\226\347\240\201/1.jpg" new file mode 100644 index 00000000..124da700 Binary files /dev/null and "b/2020/03/15/\347\274\226\347\240\201/1.jpg" differ diff --git "a/2020/03/15/\347\274\226\347\240\201/index.html" "b/2020/03/15/\347\274\226\347\240\201/index.html" new file mode 100644 index 00000000..e36b8be5 --- /dev/null +++ "b/2020/03/15/\347\274\226\347\240\201/index.html" @@ -0,0 +1,821 @@ + + + + + + + + + 计算机组成原理——编码 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/1.png" "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/1.png" new file mode 100644 index 00000000..28296a96 Binary files /dev/null and "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/1.png" differ diff --git "a/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/2.jpg" "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/2.jpg" new file mode 100644 index 00000000..6779040c Binary files /dev/null and "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/2.jpg" differ diff --git "a/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/index.html" "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/index.html" new file mode 100644 index 00000000..d897be14 --- /dev/null +++ "b/2020/07/09/\344\272\272\345\210\260\345\244\247\344\272\214\344\272\272\347\224\237\350\277\267\350\214\253\357\274\210\344\270\223\344\270\232\346\225\231\350\202\262\350\242\253\350\277\253\345\206\231\346\226\207\357\274\211/index.html" @@ -0,0 +1,813 @@ + + + + + + + + + 人到大二人生迷茫(专业教育被迫写文) | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/07/10/Hexo\345\215\232\345\256\242\346\220\255\345\273\272/index.html" "b/2020/07/10/Hexo\345\215\232\345\256\242\346\220\255\345\273\272/index.html" new file mode 100644 index 00000000..394ccc9f --- /dev/null +++ "b/2020/07/10/Hexo\345\215\232\345\256\242\346\220\255\345\273\272/index.html" @@ -0,0 +1,859 @@ + + + + + + + + + Hexo博客搭建 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/07/12/python\345\256\236\347\216\260\351\201\227\344\274\240\347\256\227\346\263\225/index.html" "b/2020/07/12/python\345\256\236\347\216\260\351\201\227\344\274\240\347\256\227\346\263\225/index.html" new file mode 100644 index 00000000..6c371ead --- /dev/null +++ "b/2020/07/12/python\345\256\236\347\216\260\351\201\227\344\274\240\347\256\227\346\263\225/index.html" @@ -0,0 +1,842 @@ + + + + + + + + + python实现遗传算法 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/07/15/\346\250\241\346\213\237\351\200\200\347\201\253matlab\345\256\236\347\216\260\357\274\210TSP\344\270\272\344\276\213\357\274\211/index.html" "b/2020/07/15/\346\250\241\346\213\237\351\200\200\347\201\253matlab\345\256\236\347\216\260\357\274\210TSP\344\270\272\344\276\213\357\274\211/index.html" new file mode 100644 index 00000000..1e416759 --- /dev/null +++ "b/2020/07/15/\346\250\241\346\213\237\351\200\200\347\201\253matlab\345\256\236\347\216\260\357\274\210TSP\344\270\272\344\276\213\357\274\211/index.html" @@ -0,0 +1,846 @@ + + + + + + + + + 模拟退火matlab实现(TSP为例) | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/07/16/matlab\347\256\200\345\215\225\345\276\256\345\210\206\346\226\271\347\250\213\346\261\202\350\247\243/index.html" "b/2020/07/16/matlab\347\256\200\345\215\225\345\276\256\345\210\206\346\226\271\347\250\213\346\261\202\350\247\243/index.html" new file mode 100644 index 00000000..c0c6aa25 --- /dev/null +++ "b/2020/07/16/matlab\347\256\200\345\215\225\345\276\256\345\210\206\346\226\271\347\250\213\346\261\202\350\247\243/index.html" @@ -0,0 +1,840 @@ + + + + + + + + + matlab简单微分方程求解 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/09/java\347\232\204String\345\270\270\347\224\250\346\223\215\344\275\234/index.html" "b/2020/09/09/java\347\232\204String\345\270\270\347\224\250\346\223\215\344\275\234/index.html" new file mode 100644 index 00000000..94854eb4 --- /dev/null +++ "b/2020/09/09/java\347\232\204String\345\270\270\347\224\250\346\223\215\344\275\234/index.html" @@ -0,0 +1,873 @@ + + + + + + + + + java的String常用操作 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/1.png" "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/1.png" new file mode 100644 index 00000000..864fec63 Binary files /dev/null and "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/1.png" differ diff --git "a/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/2.png" "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/2.png" new file mode 100644 index 00000000..8e2e1d90 Binary files /dev/null and "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/2.png" differ diff --git "a/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/3.png" "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/3.png" new file mode 100644 index 00000000..fca0711e Binary files /dev/null and "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/3.png" differ diff --git "a/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/index.html" "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/index.html" new file mode 100644 index 00000000..28429947 --- /dev/null +++ "b/2020/09/10/\346\225\260\346\215\256\345\272\223E-R\345\233\276\344\273\213\347\273\215/index.html" @@ -0,0 +1,841 @@ + + + + + + + + + 数据库E-R图介绍 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/11/\345\271\266\345\217\221\346\216\247\345\210\266\346\234\272\345\210\266\347\232\204\345\277\205\350\246\201\346\200\247/index.html" "b/2020/09/11/\345\271\266\345\217\221\346\216\247\345\210\266\346\234\272\345\210\266\347\232\204\345\277\205\350\246\201\346\200\247/index.html" new file mode 100644 index 00000000..609f7040 --- /dev/null +++ "b/2020/09/11/\345\271\266\345\217\221\346\216\247\345\210\266\346\234\272\345\210\266\347\232\204\345\277\205\350\246\201\346\200\247/index.html" @@ -0,0 +1,816 @@ + + + + + + + + + 并发控制机制的必要性 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/1.png" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/1.png" new file mode 100644 index 00000000..0c8bbef6 Binary files /dev/null and "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/1.png" differ diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/2.png" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/2.png" new file mode 100644 index 00000000..883d849d Binary files /dev/null and "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/2.png" differ diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/3.png" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/3.png" new file mode 100644 index 00000000..d0f67153 Binary files /dev/null and "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/3.png" differ diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/4.png" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/4.png" new file mode 100644 index 00000000..8dbf055d Binary files /dev/null and "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/4.png" differ diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/5.jpg" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/5.jpg" new file mode 100644 index 00000000..c562cd8d Binary files /dev/null and "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/5.jpg" differ diff --git "a/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/index.html" "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/index.html" new file mode 100644 index 00000000..2834fb63 --- /dev/null +++ "b/2020/09/13/Business-Intelligence-BI-System\344\273\213\347\273\215/index.html" @@ -0,0 +1,836 @@ + + + + + + + + + Business Intelligence(BI) System介绍 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/21/\350\277\233\347\250\213/index.html" "b/2020/09/21/\350\277\233\347\250\213/index.html" new file mode 100644 index 00000000..415ba37a --- /dev/null +++ "b/2020/09/21/\350\277\233\347\250\213/index.html" @@ -0,0 +1,826 @@ + + + + + + + + + 进程 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/1.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/1.png" new file mode 100644 index 00000000..b63572f9 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/1.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/2.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/2.png" new file mode 100644 index 00000000..aab938f2 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/2.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/3.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/3.png" new file mode 100644 index 00000000..1705c321 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/3.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/4.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/4.png" new file mode 100644 index 00000000..d3a7b514 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/4.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/5.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/5.png" new file mode 100644 index 00000000..52264b72 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/5.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/6.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/6.png" new file mode 100644 index 00000000..ccce9c9d Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/6.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/8.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/8.png" new file mode 100644 index 00000000..a79b43d1 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/8.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/9.png" "b/2020/09/24/htmlcss\345\233\236\351\241\276/9.png" new file mode 100644 index 00000000..30c2eec8 Binary files /dev/null and "b/2020/09/24/htmlcss\345\233\236\351\241\276/9.png" differ diff --git "a/2020/09/24/htmlcss\345\233\236\351\241\276/index.html" "b/2020/09/24/htmlcss\345\233\236\351\241\276/index.html" new file mode 100644 index 00000000..56169d9f --- /dev/null +++ "b/2020/09/24/htmlcss\345\233\236\351\241\276/index.html" @@ -0,0 +1,1019 @@ + + + + + + + + + htmlcss回顾 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/1.png" "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/1.png" new file mode 100644 index 00000000..af36f0e8 Binary files /dev/null and "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/1.png" differ diff --git "a/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/2.png" "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/2.png" new file mode 100644 index 00000000..b9b39e5a Binary files /dev/null and "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/2.png" differ diff --git "a/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/3.png" "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/3.png" new file mode 100644 index 00000000..5c67ed83 Binary files /dev/null and "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/3.png" differ diff --git "a/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/index.html" "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/index.html" new file mode 100644 index 00000000..b885fb82 --- /dev/null +++ "b/2020/09/26/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\346\215\256\347\261\273\345\236\213\344\270\216\345\237\272\346\234\254\351\200\273\350\276\221\350\257\255\345\217\245/index.html" @@ -0,0 +1,871 @@ + + + + + + + + + js基础——数据类型与基本逻辑语句 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/27/js\345\237\272\347\241\200\342\200\224\342\200\224\345\207\275\346\225\260/index.html" "b/2020/09/27/js\345\237\272\347\241\200\342\200\224\342\200\224\345\207\275\346\225\260/index.html" new file mode 100644 index 00000000..113083f1 --- /dev/null +++ "b/2020/09/27/js\345\237\272\347\241\200\342\200\224\342\200\224\345\207\275\346\225\260/index.html" @@ -0,0 +1,825 @@ + + + + + + + + + js基础——函数 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/29/SQL\350\257\255\345\217\245\342\200\224\342\200\224\342\200\224\342\200\224\346\225\260\346\215\256\345\256\232\344\271\211/index.html" "b/2020/09/29/SQL\350\257\255\345\217\245\342\200\224\342\200\224\342\200\224\342\200\224\346\225\260\346\215\256\345\256\232\344\271\211/index.html" new file mode 100644 index 00000000..b48d8206 --- /dev/null +++ "b/2020/09/29/SQL\350\257\255\345\217\245\342\200\224\342\200\224\342\200\224\342\200\224\346\225\260\346\215\256\345\256\232\344\271\211/index.html" @@ -0,0 +1,823 @@ + + + + + + + + + SQL语句————数据定义 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/1.png" "b/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/1.png" new file mode 100644 index 00000000..17361523 Binary files /dev/null and "b/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/1.png" differ diff --git "a/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/index.html" "b/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/index.html" new file mode 100644 index 00000000..314da514 --- /dev/null +++ "b/2020/09/29/js\345\237\272\347\241\200\342\200\224\342\200\224\346\225\260\347\273\204\345\257\271\350\261\241-Array-object/index.html" @@ -0,0 +1,849 @@ + + + + + + + + + js基础——数组对象(Array object) | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/10/02/js\345\237\272\347\241\200\342\200\224\342\200\224\345\205\263\344\272\216\345\257\271\350\261\241/index.html" "b/2020/10/02/js\345\237\272\347\241\200\342\200\224\342\200\224\345\205\263\344\272\216\345\257\271\350\261\241/index.html" new file mode 100644 index 00000000..10b4b7d5 --- /dev/null +++ "b/2020/10/02/js\345\237\272\347\241\200\342\200\224\342\200\224\345\205\263\344\272\216\345\257\271\350\261\241/index.html" @@ -0,0 +1,848 @@ + + + + + + + + + js基础——关于对象 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/10/02/\347\274\226\350\257\221\345\216\237\347\220\206\347\254\254\344\272\214\347\253\240\342\200\224\342\200\224\346\226\207\346\263\225\345\210\206\347\261\273/index.html" "b/2020/10/02/\347\274\226\350\257\221\345\216\237\347\220\206\347\254\254\344\272\214\347\253\240\342\200\224\342\200\224\346\226\207\346\263\225\345\210\206\347\261\273/index.html" new file mode 100644 index 00000000..6ebf61f5 --- /dev/null +++ "b/2020/10/02/\347\274\226\350\257\221\345\216\237\347\220\206\347\254\254\344\272\214\347\253\240\342\200\224\342\200\224\346\226\207\346\263\225\345\210\206\347\261\273/index.html" @@ -0,0 +1,837 @@ + + + + + + + + + 编译原理第二章——文法分类 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/10/03/\344\270\255\346\226\255\345\274\202\345\270\270\344\270\216\347\263\273\347\273\237\350\260\203\347\224\250/index.html" "b/2020/10/03/\344\270\255\346\226\255\345\274\202\345\270\270\344\270\216\347\263\273\347\273\237\350\260\203\347\224\250/index.html" new file mode 100644 index 00000000..c122f422 --- /dev/null +++ "b/2020/10/03/\344\270\255\346\226\255\345\274\202\345\270\270\344\270\216\347\263\273\347\273\237\350\260\203\347\224\250/index.html" @@ -0,0 +1,839 @@ + + + + + + + + + 中断异常与系统调用 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/10/03/\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\350\277\220\350\241\214\346\234\272\345\210\266\345\222\214\344\275\223\347\263\273\347\273\223\346\236\204/index.html" "b/2020/10/03/\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\350\277\220\350\241\214\346\234\272\345\210\266\345\222\214\344\275\223\347\263\273\347\273\223\346\236\204/index.html" new file mode 100644 index 00000000..3bedf343 --- /dev/null +++ "b/2020/10/03/\346\223\215\344\275\234\347\263\273\347\273\237\347\232\204\350\277\220\350\241\214\346\234\272\345\210\266\345\222\214\344\275\223\347\263\273\347\273\223\346\236\204/index.html" @@ -0,0 +1,851 @@ + + + + + + + + + 操作系统的运行机制和体系结构 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/10/13/\344\272\272\344\272\272\351\203\275\346\230\257\344\272\247\345\223\201\347\273\217\347\220\206\350\257\273\345\220\216\346\204\237/index.html" "b/2020/10/13/\344\272\272\344\272\272\351\203\275\346\230\257\344\272\247\345\223\201\347\273\217\347\220\206\350\257\273\345\220\216\346\204\237/index.html" new file mode 100644 index 00000000..76f3e690 --- /dev/null +++ "b/2020/10/13/\344\272\272\344\272\272\351\203\275\346\230\257\344\272\247\345\223\201\347\273\217\347\220\206\350\257\273\345\220\216\346\204\237/index.html" @@ -0,0 +1,824 @@ + + + + + + + + + 人人都是产品经理读后感 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/11/01/\346\225\260\346\215\256\345\272\223\345\244\215\344\271\240\351\242\230/index.html" "b/2020/11/01/\346\225\260\346\215\256\345\272\223\345\244\215\344\271\240\351\242\230/index.html" new file mode 100644 index 00000000..df6a2b77 --- /dev/null +++ "b/2020/11/01/\346\225\260\346\215\256\345\272\223\345\244\215\344\271\240\351\242\230/index.html" @@ -0,0 +1,855 @@ + + + + + + + + + 数据库复习题 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/11/06/\344\277\241\345\217\267\351\207\217\346\234\272\345\210\266\347\273\217\345\205\270\344\276\213\345\255\220/index.html" "b/2020/11/06/\344\277\241\345\217\267\351\207\217\346\234\272\345\210\266\347\273\217\345\205\270\344\276\213\345\255\220/index.html" new file mode 100644 index 00000000..58df0496 --- /dev/null +++ "b/2020/11/06/\344\277\241\345\217\267\351\207\217\346\234\272\345\210\266\347\273\217\345\205\270\344\276\213\345\255\220/index.html" @@ -0,0 +1,814 @@ + + + + + + + + + 信号量机制经典例子 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2020/12/21/datawhale-pandas\346\225\260\346\215\256\345\210\206\346\236\220\351\242\204\345\244\207/index.html" "b/2020/12/21/datawhale-pandas\346\225\260\346\215\256\345\210\206\346\236\220\351\242\204\345\244\207/index.html" new file mode 100644 index 00000000..560a4a36 --- /dev/null +++ "b/2020/12/21/datawhale-pandas\346\225\260\346\215\256\345\210\206\346\236\220\351\242\204\345\244\207/index.html" @@ -0,0 +1,1748 @@ + + + + + + + + + datawhale-pandas数据分析预备 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/01/20/datawhale-pandas\347\274\272\345\244\261\346\225\260\346\215\256\345\244\204\347\220\206/index.html" "b/2021/01/20/datawhale-pandas\347\274\272\345\244\261\346\225\260\346\215\256\345\244\204\347\220\206/index.html" new file mode 100644 index 00000000..7f385108 --- /dev/null +++ "b/2021/01/20/datawhale-pandas\347\274\272\345\244\261\346\225\260\346\215\256\345\244\204\347\220\206/index.html" @@ -0,0 +1,1260 @@ + + + + + + + + + datawhale-pandas缺失数据处理 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/20/datawhale\351\230\277\351\207\214\344\272\221\345\244\251\346\261\240\350\257\255\344\271\211\345\210\206\345\211\262\346\257\224\350\265\233-Task1-\350\265\233\351\242\230\347\220\206\350\247\243\345\222\214baseline\344\273\243\347\240\201/index.html" "b/2021/02/20/datawhale\351\230\277\351\207\214\344\272\221\345\244\251\346\261\240\350\257\255\344\271\211\345\210\206\345\211\262\346\257\224\350\265\233-Task1-\350\265\233\351\242\230\347\220\206\350\247\243\345\222\214baseline\344\273\243\347\240\201/index.html" new file mode 100644 index 00000000..468ec182 --- /dev/null +++ "b/2021/02/20/datawhale\351\230\277\351\207\214\344\272\221\345\244\251\346\261\240\350\257\255\344\271\211\345\210\206\345\211\262\346\257\224\350\265\233-Task1-\350\265\233\351\242\230\347\220\206\350\247\243\345\222\214baseline\344\273\243\347\240\201/index.html" @@ -0,0 +1,885 @@ + + + + + + + + + datawhale阿里云天池语义分割比赛-Task1 赛题理解和baseline代码 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/22/datawhale-\350\257\255\344\271\211\345\210\206\345\211\262task2\346\225\260\346\215\256\346\211\251\345\242\236/index.html" "b/2021/02/22/datawhale-\350\257\255\344\271\211\345\210\206\345\211\262task2\346\225\260\346\215\256\346\211\251\345\242\236/index.html" new file mode 100644 index 00000000..235b41d7 --- /dev/null +++ "b/2021/02/22/datawhale-\350\257\255\344\271\211\345\210\206\345\211\262task2\346\225\260\346\215\256\346\211\251\345\242\236/index.html" @@ -0,0 +1,885 @@ + + + + + + + + + datawhale-语义分割task2数据扩增 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task3-\350\257\255\344\271\211\345\210\206\345\211\262\346\250\241\345\236\213\345\217\221\345\261\225/index.html" "b/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task3-\350\257\255\344\271\211\345\210\206\345\211\262\346\250\241\345\236\213\345\217\221\345\261\225/index.html" new file mode 100644 index 00000000..36ef5d1f --- /dev/null +++ "b/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task3-\350\257\255\344\271\211\345\210\206\345\211\262\346\250\241\345\236\213\345\217\221\345\261\225/index.html" @@ -0,0 +1,972 @@ + + + + + + + + + datawhale语义分割-Task3 语义分割模型发展 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task4-\350\257\204\344\273\267\345\207\275\346\225\260\344\270\216\346\215\237\345\244\261\345\207\275\346\225\260/index.html" "b/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task4-\350\257\204\344\273\267\345\207\275\346\225\260\344\270\216\346\215\237\345\244\261\345\207\275\346\225\260/index.html" new file mode 100644 index 00000000..9ab8ac89 --- /dev/null +++ "b/2021/02/23/datawhale\350\257\255\344\271\211\345\210\206\345\211\262-Task4-\350\257\204\344\273\267\345\207\275\346\225\260\344\270\216\346\215\237\345\244\261\345\207\275\346\225\260/index.html" @@ -0,0 +1,932 @@ + + + + + + + + + datawhale语义分割-Task4 评价函数与损失函数 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/24/docker\345\256\211\350\243\205\345\222\214\347\256\200\346\230\223\345\216\237\347\220\206/index.html" "b/2021/02/24/docker\345\256\211\350\243\205\345\222\214\347\256\200\346\230\223\345\216\237\347\220\206/index.html" new file mode 100644 index 00000000..53ba8641 --- /dev/null +++ "b/2021/02/24/docker\345\256\211\350\243\205\345\222\214\347\256\200\346\230\223\345\216\237\347\220\206/index.html" @@ -0,0 +1,842 @@ + + + + + + + + + docker安装和简易原理 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/24/docker\345\270\270\347\224\250\345\221\275\344\273\244/index.html" "b/2021/02/24/docker\345\270\270\347\224\250\345\221\275\344\273\244/index.html" new file mode 100644 index 00000000..5fce8f12 --- /dev/null +++ "b/2021/02/24/docker\345\270\270\347\224\250\345\221\275\344\273\244/index.html" @@ -0,0 +1,893 @@ + + + + + + + + + docker常用命令 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/02/25/docker\351\225\234\345\203\217\346\223\215\344\275\234/index.html" "b/2021/02/25/docker\351\225\234\345\203\217\346\223\215\344\275\234/index.html" new file mode 100644 index 00000000..12b8a940 --- /dev/null +++ "b/2021/02/25/docker\351\225\234\345\203\217\346\223\215\344\275\234/index.html" @@ -0,0 +1,944 @@ + + + + + + + + + docker镜像操作 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/04/12/MTCNN\350\256\272\346\226\207\345\222\214pytorch\344\273\243\347\240\201\350\247\243\350\257\273/index.html" "b/2021/04/12/MTCNN\350\256\272\346\226\207\345\222\214pytorch\344\273\243\347\240\201\350\247\243\350\257\273/index.html" new file mode 100644 index 00000000..9b9f890b --- /dev/null +++ "b/2021/04/12/MTCNN\350\256\272\346\226\207\345\222\214pytorch\344\273\243\347\240\201\350\247\243\350\257\273/index.html" @@ -0,0 +1,877 @@ + + + + + + + + + MTCNN论文和pytorch代码解读 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/04/22/yolov1-3\350\256\272\346\226\207\350\247\243\346\236\220/index.html" "b/2021/04/22/yolov1-3\350\256\272\346\226\207\350\247\243\346\236\220/index.html" new file mode 100644 index 00000000..c30ae04b --- /dev/null +++ "b/2021/04/22/yolov1-3\350\256\272\346\226\207\350\247\243\346\236\220/index.html" @@ -0,0 +1,870 @@ + + + + + + + + + yolov1-3论文解析 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/05/09/EfficientNet\350\256\272\346\226\207\350\247\243\350\257\273\345\222\214pytorch\344\273\243\347\240\201\345\256\236\347\216\260/index.html" "b/2021/05/09/EfficientNet\350\256\272\346\226\207\350\247\243\350\257\273\345\222\214pytorch\344\273\243\347\240\201\345\256\236\347\216\260/index.html" new file mode 100644 index 00000000..ffddbe4e --- /dev/null +++ "b/2021/05/09/EfficientNet\350\256\272\346\226\207\350\247\243\350\257\273\345\222\214pytorch\344\273\243\347\240\201\345\256\236\347\216\260/index.html" @@ -0,0 +1,858 @@ + + + + + + + + + EfficientNet论文解读和pytorch代码实现 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/06/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\345\237\272\347\241\200\342\200\224\342\200\224\345\277\253\351\200\237\346\216\222\345\272\217\344\270\216\345\275\222\345\271\266\346\216\222\345\272\217/index.html" "b/2021/06/06/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\345\237\272\347\241\200\342\200\224\342\200\224\345\277\253\351\200\237\346\216\222\345\272\217\344\270\216\345\275\222\345\271\266\346\216\222\345\272\217/index.html" new file mode 100644 index 00000000..0ee4a08a --- /dev/null +++ "b/2021/06/06/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\345\237\272\347\241\200\342\200\224\342\200\224\345\277\253\351\200\237\346\216\222\345\272\217\344\270\216\345\275\222\345\271\266\346\216\222\345\272\217/index.html" @@ -0,0 +1,830 @@ + + + + + + + + + 数据结构与算法基础——快速排序与归并排序 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/13/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\345\210\267\351\242\230\342\200\224\342\200\224\351\223\276\350\241\250/index.html" "b/2021/06/13/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\345\210\267\351\242\230\342\200\224\342\200\224\351\223\276\350\241\250/index.html" new file mode 100644 index 00000000..d08c9d36 --- /dev/null +++ "b/2021/06/13/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\345\210\267\351\242\230\342\200\224\342\200\224\351\223\276\350\241\250/index.html" @@ -0,0 +1,824 @@ + + + + + + + + + 数据结构与刷题——链表 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/15/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\342\200\224\342\200\224\344\272\214\345\210\206/index.html" "b/2021/06/15/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\342\200\224\342\200\224\344\272\214\345\210\206/index.html" new file mode 100644 index 00000000..d3602ad7 --- /dev/null +++ "b/2021/06/15/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225\342\200\224\342\200\224\344\272\214\345\210\206/index.html" @@ -0,0 +1,840 @@ + + + + + + + + + 数据结构与算法——二分 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/16/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224voting-bagging/index.html" "b/2021/06/16/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224voting-bagging/index.html" new file mode 100644 index 00000000..2845fa34 --- /dev/null +++ "b/2021/06/16/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224voting-bagging/index.html" @@ -0,0 +1,901 @@ + + + + + + + + + 集成学习专题——voting&bagging | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224GBDT/index.html" "b/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224GBDT/index.html" new file mode 100644 index 00000000..2ebf1ef3 --- /dev/null +++ "b/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224GBDT/index.html" @@ -0,0 +1,879 @@ + + + + + + + + + 集成学习专题——GBDT | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224adaboost\345\216\237\347\220\206\345\222\214sklearn\345\256\236\347\216\260/index.html" "b/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224adaboost\345\216\237\347\220\206\345\222\214sklearn\345\256\236\347\216\260/index.html" new file mode 100644 index 00000000..9986d91c --- /dev/null +++ "b/2021/06/17/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224adaboost\345\216\237\347\220\206\345\222\214sklearn\345\256\236\347\216\260/index.html" @@ -0,0 +1,925 @@ + + + + + + + + + 集成学习专题——adaboost原理和sklearn实现 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/06/18/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224Xgboost-LightGBM/index.html" "b/2021/06/18/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224Xgboost-LightGBM/index.html" new file mode 100644 index 00000000..d6e031d7 --- /dev/null +++ "b/2021/06/18/\351\233\206\346\210\220\345\255\246\344\271\240\344\270\223\351\242\230\342\200\224\342\200\224Xgboost-LightGBM/index.html" @@ -0,0 +1,1121 @@ + + + + + + + + + 集成学习专题——Xgboost&LightGBM | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2021/10/16/PAT\347\254\224\350\256\260/index.html" "b/2021/10/16/PAT\347\254\224\350\256\260/index.html" new file mode 100644 index 00000000..35852ac6 --- /dev/null +++ "b/2021/10/16/PAT\347\254\224\350\256\260/index.html" @@ -0,0 +1,958 @@ + + + + + + + + + PAT笔记 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/1.jpg" "b/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/1.jpg" new file mode 100644 index 00000000..4747ece8 Binary files /dev/null and "b/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/1.jpg" differ diff --git "a/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/index.html" "b/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/index.html" new file mode 100644 index 00000000..98eb898b --- /dev/null +++ "b/2022/01/08/\345\233\236\351\246\226\345\220\221\346\235\245\350\220\247\347\221\237\345\244\204\357\274\214\345\275\222\345\216\273\357\274\214\344\271\237\346\227\240\351\243\216\351\233\250\344\271\237\346\227\240\346\231\264\357\275\2342021\345\271\264\347\273\210\346\200\273\347\273\223/index.html" @@ -0,0 +1,898 @@ + + + + + + + + + 回首向来萧瑟处,归去,也无风雨也无晴|2021年终总结 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/1.jpg" "b/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/1.jpg" new file mode 100644 index 00000000..4747ece8 Binary files /dev/null and "b/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/1.jpg" differ diff --git "a/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/index.html" "b/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/index.html" new file mode 100644 index 00000000..b76df4c9 --- /dev/null +++ "b/2022/01/08/\350\217\234\351\270\241\347\232\204\347\256\227\346\263\225\345\262\227\346\227\245\345\270\270\345\256\236\344\271\240\351\235\242\347\273\217\346\200\273\347\273\223/index.html" @@ -0,0 +1,931 @@ + + + + + + + + + 菜鸡的算法岗日常实习面经总结 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2022/03/31/\346\227\242\345\276\200\344\270\215\346\201\213\357\274\214\347\272\265\346\203\205\345\220\221\345\211\215\357\274\214\346\261\237\346\271\226\345\206\215\350\247\201\342\200\224\342\200\22422\345\262\201\351\202\243\345\271\264\357\274\214\345\234\250\345\214\227\344\272\254\347\232\204\346\227\245\345\255\220/index.html" "b/2022/03/31/\346\227\242\345\276\200\344\270\215\346\201\213\357\274\214\347\272\265\346\203\205\345\220\221\345\211\215\357\274\214\346\261\237\346\271\226\345\206\215\350\247\201\342\200\224\342\200\22422\345\262\201\351\202\243\345\271\264\357\274\214\345\234\250\345\214\227\344\272\254\347\232\204\346\227\245\345\255\220/index.html" new file mode 100644 index 00000000..1ad35a89 --- /dev/null +++ "b/2022/03/31/\346\227\242\345\276\200\344\270\215\346\201\213\357\274\214\347\272\265\346\203\205\345\220\221\345\211\215\357\274\214\346\261\237\346\271\226\345\206\215\350\247\201\342\200\224\342\200\22422\345\262\201\351\202\243\345\271\264\357\274\214\345\234\250\345\214\227\344\272\254\347\232\204\346\227\245\345\255\220/index.html" @@ -0,0 +1,821 @@ + + + + + + + + + 既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/1.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/1.jpg" new file mode 100644 index 00000000..9fdc8fb0 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/1.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/10.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/10.jpg" new file mode 100644 index 00000000..d6c2cffa Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/10.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/11.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/11.jpg" new file mode 100644 index 00000000..6d3acebc Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/11.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/12.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/12.png" new file mode 100644 index 00000000..b8f343e3 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/12.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/13.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/13.png" new file mode 100644 index 00000000..d71a3d1a Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/13.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/14.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/14.png" new file mode 100644 index 00000000..fbbefb4b Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/14.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/15.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/15.png" new file mode 100644 index 00000000..dffa3d1b Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/15.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/16.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/16.png" new file mode 100644 index 00000000..62167c65 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/16.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/17.png" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/17.png" new file mode 100644 index 00000000..c4440315 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/17.png" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/2.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/2.jpg" new file mode 100644 index 00000000..6fa3caa5 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/2.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/3.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/3.jpg" new file mode 100644 index 00000000..6fc65d32 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/3.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/4.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/4.jpg" new file mode 100644 index 00000000..3b26bdd8 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/4.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/5.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/5.jpg" new file mode 100644 index 00000000..36b73ca3 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/5.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/6.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/6.jpg" new file mode 100644 index 00000000..3f99493c Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/6.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/7.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/7.jpg" new file mode 100644 index 00000000..69a705ea Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/7.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/8.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/8.jpg" new file mode 100644 index 00000000..b366bf06 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/8.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/9.jpg" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/9.jpg" new file mode 100644 index 00000000..36f253c3 Binary files /dev/null and "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/9.jpg" differ diff --git "a/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/index.html" "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/index.html" new file mode 100644 index 00000000..fce687be --- /dev/null +++ "b/2023/12/27/Dynamicgo-\346\224\257\346\214\201-Protobuf-\345\212\250\346\200\201\345\217\215\345\260\204/index.html" @@ -0,0 +1,1036 @@ + + + + + + + + + Dynamicgo 支持 Protobuf 动态反射 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/2024/06/09/Never-Stop-Thinking(1)/index.html b/2024/06/09/Never-Stop-Thinking(1)/index.html new file mode 100644 index 00000000..5899db4a --- /dev/null +++ b/2024/06/09/Never-Stop-Thinking(1)/index.html @@ -0,0 +1,843 @@ + + + + + + + + + Never Stop Thinking | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git "a/2024/10/09/ubuntu22-04-\346\227\245\345\270\270\345\214\226/index.html" "b/2024/10/09/ubuntu22-04-\346\227\245\345\270\270\345\214\226/index.html" new file mode 100644 index 00000000..794cbc29 --- /dev/null +++ "b/2024/10/09/ubuntu22-04-\346\227\245\345\270\270\345\214\226/index.html" @@ -0,0 +1,810 @@ + + + + + + + + + ubuntu22.04 日常化 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/01/index.html b/archives/2020/01/index.html new file mode 100644 index 00000000..82740bc5 --- /dev/null +++ b/archives/2020/01/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2020/1 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/03/index.html b/archives/2020/03/index.html new file mode 100644 index 00000000..6cba5808 --- /dev/null +++ b/archives/2020/03/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2020/3 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/07/index.html b/archives/2020/07/index.html new file mode 100644 index 00000000..26e4bd3c --- /dev/null +++ b/archives/2020/07/index.html @@ -0,0 +1,912 @@ + + + + + + + + + Archives: 2020/7 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/09/index.html b/archives/2020/09/index.html new file mode 100644 index 00000000..fe36fd08 --- /dev/null +++ b/archives/2020/09/index.html @@ -0,0 +1,1114 @@ + + + + + + + + + Archives: 2020/9 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/10/index.html b/archives/2020/10/index.html new file mode 100644 index 00000000..c34f6079 --- /dev/null +++ b/archives/2020/10/index.html @@ -0,0 +1,916 @@ + + + + + + + + + Archives: 2020/10 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/11/index.html b/archives/2020/11/index.html new file mode 100644 index 00000000..d86cad38 --- /dev/null +++ b/archives/2020/11/index.html @@ -0,0 +1,798 @@ + + + + + + + + + Archives: 2020/11 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/12/index.html b/archives/2020/12/index.html new file mode 100644 index 00000000..7f3b3121 --- /dev/null +++ b/archives/2020/12/index.html @@ -0,0 +1,764 @@ + + + + + + + + + Archives: 2020/12 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/index.html b/archives/2020/index.html new file mode 100644 index 00000000..33994c00 --- /dev/null +++ b/archives/2020/index.html @@ -0,0 +1,1118 @@ + + + + + + + + + Archives: 2020 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/page/2/index.html b/archives/2020/page/2/index.html new file mode 100644 index 00000000..16c8a7ae --- /dev/null +++ b/archives/2020/page/2/index.html @@ -0,0 +1,1114 @@ + + + + + + + + + Archives: 2020 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2020/page/3/index.html b/archives/2020/page/3/index.html new file mode 100644 index 00000000..d7bc52da --- /dev/null +++ b/archives/2020/page/3/index.html @@ -0,0 +1,916 @@ + + + + + + + + + Archives: 2020 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/01/index.html b/archives/2021/01/index.html new file mode 100644 index 00000000..c6aa19e6 --- /dev/null +++ b/archives/2021/01/index.html @@ -0,0 +1,764 @@ + + + + + + + + + Archives: 2021/1 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/02/index.html b/archives/2021/02/index.html new file mode 100644 index 00000000..6bed71ab --- /dev/null +++ b/archives/2021/02/index.html @@ -0,0 +1,1004 @@ + + + + + + + + + Archives: 2021/2 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/04/index.html b/archives/2021/04/index.html new file mode 100644 index 00000000..84055b89 --- /dev/null +++ b/archives/2021/04/index.html @@ -0,0 +1,798 @@ + + + + + + + + + Archives: 2021/4 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/05/index.html b/archives/2021/05/index.html new file mode 100644 index 00000000..166a5571 --- /dev/null +++ b/archives/2021/05/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2021/5 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/06/index.html b/archives/2021/06/index.html new file mode 100644 index 00000000..a85c7165 --- /dev/null +++ b/archives/2021/06/index.html @@ -0,0 +1,1004 @@ + + + + + + + + + Archives: 2021/6 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/10/index.html b/archives/2021/10/index.html new file mode 100644 index 00000000..69fe0bb0 --- /dev/null +++ b/archives/2021/10/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2021/10 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/index.html b/archives/2021/index.html new file mode 100644 index 00000000..47ea47cc --- /dev/null +++ b/archives/2021/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + Archives: 2021 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2021/page/2/index.html b/archives/2021/page/2/index.html new file mode 100644 index 00000000..f753693d --- /dev/null +++ b/archives/2021/page/2/index.html @@ -0,0 +1,1088 @@ + + + + + + + + + Archives: 2021 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2022/01/index.html b/archives/2022/01/index.html new file mode 100644 index 00000000..0a61897f --- /dev/null +++ b/archives/2022/01/index.html @@ -0,0 +1,802 @@ + + + + + + + + + Archives: 2022/1 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2022/03/index.html b/archives/2022/03/index.html new file mode 100644 index 00000000..c0ac4ccc --- /dev/null +++ b/archives/2022/03/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2022/3 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2022/index.html b/archives/2022/index.html new file mode 100644 index 00000000..459de59d --- /dev/null +++ b/archives/2022/index.html @@ -0,0 +1,840 @@ + + + + + + + + + Archives: 2022 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html new file mode 100644 index 00000000..215c4b78 --- /dev/null +++ b/archives/2023/12/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2023/12 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 00000000..7439fb03 --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2023 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2024/06/index.html b/archives/2024/06/index.html new file mode 100644 index 00000000..d6be4121 --- /dev/null +++ b/archives/2024/06/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2024/6 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2024/10/index.html b/archives/2024/10/index.html new file mode 100644 index 00000000..e29f7a83 --- /dev/null +++ b/archives/2024/10/index.html @@ -0,0 +1,760 @@ + + + + + + + + + Archives: 2024/10 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 00000000..4b6e37f6 --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,798 @@ + + + + + + + + + Archives: 2024 | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 00000000..96a8ff1b --- /dev/null +++ b/archives/index.html @@ -0,0 +1,1152 @@ + + + + + + + + + Archives | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 00000000..012d2b43 --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,1110 @@ + + + + + + + + + Archives | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 00000000..686aa5de --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,1140 @@ + + + + + + + + + Archives | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 00000000..62c419e1 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,1122 @@ + + + + + + + + + Archives | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/archives/page/5/index.html b/archives/page/5/index.html new file mode 100644 index 00000000..2b94c7ed --- /dev/null +++ b/archives/page/5/index.html @@ -0,0 +1,1106 @@ + + + + + + + + + Archives | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/assets/liang.jpg b/assets/liang.jpg new file mode 100644 index 00000000..bf659158 Binary files /dev/null and b/assets/liang.jpg differ diff --git a/assets/liangx.jpg b/assets/liangx.jpg new file mode 100644 index 00000000..f527cfec Binary files /dev/null and b/assets/liangx.jpg differ diff --git a/atom.xml b/atom.xml new file mode 100644 index 00000000..2fbfab75 --- /dev/null +++ b/atom.xml @@ -0,0 +1,520 @@ + + + khan's study and life blog - 学习站 + + + + + + 2024-10-17T07:11:10.363Z + https://jackyin.space/ + + + Jack Yin | INFJ + + + + Hexo + + + ubuntu22.04 日常化 + + https://jackyin.space/2024/10/09/ubuntu22-04-%E6%97%A5%E5%B8%B8%E5%8C%96/ + 2024-10-09T10:17:37.000Z + 2024-10-17T07:11:10.363Z + + 最近有在折腾一些Ubuntu日常化的东西,给电脑重新装了双系统,相比前几年,ubuntu22.04之后系统确实变得非常好用了,软件生态支持也变多了,为了更加日常化的使用折腾了一些相关软件的安装,这边做一个简单的记录。

ubuntu安装卸载

ubuntu的安装卸载以及分区教程还是有些麻烦的,我也是参考了b战上面一个不错的up主的教学,期间有差点把自己windows引导搞出问题,然后用驱动精灵修复了。注意计算机专业同学还是尽量用英语安装,且安装以后禁用掉软件和内核更新,在一生一芯中有提到,禁用方法很简单自行百度即可。
参考链接:Windows 和 Ubuntu 双系统的安装和卸载

Easyconnect

目前华科的VPN是支持ubuntu系统的,这确实提供了学生在连接校园网和服务器上的便利。当然安装可能会打不开的小问题。
参考链接:解决方案,需下载的软件内有可用的百度云网址

VPN-Clash

找了一个不错的ubuntu支持的带有客户端的clash,亲测可用,导入任意可用的订阅链接就行。
参考链接:Devpn

QQ

QQ 9可以直接在ubuntu22.04上直接使用。
参考链接:QQ 9官网

QQ 音乐

官方目前已经有可支持的版本,再也不用担心冲了会员用不了啦!偶尔会有闪退问题,但是不影响。
参考链接:QQ音乐官网

WPS

WPS是在linux系统下可支持office三件套的工具,有一些中文汉化的问题,解决方案跟下面一样,不过实际下载之后发现,在/opt/kingsoft/wps-office/office6/mui下面本来就有语言包,只需要像下面的链接一样,移除下载后的其他语言安装包,只保留default zh_CN就能直接汉化,虽然在选择字体上好像还有点问题没解决,但是算是能用了至少。
参考链接:参考链接

中文输入法

在b战找到了一个简单不错的中文输入法——rime输入法,感觉非常好用,安装后如果没有效果记得重启下电脑。
参考链接:rime输入法安装

微信

微信的安装好像有很多版本了,官方也有在做统一的OS支持,这里我用的可能不一定是最好的版本,但是可以支持文字和图片截图,还能打开小程序和公众号,只是看不了朋友圈,安装过程没有踩坑。
参考链接:2024如何在Ubuntu上安装原生微信wechat weixin

浏览器

Edge & Chrome 目前都支持linux的相关系统了,不用担心使用问题,编程相关的软件就更方便了。

End

一生一芯可以启动了!

]]>
+ + + + <p>最近有在折腾一些Ubuntu日常化的东西,给电脑重新装了双系统,相比前几年,ubuntu22.04之后系统确实变得非常好用了,软件生态支持也变多了,为了更加日常化的使用折腾了一些相关软件的安装,这边做一个简单的记录。</p> + + + + + + + +
+ + + Never Stop Thinking + + https://jackyin.space/2024/06/09/Never-Stop-Thinking(1)/ + 2024-06-09T07:51:56.000Z + 2024-10-09T09:20:00.630Z + + Forward

“Never Stop Thinking”,永远不要停止思考。很美妙又很内耗的一句话呢,大概贯穿了我这快两年的研究生生涯吧。

这篇blog的标题在拿下暑期实习offer的时候就写下了,不过直到最近才算是闲下来(在朋友们的内推下,我的秋招确实异常顺利,由于厌倦了背八股文和面试,在拿到几家不错的offer后,我差不多就早早结束了我的秋招,回家摆烂了大半个月,中途在折腾ubuntu双系统,直接放弃了米哈游的笔试邀请,好想去米啊😭),是时候把萦绕在脑子里面胡思乱想的内存碎片,整理出来了。

Hello World

#include <stdio.h>
int main()
{
printf("Hello World!");
return 0;
}

梦还是从它说起吧,”Hello World”——世界上第一个程序,它源自C语言之父记忆中的不知名漫画,漫画里描述了小鸡破壳而出时,向世界发出问候的片段。当年贝尔实验室的那群开发人员应该想象不到几十年后,世界真能以这样的方式建立连接。

最近一年为了准备面试,又重头看那些基础的时候,我有了一些新的理解。我不禁感慨,计算机确实是人类智慧的结晶,正如它的名字Computer Science一样,它背后的设计思想与自然科学定理同等重要,是真正的Theory/Science,尽管对人们来说它最大的价值只是作为Technique/Tool

Computer Science,我认为绝对是一个天生浪漫与人文的学科。世界上第一台计算机ENIAC诞生于1946年的2月14日。Ada语言为纪念Ada Lovelace世界第一个程序员而命名。从操作系统,数据结构,到设计模式,许多都源自于人类直觉的抽象思维与逻辑。每个不同的语言,都夹带了作者非常浓厚的设计理念和优雅美学(虽然我觉得Java语法和Python环境真的是屎,我应该这辈子都学不会JAVA吧)。每个不同的应用方向,都有很多与众不同的magic number和经验主义。写到这突然想起来,大一被指针概念折磨的时候,看浙大网课翁恺老师说的那句”计算机的一切都是人想出来的,总有一天你都能学会的!“。虽然后半句我觉得我应该有很多东西这辈子都学不会吧,不过还好计算机不用学物理捏。

冯诺依曼,香农,Linus那些群星闪耀的名字,不仅是天才,更是一群勇士。他们用上帝给予的天赋,造就了用来计算上帝法则的机器。很难想象,你真的能用区区一组指令集管理一块电路板上有限的微电子信号,去无限逼近这变幻莫测的世界,即使你坚信它的理论误差是有保证的;你也很难想象,熵这种宇宙物理概念,真的可以被量化成字节信息,用于描述概率分布,奠定了AI发展的基础。这种用有限离散推演无穷万物的超前思想,真的令人敬佩。

在我眼中,计算机科学家就是这样一群,妄想穷尽0和1排列组合去模拟世界运转法则的勇者。

The Gifted World

人无完人,我们必须承认绝大部分人都没有他们那样的天赋,但这好像并不妨碍我们参与和扩展他们的工作。在计算机的世界里,许多伟大的project往往是被全球社区驱动,即使是帮忙翻译文档这样小的贡献,也能受到官方的认可,而且这些社区的人总是feel free to touch when you are ready。对于现代计算机而言,不同天赋层次的人们都能发挥他重要的作用。因为一个应用或者系统的正确运行,离不开每一行代码逻辑,不论它的设计是否优雅。稳定性总是凌驾于一切优雅之道,而优雅的设计也是为了提供更好的稳定性。

上帝并没有给我什么天赋,就连我的best friend,Leo对我的评价也是说我非常努力,尽管天赋并不突出。(虽然我有点伤心,还是夸我有天赋好听一点www)但我觉得努力本身也是一种天赋吧,因为如何审时度势,最大化努力的收益,规划有限的时间,预估未知的机遇和风险,都是对人的一种考验。我也想把这句话送给所有正在努力的人们,我相信你们都是聪明且执行力很强的人

幸运的是,即使菜鸡如我,也的确能真实地触碰到那个Gifted World。在这短短几年的游学里,我认识了各种各样的大佬们,他们有的曾放弃过科大少年班,有的极致的偏科(语文英语70分),有的来自清北复交,有的家境无敌,有的是素未谋面的开源大佬或者学术同仁,我从他们的身上听闻了很多独特的经历,也学习了一些经验。听起来这种感觉像打怪升级偷师学艺,好在大家都乐意教我一手。除此之外,我也真实的接触过各种chance,参与过一些很棒的开源项目并且已经有真实地应用,看到自己做的东西有被人使用还是很开心的;也曾荣幸接到过华科存储天才少年实验室的直博offer(问了我无条件信任的人后决定拒绝,还好没去,那里面push的不像人样,逼出来的天才不是我心中的天才);体验过国际学术会议,加了几个海外不错的工作者和教授。

The Sketch World

世界就是草台班子。我也不知道怎么翻译更合适,就姑且叫它The Sketch World吧,经过这几年的体验,确实更深刻的体会到了这一点。

且不谈俄乌冲突,巴以开火,留美学生被枪击,那些我庆幸未曾经历过战争与新闻(事实上,我网上冲浪的渠道并不多,不玩抖音和微博,小红书还是今年出国前社会姐推荐给我用的,不过体验下来确实还不错),从我自身的所见所闻就足以确信这个世界的不完美。

浮躁充斥着整个社会。在学术界,热门的东西总在被过度宣传,即使是MIT,哈佛的论文也存在着许多灌水与强行解释,甚至有的会将公式写错。很多人开源的代码质量也很差,复现性不高。我自己身在学阀的实验室体系下,也真实地感受过那些窒息和黑暗的利益瓜葛。很巧的是,和我一起实习的一位南京大学的同学,没想到竟然是以前我联系过的很有名的老师的学生,但从他的描述来看,似乎现在老师也没有在好好带学生了,硕士去打黑工,博士刷引用。答辩还遇到个伯克利的同学,感觉不论是工作内容,还是算法理解上都显得比较粗浅。大概有实力的人在哪都是少数吧,看来我认识的朋友们已经都是这个世界很强的存在了。在工业界,企业的招聘信息铺天盖地,仿佛开启了时代加速器,每个人的时间线都被各种笔试面试精准切分,学生都成了提线木偶。公司极致的商业化和产品化,也不断push着人们急于求成,风险预估,这种氛围甚至能影响到实习生,听说有多个实习生为了竞争一个留用名额闹得不愉快。内卷环境下,读书和工作都是围城,人们不可避免地焦虑着自己的未来。国外的月亮也没有那么圆,济州岛的公交和航班日常迟到半个小时以上;今年还见到了十多年没见过的一直在英国留学的Nancy,她说伦敦街头都是大麻的味道,爱丁堡有人随处吐痰,明明自己不讲卫生还嫌弃中国人没素质;世华也说美国留子都很假,宣扬着一些所谓的自由。或许在草台本质的世界,尽力做到自己心中认为的最好,说不定就已经是世界一级棒了,每个人都不应该妄自菲薄。

The Data World

数字化是现代社会的必然趋势,未来也是,这也是计算机如此热门的原因之一。兴趣使然,从18年到现在,我大概对业务应用,基础架构,AI算法等不同计算机领域都有一些浅薄的经历,也去过两家不同行业性质的大厂实习。在数字信息化的浪潮中,我既是体验者,也是参与者,研究者,偶尔也是观察者。

这多重的角色总是带给我不同的思考,尤其是GPT时代,海量的数据在庞大的算力体系下的确涌现了它的能力。从更高维的视角来看,我想GPT本质上是对信息的高度压缩,从而产生了类脑的记忆能力。这样一看,原来人类千万年来对这个世界的认知,浓缩过后也才不过几百GB参数罢了。ChatGPT的诞生的确是近年来AI领域最伟大的进步,尽管它并不具有任何推理能力。但我们试想小孩学习的思维过程,人们对于知识的理解和运用,一定是先出于记忆和模仿,进而产生概念和思维,最后做出推理和行为,并得到与环境交互的反馈。不论是生物还是机械体,或许记忆都是产生智能和情感的必然前提吧,如果舍弃掉这一切,人类大概就能像细菌和水母那样活上几万年了吧,但显然我们的DNA拒绝了这样的进化。我也很期待在我活着的时候能看到AI在思维推理上的进步,深度学习的范式注定只是一个过渡阶段,最近的OpenAI的o1似乎已经在进行尝试了。最近非常沉迷于战双帕弥什(来生去库洛做游戏!)和崩坏星穹铁道,里面有很多时空,星神,机械体,战争,人类的思考,其中人机构造体与机械体意识觉醒的设定好像真有一点合理性。在更远的未来,或许脑机接口还真有可能成为现实,一方面为人脑提供更强大的算力,还能让AI在人脑的帮助下由推理能力出自衍生出自我意识。或许当人们真的让机械体拥有自我意识的那天,估计也搞懂了人类是否具有可以被物质捕捉的“灵魂”。

然而,不论是什么时代,数据安全一定是数字化的最大挑战。我私以为这无可避免,当你的信息交给平台后,你的数据就不再完全属于你,即使你关闭了很多的权限,更别说你在平台上自发的消费行为和数据输出。说起来这十分嘲讽,虽然国内外平台都在强调数据的私有保存,但实际上这一定是做不到的。完全自由化的交互,对信息的管理和容错而言,成本很大,无法溯源的订单,非法传播的内容,也在一定程度上影响着用户的体验。那么有人监管会更好吗,或许只是大部分人没接触到罢了。ChatGPT偷偷窃取了许多个人数据进行训练,Stable Diffusion中夹杂着许多性侵,恐怖的图片,国内短视频后台的审核数据量也是十分惊人,大数据推送,用户画像不知是在走向智能还是挖掘人心。天下皆为利益熏心,个人信息也可以是巨大的资本原始资料。

技术本身是无罪的,当你在做研究时,你会觉得这些抽象化的问题很值得思考,可一旦面向具象化的现实应用就会变成一把双刃剑。这很符合我对人性本恶的看法,而且这个问题也困扰我至今。但还是请允许我向数字化工程的各类从业者致敬,如果没有他们负重前行,网络环境恐怕会比现在更糟吧。

My Chaos World

我的世界很混沌,计划永远赶不上变化。而我也认为自己很虚无,总是觉得意义一定是伴随某种立场而存在的,如果要归根到底的话,仿佛这世间一切都毫无意义。不过这种想法倒是让我成了生活的体验派,想尝试什么就去做,想追寻什么就去追,不再追问自己旅途的意义,把世界当作一个巨大的集邮。这看似自由的背后,其实还挺不容易的,中间也遇到过很多很多的困难和怀疑,这个世界有好人,也真的有坏人。尽管也有一些事情不尽人意,我也觉得自己已经做的很好了,毕竟每个人都值得更好的。更重要的是,相比以前,我学会了认识和承认自身的问题,我大概是越活越不要脸咯。

我大概永远都不会忘记,研一入学那年高等数学挂科的日子。我心里也很清楚那年去上研究生的状态真的很差。习惯了从大二开始就不听课最后冲刺刷分,我研一就没怎么上过早八的数学课。那年很冷,是我第二次看到武汉下雪,华科上学都得骑8分钟,而我经常电动车没电,所以我每次都懒得去,就算起来了也是直接去实验室,不想浪费时间。我还和爸妈吹,我大学三年都没听过课,八九十分随便考。然而快考试了我才发现,我真的什么都忘了,第一次体会到了那种知识不进脑子的感觉,不过那时我还没有意识到问题的严重性,把往年试卷刷了个遍后,感觉考察的知识点比较固定,重点学会就行了,于是我一边看EVA摸鱼,一边囫囵吞枣地看课本。意料之外的是,那次试卷老师出的很难,几乎所有人考完都整破防了,我跟rb说自己差不多扣了二三十分了,尽管数学没有平时分,但是我仍然自我感觉良好。而后武汉疫情复发,考完数学后,我就放假回家了。

有一天聂神跟我说数学出成绩了,他说他85,我心想这么高,老师肯定捞人了。我打开系统,漫不经心地扫了一眼,应用高等工程数学,学期1,学分3,学时48,成绩40,绩点为空。怎么没有一个数字大于60?我怀疑自己看错了,又刷新了好几遍,突然意识到,我tm居然挂科了????梦该醒了,这次不是流星划过,而是真正的陨石撞地球。我彻夜未眠,没有补考,只能重修,8个大字在我脑子里面盘旋,我的脑子里闪过了无数画面,所有的奖学金与我无缘,所有的计划被打碎,从毕业的那个暑假开始到今天为止,整个人就没有一天正常过,所有的原因都不是原因,我做了非常对不起自己和父母的事情。我把自己的生活搞得一团糟,一学期没想出一个合适的科研课题,现在还要把自己搞延毕了,我果然不配读这样的学校,后悔和难过到了极点,不亚于18年和19年的那两个夜晚。”我想和谁说”,”说了有用吗”,”这次能别再逃避了吗”

是啊,我一直都在逃避,这次也不例外。我始终不相信我的数学能考成这样,于是第二天我决定找老师查卷,就算挂了,我也要知道真相。”挂科的试卷都是老师反复检查过的,不会有错,试卷的标准答案已经丢了”,老师一开始不愿意理我,但最后在我的反复折磨下,去学校把我的试卷翻了出来,然后逐个题目给我开始解释。”你的这份做的很烂”,于是我把我认为绝不会错的那些题都让他看了一遍,”牛顿插值这题,你第一问就算错了,第三问两种方法算出来一定是一样的,我上课讲过,如果你认真听了,你就会知道自己算错了”,”Jordan矩阵也算错了”,”最小二乘法你的矩阵一开始就抄错了,给了1分公式分”,最离谱的是求数值积分的那题,我嫌麻烦但弄巧成拙,用应试教育下的那魔鬼般的等价变形技巧转换题意后用切比雪夫计算,得到了平常考试下最完美自信的结果——$\pi/2$,老师看到我的解法也沉默了半小时,最后还是判定我的做法不严谨,并批评我为什么不用勒让德老老实实做。计算错误一直是我最大的梦魇,笼罩了我学生时代大大小小所有的考试,我总是宽慰自己重要的是学知识,计算都是小问题,直到今天酿成大祸,8个大题除了欧拉证明题全军覆没,与那年理综物理选择题连错5个如出一辙。我无话可说,那就研二重修吧,接受现实,反正学校那些没用的机制我也早就厌倦了,正好可以完全关注在评价体系外更有价值的内容,接触到了那些很棒的开源项目。

研二开学,我和宿舍新来的学弟一起去上数学课,我发誓这学期要好好学数学绝不翘课,结果开学第一节课老师就说”我们这学期有平时分了,上学期挂科的人太多了”,我无奈苦笑,内心万马奔腾,仿佛老天爷跟我开了个巨大的玩笑。那是一段非常难顶的日子,我瞒着所有人每天复习着数学,同时还要跑实验汇报科研进展,还要负责自己偷偷报名的CCF开源项目,直到考数学的前一周我还在写代码。更搞笑的是,那年的考试题目出乎意料的简单,矩阵大小甚至不超过三阶,更不存在做不完的情况,现在想想还真是嘲讽呢。考完出分自然是过了,那天刚好还是我的生日,但总算能松一口气了。由于没有补考,华科成绩单上也只会显示我的最新分数,算是不幸中的万幸了,对以后也没有什么大的影响。

我的世界好像总是能搞出点意外,保研阴差阳错,去深圳遇到台风,长沙回家买票打不到车,去山东遇到地震,找实习各种挂简历,面试不会写快速排序,去济州岛visa取不了钱,电脑进水报废,老天爷还真是喜欢看我曲线救国。再加上自己丢三落四,手机日常没电的习惯,我每天都能闹出点笑话,不过这的确让我的生活很难一成不变,always in chaos。还好我的记忆力很不错,东西大多能记起来在哪丢的,十几年没玩过的赛尔号账号密码都能想起来。大概我的脑子就用来记这些七七八八了,我学不进知识是有原因的。

The Restart World

相比前两年的悲惨世界,我的研三的确有一种《重启人生》(太好看了!)的感觉,比起大四保研出去实习+回来被考驾照折磨更闲了,最近的精神状态很颠,有一种年纪轻轻就财富自由的感觉😍。在8月份离职后先在家躺了快大半个月,赶上了时间陪即将去伦敦的Leo最后告别,我骗老师说我找不到工作,老师说不用我开组会了优先去找工作,暑假在待遇拉满的阿里实习,的确也赚到了一笔不小的收益,还能申请奖学金。一回到学校,桌子上一堆礼物,有学校发的月饼,两博士学长出去给我带了巴塞罗那的蜥蜴钥匙扣和新西兰的巧克力,还有wy姐姐@SIGMOD24开会给我带的南美洲智利的纪念品,希望她能如愿苏黎世以后说不定还能捞我,之前拜托曼子说武大的南极考察队到时候给我带个石头回来,今年大概有时间去武大蹭一下陈铭老师的课了,只可惜我的论文rebuttal加分后还是没能如愿温哥华,不然我大概就完成了集齐五大洲的梦想了,不过也习惯了,老天爷总要给我制造一些遗憾,当时那时候忙着找实习确实也没太多时间搞自己的论文,最近又思考改了一些东西,小修几天投了ICLR2025,期待一下明年1月新加坡有没有机会吧,还是很希望自己的工作能被认可的。今年国庆虽然没有出去玩,但是有朋友来武汉过来找我还挺开心的,最近在学校狂玩战双,王者,健身和多吃饭又重新提上日程,节后要提前开启我的毕业旅行了,无人机,相机计划也能启动了,大概会先逛一下川渝,南京,然后飞日本一周,有时间去看一下在大阪的表姐,名侦探柯南圣地巡礼,体验下日本电车,富士山,希望能赶上日本的百鬼夜行和烟火大会!还有什么特别想做的大概就是学点音乐🥰,学习一下家传的厨艺。考个雅思托福?在Leo的影响下,最近的确开始喜欢听taylor Swift和Ed Sheeran了。

多珍惜当下的学生时光吧,像这样20几岁,有时间又有钱,家里人也都还健在的黄金时代,大概这辈子也就这一次哈哈哈哈,会一直被运气捉弄的人才永远是二流,这回总算是上帝的时间先输给我了

The Future World

后疫情时代未来并没有变好,各行各业的门槛越来越高,回想几个月前找实习的时候也是到处碰壁,卡双9学历,不招人,面到心力憔悴,自我怀疑。到了企业实习,发现全都是清北华五硕士,连本科生都没见到几个。CS会议论文投稿量从几千上升到几万,审稿质量急剧下降,创新性变成了排列组合的算力游戏,中稿像中彩票,祈祷不要遇到恶心的审稿人,没中就继续堆工作量,无限闭环。涝的涝死,旱的旱死,如今的CS圈子就是这样的,基于自身的情况,我考虑过很多选择,也做过很多方面的尝试,但面对不可知的未来,即使我在这个圈子里算做的还行,也无法坚定自己的心。

我想去大厂工作早点赚钱,爸妈最近几年确实在不断变老,而我还不能完全让自己独立,我不想依靠他们,我希望他们自己的钱花在自己的身上。我也想让自己的家过的好一些,买得起跑车,房子,看得起演唱会,出去旅游玩得起。并且我拿到了不错的offer,广平说老板对我印象很好,我也感觉那个老板很有意思,在抖音做几年业务,换一些期权,业务也比较稳定,不太容易裁员,和广平一起住房应该也很有趣,听说以后也有机会去北美tiktok,哪天抖音真上市了,财富自由的白日梦就真的成了。或者去美团跟学长做核心算法,学长在那边职级很高,认识不少其他公司的高层,团队跟清华崔鹏老师和南大LamdA实验室都有合作,以后在工业界和学术界都有更多的connection,发展也还行。又或者去华为做CPU/GPU底层设计,做中国自己的硬件产品。我不可否认,CS行业确实是我们这个时代为数不多能快速积累原始资本的行业,与之相应的,自然也要付出相应的代价。对了,我还把自己和朋友们的一些春秋招面经都总结到了一个文档上,到时候开源分享出来,感觉能造福接下来一两年的学弟学妹们了,不过也有可能让大家更卷了,但比起卷还是缩小信息差更重要。

我也有点想去海外名校读Phd,做一些真正有影响力的研究。我记得当我读Invariant Risk Minimization这篇不变性理论的开山之作时,我第一次被作者的motivation所惊艳,**”任何事物一旦用正确的变量表示,可能都将遵守精确的物理法则,正如苹果和群星都遵循引力方程”,这是一种非常伟大似乎又有点合理的假设,企图用机器学习由果推因,探索现实数据中潜在的统一条件概率期望定式,让我不得不感叹人类思想的超前和勇敢,突然有点庆幸研究生做的是分布外泛化理论了。虽然以我现有的能力还没有资格评判一篇论文或者工作的价值深远影响,但我自认为自己的科研taste还算不错,科研态度应该也是课题组最严谨的。算法面试的时候,学长说我从1面到4面的面试官都是三清博士,而且都对我在投的工作和过往的经历表示非常认可,上次NIPS的审稿人也说认为工作具有潜力但需要进一步修改,或许我所拥有的特质可能还真是这个世界所需要的呢。尽管国内学术氛围真的很差劲,做学术大概率10年内赚不到钱,做实验有时候也很让人糟心,但我的确还挺喜欢这种可以一直保持专注和思考的感觉,也挺喜欢计算机的,学校的氛围和时间也相对更自由,也有机会去体验在Google,Facebook实习。或许我真的可以把自己对CS的理解和经历,真的教给未来年轻的同学们**,相比那些从来没出国,从来没去工业界实习过的教授,我的确有更多的经验,而更自私的来说,CS学术界也确实更接近我环游世界的梦想。我很享受那种一直在路上,脑子放空,脱离现实的感觉,像旅行青蛙,去各种地方开会旅游,把我看到的有趣的东西带回来,送给我想送的人,当然我也深知学术圈的那些肮脏交易,飞升疾走,一切圈子都没有那么存粹。

如果我哪天决定要走这条路,就意味着我要和国内顶尖的那群清北复交大佬们宣战,感觉自己的经历还是差点意思。不过我也有联系和关注过CUHK的老师,MSRA的研究员,北美的老师。我觉得我和他们相比,在CS广度上的经历应该会更特别一些,虽然深度上可能比不过那些出身条件就很好的同学,大概还是能引起一些老师的兴趣,时间也肯定能弥补在深度上的差距。不过我不想向身边的某些同学和学长一样,为了逃避工作而申请PHD,因此没有全力陶瓷准备暑研和英语,对我而言缺的也只是chance和决心,而且抱着那种心态读大概率会让我丢失本心,也浪费钱和时间。可能工作一年再看吧,积累更多工业界的经历,以后回国当老师找这些前东家合作,funding肯定也不愁。本来有联系MSRA-system组争取一下实习,最后对方还是觉得方向不太match拒绝了。有时间的话可能会参加一些中科院的“一生一芯”remote项目,增加一下偏系统的经历,希望在毕业之前能看到自己造的risc-V芯片。不过看到实验室有同学联系了今年ETH的老师,心里确实也挺羡慕的,有时候我也在想是不是我考个英语,此生真的有机会去ETH,普林斯顿吗,好像去爱因斯坦的母校看看😭

我也想沉下心做一些更底层的东西。最近一年跳出AI圈,接触了许多偏开发和架构的东西,那些大模型的论文让我感觉很无聊,比起浮躁的AI社区,感觉这些工作的周期更长,也更加的solid。如果往计算机系统方向发展,正好可以借助我大老板IEEE fellow的地位,去北美争取到几个不错的加州系列的华人老师,而且相对于AI申请没有那么卷。从我接触到的视角来看,国内在系统方向上的确人才很稀缺,再加上美国对中国已经全面禁用了高性能设备的出售,国内企业也只有华为真的在做相关的硬件支持和系统设计,但算力的进化一定是未来的必然趋势,也具有重要的战略意义,战略意义?从我口中说出来还挺奇怪的,我好像的确谈不上什么能对国家产生贡献的人,也没有那么强烈的军国情结,不过我确实有清楚的记得一些让我很反感讨厌的事情,这几年facebook的开源框架和下载官网上,CMT会议投稿的网站上,一直有着支持乌克兰的字眼,使用llama,chatgpt选china就会被ban,这很嘲讽,谁说科学没有国界,不与政治挂钩,大家从一开始明明就分的很清楚。如果有机会的话,以后不想跟风做非常火热的应用迭代,比较想做ML Theory / system arch更基础的内容,但我相信多少能在应用中体现价值,这也一定是如今和以后国内CS圈很需要的东西。我们不能一直走国外做技术创新,国内做应用创新的老路,但我也能理解肯定会经历先学别人再自研的过程。

我也想回家养老,出来实习的两次经历的确让我感觉到在外打工的窒息,更别说如果真有一天要出国回不来那该有多痛苦,每一天上班我都想辞职不干了,找个稳定的工作在湖南舒舒服服,饭菜又好吃。回家躺尸大半个月更是让我感觉小地方的生活节奏实在是太舒适了,我今年竟然能在家里的晚上看到天上的星星了,小县城晚上光污染越来越少了,估计大多数人都跑到外面去了吧。能陪着爸妈真的很幸福,偶尔还能帮他们分担一些工作,爷爷奶奶啥的有什么问题都能及时赶过来,尤其是这几年爷爷的身体确实越来越差了,有时候想到这些东西,有一种很强烈的无力感,或许下辈子我应该去学医,好歹能救一救自己的亲人,至少如果外面医生开的药有问题我还能看出来。这些残酷的现实和真相,总是让我觉得自己真的很没用,天天内耗在那些本就毫无意义的想法上,能和几个知心朋友们聚一聚,有个安心的家,也不必像苏轼那样哀吾生之须臾,羡长江之无穷。蓼叶湖,湘江,长江,东湖,长白山,海洋,田园,吸引我的从来都不是外面的喧嚣与人流,而是这些宁静的自然,总有一天我会回到这里

仔细想想这些年,我好像一直在入圈和退圈,不过这辈子应该都不会踏入商界和政界吧,一直呆在体制内的家庭已经让我厌倦了这些,好像奶奶说以前有人算命说我以后能当什么大官哈哈哈。从大学时期,一边搞好学业一边又接触学生工作,不想当高分低能又多学技术打比赛,竞赛加分拉满然后又退出内卷竞争,又跳出象牙塔去北京实习,又尝试去体验马拉松,健身,学游泳,再学会去思考尝试科研,做一些理论推导,之后又跳出AI看system的论文,做开源项目,顺手带了个湖北警校的同学去参会(说以后可以帮我解决停车罚单hhh),或许工作一两年我又会离开工业界学个英语回归学术界或者回家养老呢,但正是这些奇奇怪怪的这些经历,让我遇到了各种朋友,见证并参与了各种各样的人生,也收集了很多很多家公司/旅游的纪念品,这就是读万卷书,行万里路,天下江湖皆朋友的感觉吧。或许有一个人生秘诀是,只需要做好一件领域内的事,再拿出跟同领域人不一样的筹码,往往更容易成为天平的胜者。

当然,我也知道自己曾经做过一些不好的事情,有些到今天我还没能说对不起,但那些人那些事我都一直记得。我也在这些年不断地反思,看到了自己的自私冲动,自以为是,我大概不是什么好人。同样我也真的很感激,大家都对我真的真的真的太好了,尽管我并不太喜欢这个世界,我也真的希望有一天我真的能做点什么能帮到他们,包括那些对不起的人和事,我认为说一句抱歉太弱了,不如哪天真的能帮到点什么。其实不是完全做自己想做的事情才快活,而是去做自己心中认为正确的事情,即使有些事情他会背离你的意愿和理想,浪费你的时间,突然好像找到了自己没能更进一步的一个重要原因呢。但我还是想告诉自己,请永远不要忘记自己是如何受人恩惠,才走到今天的。

不过关于未来想太多也没用,人的想法总是一直在改变,或许再经历一些事情又不一样了,放弃和坚持都是很需要勇气的,对每个人都是。梦里说露西亚最后死在了我的怀里,阿呆蛙找遍地球也没能找到奇迹四叶草。真是可笑,明明都这么虚无了,却还是想为这个世界做点什么。我这该死的魔羯啊,总是天真地,贪婪地,死死抓住理想和现实都不放手,义无反顾地走向深渊,开拓着自己的道。希望在这个时代望着星空做春秋大梦的人,都能拥有那一份英雄主义的勇气,才智,以及幸福

]]>
+ + + + + + <h2 id="Forward"><a href="#Forward" class="headerlink" title="Forward"></a>Forward</h2><p><strong>“Never Stop Thinking”,永远不要停止思考</strong>。很< + + + + + + + + +
+ + + Dynamicgo 支持 Protobuf 动态反射 + + https://jackyin.space/2023/12/27/Dynamicgo-%E6%94%AF%E6%8C%81-Protobuf-%E5%8A%A8%E6%80%81%E5%8F%8D%E5%B0%84/ + 2023-12-27T08:57:00.000Z + 2024-10-09T08:43:45.180Z + + 背景

Dynamicgo 是字节跳动自研的高性能 Golang RPC 编解码基础库,能在动态处理 RPC 数据(不依赖代码生成)的同时保证高性能,主要用于实现高性能 RPC 动态代理场景(见 dynamicgo 介绍)。
Protobuf 是一种跨平台、可扩展的序列化数据传输协议,该协议序列化压缩特性使其具有优秀的传输速率,在常规静态 RPC 微服务场景中已经得到了广泛的应用。但是对于上述特殊的动态代理场景,我们调研发现目前业界主流的 Protobuf 协议基础库并不能满足我们的需求:

  • google.golang.org/protobuf:Protobuf 官方源码支持协议转换和字段动态反射。实现过程依赖于反射完整的中间结构体 Message 对象来进行管理,使用过程中带来了很多不必要字段的数据性能开销,并且在处理多层嵌套数据时操作较为复杂,不支持内存字符串 io 流 IDL 解析。
  • github.com/jhump/protoreflect:Protobuf 动态反射第三方库可支持文件和内存字符串 io 流 IDL 解析,适合频繁泛化调用,协议转换过程与官方源码一致,均未实现 inplace 转换,且内部实现存在Go版本兼容性问题。
  • github.com/cloudwego/fastpb:Protobuf 快速序列化第三方库,通过静态代码方式读写消息结构体,不支持协议转换和动态 IDL 解析。
    因此如何设计自研一个功能完备、高性能、可扩展的 Protobuf 协议动态代理基础库是十分有必要的。
    @khan-yin@iStitches两位同学经过对 Protobuf 协议源码机制的深入学习,设计了高性能 Protobuf 协议动态泛化调用链路,能满足绝大多数 Protobuf 动态代理场景,并且性能优于官方实现,目前 PR#37 已经合入代码仓库。

    Protobuf 设计思想

    由于 Protobuf 协议编码格式细节较为复杂,在介绍链路设计之前我们有必要先了解一下 Protobuf 协议的设计思想,后续的各项设计都将在严格遵守该协议规范的基础上进行改进。

官方源码链路思想

Protobuf 源码链路过程主要涉及三类数据类型之间的转换,以 Message 对象进行管理,自定义 Value 类实现反射和底层存储,用 Message 对象能有效地进行管理和迁移,但也带来了许多反射和序列化开销。

Protobuf编码格式

Protobuf 编码字段格式大体上遵循 TLV(Tag,Length,Value) 的结构,但针对具体的类型存在一些编码差异,这里我们将较为全面的给出常见类型的编码模式。

Message Field

Protobuf 的接口必定包裹在一个 Message 类型下,因此无论是 request 还是 response 最终都会包裹成一个 Message 对象,那么 Field 则是 Message 的一个基本单元,任何类型的字段都遵循这样的 TLV 结构:

  • Tag 由字段编号 Field_number 和 wiretype 两部分决定,对位运算后的结果进行 varint 压缩,得到压缩后的字节数组作为字段的 Tag。
  • wiretype 的值则表示的是 value 部分的编码方式,可以帮助我们清楚如何对 value 的读取和写入。到目前为止,wiretype只有 VarintType,Fixed32Type,Fixed64Type,BytesType 四类编码方式。其中VarintType 类型会被压缩后再编码,属于 Fixed32Type 和 Fixed64Typ 固定长度类型则分别占用4字节和8字节,而属于不定长编码类型 BytesType 的则会编码计算 value 部分的 ByteLen 再拼接 value 。
  • ByteLen 用于编码表示 value 部分所占的字节长度,同样我们的 bytelen 的值也是经过 varint 压缩后得到的,但bytelen并不是每个字段都会带有,只有不定长编码类型 BytesType 才会编码 bytelen 。ByteLen 由于其不定长特性,计算过程在序列化过程中是需要先预先分配空间,记录位置,等写完内部字段以后再回过头来填充。
  • Value 部分是根据 wiretype 进行对应的编码,字段的 value 可能存在嵌套的 T(L)V 结构,如字段是 Message,Map等情况。

Message

关于 Message 本身的编码是与上面提到的字段编码一致的,也就是说遇到一个 Message 字段时,我们会先编码 Message 字段本身的 Tag 和 bytelen,然后再来逐个编码 Message 里面的每个字段。但需要提醒注意的是,在最外层不存在包裹整个 Message 的 Tag 和 bytelen 前缀,只有每个字段的 TLV 拼接。

List

list字段比较特殊,为了节省存储空间,根据list元素的类型分别采用不同的编码模式。

  • Packed List Mode
    如果list的元素本身属于 VarintType/Fixed32Type/Fixed64Type 编码格式,那么将采用 packed 模式编码整个 List ,在这种模式下的 list 是有 bytelen 的。Protobuf3 默认对这些类型启用 packed。

  • UnPacked List Mode
    当 list 元素属于 BytesType 编码格式时,list 将使用 unpacked 模式,直接编码每一个元素的 TLV,这里的 V 可能是嵌套的如List模式,那么 unpacked 模式下所有元素的 tag 都是相同的,list 字段的结束标志为与下一个 TLV 字段编码不同或者到达 buf 末尾。

Map

Map 编码模式与 unpacked list 相同,根据官方设计思想,Map 的每个 KV 键值对其实本质上就是一个 Message,固定 key 的 Field_number 是1,value 的 Field_number 是2,那么 Map 的编码模式就和 List<Message> 一致了。

源码 Descriptor 细节

这里主要介绍一下源码的 descriptor 设计上的一些需要注意的细节。

  • Service 接口由 ServiceDescriptor 来描述,ServiceDescriptor 当中可以拿到每个 rpc 函数的 MethodDescriptor。
  • MethodDescriptor 中 Input() 和 output() 两个函数返回值均为 MessageDescriptor 分别表示 request 和 response 。
  • MessageDescriptor 专门用来描述一个 Message 对象(也可能是一个 MapEntry ),可以通过 Fields() 找到每个字段的 FieldDescriptor 。
  • FieldDescriptor 则兼容所有类型的描述。

动态反射

针对 Protobuf 的反射使用场景,我们归纳出以下需求:

  • 具有完整的结构自描述和具体类型反射功能,兼容 scalar 类型以及复杂嵌套的 MESSAGE/LIST/MAP 结构。
  • 支持字节流模式下的对任意局部进行动态数据修改与遍历。
  • 保证数据可并发读。
    这里我们借助 Go reflect 的设计思想,把通过 IDL 解析得到的准静态类型描述(只需跟随 IDL 更新一次)TypeDescriptor 和 原始数据单元 Node 打包成一个完全自描述的结构—— Value,提供一套完整的反射 API。

IDL 静态文件 parse 过程:
为了提供文件流和内存字符串 io 流的 idl 文件解析,同时保证保证 go 版本兼容性,我们利用protoreflect@v1.8.2解析结果完成按需构造。从实现原理上来看,与高版本 protoreflect 利用protocompile对原始链路再 make 出源码的 warp 版本一致,更好的实现或许是处理利用 protoreflect 中的 ast 语法树构造。

Descriptor设计

Descriptor 的设计原理基本尽可能与源码保持一致,但为了更好的自反射性,我们抽象了一个 TypeDescriptor 来表示更细粒度的类型。

FieldDescriptor

type FieldDescriptor struct {
kind ProtoKind // the same value with protobuf descriptor
id FieldNumber
name string
jsonName string
typ *TypeDescriptor
}
  • FieldDescriptor: 设计上希望变量和函数作用与源码 FieldDescriptor 基本一致,增加*TypeDescriptor可以更细粒度的反应类型以及对 FieldDescriptor 的 API 实现。
  • kind:与源码 kind 功能一致,LIST 情况下 kind 是列表元素的 kind 类型,MAP 和 MESSAGE 情况下都为 messagekind。

TypeDescriptor

type TypeDescriptor struct {
baseId FieldNumber // for LIST/MAP to write field tag by baseId
typ Type
name string
key *TypeDescriptor
elem *TypeDescriptor
msg *MessageDescriptor // for message, list+message element and map key-value entry
}
  • baseId:因为对于 LIST/MAP 类型的编码特殊性,如在 unpack 模式下,每一个元素都需要编写 Tag,我们必须在构造时针对 LIST/MAP 提供 fieldnumber,来保证读取和写入的自反射性。
  • msg:这里的 msg 不是仅 Message 类型独有,主要是方便 J2P 部分对于 List 和裁剪场景中 map 获取可能存在 value 内部字段缺失的 MapEntry 的 MassageDescriptor(在源码的设计理念当中 MAP 的元素被认为是一个含有 key 和 value 两个字段的 message )的时候能直接利用 TypeDescriptor 进入下一层嵌套。
  • typ:这里的 Type 是对源码的 FieldDescriptor 更细粒度的表示,即对 LIST/MAP 做了单独定义

MessageDescriptor

type MessageDescriptor struct {
baseId FieldNumber
name string
ids FieldNumberMap // store by tire tree
names FieldNameMap // store name and jsonName for FieldDescriptor
}
  • MessageDescriptor: 利用 Tire 树结构实现更高性能的字段 id 和字段 name 的存储和查找。

数据存储设计

从协议本身的 TLV 嵌套思想出发,我们利用字节流的编码格式,建立健壮的自反射性结构体处理任意类型的解析。

Node结构

type Node struct {
t proto.Type // node type
et proto.Type // for map value or list element type
kt proto.Type // for map key type
v unsafe.Pointer
l int // ptr len
size int // only for MAP/LIST element counts
}

具体的存储规则如下:

  • 基本类型 Node 表示:指针 v 的起始位置不包含 tag,指向 (L)V,t = 具体类型。
  • MESSAGE 类型:指针 v 的起始位置不包含 tag,指向 (L)V,如果是 root 节点,那么 v 的起始位置本身没有前缀的 L,直接指向了 V 即第一个字段的 tag 上,而其余子结构体都包含前缀 L。
  • LIST类型:为了兼容 List 的两种模式和自反射的完整性,我们必须包含 list 的完整片段和 tag。因此 List 类型的节点,v 指向 list 的 tag 上,即如果是 packed 模式就是 list 的 tag 上,如果是 unpacked 则在第一个元素的 tag 上。
  • MAP类型:Map 的指针 v 也指向了第一个 pair 的 tag 位置。
  • UNKNOWN类型Node表示:无法解析的合理字段,Node 会将 TLV 完整存储,多个相同字段 Id 的会存到同一节点,缺点是内部的子节点无法构建,同官方源码unknownFields原理一致。
  • ERROR类型Node表示:在 setnotfound 中,若片段设计与上述规则一致则可正确构造插入节点。

虽然 MAP/LIST 的父级 Node 存储有些变化,但是其子元素节点都是基本类型 / MESSAGE,所以叶子节点存储格式都是基本的 (L)V,这也便于序列化和数据基本单位的原子操作。

Value结构

value 的结构本身是对 Node 的封装,将 Node 与相应的 descriptor 封装起来,但不同于 thrift,在 Protobuf 当中由于片段无法完全自解析出具体类型,之后的涉及到具体编码的部分操作不能脱离 descriptor,部分 API 实现只能 Value 类作为调用单位。

type Value struct {
Node
Desc *proto.TypeDescriptor
IsRoot bool
}

由于从 rpc 接口解析后我们直接得到了对应的 TypeDescriptor,再加上 root 节点本身没有前缀TL的独特编码结构,我们通过设置IsRoot标记来区分 root 节点和其余节点,实现 Value 结构的 Descriptor 统一。

数据编排

不同于源码 Message 对象数据动态管理的思想,我们设计了更高效的动态管理方式。我们借助 DOM (Document Object Model)思想,将原始字节流数据层层包裹的结构,抽象成多层嵌套的 BTree 结构,实现对数据的定位,切分,裁剪等操作的 inplace 处理。

Path与PathNode

为了准确描述 DOM 中数据节点之间的嵌套关系,我们设计了 Path 结构,在 Path 的基础上,我们组合对应的数据单元 Node,然后再通过一个 Next 数组动态存储子节点,便可以组装成一个类似于 BTree 的泛型单元结构。

// Path represents the relative position of a sub node in a complex parent node
type Path struct {
t PathType // 类似div标签的类型,用来区分field,map,list元素,帮助判定父级嵌套属于什么类型结构
v unsafe.Pointer // PathStrKey, PathFieldName类型,存储的是Key/FieldName的字符串指针
l int
// PathIndex类型,表示LIST的下标
// PathIntKey类型,表示MAPKey的数值
// PathFieldId类型,表示字段的id
}

pathes []Path : 合理正确的Path数组,可以定位到嵌套复杂类型里具体的key/index的位置


type PathNode struct {
Path // DOM tree中用于定位当前Node的位置,并包含FieldId/FieldName/Key/index信息
Node // 存储了复杂嵌套关系中该位置对应的具体bytes片段
Next []PathNode // 下层嵌套的Node节点,基本类型下层Next为空
}

构建DOM Tree

构建 DOM 支持懒加载和全加载,在懒加载模式下 LIST/MAP 的 Node 当中 size 不会同步计算,而全加载在构造叶子节点的同时顺便更新了 size,构造后的节点都将遵循上述存储规则,具有自反射性和结构完整性。

查找字段

支持任意Node查找,查找函数设计了三个外部API:GetByPath,GetByPathWithAddress,GetMany。

  • GetByPath:返回查找出来的 Value ,查找失败返回 ERROR 类型的节点。
  • GetByPathWithAddress:返回Value和当前调用节点到查找节点过程中每个 Path 嵌套层的 tag 位置的偏移量。 []address[]Path 个数对应,若调用节点为 root 节点,那么可记录到 buf 首地址的偏移量。
  • GetMany:传入当前嵌套层下合理的 []PathNode 的 Path 部分,直接返回构造出来多个 Node,得到完整的[]PathNode,可继续用于 MarshalMany

设计思路:
查找过程是根据传入的 []Path 来循环遍历查找每一层 Path 嵌套里面对应的位置,根据嵌套的 Path 类型(fieldId,mapKey,listIndex),调用对应的 search 函数。不同于源码翻译思路,由于 Node 的自反射性设计,我们可以直接实现字节流定位,无需依赖 Descriptor 查找,并跳过不必要的字段翻译。构造最终返回的 Node 时,根据具体类型看是否需要去除 tag 即可,返回的 []address 刚好在 search 过程中完成了每一层 Path 的 tag 偏移量记录。

动态插入/删除

新增数据思想采用尾插法,保证 pack/unpack 数据的统一性,完成插入操作后需要更新嵌套层 bytelen。

  • SetByPath:只支持 root 节点调用,保证 UpdateByLen 更新的完整和正确性。
  • SetMany:可支持局部节点插入。
  • UnsetByPath:只支持 root 节点调用,思想同插入字段,即找到对应的片段后直接将片段置空,然后更新updatebytelen。

Updatebytelen细节:

  • 计算插入完成后新的长度与原长度的差值,存下当前片段增加或者减少的diffLen。
  • 从里向外逐步更新 []Path 数组中存在 bytelen 的嵌套层(只有packed list和message)的 bytelen 字节数组。
  • 更新规则:先 readTag,然后再 readLength,得到解 varint 压缩后的具体 bytelen 数值,计算 newlen = bytelen + diffLen,计算 newbytelen 压缩后的字节长度与原 bytelen 长度的差值 sublen,并累计diffLen += sublen。
  • 指针向前移动到下一个 path 和 address。

DOM序列化

  • Marshal:建好 PathNode 后,可遍历拼接 DOM 的所有叶子节点片段,Tag 部分会通过 Path 类型和 Node 类型进行补全,bytelen 根据实际遍历节点进行更新。
  • MarshalTo:针对数据裁剪场景,该设计方案具有很好的扩展性,可直接比对新旧 descriptor 中共有的字段 id,对字节流一次性拼接写入,无需依赖中间结构体,可支持多层嵌套字段缺失以及 LIST/MAP 内部元素字段缺失。

协议转换

ProtoBuf——>JSON

Protobuf->JSON 协议转换的过程可以理解为逐字节解析 ProtoBuf,并结合 Descriptor 类型编码为 JSON 到输出字节流,整个过程是 in-place 进行的,并且结合内存池技术,仅需为输出字节流分配一次内存即可。

ProtoBuf——>JSON 的转换过程如下:

  1. 根据输入的 Descriptor 指针类型区分,若为 Singular(string/number/bool/Enum) 类型,跳转到第5步开始编码;
  2. 按照 Message([Tag] [Length] [TLV][TLV][TLV]….)编码格式对输入字节流执行 varint解码,将Tag解析为 fieldId(字段ID)、wireType(字段wiretype类型);
  3. 根据第2步解析的 fieldId 确定字段 FieldDescriptor,并编码字段名 key 作为 jsonKey 到输出字节流;
  4. 根据 FieldDescriptor 确定字段类型(Singular/Message/List/Map),选择不同编码方法编码 jsonValue 到输出字节流;
  5. 如果是 Singular 类型,直接编码到输出字节流;
  6. 其它类型递归处理内部元素,确定子元素 Singular 类型进行编码,写入输出字节流中;
  7. 及时输入字节流读取位置和输出字节流写入位置,跳回2循环处理,直到读完输入字节流。

JSON——>ProtoBuf

协议转换过程中借助 JSON 状态机原理和 sonic 思想,设计 UserNodeStack 实现了接口 Onxxx(OnBool、OnString、OnInt64….)方法达到编码 ProtoBuf 的目标,实现 in-place 遍历 JSON 转换。

VisitorUserNode 结构

因为在编码 Protobuf 格式的 Mesage/UnpackedList/Map 类型时需要对字段总长度回写,并且在解析复杂类型(Message/Map/List)的子元素时需要依赖复杂类型 Descriptor 来获取子元素 Descriptor,所以需要 VisitorUserNode 结构来保存解析 json 时的中间数据。

type VisitorUserNode struct {
stk []VisitorUserNodeStack
sp uint8
p *binary.BinaryProtocol
globalFieldDesc *proto.FieldDescriptor
}
  • stk:记录解析时中间变量的栈结构,在解析 Message 类型时记录 MessageDescriptor、PrefixLen;在解析 Map 类型时记录 FieldDescriptor、PairPrefixLen;在解析 List 类型时记录 FieldDescriptor、PrefixListLen;
  • sp:当前所处栈的层级;
  • p:输出字节流;
  • globalFieldDesc:每当解析完 MessageField 的 jsonKey 值,保存该字段 Descriptor 值;

VisitorUserNodeStack 结构

记录解析时字段 Descriptor、回写长度的起始地址 PrefixLenPos 的栈结构。

type VisitorUserNodeStack struct {
typ uint8
state visitorUserNodeState
}
  • typ:当前字段的类型,取值有对象类型(objStkType)、数组类型(arrStkType)、哈希类型(mapStkType);
  • state:存储详细的数据值;

visitorUserNodeState 结构

type visitorUserNodeState struct {
msgDesc *proto.MessageDescriptor
fieldDesc *proto.FieldDescriptor
lenPos int
}
  • msgDesc:记录 root 层的动态类型描述 MessageDescriptor;
  • fieldDesc:记录父级元素(Message/Map/List)的动态类型描述 FieldDescriptor;
  • lenPos:记录需要回写 PrefixLen 的位置;

协议转换过程

JSON——>ProtoBuf 的转换过程如下:

  1. 从输入字节流中读取一个 json 值,并判断其具体类型(object/array/string/float/int/bool/null);
  2. 如果是 object 类型,可能对应 ProtoBuf MapType/MessageType,sonic 会按照 OnObjectBegin()->OnObjectKey()->decodeValue()... 顺序处理输入字节流
  • OnObjectBegin()阶段解析具体的动态类型描述 FieldDescriptor 并压栈;
  • OnObjectKey() 阶段解析 jsonKey 并以 ProtoBuf 格式编码 Tag、Length 到输出字节流;
  • decodeValue()阶段递归解析子元素并以 ProtoBuf 格式编码 Value 部分到输出字节流,若子类型为复杂类型(Message/Map),会递归执行第 2 步;若子类型为复杂类型(List),会递归执行第 3 步。
  1. 如果是 array 类型,对应 ProtoBuf PackedList/UnpackedList,sonic 会按照 OnObjectBegin()->OnObjectKey()->OnArrayBegin()->decodeValue()->OnArrayEnd()... 顺序处理输入字节流
  • OnObjectBegin()阶段处理解析 List 字段对应动态类型描述 FieldDescriptor 并压栈;
  • OnObjectKey()阶段解析 List 下子元素的动态类型描述 FieldDescriptor 并压栈;
  • OnArrayBegin()阶段将 PackedList 类型的 Tag、Length 编码到输出字节流;
  • decodeValue()阶段循环处理子元素,按照子元素类型编码到输出流,若子元素为复杂类型(Message),会跳转到第 2 步递归执行。
  1. 在结束处理某字段数据后执行 onValueEnd()、OnArrayEnd()、OnObjectEnd(),获取栈顶 lenPos 数据,对字段长度部分回写并退栈。
  2. 更新输入和输出字节流位置,跳回第 1 步循环处理,直到处理完输入流数据。

性能测试

构造与 Thrift 性能测试基本相同的baseline.proto 文件,定义了对应的简单( Small )、复杂( Medium )、简单缺失( SmallPartial )、复杂缺失( MediumPartial ) 两个对应子集,并用 kitex 命令生成了对应的 baseline.pb.go 。 主要与 Protobuf-Go 官方源码进行比较,部分测试与 kitex-fast 也进行了比较,测试环境如下:

  • OS:Windows 11 Pro Version 23H2
  • GOARCH: amd64
  • CPU: 11th Gen Intel(R) Core(TM) i5-1135G7 @ 2.40GHz
  • Go VERSION:1.20.5

反射

  • 图中列举了 DOM 常用操作的性能,测试细节与 thrift 相同。
  • MarshalTo 方法:相比 ProtobufGo 提升随着数据规模的增大趋势越明显,ns/op 开销约为源码方法的0.29 ~ 0.32。

字段Get/Set定量测试

  • factor 用于修改从上到下扫描 proto 文件字段获取比率。
  • 定量测试比较方法是 ProtobufGo 的 dynamicpb 模块和 DynamicGo 的 Get/SetByPath,SetMany,测试对象是medium data 的情况。
  • Set/Get 字段定量测试结果均优于 ProtobufGo,且在获取字段越稀疏的情况下性能加速越明显。
  • Setmany 性能加速更明显,在 100% 字段下 ns/op 开销约为 0.11。

序列化/反序列

  • 序列化在 small 规模略高于 ProtobufGo,medium 规模的数据上性能优势更明显,ns/op 开销约为源码的0.54 ~ 0.84。
  • 反序列化在 reuse 模式下,small 规模略高于 ProtobufGo,在 medium 规模数据上性能优势更明显,ns/op 开销约为源码的0.44 ~ 0.47,随数据规模增大性能优势增加。

协议转换

  • Json2Protobuf 优于 ProtobufGo,ns/op 性能开销约为源码的0.21 ~ 0.89,随着数据量规模增大优势增加。
  • Protobuf2Json 性能明显优于 ProtobufGo,ns/op 开销约为源码的0.13 ~ 0.21,而相比 Kitex,ns/op 约为Sonic+Kitex 的0.40 ~ 0.92,随着数据量规模增大优势增加。

应用与展望

目前 dynamicgo 对于 Protobuf 协议的可支持的功能包括:

  • 替代官方源码的 JSON 协议转换,实现更高性能的 HTTP<>PB 动态网关
  • 支持 IDL 内存字符串动态解析和数据泛化调用,可辅助 Kitex 提升 Protobuf 泛化调用模块性能。
  • 支持动态数据裁剪、聚合等 DSL 场景,实现高性能 PB BFF 网关。

目前 dynamicgo 还在迭代中,接下来的工作包括:

  1. 支持 Protobuf 特殊字段,如 Enum,Oneof 等;
  2. 对于 Protobuf 协议转换提供 Http-Mapping 的扩展和支持;
  3. 继续扩展优化多种协议之间的泛化调用过程,集成到 Kitex 泛化调用模块中;

也欢迎感兴趣的个人或团队参与进来,共同开发!

代码仓库:https://github.com/cloudwego/dynamicgo
本文作者:尹可汗,徐健猇、段仪 | 来自:官方微信推文

]]>
+ + + + <h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>Dynamicgo 是字节跳动自研的高性能 Golang RPC 编解码基础库,能在动态处理 RPC 数据(不依赖代码生成)的同时保证高性能,主要用于实现高性能 RPC 动态代理场景(见 <a href="https://mp.weixin.qq.com/s/KPfD5qp70uup6_ZI9UdYww" target="_blank" rel="noopener">dynamicgo 介绍</a>)。<br>Protobuf 是一种跨平台、可扩展的序列化数据传输协议,该协议序列化压缩特性使其具有优秀的传输速率,在常规静态 RPC 微服务场景中已经得到了广泛的应用。但是对于上述特殊的动态代理场景,我们调研发现目前业界主流的 Protobuf 协议基础库并不能满足我们的需求:</p> +<ul> +<li><a href="https://github.com/protocolbuffers/protobuf-go" target="_blank" rel="noopener">google.golang.org/protobuf</a>:Protobuf 官方源码支持协议转换和字段动态反射。实现过程依赖于反射完整的中间结构体 Message 对象来进行管理,使用过程中带来了很多不必要字段的数据性能开销,并且在处理多层嵌套数据时操作较为复杂,不支持内存字符串 io 流 IDL 解析。</li> +<li><a href="https://github.com/jhump/protoreflect" target="_blank" rel="noopener">github.com/jhump/protoreflect</a>:Protobuf 动态反射第三方库可支持文件和内存字符串 io 流 IDL 解析,适合频繁泛化调用,协议转换过程与官方源码一致,均未实现 inplace 转换,且内部实现存在Go版本兼容性问题。</li> +<li><a href="https://github.com/cloudwego/fastpb" target="_blank" rel="noopener">github.com/cloudwego/fastpb</a>:Protobuf 快速序列化第三方库,通过静态代码方式读写消息结构体,不支持协议转换和动态 IDL 解析。<br>因此如何设计自研一个功能完备、高性能、可扩展的 Protobuf 协议动态代理基础库是十分有必要的。<br><a href="https://github.com/khan-yin" target="_blank" rel="noopener">@khan-yin</a>和<a href="https://github.com/iStitches" target="_blank" rel="noopener">@iStitches</a>两位同学经过对 Protobuf 协议源码机制的深入学习,设计了高性能 Protobuf 协议动态泛化调用链路,能满足绝大多数 Protobuf 动态代理场景,并且性能优于官方实现,目前 PR<a href="https://github.com/cloudwego/dynamicgo/pull/37" target="_blank" rel="noopener">#37</a> 已经合入代码仓库。</li></ul> + + + + + + + +
+ + + 既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子 + + https://jackyin.space/2022/03/31/%E6%97%A2%E5%BE%80%E4%B8%8D%E6%81%8B%EF%BC%8C%E7%BA%B5%E6%83%85%E5%90%91%E5%89%8D%EF%BC%8C%E6%B1%9F%E6%B9%96%E5%86%8D%E8%A7%81%E2%80%94%E2%80%9422%E5%B2%81%E9%82%A3%E5%B9%B4%EF%BC%8C%E5%9C%A8%E5%8C%97%E4%BA%AC%E7%9A%84%E6%97%A5%E5%AD%90/ + 2022-03-30T16:41:32.000Z + 2024-10-09T08:43:45.316Z + + 既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子

2022年3月31日0:52,睡不着,日常拖延症+强迫症导致清东西到现在,等会还想清扫一下弄脏的地板。

莲竹花园甲2号楼一门101,从今天起,这里将不再是我的家,本来是昨天的机票,天气不似预期,不打算买高铁,还想再飞上一次云霄,所以倔强的又改签了机票,不过正好也让我多看一眼这里吧,最近东航事件其实让我也有一点小慌,希望能平安到达吧。

不出所料,我对这个城市并没有什么留恋,每天晚上我都会思考很多,有天夜里我的脑海里突然冒出来了那句:劝君更进一杯酒,西出阳关无故人。 这一刻我才真正明白什么是独在异乡为异客的感觉,什么才是我心里最想要的。

从南山南到北海北

作为一个一直生活在南方的人,第一次在北京生活,拥挤的早晚高峰,寒风和冰雪的夜晚,疫情形势也不断变化,恰逢过年,回家的日子也迟迟不敢定下来,奇怪,你可能会好奇,在大厂工作我竟然并没有提到工作的压力,仔细想来,其实美团的作息是相对舒服的10-8-5,尽管工作和技术基础我有许多不足,但mentor比较照顾我,不会刻意去push进度,更多的是希望让我自己去探索和思考,所以更多的工作压力还是来自于我自己一贯所坚持的负责和标准。这是一件好事,说明我做事情有自己的原则和态度,但有时候也会让自己比较心累,毕竟作为一个新人,从0-1去启动项目,虽然我是个自信的人,即使遇到问题也会尽可能自己去想办法,但我也深知自己的代码习惯和知识结构存在很多不足,害怕的不是做不好做不成,而是做事的效率和维护性,其实这也是我应该要从这些前辈身上要学到的经验。

年前一周,我申请了远程实习提前坐飞机回家了,到家的一刻才明白,这种人间烟火气才真的是生活,说来有愧,从回家到过年收假的时间,工作上我确实有点摆烂了哈哈哈,我知道这应该最后一个这么长时间的寒假了,经过将近1个月的在外实习也格外体会到了这种归家的温暖,去学一学切菜炒菜,陪一陪老年人,约一场球,见想见的人,街头漫步,吃点臭干子,米粉,麻辣烫,和朋友分享一些见闻,借酒消愁,确实愁更愁。

时间很快,大年初五的下午,我就启程返工了,毕竟现在的身份是打工人而不是大学生。和我一同去北京的还有广平,也在美团,我们都不打算实习很久,刚好我房子够住2个人,就一起住了一个月,不得不说多了一个人生活确实没有这么孤单了,尽管工作和拥挤依旧麻烦,但至少回家轻松快活一些,虽然有时候会有一些赌气和争吵,睡眠问题,但不管怎么说,互相都分担了一些对未来的焦虑和思考,一块出去玩,打游戏开黑,去什刹海,天安门,吃各种小吃,也算是度过一段不那么枯燥的时间。

在实习的这段日子里,最大的一个体会就是要学会如何平衡生活与工作,这个问题也是以后一定会要去面对的。也许是第一次实习,虽然不算很难的任务,但因为自己很多基础,技术,学习方法都还不够到位,上手项目和方向也不了解,所以效率上比较低,也许是拖延症,情绪化,该完成的任务没能及时完成,答应朋友的事情,也常常会忘记,衣服也有时候会拖着没洗,又或许是自己的性格本来就有些内向,在偏严肃的职场氛围下比起在学校,自己显得有些不自然,自己整个人的状态和生活界限变得模糊起来,当一个人进入这样的状态的时候,会发觉整个人比较迷茫,做事情专注度不够,热情也会逐渐消失。

在3月底,我决定从公司离职,一方面是想好好享受一下最后的大学时光,另一方面是想留出一段空白期,让自己再去学一学自己想学的内容,不得不说回归自由的感觉真的让人十分快乐,从公司买了好些纪念品,在最后几天,去见一见同学,逛一逛北京的大学,中关村,终于要飞走了,这段旅程终于要结束了,但接下来的未来好像还是看不清。

执念

看到执念这个词,这里我说一句大胆的话,在我未来的5-8年时间里,若我能成功,一定是因为心中的执念,若我输得一败涂地,也一定是因为那执念。

说来嘲讽,回想起来从小到大,我好像一直被这种执念所影响,也因为自己的固执,失去了各种各样的机会,但是我却很难改变,除了我这辈子认定的人以外,我几乎听不进去其他人的话,而且越是被人否定,越是想要证明自己的能力,我也不知道这是一种多么要强的心理,就好像明知道是火坑,也觉得自己跟别人不一样,能跨过去,然而事实大多是自己被烧得满身伤痕,甚至还在那叫嚣着他们不敢跳。

我的性格大家也知道,带有棱角,有个性,孤傲却又内向自卑,坚忍,舍得努力,看似矛盾,其实说白了也就是不太谦虚,爱吹吹牛逼,但却不是耍嘴皮子,对自己还是很负责的,但是这样也经常惹来一些麻烦,不合群,自作主张,在乎得失,也是我如此固执的原因之一。

随着年龄增大,我突然发现每一次选择的人生代价越来越大,自己的眼界和思想局限性也越来越明显,也许是从小就不爱看书(现在想看书却没多少时间,也很难静下心来)以及身处的环境的原因,思想成熟得很慢,自大,考虑问题过于天真,没能及时跟上时代,时而觉得一切皆有可能,时而又觉得一切皆是虚妄。去年的时候,我还觉得自己年轻,有无限可能,直到保研结束以后,我才恍然明白,其实我从18岁那年的夏天开始,就已经不再年轻,尽管我是在努力的朝改善未来的方向走,往后的岁月每一次决定都是那么矛盾,迷茫,自卑,妥协,后悔。

后悔,我总是做事情让自己有多个选择留有退路,但似乎给自己留选择本质上就是一种后悔,当你没能选到最理想的选择时,自然就会后悔吧。

2024.06.02 更新

哈哈哈哈最近难得休闲几天,看到以前写的这些,看问题角度加上当时的个人情绪驱使文案还是略显年轻了,回过头来看其实无所谓后悔不后悔的,已经把这里标题的后悔去掉了,我一贯以来的行为准则就是对自己的选择负责,不论是什么样的未来,勇敢且不要停止思考,相信自己的光就好,这不仅仅会给自己能量也一定会给他人的生命带来光亮。

]]>
+ + + + <h2 id="既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子"><a href="#既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子" class="headerlink" title="既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子"></a>既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子</h2><p>2022年3月31日0:52,睡不着,日常拖延症+强迫症导致清东西到现在,等会还想清扫一下弄脏的地板。</p> +<p><strong>莲竹花园甲2号楼一门101,从今天起,这里将不再是我的家</strong>,本来是昨天的机票,天气不似预期,不打算买高铁,还想再飞上一次云霄,所以倔强的又改签了机票,不过正好也让我多看一眼这里吧,最近东航事件其实让我也有一点小慌,希望能平安到达吧。</p> +<p>不出所料,我对这个城市并没有什么留恋,每天晚上我都会思考很多,有天夜里我的脑海里突然冒出来了那句:<strong>劝君更进一杯酒,西出阳关无故人。</strong> 这一刻我才真正明白什么是独在异乡为异客的感觉,什么才是我心里最想要的。</p> + + + + + + + +
+ + + 菜鸡的算法岗日常实习面经总结 + + https://jackyin.space/2022/01/08/%E8%8F%9C%E9%B8%A1%E7%9A%84%E7%AE%97%E6%B3%95%E5%B2%97%E6%97%A5%E5%B8%B8%E5%AE%9E%E4%B9%A0%E9%9D%A2%E7%BB%8F%E6%80%BB%E7%BB%93/ + 2022-01-08T12:06:00.000Z + 2024-10-09T08:43:45.343Z + + 66CC884772E6FB9A1E2BA12BC9E7C9C4.jpg

前言

第一次在掘金写面经,其实今年过得不尽人意,好在能找找实习调整一下心态吧,终于有钱换手机了!要说有什么新年愿望,那就希望2022一切好运吧。 虽然是实习面经但是其实也没怎么准备,随缘,放弃了bat的部门,估计对学历和论文有门槛(尝试性投了深圳字节直接挂简历,我永远喜欢bytedance😭),10月投b站简历挂,旷视面试没过以后就没投了,后面去学车了,结果科目二没过,有点闲看到有朋友也在投,就不抱希望还是投了3家,比较幸运最后拿到了美团和商汤的实习offer,感谢面试官们手下留情🤣。

个人情况:

  • 学校:211 大四
  • 成绩:前5%
  • 项目:3段CV相关项目经历,无论文,两个算法实践工程落地项目,一段kaggle竞赛铜牌,总体上来说都比较水
  • 算法能力:无ACM,比较菜只是比较喜欢刷,leetcode400题(以easy+medium为主,剑指offer+程序员面试经典+每日一题/周赛)

因为感觉自己很菜找不到实习,所以都没找内推,也没有海投,不过好像大多都会给面试机会的,感觉如果能找内推可能会更好一点。没想到最后能去美团当外卖骑手了😁!

旷视

旷视的实习面试是最早的,不过也面试通知也等了好久,hr说有两个面试官mark了我的简历,所以面了两个组,当时是第一次面试,比较紧张,虽然面试问的不难,但是有些地方答的不好,面试问题记不太清了。另一个面试官,我等了半小时结果被他放鸽子了,改天再面的。。。

  • 手写IoU
  • 求三个部分的IoU,根据定义就是求:$\frac{A \cap B \cap C}{A \cup B \cup C} $,只用讲思路,其实就是容斥原理,当时有点紧张,公式最后一项系数写错了一直没看出来,场面一度尴尬。
  • 讲解Focal loss的原理作用
  • 为什么会用到StratifiedKFold,和KFold有什么区别
  • 介绍一下比赛用到的TTACutmix方法(Cutoutmixup的结合,最好三个都讲解一下)
  • 讲讲Resnet(建议读一下论文,从目的,作用,残差结构的形式,反向传播梯度计算,机器学习GBDT思想等角度进行阐述)
  • 目标检测的mAP达到了多少,有没有测过双目测距的精准度,为啥使用wifi和flask推流通信,这样会比较慢(树莓派算力不够,跑着跑着宕机了),小车目标检测的帧数能达到多少fps(emm我们只是做了一个无人清洁车落地的demo,只测了模型目标检测在数据集上的mAP,其他的更多的是我们自己提供一种idea,具体指标没有测试过😥)。
  • 旋转矩阵不能开空间,其实做过但是面试很容易紧张卡住,有想到思路但是没写对有点bug,不过面试官说我思路是对的,面完就发现原来是下标对错了。。。
  • 团队合作交流是如何分工和解决问题的?
  • 其他人或者老师给你任务安排时,如果与你的想法不合时,你会如何做?

手写IoU

import numpy as np

def IoU(bounding_box,ground_truth):
"""

:param bounding_box: [[x1,y1,x2,y2,score]]
:param ground_truth: [x1,y1,x2,y2]
:return:
"""
x1 = bounding_box[:,0]
y1 = bounding_box[:,1]
x2 = bounding_box[:,2]
y2 = bounding_box[:,3]
score = bounding_box[:,4]

areas = (x2-x1) * (y2-y1)
gt_area = (ground_truth[2] - ground_truth[0]) * (ground_truth[3] - ground_truth[1])

xx1 = np.maximum(x1,ground_truth[0])
yy1 = np.maximum(y1,ground_truth[1])
xx2 = np.minimum(x2,ground_truth[2])
yy2 = np.minimum(y2,ground_truth[3])

h = np.maximum(0,yy2-yy1)
w = np.maximum(0,xx2-xx1)

inter = w * h

ovr = inter / (gt_area + areas - inter) # np.true_divide(inter, (gt_area + areas - inter))

return ovr

旋转矩阵

class Solution {
public:
void rotate(vector<vector<int>>& matrix) {
int n = matrix.size();
for(int i=0;i<n/2;i++)
{
for(int j=0;j<(n+1)/2;j++)
{
// (i,j) (j,n-i-1) (n-j-1,i) (n-i-1,n-j-1)
swap(matrix[i][j],matrix[n-i-1][n-j-1]);
swap(matrix[i][j],matrix[n-j-1][i]);
swap(matrix[j][n-i-1],matrix[n-i-1][n-j-1]);
}
}
}
};

小米

小米面试其实是当时最好的选择,因为就在武汉本地,也不用外出,但是当时面试确实不太好,面试官对我其中一个项目比较感兴趣,被疯狂怼着追问细节。

  • 描述项目中用到的SIFT匹配和直方图相似度比对基本原理。
  • one-stage和two-stage的区别。
  • 双目摄像头视觉下应该可以得到整个三维空间下的信息,没考虑方向角度的问题,对测距的处理有些草率(没有很懂,之后再去了解了解,只用到了物理上小孔成像的原理😰
  • 为什么不直接在树莓派上推理,采用推流和主机服务器去进行计算,速度和精度如何
  • 继续追问项目细节。
  • 手写SIFT匹配过程,直接人傻了😭(被面试官怼对传统图像处理了解不深,只会玩玩深度学习搭积木)

美团-智能视觉 offer

美团面试官面试体验比较好,没有过分针对,对待我这种本科生可能相对更看重对我的motivation和potential吧感觉,评价也比较好。

一面

  • 聊项目,做项目的目的和缘由,你觉得有什么亮点。
  • 讲讲one-stage和two-stage的区别。
  • anchor-free的方式比如FCOS有了解吗
  • 看你有用过ViT,能不能讲讲transformer的架构,再讲讲vit是怎么做的,BERT有了解吗,跟vit有什么区别
  • 看你项目经常用到kaiming的东西,kaiming最近新出的MAE有了解吗(虽然面试官看着年龄有点大,不过还挺紧跟潮流的,kaiming yyds!
  • 讲讲SIFT匹配到双目测距的过程和原理
  • 为什么要用树莓派采集图像借助flask推流,再由主机进行模型推理
  • 对GNN和GCN有了解吗
  • 讲讲人脸检测MTCNN是怎么做的
  • 聊美团这边的业务,问我有没有这方面技术的了解
  • 自己出的算法题,以条形码识别为背景,有点像是去除干扰字符的匹配,用双指针解决即可。

二面

  • 聊项目缘由,团队协作。
  • 讲讲transformer,讲讲position encoding的方法,作者用这种三角函数的方式有什么特点,在vit里面是如何做位置编码的。
  • 介绍self-attentiontransfomerencodedecode有什么区别,你对这两部分有什么理解,以及相对于CNN的一些特点。
  • 项目用的数据集有多大。
  • 项目目标检测用的什么指标,达到了什么效果。
  • 聊美团业务,问我有没有兴趣。
  • 出了个hard题扰乱字符串,不会,简单讲了一下dfs暴力的思路但还是没理清楚写不出😭,后面换了个简单点的题不过要求让我用python写

商汤-基础视觉 offer

一面

一面比较简单,面试官也比较和蔼。

  • 自己出的题,二维矩阵找最长的严格单调上升的一个连续序列(可以跨行转弯,对角线不算),节点可上下左右移动。先用dfs暴力,然后再用记忆化优化了一下。虽然不难但是写的有点慢。
  • 聊项目。
  • 讲讲Batch Normalization(建议从目的,由来,公式解析,理解操作过程,作用以及使用场景等方面来讲解附博客,看完发现自己面试讲的好烂)
  • 介绍小批量梯度下降
  • 讲讲分布不均衡的数据如何处理(讲了讲数据增强,过采样比如SMOTE,欠采样,调整样本对分类的权重,如FocalLoss,这个我感觉回答的不是很好,希望评论区有更好的理解)
  • 有没有搭建或者使用过单机多卡和多机多卡,是否了解多卡时神经网络的梯度反向传播是如何计算的(没钱没资源🤣,瞎猜了一波可能和计算图的节点资源分配有关)

    二面

    二面其实感觉面试有点糟糕,连问了十几个八股文,做题也出了一些问题,自闭,答也能答出来一些但是整体感觉不好。。。。不过最后比较幸运还是让我过了。
  • 简单介绍自己的项目和自己觉得有亮点的地方
  • 讲讲one-stage和two-stage的区别和特点
  • 什么是RPN,作用是什么
  • 什么是FPN,有什么特点,这种多尺度是怎么实现和进行预测的
  • 讲述yolov3预测目标的过程(比较关键的几个要点我觉得是损失函数,模型输出,非极大抑制,多种变种的IoU,SPP空间金字塔,以及论文中有提到yolov3的anchor是kmeans聚类出来的,可能会让你手写kmeans)
  • 为什么two-stage要比one-stage的精度要高,你觉得本质是什么
  • yolov3的三个特征图大尺寸的用来预测大的图还是小的图
  • anchor-free的方式有了解吗,和anchor-based的差异在哪,本质和原理是什么
  • 介绍一下CenterNet和FCOS,中心度的公式和理论,预测过程
  • 什么是梯度消失和梯度爆炸,如何解决(提到某些要点或者答错了会继续追问,没有答的很全)
  • 进程和线程的区别,python的多线程如何实现
  • maxpool是如何进行反向传播的(建议看看cs231n,首先要明确的是pool层中是没有参数的,然后再来将maxpool,其实我当时也忘了,我记得好像跟maxout的反向传播差不多)
  • 讲讲Batch Normalization,以及在训练和预测过程的计算方式
  • 讲讲dropout,以及在训练和预测过程的计算方式(建议看看cs231n),你觉得和机器学习当中哪种集成方式比较像(这个我不是很清楚希望各位大佬回答一下,当时瞎说了一个boosting🤣)
  • 剑指 Offer 31. 栈的压入、弹出序列 思路大致是对的但是没想得特别清楚,比较紧张,写了很久
  • 剑指 Offer 39. 数组中出现次数超过一半的数字 第二题直接限制时间复杂度$O(n)$,空间复杂度$O(1)$,我只会哈希方法,然后和面试官说了一下最优解方法我只记得叫摩尔投票,然后具体忘了。

栈的压入、弹出序列

class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> stk;
int n = popped.size();
int m = pushed.size();
int j = 0;
for(int i=0;i<m;i++)
{
stk.push(pushed[i]);
while(stk.size()&&stk.top()==popped[j])
{
j++;
stk.pop();
}
}
return stk.empty();
}
};

其他

还有一些感觉比较重要,但是没有被问道的东西,包括各种评价指标的含义等等,包括数学基础等等。
经典教程推荐:cs231n,吴恩达,李宏毅,动手学深度学习,《统计学习方法》
关于八股文方面这里推荐一个DeepLearning-500-questions

手写非极大抑制

使用非极大抑制的前提是,我们已经得到了一组候选框和对应label的置信分数,以及groud truth的信息,通过设定阈值来删除重合度较高的候选框。
算法流程如下:

  • 根据置信度得分进行排序
  • 选择置信度最高的比边界框添加到最终输出列表中,将其从边界框列表中删除
  • 计算所有边界框的面积
  • 计算置信度最高的边界框与其它候选框的IoU。
  • 删除IoU大于阈值的边界框
  • 重复上述过程,直至边界框列表为空。
import numpy as np

def nms(dets, threshod, mode="Union"):
"""
greedily select boxes with high confidence
keep boxes overlap <= thresh
rule out overlap > thresh
:param dets: [[x1, y1, x2, y2 score]]
:param threshod: retain overlap <= thresh
:return: indexes to keep
"""
x1 = dets[:, 0]
y1 = dets[:, 1]
x2 = dets[:, 2]
y2 = dets[:, 3]

scores = dets[:, 4]

areas = (x2 - x1 + 1) * (y2 - y1 + 1)
order = scores.argsort()[::-1] # reverse

keep = []

while order.size() > 0:
i = order[0]
keep.append(i)
# A & B left top position
xx1 = np.maximun(x1[i], x1[order[1, :]])
yy1 = np.maximun(y1[i], y1[order[1, :]])
# A & B right down position
xx2 = np.minimum(x2[i], x2[order[1, :]])
yy2 = np.minimum(y2[i], y2[order[1:]])

w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)

inter = w * h

# cacaulate the IOU between box which have largest score with other boxes
if mode == "Union":
# area[i]: the area of largest score
ovr = inter / (areas[i] + areas[order[1:]] - inter)
elif mode == "Minimum":
ovr = inter / np.minimum(areas[i], areas[order[1:]])
# delete the IoU that higher than threshod
inds = np.where(ovr <= threshod)[0]
order = order[inds + 1] # +1: eliminates the first element in order

return keep

手写Kmeans方法

参考链接:https://www.cnblogs.com/lunge-blog/p/11657415.html

这个版本不是最佳写法,某些处理有点暴力,可以用矩阵和numpy相关的操作会更简洁,但是退出迭代的条件写的很全的,有达到迭代次数,中心点集不变,中心点变化范围小于$\delta$

import numpy as np
import matplotlib.pyplot as plt

n = 100
a = np.random.randn(0,50,n)
b = np.random.rand(0,50,n)
x = np.random.randint(0,50,n)
y = np.random.randint(0,50,n)
points = np.array(list(zip(x,y)))

def distance(x,y):
return np.sqrt(np.sum((x-y)**2))

def k_means(points,k=5,epochs=500,delta=1e-3):
# 初始化聚类中心
center_ids = np.random.randint(0,n,k)
centers = points[center_ids]

# 聚类集合初始化
results = []
for i in range(k):
results.append([])
step = 1
flag = True

# 计算各点到中心的距离
while flag and step < epochs:
# 重新迭代
for i in range(k):
results[i] = []
# 计算每个点到距离中心的距离
for i in range(len(points)):
point = points[i]
min_dis = np.inf
min_id = 0

for idx, center in enumerate(centers):
dis = distance(center,point)
if min_dis > dis:
min_dis = dis
min_id = idx
results[min_id].append(point)

# 更新聚类中心
for idx, old_center in enumerate(centers):
new_center = np.array(results[idx]).mean(axis=0)
if distance(center, new_center) > delta:
centers[idx] = new_center
flag = False

# flag=True说明聚类中心已经不变了则可以退出了
if flag:
break
else:
flag = True
step += 1

return results,centers



plt.plot(x,y,'ro')
results,centers=k_means(points,k=5)
color=['ko','go','bo','yo','co']
for i in range(len(results)):
result=results[i]
plt.plot([res[0] for res in result],[res[1] for res in result],color[i])
plt.plot([res[0] for res in centers],[res[1] for res in centers],'ro')
plt.show()

总结

本人能力有限,如果上述回答有任何错误,还请各位大佬及时指出

  • 不同面试官的面试风格不一样,项目相关的知识积累问的会比较多(项目水没关系但相关技术还是要搞懂),项有的会考察广度和思维潜力,有的会考察基础(八股),算法题感觉并没有那种重要,把剑指offer刷了应该差不多。
  • 关于八股文的看法,其实更多的还是要多理解,一些相关原理和数学还是多看看相关论文和经典课程,到时候也不用刻意记也能按自己的想法说出一点(瞎吹),感觉面试官想要的答案并不一定是你能完整的说出来,而是有自己理解的正确描述(这个可能需要在代码实践和理论知识之间多反复几次体会会比较好)。
  • 代码实践还是要多一些,其实很多东西我了解的并不深入,只是大致理解过原理和思路,这样还是不太好,开始害怕顶不住实习压力了。
  • 不用害怕,尽量多交流,避免场面陷入尴尬。
  • 反问环节我一般问的是来这边的工作内容,学习的建议和评价,培养和安排之类的。

「掘金链接:菜鸡的算法岗日常实习面经总结

]]>
+ + + + <p><img src="/2022/01/08/%E8%8F%9C%E9%B8%A1%E7%9A%84%E7%AE%97%E6%B3%95%E5%B2%97%E6%97%A5%E5%B8%B8%E5%AE%9E%E4%B9%A0%E9%9D%A2%E7%BB%8F%E6%80%BB%E7%BB%93/1.jpg" alt="66CC884772E6FB9A1E2BA12BC9E7C9C4.jpg"></p> +<h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><blockquote> +<p>第一次在掘金写面经,其实今年过得不尽人意,好在能找找实习调整一下心态吧,终于有钱换手机了!<strong>要说有什么新年愿望,那就希望2022一切好运吧。</strong> 虽然是实习面经但是其实也没怎么准备,随缘,放弃了bat的部门,估计对学历和论文有门槛(尝试性投了深圳字节直接挂简历,<strong>我永远喜欢bytedance</strong>😭),10月投b站简历挂,旷视面试没过以后就没投了,后面去学车了,结果科目二没过,有点闲看到有朋友也在投,就不抱希望还是投了3家,比较幸运最后拿到了美团和商汤的实习offer,感谢面试官们手下留情🤣。</p> +</blockquote> + + + + + + + + + +
+ + + 回首向来萧瑟处,归去,也无风雨也无晴|2021年终总结 + + https://jackyin.space/2022/01/08/%E5%9B%9E%E9%A6%96%E5%90%91%E6%9D%A5%E8%90%A7%E7%91%9F%E5%A4%84%EF%BC%8C%E5%BD%92%E5%8E%BB%EF%BC%8C%E4%B9%9F%E6%97%A0%E9%A3%8E%E9%9B%A8%E4%B9%9F%E6%97%A0%E6%99%B4%EF%BD%9C2021%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/ + 2022-01-08T12:04:00.000Z + 2024-10-09T08:43:45.306Z + + 66CC884772E6FB9A1E2BA12BC9E7C9C4.jpg

⏱2021-2022

说来惭愧,没想到在掘金这样神圣的技术社区,我的第一篇文章竟然是与技术无关的年终总结。(主要是想白嫖到周边棒球帽🧢,本来是打算发布已经写好的算法岗实习面经,有兴趣的朋友可以继续看看)

时间总是过的很快,我也是偶然间打开掘金看到的这个活动才意识到今年已经快要过去了,想了很久2021年对我而言到底意味着什么,好像过得很混乱,想的太多,做的太少,以前总是能在不确定性中规划好一些时间,但今年很多事情都是被时间推着走入不确定的维度。

读研or就业的思考

这个问题其实在2年前就有在思考这件事情,虽然学生思维存在着一些局限性,但是你不得不承认这件事情确实是你需要尽早想清楚的事情,话是这么说其实还是当局者迷,旁观者清,尽管有一些我认识的人给过我他们的思考,我自己也没在最需要想清楚的时候想清楚这件事情,可能很多感受只有触碰到结果了才真正明白吧。
这个问题抛出来,我写起来还是不知从何说起,没有正确答案,未来都是未知的,害怕失去现有的一切,凭我的经验来看,还是要多遵从自己的内心,不要完全理性的去权衡利弊,失去如果每个选择都会后悔,就不要选让自己更后悔的那个。还是说一下自己当时思考的几件事情:

  • 读研是为了什么,去企业又是为了什么
  • 对于未来到底想做什么
  • 抛开家长和他人的观点,你对自己的性格和能力是否足够了解,是否足够自信
  • 都是最坏的情况,更能接受哪个选择
  • 如何承受选择带来的代价和自我和解之道

    去黄鹤楼,看樱花

    3月樱花又开了,大一没来得及看樱花,大二由于疫情影响也没能去成,大三正好有朋友过来武汉找我玩,就带着去黄鹤楼,隔壁学校赏樱花,那几天每天晚上和朋友们聊天一整夜,太久没一块说话了吧,我和他约定好考完研再来武汉陪我过生日。
    image.png

    春招面网易

    4月有好友正好在做网易的春招宣传,内推了我一手,抱着涨点面试经验的心态,面了一下网易的算法岗,匆忙改了一版简历,笔试比较简单过了2/3,面试还行但还是没过,后面准备夏令营啥的也没有再投了。

    茶颜悦色&湖南师大&湖南大学

    在湖南呆了这么久,这是第一次喝茶颜悦色,leo点的幽兰拿铁,晚上吃了一顿火锅直接拉肚子到凌晨2点,去了当初高二数学竞赛培训的湖师大,看了看那些当时买礼物的精品店和饭店,后面去了湖南大学找同学吃饭,湖南大学的建筑风格很不错,嘿嘿,不愧是湖大!

    有幸与神三元吃饭

    毕业季,神三元学长也要毕业了,在学校一直听着他的江湖神话,终于有朝一日能见上一面了,迫不及待和朋友一起跑到另一个校区追星。见面一看确实是一表人才,吃饭紧张到有点不知道说话。不过听大佬聊技术趋势和工作思考,还是有很多不一样的体会。

在这里插入图片描述

bytecamp再送人头

去年暑假参加了一次bytecamp的笔试,感觉挺有意思的,虽然当时也没过,今年再参加编程又爆0了,第一题是树形dp模版题,但是我当时忘了,后面两个就更难了不会。

滚滚长江东逝水——再会江滩

暑假放假回家前,去了一次江滩,之前带朋友去的是汉口江滩,这次去武昌江滩看的,也算是两岸都看过了,虽然武汉夏天很热,但是长江的风吹过来还是很舒服的。
image.png

C11027AD58708F01003156F1C1F34870.jpg

魔都体验卡

有幸参加SIST的夏令营,体验了3天公费旅游的感觉,还吃了西餐,和朋友去了上海外滩和金融中心,半夜两点给健哥写前端。听说上海的天空很低!
image.png

image.png

梦碎了

9月差一点点,最后还是没能去到自己最想去的地方,感觉自己的学生时代已经结束了,梦碎了,不展开了,容易晚上emo😭

4年后再来南山区

18年国庆来深圳,只觉得繁华,人上人,4年后再来觉得这里还是缺少了一些文化感和年代感的东西,感谢朋友们的盛情招待,看海没赶上好时候,跟小w发我的照片完全不一样😔,第一次吃椰子鸡,去了SUST看夕阳,感受了朋友在字节跳动的“快乐”生活(我永远喜欢bytedance),遇到了突然其来的台风和大暴雨,沿着大沙河逛THU和PKU

image.png

image.png

image.png

最爱东湖与武大

在武汉,我独爱东湖,这次有幸还坐船浏览了对岸,去了磨山,一路听着粤语歌在东湖漫步,会有很多很多想法。逛完东湖与武大同学小歇畅聊,有幸参观了周恩来闻一多先生的居所,一起吃饭听说他搞家教日薪1k+我羡慕。

image.png

image.png

image.png

image.png

image.png

摆烂的大四软测

大四一学期没听课,软测临时抱佛脚,卷了3年才知道整张试卷瞎写的感觉原来这么爽,还好没挂。

CLANNAD

看了一直没看的CLANNAD,不得不说这个剧表达的东西很深刻,给了我很多生活的思考,我觉得是我心中看过的最好的动漫之一了,以后可以再看一遍,好像要一个团子啊🥺!
image.png

科目二的败北

和朋友天天早出晚归跑去练科目二,到了考场发现自己学的东西都白学了,侧方直接挂,然后倒库紧张又挂了。。。坡上两只狗
image.png

12月所思

12月陷入了一段特别迷茫的时间,他们说我所担心的并不能约束你,只能促进你,不要老是患得患失,后面拿了实习offer后开心了一些,等考研的朋友考完一起舒服了几天,后面的实训课继续摆烂,可惜说好来武汉陪我过生日的同学最后还是没来,那天写实训代码写到1点才睡,不过随着一年又一年,我倒是觉得就当平常日挺好的,也不用刻意去记,能想起来就想起来吧。

回家的所闻所见

纠结了很长时间关于寒假外出实习的事情,最后还是觉得去体验一下比较好,害怕过年回家待不了太久,所以提前跑路回家了几天,比较难受的是遇到了一些不好的事情,还是要常回家看看🙏

啃了一些原理+Leetcode400题

今年感觉自己花在学习上的时间没有特别多,更多的时间被虚无的思考给浪费掉了,除了一些kaggle和工程代码之外,今年做了一些不一样的事情主要就是手推了《统计学习方法》当中一些基本算法,西瓜书也看了一些,leetocde不知不觉突破400题了! 还是很菜,只不过把刷题当成习惯了。
image.png

关于十年后再来北京这件事

今年跨年有些不一样,12.31飞北京跨年,下午处理好了租房的问题,人生地不熟,接下来元旦几天都是被朋友带着玩哈哈哈。

Dr.Pepper & Sky

在旅店晚上喝了一杯命运石之门的Dr.Pepper,有一种穿越时空的味道 上次坐飞机还是10多年前,再一次飞上蓝天还是很激动!
image.png
image.png

清华五道口

十年前曾踏过清华的大门,十年后还是没能跨进你的大门,来生请等我。

单车刷夜去天安门和祖国母亲一起跨年

作为一名预备党员,元旦必然要在天安门通宵等升旗,被北方的寒风给冻傻了,和祖国母亲一起放飞和平鸽!
image.png

image.png

海底捞被朋友抓去过生日

虽然生日过了,但是他们想在北京陪我过一次,店里送了相框,正好一起拍照留作纪念,摆在新家当饰品,第一次在海底捞过生日社死。
在这里插入图片描述

四季民福故宫店北京烤鸭南锣鼓巷中关村中科院

吃了很离谱的豆汁正宗北京烤鸭
image.png
image.png

环球影城,我要上魔法学院!

在环球影城玩了一天,看过的电影不多,环球影城的这几个设施特别还原,喝了魔法黄油啤酒,买了小黄人的盲盒。

image.png

image.png

image.png

美团实习ing

太菜了只会摸鱼,要开始新的生活了
image.png

To 2022

  • 请你继续保持对技术的热情,脚踏实地,努力学习,祝你好运
  • 好好体验实习,工作,一个人独立生活的感觉
  • 考完驾照,厨艺++,滑一次雪,想看看北京冬奥会
  • 劳逸结合,自律坚持,锻炼身体,要顶天立地,才能闯出自己的路
  • 读万卷书,行万里路,在更多地方留下你的足迹
  • 请做到一件很多年你都没能做到的事情
  • 以高标准要求自己,但是别当成包袱,好的坏的都是一场体验
  • 还有不能忘记的音乐梦!
  • 希望未来以后有机会当一个speaker

「掘金链接:回首向来萧瑟处,归去,也无风雨也无晴|2021年终总结

]]>
+ + + + <p><img src="/2022/01/08/%E5%9B%9E%E9%A6%96%E5%90%91%E6%9D%A5%E8%90%A7%E7%91%9F%E5%A4%84%EF%BC%8C%E5%BD%92%E5%8E%BB%EF%BC%8C%E4%B9%9F%E6%97%A0%E9%A3%8E%E9%9B%A8%E4%B9%9F%E6%97%A0%E6%99%B4%EF%BD%9C2021%E5%B9%B4%E7%BB%88%E6%80%BB%E7%BB%93/1.jpg" alt="66CC884772E6FB9A1E2BA12BC9E7C9C4.jpg"></p> +<h2 id="⏱2021-2022"><a href="#⏱2021-2022" class="headerlink" title="⏱2021-2022"></a>⏱2021-2022</h2><blockquote> +<p>说来惭愧,没想到在掘金这样神圣的技术社区,我的第一篇文章竟然是与技术无关的年终总结。(主要是想白嫖到周边棒球帽🧢,本来是打算发布已经写好的<a href="https://juejin.cn/post/7050660953846710302" target="_blank" rel="noopener">算法岗实习面经</a>,有兴趣的朋友可以继续看看)</p> +</blockquote> +<p>时间总是过的很快,我也是偶然间打开掘金看到的这个活动才意识到今年已经快要过去了,想了很久2021年对我而言到底意味着什么,好像过得很混乱,<strong>想的太多,做的太少,以前总是能在不确定性中规划好一些时间,但今年很多事情都是被时间推着走入不确定的维度。</strong></p> + + + + + + + +
+ + + PAT笔记 + + https://jackyin.space/2021/10/16/PAT%E7%AC%94%E8%AE%B0/ + 2021-10-16T06:19:00.000Z + 2024-10-09T08:43:45.243Z + + PAT笔记

这里记录了一下常用的保研机试,剑指offer和PAT题目分类解析,主要用来快速回顾和复习相关模板,以及数据结构相关的知识点。

字符串

  • 在c++中处理字符串类型的题目时,我们一般使用string,有时候我们也使用char[]方式进行操作。
  • HH:MM:SS可以直接通过字符串字典序排序
  • 输入一个包含空格的字符串需要使用getline(cin,s1)

    STL

  • vector<int>本省具备有字典序比较的方法,重载了< == >的运算符号
  • vector<int>::iterator iter=find(vec.begin(),vec.end(),target); if(iter==vec.end()) cout << "Not found" << endl;

高精度

  • int的范围$-2 \times 10^9 - 2 \times 10^9$
  • long long $-9 \times 10^{18} - 9 \times 10^{18}$
  • vector按位存储
    在这里插入图片描述

    进制转换

  • 其他进制化成10进制,采用秦九韶算法
    在这里插入图片描述
typedef long long LL;
LL get(char c)
{
if(c<='9') return c-'0';
else return c-'a' + 10;
}

LL getnum(string a,LL r)
{
LL res=0;
for(int i=0;i<a.size();i++)
{
res = res * r + get(a[i]);
}
return res;
}
  • 十进制转其他进制的方法,使用带余除法
    在这里插入图片描述
int get(char c)
{
if(c<='9') return c-'0';
else return c-'a' + 10;
}


char tochar(int c)
{
if(c<=9) return c+'0';
else return 'a' + c - 10;
}

//一个r进制数num转10进制
int numr_to10(string num,int r)
{
int res = 0;
for(int i=0;i<num.size();i++)
{
res = res * r + get(num[i]);
}
return res;
}

//一个10进制数num转r进制
string num10_tor(string num,int r)
{
string res;
int n = numr_to10(num,10); //先转成10进制整型
while(n)
{
// cout<<tochar(n % r)<<endl;
res = tochar(n % r) + res;
n /= r;
}
return res;
}
// cout<<numr_to10("6a",16)<<" "<<num10_tor("15",16)<<endl;

判断质数

//判断一个数是否为质数
bool is_prime(int n)
{
if (n < 2) return false; // 1和0不是质数
for(int i=2;i*i<=n;i++)
{
if(n % i == 0) return false;
}
return true;
}

手写堆排序

堆是一个完全二叉树的结构,分为小根堆和大根堆两种结构。

  • 小根堆的递归定义:小根堆的每个节点都小于他的左右孩子节点的值,树的根节点为最小值。
  • 大根堆的递归定义:大根堆的每个节点都大于他的左右孩子节点的值,树的根节点为最大值。
    在STL当中可以使用prioirty_queue来轻松实现大根堆和小根堆,但是只能实现前3个功能,有时候我们不得不自己实现一个手写的堆,同时这样也能让我们更理解堆排序的过程。
    在这里插入图片描述

在AcWing基础课当中有两道经典例题,AcWing 839. 模拟堆(这个复杂一点)AcWing 838. 堆排序
这里给出堆排序的模板级代码

#include <iostream>
using namespace std;

const int N = 100010;

int heap[N],heapsize=0;

void down(int x)// 参数下标
{
int p =x;
if(2*x<=heapsize && heap[2*x]<heap[p]) p = 2*x;//左子树

if(2*x+1<=heapsize && heap[2*x+1]<heap[p]) p=2*x+1;//右子树

if(p!=x)
{
swap(heap[p],heap[x]); //说明存在比父节点小的孩子节点
down(p); //继续向下递归down
}
}


void up(int x)// 参数下标
{
while(x / 2 && heap[x] < heap[x/2]) //父节点比子节点大则交换
{
swap(heap[x],heap[x/2]);
x >>= 1; // x = x/2
}
}

int main()
{
int n,m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) scanf("%d", &heap[i]);
heapsize=n;

// O(n)建堆
for (int i = n / 2; i; i -- ) down(i);

while (m -- )
{
printf("%d ",heap[1]); //最小值是小根堆的堆顶
// 删除最小值,并重新建堆排序,从而获得倒数第二小的元素
heap[1] = heap[heapsize];
heapsize--;
down(1);
}
return 0;
}

STL写法:priority_queue默认是大根堆,less<int>是对第一个参数的比较类,表示数字大的优先级越大,而greater<int>表示数字小的优先级越大,可以实现结构体运算符重载。
首先要引入头文件:#include<queue>
大根堆:

priority_queue<int> q;
priority_queue<int, vector<int>, less<int> >q;

小根堆:

priority_queue < int, vector<int>, greater<int> > q;

树是一种特殊的数据结构形式,在做题的过程当中,根据我的经验当题目需要使用树结构的时候主要有以下几种模式。

  • 二叉树形式,在二叉树模型下,我们可以根据题目建立出静态的树形结构,构建每个节点左右孩子索引表来建立树的结构同时实现对树的遍历。如果已知或可以求得节点之间的关系,可以通过节点的度数或者访问标记找到根节点。,当然也是可以通过邻接表的方式创建二叉树。
  • 多叉树形式,多叉树形式其实又类似于无向连通图的概念,常通过创建邻接表或者临接矩阵的方式建立树,并实现进行树的遍历,也是可以根据节点关系求出根节点的。注意在临接表当中,边的数量一般大于节点数量的两倍即我们需要开票邻接表的边数空间为$M = 2 \times N + d$
  • 森林,多连通块的方式,这种也是利用无向图的方式,以邻接表或者临接矩阵的方式构建树的结构,同时我们可以利用并查集的方式得到当前无向图中含有的连通块数量并找到根节点。

二叉树左右孩子索引表模型

const int N = 100010;
int l[N],r[N]// 第i个节点的左孩子和右孩子的索引
bool has_father[N]; //建立树的时候判断一下当前节点有没有父节点,可用于寻找根节点

//初始化,-1表示子节点为空
memset(l,-1,sizeof l);
memset(r,-1,sizeof r);

// 查找根节点的过程
if(l[i]>=0) has_father[l[i]]=true;
if(r[i]>=0) has_father[r[i]]=true;
//查找根节点
int root = 0;
while(has_father[root]) root++;

二叉树的遍历过程(以先序遍历为例子)

void dfs(int root)
{
if(root==-1) return;
cout<<root<<endl;
if(l[root]>=0) dfs(l[root]);
if(r[root]>=0) dfs(r[root]);
}

临接表模型

const int N = 100010;
const int M = 2 * N + 10;
int h[N];//邻接表的N个节点头指针,h[i]表示以i为起点的,最新的一条边的编号
int e[M];// e[i] 表示第i条边的所指向的终点
int ne[M];// ne[i]表示与第i条边起点相同的下一条边的编号
int idx;// idx表示边的编号,每增加一条边就++

// 添加一条从a到b的边,如果是无向图,每次添加时要add(a,b)和add(b,a)
void add(int a,int b)
{
e[idx] = b; // 第idx条边的终点为b
ne[idx] = h[a]; // h[a] 和 第idx都是以a为起点的边,通过ne[idx]串联起来,找到上一条以a为起点的边h[a]
h[a] = idx ++; // 更新当前以a为起点的边的最新编号
}

//初始化,-1表示节点为空
memset(h,-1,sizeof h);

临接表遍历过程方法1

// x为起点,father为x的来源,防止节点遍历走回头路导致死循环
void dfs(int x,int father)
{
cout<<x<<endl;
for(int i = h[x];~i;i=ne[i]) // ~i就是i!=-1的意思
{
int to = e[i];
if(to==father) continue;
dfs(to,x);
}
}
dfs(x,-1);

临接表遍历过程方法2

const int N = 100010;
bool isvisited[N];
void dfs(int x)
{
isvisited[x]=true;
cout<<x<<endl;
for(int i = h[x];~i;i=ne[i])
{
int to = e[i];
if(isvisited[to]) continue;
dfs(to);
}
}
dfs(x);

树的深度

临接表模型:AcWing1498. 最深的根

int getdepth(int x,int father)
{
// cout<<"father"<<father<<" node"<<x<<endl;
int depth = 0;
for(int i = h[x];~i;i=ne[i])
{
int to = e[i];
if(to==father) continue;
depth = max(depth,getdepth(to,x)+1);
}
return depth;
}

二叉树模型:剑指 Offer 55 - I. 二叉树的深度

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if(root==NULL) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};

多叉树模型(该题也是求叶子节点个数的经典写法):AcWing 1476. 数叶子结点

const int N = 100010;
int max_depth = 0;
int cnt[N];
void dfs(int x,int depth)
{
//说明是叶子节点
if(h[x]==-1)
{
cnt[depth]++;
max_depth = max(max_depth,depth);
return;
}

for(int i=h[x];~i;i=ne[i])
{
dfs(e[i],depth+1);
}
}
dfs(root,0)
//输出每一层的叶子个数
for(int i=0;i<=max_depth;i++) cout<<" "<<cnt[i];

二叉搜索树

二叉搜索树 (BST) 递归定义为具有以下属性的二叉树:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值
  • 若它的右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值
  • 它的左、右子树也分别为二叉搜索树

二叉搜索树的中序遍历一定是有序的

完全二叉树

完全二叉树 (CBT) 定义为除最深层外的其他层的结点数都达到最大个数,最深层的所有结点都连续集中在最左边的二叉树。
构造完全二叉树的方法,可以直接开辟一个一维数组利用左右孩子与根节点的下标映射关系。如果通过中序遍历的方式以单调递增的方式来赋值则构造出了一颗完全二叉搜索树。
在这里插入图片描述
完全二叉树的赋值填充和构造过程(这里我们以中序遍历为例子):
例题:AcWing 1550. 完全二叉搜索树

//中序遍历填充数据
int cnt; //记录已经赋值的节点下标
void dfs(int x) // 根节点为1-n
{
if(2*x <=n) dfs(2*x);
h[x] = a[cnt++];
if(2*x+1<=n) dfs(2*x+1);
}

void dfs(int u, int& k) // 中序遍历,k引用实现下标迁移
{
if (u * 2 <= n) dfs(u * 2, k);
tr[u] = w[k ++ ];
if (u * 2 + 1 <= n) dfs(u * 2 + 1, k);
}

完全二叉树的节点个数规律:

  • 具有n个结点的完全二叉树的深度为$\lfloor log_2{n} \rfloor+ 1$
  • 完全二叉树如果为满二叉树,且深度为$k$则总节点个数为$2^{k}-1$
  • 完全二叉树的第$i(i \geq 1)$层的节点数最大值为$2^{i-1}$
  • 完全二叉树最后一层按从左到右的顺序进行编号,上面的层数皆为节点数的最大值,因此不会出现左子树为空,右子树存在的节点
  • 根据完全二叉树的结构可知:完全二叉树度为1的节点只能为1或者0,则有当节点总数为$n$时,如果$n$为奇数,则$n_0 = (n+1)/2$,如果$n$为偶数,则$n_0 = n / 2$

    关于最后一条性质的一些拓展
    二叉树的重要性质:在任意一棵二叉树中,若叶子结点的个数为$n_0$,度为2的结点数为$n_2$,则$n_0=n_2+1$
    证明:
    假设该二叉树总共有$n$个结点$(n=n_0+n_1+n_2)$,则该二叉树总共会有$n-1$条边,度为2的结点会延伸出两条边,度为1的结点会延伸出1条边。
    则有$n - 1 = n_0+n_1+n_2- 1= 2 \times n_2 + n_1$
    联立两式得到:$n_0=n_2+1$
    拓展到完全二叉树,因为完全二叉树度为1的节点只有0个或者1个。即$n_1 = 0 或 1$
    则节点总数$n=n_0+n_1+n_2 = 2 *n_0 + n_1 - 1$
    由于节点个数必须为整数,因此可以得到以下结论:
    当$n$为奇数时,必须使得$n_1=0$,则$n_0=(n + 1) / 2,n_2=n_0-1=(n + 1) / 2-1$
    当$n$为偶数时,必须使得$n_1=1$,则$n_0=n / 2,n_2=n_0-1=n /2 -1$

例题(递归解法):leetcode 完全二叉树的节点个数

/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int countNodes(TreeNode root) {
return root==null ? 0:countNodes(root.left)+countNodes(root.right)+1;
}
}

完全二叉树

二叉平衡树

AVL树

  • AVL树是一种自平衡二叉搜索树。
  • 在AVL树中,任何节点的两个子树的高度最多相差 1 个。
  • 如果某个时间,某节点的两个子树之间的高度差超过 1,则将通过树旋转进行重新平衡以恢复此属性。
  • AVL本质上还是维护一个二叉搜索树,所以不管如果旋转,其中序遍历依旧是不变的。
    旋转法则:

在这里插入图片描述AVL插入分为一下几种情况:

  • LL型:新节点的插入位置在A的左孩子的左子树上,则右旋A
  • RR型:新节点的插入位置在A的右孩子的右子树上,则左旋A
  • LR型:新节点的插入位置在A的左孩子的右子树上,则左旋B,右旋A
  • RL型:新节点的插入位置在A的右孩子的左子树上,则右旋B,左旋A
    在这里插入图片描述

红黑树

数据结构中有一类平衡的二叉搜索树,称为红黑树。
它具有以下 5 个属性:

  • 节点是红色或黑色。
  • 根节点是黑色。
  • 所有叶子都是黑色。(叶子是 NULL节点)
  • 每个红色节点的两个子节点都是黑色。
  • 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
    在这里插入图片描述

    图论相关

    并查集

    经典例题:AcWing 836. 合并集合
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010;

int p[N];

int find(int x) // 查找x的祖先节点,并在回溯的过程当中进行路径压缩,将各节点直接指向根节点
{
if(x!=p[x]) p[x] = find(p[x]); // x和p[x]不相等,则继续向上找父节点的父节点
return p[x];
}

int main()
{
int n;
int m;
scanf("%d%d", &n, &m);

for(int i=1;i<=n;i++)
p[i]=i;

while (m -- )
{
char op[2];
int a,b;
scanf("%s%d%d", op,&a,&b);
int roota = find(a);
int rootb = find(b);
if(op[0]=='M')
{

if(roota == rootb) continue;
p[roota] = rootb; // root merge
}
else
{
cout<< (roota==rootb ? "Yes":"No")<<endl;
}

}
return 0;
}

dijstra算法

  • 临接矩阵形式,适用于点的数量$N < 1000$的情形,朴素算法即可解决
  • 邻接表形式,当$N>10000$,需要添加堆优化
    一般来说堆优化版本的考试用的不多,这里就只介绍了朴素版本。
    Dijkstra求最短路 I
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 510;
const int inf = 0x3f3f3f3f;
int n,m;
int g[N][N]; // 稠密图使用邻接矩阵
int dist[N]; // 存储距离
bool vis[N]; // 标志到该节点的距离是否已经被规整为最短距离

void dijkstra(int x)
{
memset(dist, inf, sizeof dist);
dist[x] = 0;

for(int i=0;i<n;i++)//外层循环n次遍历每个节点
{
int t= -1;

for(int j=1;j<=n;j++)
{
if(!vis[j]&&(t==-1 || dist[t]>dist[j])) t =j;
}
if(t==-1) break;
vis[t]=true;

for(int j=1;j<=n;j++)
{
if(!vis[j])
{
dist[j] = min(dist[j],dist[t]+g[t][j]);
}
}
}

if(dist[n]==inf) puts("-1");
else cout<<dist[n]<<endl;

}


int main()
{
scanf("%d%d", &n, &m);
memset(g, inf, sizeof g);
for(int i=0;i<m;i++)
{
int x,y,z;
scanf("%d%d%d", &x, &y,&z);
if(x==y) g[x][y]=0; // 自环
g[x][y] = min(g[x][y],z); // 重边仅记录最小的边
}

dijkstra(1);
return 0;
}

最小生成树Prime

AcWing 858.Prime算法求最小生成树

//这里填你的代码^^
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 510, INF = 0x3f3f3f3f;
int n,m;

int g[N][N]; //稠密图使用prim和邻接矩阵
int dist[N];
bool isvisited[N];

int prime(int x)
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
dist[x]=0;
for(int i=0;i<n;i++)
{
int t=-1;
for(int j=1;j<=n;j++)
if(!isvisited[j] && (t==-1 || dist[t] > dist[j]))
t= j;

if(dist[t] == INF) return -1;
//标记访问
res += dist[t];
isvisited[t]=true;

//更新dist
for(int j=1;j<=n;j++)
{
dist[j] = min(dist[j],g[t][j]);
}
}
return res;
}


int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
while (m -- )
{
int a,b,c;
scanf("%d%d%d", &a, &b,&c);
g[a][b] = g[b][a] = min(g[a][b],c); //无向图
}


int t = prime(1);

if(t==-1)
cout<<"impossible"<<endl;
else
cout<<t<<endl;

return 0;
}

最小生成树Kruskal

AcWing859.Kruskal算法求最小生成树

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 100010, INF =0x3f3f3f3f;
const int M = 2*N;

int n,m;

struct Edge
{
int x;
int y;
int w;
bool operator < (const Edge & E) const
{
return w < E.w;
}
}edge[M];

int p[N]; //并查集

int find(int x)//找祖宗节点
{
if(x!=p[x]) p[x] = find(p[x]);
return p[x];
}

int kruskal()
{
int res = 0;
int cnt=0;
sort(edge,edge+m);
for(int i=1;i<=n;i++) p[i]=i;//初始化并查集

for(int i=0;i<m;i++)
{
int x = edge[i].x, y = edge[i].y, w = edge[i].w;

int a = find(x);
int b = find(y);
//不是连通的
if(a!=b)
{
p[b] = a;
res += w;
cnt++;
}
}
//路径数量<n-1说明不连通
if (cnt<n-1) return INF;
return res;
}

int main()
{
scanf("%d%d", &n, &m);
for (int i = 0; i < m; i ++ )
{
scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].w);
}

int t = kruskal();

if(t == INF) cout<< "impossible"<<endl;
else cout<<t<<endl;

return 0;
}

哈密顿图

  • 通过图中所有顶点一次且仅一次的通路称为哈密顿通路。
  • 通过图中所有顶点一次且仅一次的回路称为哈密顿回路。
  • 具有哈密顿回路的图称为哈密顿图。
  • 具有哈密顿通路而不具有哈密顿回路的图称为半哈密顿图

欧拉图

  • 通过图中所有边恰好一次且行遍所有顶点的通路称为欧拉通路。
  • 通过图中所有边恰好一次且行遍所有顶点的回路称为欧拉回路。
  • 具有欧拉回路的无向图或有向图称为欧拉图。
  • 具有欧拉通路但不具有欧拉回路的无向图或有向图称为半欧拉图。
  • 如果一个连通图的所有顶点的度数都为偶数,那么这个连通图具有欧拉回路,且这个图被称为欧拉图。
  • 如果一个连通图中有两个顶点的度数为奇数,其他顶点的度数为偶数,那么所有欧拉路径都从其中一个度数为奇数的顶点开始,并在另一个度数为奇数的顶点结束。

在这里插入图片描述

数学

gcd

LL gcd(LL a, LL b)  // 欧几里得算法
{
return b ? gcd(b, a % b) : a;
}

1的个数(数位dp)

ACWing1533.1的个数
剑指 Offer 43. 1~n 整数中 1 出现的次数

给定一个数字 N,请你计算 1∼N 中一共出现了多少个数字 1。
例如,N=12 时,一共出现了 5 个数字 1,分别出现在 1,10,11,12 中。

解题思路:相关视频链接
在这里插入图片描述

class Solution {
public:
int countDigitOne(int n) {
vector<int> num;
while(n) num.push_back(n%10), n/=10;
int res = 0;
for(int i=num.size()-1;i>=0;i--)
{
int d = num[i];
int left=0,right=0,power=1;
for(int j=num.size()-1;j>i;j--) left = left * 10 + num[j];
for(int j=i-1;j>=0;j--) right = right * 10 + num[j], power*=10;

if(d==0) res += left*power;
else if(d==1) res += left*power + right + 1;
else res += (left+1) * power;
}
return res;
}
};
]]>
+ + + + <h1 id="PAT笔记"><a href="#PAT笔记" class="headerlink" title="PAT笔记"></a>PAT笔记</h1><p>这里记录了一下常用的保研机试,剑指offer和PAT题目分类解析,主要用来快速回顾和复习相关模板,以及数据结构相关的知识点。</p> +<h2 id="字符串"><a href="#字符串" class="headerlink" title="字符串"></a>字符串</h2><ul> +<li>在c++中处理字符串类型的题目时,我们一般使用<code>string</code>,有时候我们也使用<code>char[]</code>方式进行操作。</li> +<li><code>HH:MM:SS</code>可以直接通过字符串字典序排序</li> +<li>输入一个包含空格的字符串需要使用<code>getline(cin,s1)</code><h2 id="STL"><a href="#STL" class="headerlink" title="STL"></a>STL</h2></li> +<li><code>vector&lt;int&gt;</code>本省具备有字典序比较的方法,重载了<code>&lt; == &gt;</code>的运算符号</li> +<li><code>vector&lt;int&gt;::iterator iter=find(vec.begin(),vec.end(),target); if(iter==vec.end()) cout &lt;&lt; &quot;Not found&quot; &lt;&lt; endl;</code></li> +</ul> + + + + + + + +
+ + + 集成学习专题——Xgboost&LightGBM + + https://jackyin.space/2021/06/18/%E9%9B%86%E6%88%90%E5%AD%A6%E4%B9%A0%E4%B8%93%E9%A2%98%E2%80%94%E2%80%94Xgboost-LightGBM/ + 2021-06-17T16:11:00.000Z + 2024-10-09T08:43:45.344Z + + XGBoost算法

XGBoost是陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中并取得了不错的成绩。XGBoost本质上还是一个GBDT,但是力争把速度和效率发挥到极致,所以叫X (Extreme) GBoosted, 包括前面说过,两者都是boosting方法。XGBoost是一个优化的分布式梯度增强库,旨在实现高效,灵活和便携。 它在Gradient Boosting框架下实现机器学习算法。 XGBoost提供了并行树提升(也称为GBDT,GBM),可以快速准确地解决许多数据科学问题。 相同的代码在主要的分布式环境(Hadoop,SGE,MPI)上运行,并且可以解决超过数十亿个样例的问题。XGBoost利用了核外计算并且能够使数据科学家在一个主机上处理数亿的样本数据。最终,将这些技术进行结合来做一个端到端的系统以最少的集群系统来扩展到更大的数据集上。Xgboost以CART决策树为子模型,通过Gradient Tree Boosting实现多棵CART树的集成学习,得到最终模型。下面我们来看看XGBoost的最终模型构建:

引用陈天奇的论文,我们的数据为:$\mathcal{D}=\left{\left(\mathbf{x}{i}, y{i}\right)\right}\left(|\mathcal{D}|=n, \mathbf{x}{i} \in \mathbb{R}^{m}, y{i} \in \mathbb{R}\right)$
(1) 构造目标函数:
假设有K棵树,则第i个样本的输出为$\hat{y}{i}=\phi\left(\mathrm{x}{i}\right)=\sum_{k=1}^{K} f_{k}\left(\mathrm{x}{i}\right), \quad f{k} \in \mathcal{F}$,其中,$\mathcal{F}=\left{f(\mathbf{x})=w_{q(\mathbf{x})}\right}\left(q: \mathbb{R}^{m} \rightarrow T, w \in \mathbb{R}^{T}\right)$
因此,目标函数的构建为:
$$
\mathcal{L}(\phi)=\sum_{i} l\left(\hat{y}{i}, y{i}\right)+\sum_{k} \Omega\left(f_{k}\right)
$$
其中,$\sum_{i} l\left(\hat{y}{i}, y{i}\right)$为loss function,$\sum_{k} \Omega\left(f_{k}\right)$为正则化项。
(2) 叠加式的训练(Additive Training):
给定样本$x_i$,$\hat{y}i^{(0)} = 0$(初始预测),$\hat{y}_i^{(1)} = \hat{y}_i^{(0)} + f_1(x_i)$,$\hat{y}_i^{(2)} = \hat{y}_i^{(0)} + f_1(x_i) + f_2(x_i) = \hat{y}_i^{(1)} + f_2(x_i)$…….以此类推,可以得到:$ \hat{y}_i^{(K)} = \hat{y}_i^{(K-1)} + f_K(x_i)$ ,其中,$ \hat{y}_i^{(K-1)} $ 为前K-1棵树的预测结果,$ f_K(x_i)$ 为第K棵树的预测结果。
因此,目标函数可以分解为:
$$
\mathcal{L}^{(K)}=\sum
{i=1}^{n} l\left(y_{i}, \hat{y}{i}^{(K-1)}+f{K}\left(\mathrm{x}{i}\right)\right)+\sum{k} \Omega\left(f_{k}\right)
$$
由于正则化项也可以分解为前K-1棵树的复杂度加第K棵树的复杂度,因此:$\mathcal{L}^{(K)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}{i}^{(K-1)}+f{K}\left(\mathrm{x}{i}\right)\right)+\sum{k=1} ^{K-1}\Omega\left(f_{k}\right)+\Omega\left(f_{K}\right)$,由于$\sum_{k=1} ^{K-1}\Omega\left(f_{k}\right)$在模型构建到第K棵树的时候已经固定,无法改变,因此是一个已知的常数,可以在最优化的时候省去,故:
$$
\mathcal{L}^{(K)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}{i}^{(K-1)}+f{K}\left(\mathrm{x}{i}\right)\right)+\Omega\left(f{K}\right)
$$
(3) 使用泰勒级数近似目标函数:
$$
\mathcal{L}^{(K)} \simeq \sum_{i=1}^{n}\left[l\left(y_{i}, \hat{y}^{(K-1)}\right)+g_{i} f_{K}\left(\mathrm{x}{i}\right)+\frac{1}{2} h{i} f_{K}^{2}\left(\mathrm{x}{i}\right)\right]+\Omega\left(f{K}\right)
$$
其中,$g_{i}=\partial_{\hat{y}(t-1)} l\left(y_{i}, \hat{y}^{(t-1)}\right)$和$h_{i}=\partial_{\hat{y}^{(t-1)}}^{2} l\left(y_{i}, \hat{y}^{(t-1)}\right)$
在这里,我们补充下泰勒级数的相关知识:
在数学中,泰勒级数(英语:Taylor series)用无限项连加式——级数来表示一个函数,这些相加的项由函数在某一点的导数求得。具体的形式如下:
$$
f(x)=\frac{f\left(x_{0}\right)}{0 !}+\frac{f^{\prime}\left(x_{0}\right)}{1 !}\left(x-x_{0}\right)+\frac{f^{\prime \prime}\left(x_{0}\right)}{2 !}\left(x-x_{0}\right)^{2}+\ldots+\frac{f^{(n)}\left(x_{0}\right)}{n !}\left(x-x_{0}\right)^{n}+……
$$
由于$\sum_{i=1}^{n}l\left(y_{i}, \hat{y}^{(K-1)}\right)$在模型构建到第K棵树的时候已经固定,无法改变,因此是一个已知的常数,可以在最优化的时候省去,故:
$$
\tilde{\mathcal{L}}^{(K)}=\sum_{i=1}^{n}\left[g_{i} f_{K}\left(\mathbf{x}{i}\right)+\frac{1}{2} h{i} f_{K}^{2}\left(\mathbf{x}{i}\right)\right]+\Omega\left(f{K}\right)
$$
(4) 如何定义一棵树:
为了说明如何定义一棵树的问题,我们需要定义几个概念:第一个概念是样本所在的节点位置$q(x)$,第二个概念是有哪些样本落在节点j上$I_{j}=\left{i \mid q\left(\mathbf{x}{i}\right)=j\right}$,第三个概念是每个结点的预测值$w{q(x)}$,第四个概念是模型复杂度$\Omega\left(f_{K}\right)$,它可以由叶子节点的个数以及节点函数值来构建,则:$\Omega\left(f_{K}\right) = \gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{j}^{2}$。如下图的例子:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t1tei3pE-1623946035306)(./16.png)]
$q(x_1) = 1,q(x_2) = 3,q(x_3) = 1,q(x_4) = 2,q(x_5) = 3$,$I_1 = {1,3},I_2 = {4},I_3 = {2,5}$,$w = (15,12,20)$
因此,目标函数用以上符号替代后:
$$
\begin{aligned}
\tilde{\mathcal{L}}^{(K)} &=\sum_{i=1}^{n}\left[g_{i} f_{K}\left(\mathrm{x}{i}\right)+\frac{1}{2} h{i} f_{K}^{2}\left(\mathrm{x}{i}\right)\right]+\gamma T+\frac{1}{2} \lambda \sum{j=1}^{T} w_{j}^{2} \
&=\sum_{j=1}^{T}\left[\left(\sum_{i \in I_{j}} g_{i}\right) w_{j}+\frac{1}{2}\left(\sum_{i \in I_{j}} h_{i}+\lambda\right) w_{j}^{2}\right]+\gamma T
\end{aligned}
$$
由于我们的目标就是最小化目标函数,现在的目标函数化简为一个关于w的二次函数:$\tilde{\mathcal{L}}^{(K)}=\sum_{j=1}^{T}\left[\left(\sum_{i \in I_{j}} g_{i}\right) w_{j}+\frac{1}{2}\left(\sum_{i \in I_{j}} h_{i}+\lambda\right) w_{j}^{2}\right]+\gamma T$,根据二次函数求极值的公式:$y=ax^2 bx c$求极值,对称轴在$x=-\frac{b}{2 a}$,极值为$y=\frac{4 a c-b^{2}}{4 a}$,因此:
$$
w_{j}^{*}=-\frac{\sum_{i \in I_{j}} g_{i}}{\sum_{i \in I_{j}} h_{i}+\lambda}
$$
以及
$$
\tilde{\mathcal{L}}^{(K)}(q)=-\frac{1}{2} \sum_{j=1}^{T} \frac{\left(\sum_{i \in I_{j}} g_{i}\right)^{2}}{\sum_{i \in I_{j}} h_{i}+\lambda}+\gamma T
$$
(5) 如何寻找树的形状:
不难发现,刚刚的讨论都是基于树的形状已经确定了计算$w$和$L$,但是实际上我们需要像学习决策树一样找到树的形状。因此,我们借助决策树学习的方式,使用目标函数的变化来作为分裂节点的标准。我们使用一个例子来说明:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nCrhWA4S-1623946035310)(./17.png)]
例子中有8个样本,分裂方式如下,因此:
$$
\tilde{\mathcal{L}}^{(old)} = -\frac{1}{2}[\frac{(g_7 + g_8)^2}{H_7+H_8 + \lambda} + \frac{(g_1 +…+ g_6)^2}{H_1+…+H_6 + \lambda}] + 2\gamma \
\tilde{\mathcal{L}}^{(new)} = -\frac{1}{2}[\frac{(g_7 + g_8)^2}{H_7+H_8 + \lambda} + \frac{(g_1 +…+ g_3)^2}{H_1+…+H_3 + \lambda} + \frac{(g_4 +…+ g_6)^2}{H_4+…+H_6 + \lambda}] + 3\gamma\
\tilde{\mathcal{L}}^{(old)} - \tilde{\mathcal{L}}^{(new)} = \frac{1}{2}[ \frac{(g_1 +…+ g_3)^2}{H_1+…+H_3 + \lambda} + \frac{(g_4 +…+ g_6)^2}{H_4+…+H_6 + \lambda} - \frac{(g_1+…+g_6)^2}{h_1+…+h_6+\lambda}] - \gamma
$$
因此,从上面的例子看出:分割节点的标准为$max{\tilde{\mathcal{L}}^{(old)} - \tilde{\mathcal{L}}^{(new)} }$,即:
$$
\mathcal{L}{\text {split }}=\frac{1}{2}\left[\frac{\left(\sum{i \in I_{L}} g_{i}\right)^{2}}{\sum_{i \in I_{L}} h_{i}+\lambda}+\frac{\left(\sum_{i \in I_{R}} g_{i}\right)^{2}}{\sum_{i \in I_{R}} h_{i}+\lambda}-\frac{\left(\sum_{i \in I} g_{i}\right)^{2}}{\sum_{i \in I} h_{i}+\lambda}\right]-\gamma
$$
(6.1) 精确贪心分裂算法:
XGBoost在生成新树的过程中,最基本的操作是节点分裂。节点分裂中最重 要的环节是找到最优特征及最优切分点, 然后将叶子节点按照最优特征和最优切 分点进行分裂。选取最优特征和最优切分点的一种思路如下:首先找到所有的候 选特征及所有的候选切分点, 一一求得其 $\mathcal{L}{\text {split }}$, 然后选择$\mathcal{L}{\mathrm{split}}$ 最大的特征及 对应切分点作为最优特征和最优切分点。我们称此种方法为精确贪心算法。该算法是一种启发式算法, 因为在节点分裂时只选择当前最优的分裂策略, 而非全局最优的分裂策略。精确贪心算法的计算过程如下所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HRrbM0fp-1623946035312)(./18.png)]

(6.2) 基于直方图的近似算法:
精确贪心算法在选择最优特征和最优切分点时是一种十分有效的方法。它计算了所有特征、所有切分点的收益, 并从中选择了最优的, 从而保证模型能比较好地拟合了训练数据。但是当数据不能完全加载到内存时,精确贪心算法会变得 非常低效,算法在计算过程中需要不断在内存与磁盘之间进行数据交换,这是个非常耗时的过程, 并且在分布式环境中面临同样的问题。为了能够更高效地选 择最优特征及切分点, XGBoost提出一种近似算法来解决该问题。 基于直方图的近似算法的主要思想是:对某一特征寻找最优切分点时,首先对该特征的所有切分点按分位数 (如百分位) 分桶, 得到一个候选切分点集。特征的每一个切分点都可以分到对应的分桶; 然后,对每个桶计算特征统计G和H得到直方图, G为该桶内所有样本一阶特征统计g之和, H为该桶内所有样本二阶特征统计h之和; 最后,选择所有候选特征及候选切分点中对应桶的特征统计收益最大的作为最优特征及最优切分点。基于直方图的近似算法的计算过程如下所示:

  1. 对于每个特征 $k=1,2, \cdots, m,$ 按分位数对特征 $k$ 分桶 $\Theta,$ 可得候选切分点, $S_{k}=\left{S_{k 1}, S_{k 2}, \cdots, S_{k l}\right}^{1}$
  2. 对于每个特征 $k=1,2, \cdots, m,$ 有:
    $$
    \begin{array}{l}
    G_{k v} \leftarrow=\sum_{j \in\left{j \mid s_{k, v} \geq \mathbf{x}{j k}>s{k, v-1;}\right}} g_{j} \
    H_{k v} \leftarrow=\sum_{j \in\left{j \mid s_{k, v} \geq \mathbf{x}{j k}>s{k, v-1;}\right}} h_{j}
    \end{array}
    $$
  3. 类似精确贪心算法,依据梯度统计找到最大增益的候选切分点。
    下面用一个例子说明基于直方图的近似算法:
    假设有一个年龄特征,其特征的取值为18、19、21、31、36、37、55、57,我们需要使用近似算法找到年龄这个特征的最佳分裂点:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MKLD2poX-1623946035314)(./19.png)]

近似算法实现了两种候选切分点的构建策略:全局策略和本地策略。全局策略是在树构建的初始阶段对每一个特征确定一个候选切分点的集合, 并在该树每一层的节点分裂中均采用此集合计算收益, 整个过程候选切分点集合不改变。本地策略则是在每一次节点分裂时均重新确定候选切分点。全局策略需要更细的分桶才能达到本地策略的精确度, 但全局策略在选取候选切分点集合时比本地策略更简单。在XGBoost系统中, 用户可以根据需求自由选择使用精确贪心算法、近似算法全局策略、近似算法本地策略, 算法均可通过参数进行配置。

以上是XGBoost的理论部分,下面我们对XGBoost系统进行详细的讲解:
官方文档:https://xgboost.readthedocs.io/en/latest/python/python_intro.html
知乎总结:https://zhuanlan.zhihu.com/p/143009353

# XGBoost原生工具库的上手:
import xgboost as xgb # 引入工具库
# read in data
dtrain = xgb.DMatrix('demo/data/agaricus.txt.train') # XGBoost的专属数据格式,但是也可以用dataframe或者ndarray
dtest = xgb.DMatrix('demo/data/agaricus.txt.test') # # XGBoost的专属数据格式,但是也可以用dataframe或者ndarray
# specify parameters via map
param = {'max_depth':2, 'eta':1, 'objective':'binary:logistic' } # 设置XGB的参数,使用字典形式传入
num_round = 2 # 使用线程数
bst = xgb.train(param, dtrain, num_round) # 训练
# make prediction
preds = bst.predict(dtest) # 预测

XGBoost的参数设置(括号内的名称为sklearn接口对应的参数名字):
推荐博客:https://link.zhihu.com/?target=https%3A//blog.csdn.net/luanpeng825485697/article/details/79907149
推荐官方文档:https://link.zhihu.com/?target=https%3A//xgboost.readthedocs.io/en/latest/parameter.html

XGBoost的参数分为三种:

  • 通用参数:(两种类型的booster,因为tree的性能比线性回归好得多,因此我们很少用线性回归。)
    • booster:使用哪个弱学习器训练,默认gbtree,可选gbtree,gblinear 或dart
    • nthread:用于运行XGBoost的并行线程数,默认为最大可用线程数
    • verbosity:打印消息的详细程度。有效值为0(静默),1(警告),2(信息),3(调试)。
    • Tree Booster的参数:
      • eta(learning_rate):learning_rate,在更新中使用步长收缩以防止过度拟合,默认= 0.3,范围:[0,1];典型值一般设置为:0.01-0.2
      • gamma(min_split_loss):默认= 0,分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,但性能就不一定能保证,需要平衡。范围:[0,∞]
      • max_depth:默认= 6,一棵树的最大深度。增加此值将使模型更复杂,并且更可能过度拟合。范围:[0,∞]
      • min_child_weight:默认值= 1,如果新分裂的节点的样本权重和小于min_child_weight则停止分裂 。这个可以用来减少过拟合,但是也不能太高,会导致欠拟合。范围:[0,∞]
      • max_delta_step:默认= 0,允许每个叶子输出的最大增量步长。如果将该值设置为0,则表示没有约束。如果将其设置为正值,则可以帮助使更新步骤更加保守。通常不需要此参数,但是当类极度不平衡时,它可能有助于逻辑回归。将其设置为1-10的值可能有助于控制更新。范围:[0,∞]
      • subsample:默认值= 1,构建每棵树对样本的采样率,如果设置成0.5,XGBoost会随机选择一半的样本作为训练集。范围:(0,1]
      • sampling_method:默认= uniform,用于对训练实例进行采样的方法。
        • uniform:每个训练实例的选择概率均等。通常将subsample> = 0.5 设置 为良好的效果。
        • gradient_based:每个训练实例的选择概率与规则化的梯度绝对值成正比,具体来说就是$\sqrt{g^2+\lambda h^2}$,subsample可以设置为低至0.1,而不会损失模型精度。
      • colsample_bytree:默认= 1,列采样率,也就是特征采样率。范围为(0,1]
      • lambda(reg_lambda):默认=1,L2正则化权重项。增加此值将使模型更加保守。
      • alpha(reg_alpha):默认= 0,权重的L1正则化项。增加此值将使模型更加保守。
      • tree_method:默认=auto,XGBoost中使用的树构建算法。
        • auto:使用启发式选择最快的方法。
          • 对于小型数据集,exact将使用精确贪婪()。
          • 对于较大的数据集,approx将选择近似算法()。它建议尝试hist,gpu_hist,用大量的数据可能更高的性能。(gpu_hist)支持。external memory外部存储器。
        • exact:精确的贪婪算法。枚举所有拆分的候选点。
        • approx:使用分位数和梯度直方图的近似贪婪算法。
        • hist:更快的直方图优化的近似贪婪算法。(LightGBM也是使用直方图算法)
        • gpu_hist:GPU hist算法的实现。
      • scale_pos_weight:控制正负权重的平衡,这对于不平衡的类别很有用。Kaggle竞赛一般设置sum(negative instances) / sum(positive instances),在类别高度不平衡的情况下,将参数设置大于0,可以加快收敛。
      • num_parallel_tree:默认=1,每次迭代期间构造的并行树的数量。此选项用于支持增强型随机森林。
      • monotone_constraints:可变单调性的约束,在某些情况下,如果有非常强烈的先验信念认为真实的关系具有一定的质量,则可以使用约束条件来提高模型的预测性能。(例如params_constrained[‘monotone_constraints’] = “(1,-1)”,(1,-1)我们告诉XGBoost对第一个预测变量施加增加的约束,对第二个预测变量施加减小的约束。)
    • Linear Booster的参数:
      • lambda(reg_lambda):默认= 0,L2正则化权重项。增加此值将使模型更加保守。归一化为训练示例数。
      • alpha(reg_alpha):默认= 0,权重的L1正则化项。增加此值将使模型更加保守。归一化为训练示例数。
      • updater:默认= shotgun。
        • shotgun:基于shotgun算法的平行坐标下降算法。使用“ hogwild”并行性,因此每次运行都产生不确定的解决方案。
        • coord_descent:普通坐标下降算法。同样是多线程的,但仍会产生确定性的解决方案。
      • feature_selector:默认= cyclic。特征选择和排序方法
        • cyclic:通过每次循环一个特征来实现的。
        • shuffle:类似于cyclic,但是在每次更新之前都有随机的特征变换。
        • random:一个随机(有放回)特征选择器。
        • greedy:选择梯度最大的特征。(贪婪选择)
        • thrifty:近似贪婪特征选择(近似于greedy)
      • top_k:要选择的最重要特征数(在greedy和thrifty内)
  • 任务参数(这个参数用来控制理想的优化目标和每一步结果的度量方法。)
    • objective:默认=reg:squarederror,表示最小平方误差。
      • reg:squarederror,最小平方误差。
      • reg:squaredlogerror,对数平方损失。$\frac{1}{2}[log(pred+1)-log(label+1)]^2$
      • reg:logistic,逻辑回归
      • reg:pseudohubererror,使用伪Huber损失进行回归,这是绝对损失的两倍可微选择。
      • binary:logistic,二元分类的逻辑回归,输出概率。
      • binary:logitraw:用于二进制分类的逻辑回归,逻辑转换之前的输出得分。
      • binary:hinge:二进制分类的铰链损失。这使预测为0或1,而不是产生概率。(SVM就是铰链损失函数)
      • count:poisson –计数数据的泊松回归,泊松分布的输出平均值。
      • survival:cox:针对正确的生存时间数据进行Cox回归(负值被视为正确的生存时间)。
      • survival:aft:用于检查生存时间数据的加速故障时间模型。
      • aft_loss_distribution:survival:aft和aft-nloglik度量标准使用的概率密度函数。
      • multi:softmax:设置XGBoost以使用softmax目标进行多类分类,还需要设置num_class(类数)
      • multi:softprob:与softmax相同,但输出向量,可以进一步重整为矩阵。结果包含属于每个类别的每个数据点的预测概率。
      • rank:pairwise:使用LambdaMART进行成对排名,从而使成对损失最小化。
      • rank:ndcg:使用LambdaMART进行列表式排名,使标准化折让累积收益(NDCG)最大化。
      • rank:map:使用LambdaMART进行列表平均排名,使平均平均精度(MAP)最大化。
      • reg:gamma:使用对数链接进行伽马回归。输出是伽马分布的平均值。
      • reg:tweedie:使用对数链接进行Tweedie回归。
      • 自定义损失函数和评价指标:https://xgboost.readthedocs.io/en/latest/tutorials/custom_metric_obj.html
    • eval_metric:验证数据的评估指标,将根据目标分配默认指标(回归均方根,分类误差,排名的平均平均精度),用户可以添加多个评估指标
      • rmse,均方根误差; rmsle:均方根对数误差; mae:平均绝对误差;mphe:平均伪Huber错误;logloss:负对数似然; error:二进制分类错误率;
      • merror:多类分类错误率; mlogloss:多类logloss; auc:曲线下面积; aucpr:PR曲线下的面积;ndcg:归一化累计折扣;map:平均精度;
    • seed :随机数种子,[默认= 0]。
  • 命令行参数(这里不说了,因为很少用命令行控制台版本)
from IPython.display import IFrame
IFrame('https://xgboost.readthedocs.io/en/latest/parameter.html', width=1400, height=800)

XGBoost的调参说明:

参数调优的一般步骤

    1. 确定学习速率和提升参数调优的初始值
    1. max_depth 和 min_child_weight 参数调优
    1. gamma参数调优
    1. subsample 和 colsample_bytree 参数优
    1. 正则化参数alpha调优
    1. 降低学习速率和使用更多的决策树

XGBoost详细攻略:
具体的api请查看:https://xgboost.readthedocs.io/en/latest/python/python_api.html
推荐github:https://github.com/dmlc/xgboost/tree/master/demo/guide-python

安装XGBoost:
方式1:pip3 install xgboost
方式2:pip install xgboost

数据接口(XGBoost可处理的数据格式DMatrix)

# 1.LibSVM文本格式文件
dtrain = xgb.DMatrix('train.svm.txt')
dtest = xgb.DMatrix('test.svm.buffer')
# 2.CSV文件(不能含类别文本变量,如果存在文本变量请做特征处理如one-hot)
dtrain = xgb.DMatrix('train.csv?format=csv&label_column=0')
dtest = xgb.DMatrix('test.csv?format=csv&label_column=0')
# 3.NumPy数组
data = np.random.rand(5, 10) # 5 entities, each contains 10 features
label = np.random.randint(2, size=5) # binary target
dtrain = xgb.DMatrix(data, label=label)
# 4.scipy.sparse数组
csr = scipy.sparse.csr_matrix((dat, (row, col)))
dtrain = xgb.DMatrix(csr)
# pandas数据框dataframe
data = pandas.DataFrame(np.arange(12).reshape((4,3)), columns=['a', 'b', 'c'])
label = pandas.DataFrame(np.random.randint(2, size=4))
dtrain = xgb.DMatrix(data, label=label)

笔者推荐:先保存到XGBoost二进制文件中将使加载速度更快,然后再加载进来

# 1.保存DMatrix到XGBoost二进制文件中
dtrain = xgb.DMatrix('train.svm.txt')
dtrain.save_binary('train.buffer')
# 2. 缺少的值可以用DMatrix构造函数中的默认值替换:
dtrain = xgb.DMatrix(data, label=label, missing=-999.0)
# 3.可以在需要时设置权重:
w = np.random.rand(5, 1)
dtrain = xgb.DMatrix(data, label=label, missing=-999.0, weight=w)

参数的设置方式:

import pandas as pd
# 加载并处理数据
df_wine = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data',header=None)
df_wine.columns = ['Class label', 'Alcohol','Malic acid', 'Ash','Alcalinity of ash','Magnesium', 'Total phenols',
'Flavanoids', 'Nonflavanoid phenols','Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']
df_wine = df_wine[df_wine['Class label'] != 1] # drop 1 class
y = df_wine['Class label'].values
X = df_wine[['Alcohol','OD280/OD315 of diluted wines']].values
from sklearn.model_selection import train_test_split # 切分训练集与测试集
from sklearn.preprocessing import LabelEncoder # 标签化分类变量
le = LabelEncoder()
y = le.fit_transform(y)
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1,stratify=y)
dtrain = xgb.DMatrix(X_train, label=y_train)
dtest = xgb.DMatrix(X_test)
# 1.Booster 参数
params = {
'booster': 'gbtree',
'objective': 'multi:softmax', # 多分类的问题
'num_class': 10, # 类别数,与 multisoftmax 并用
'gamma': 0.1, # 用于控制是否后剪枝的参数,越大越保守,一般0.1、0.2这样子。
'max_depth': 12, # 构建树的深度,越大越容易过拟合
'lambda': 2, # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
'subsample': 0.7, # 随机采样训练样本
'colsample_bytree': 0.7, # 生成树时进行的列采样
'min_child_weight': 3,
'silent': 1, # 设置成1则没有运行信息输出,最好是设置为0.
'eta': 0.007, # 如同学习率
'seed': 1000,
'nthread': 4, # cpu 线程数
'eval_metric':'auc'
}
plst = list(params.items())
# evallist = [(dtest, 'eval'), (dtrain, 'train')] # 指定验证集

训练:

# 2.训练
num_round = 10
bst = xgb.train(plst, dtrain, num_round)
#bst = xgb.train( plst, dtrain, num_round, evallist )

保存模型:

# 3.保存模型
bst.save_model('0001.model')
# dump model
bst.dump_model('dump.raw.txt')
# dump model with feature map
#bst.dump_model('dump.raw.txt', 'featmap.txt')

加载保存的模型:

# 4.加载保存的模型:
bst = xgb.Booster({'nthread': 4}) # init model
bst.load_model('0001.model') # load data

设置早停机制:

# 5.也可以设置早停机制(需要设置验证集)
train(..., evals=evals, early_stopping_rounds=10)

预测:

# 6.预测
ypred = bst.predict(dtest)

绘制重要性特征图:

# 1.绘制重要性
xgb.plot_importance(bst)
# 2.绘制输出树
#xgb.plot_tree(bst, num_trees=2)
# 3.使用xgboost.to_graphviz()将目标树转换为graphviz
#xgb.to_graphviz(bst, num_trees=2)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ir9Nm1ZN-1623946035316)(output_27_1.png)]

7. Xgboost算法案例

分类案例

from sklearn.datasets import load_iris
import xgboost as xgb
from xgboost import plot_importance
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score # 准确率
# 加载样本数据集
iris = load_iris()
X,y = iris.data,iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1234565) # 数据集分割

params = {
'booster' : 'gbtree',
'objective': 'multi:softmax', # 多分类的问题
'num_class': 3,
'gamma': 0.1, # 默认= 0,分裂节点时,损失函数减小值只有大于等于gamma节点才分裂,gamma值越大,算法越保守,越不容易过拟合,但性能就不一定能保证,需要平衡。
'max_depth': 12, # 树的最大深度
'lambda': 2, # 控制模型复杂度的权重值的L2正则化项参数,参数越大,模型越不容易过拟合。
'subsample': 0.7, # 随机采样训练样本
'colsample_bytree': 0.7, # 生成树时进行的列采样,列采样率,也就是特征采样率
'min_child_weight': 3,
'silent': 0,
'eta': 0.1,
'seed': 1,
'nthread': 4,
}

plst = list(params.items())
dtrain = xgb.DMatrix(X_train,y_train)
num_rounds = 500
model = xgb.train(plst,dtrain,num_rounds) # xgboost模型训练

# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
y_pred = model.predict(dtest)

# 计算准确率
accuracy = accuracy_score(y_test,y_pred)
print("accuarcy: %.2f%%" % (accuracy*100.0))

# 显示重要特征
plot_importance(model)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8vD1cJWm-1623946035317)(output_30_1.png)]

回归案例

import xgboost as xgb
from xgboost import plot_importance
from matplotlib import pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_boston
from sklearn.metrics import mean_squared_error


# 加载数据集
boston = load_boston()
X,y = boston.data,boston.target

# XGBoost训练过程
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)

params = {
'booster': 'gbtree',
'objective': 'reg:squarederror',
'gamma': 0.1,
'max_depth': 5,
'lambda': 3,
'subsample': 0.7,
'colsample_bytree': 0.7,
'min_child_weight': 3,
'silent': 1,
'eta': 0.1,
'seed': 1000,
'nthread': 4,
}

dtrain = xgb.DMatrix(X_train, y_train)
num_rounds = 300
plst = list(params.items())
model = xgb.train(plst, dtrain, num_rounds)

# 对测试集进行预测
dtest = xgb.DMatrix(X_test)
ans = model.predict(dtest)

# 显示重要特征
plot_importance(model)
plt.show()

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Zu2NWnA-1623946035318)(output_32_1.png)]

XGBoost调参(结合sklearn网格搜索)

代码参考:https://www.jianshu.com/p/1100e333fcab

import xgboost as xgb
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import roc_auc_score

iris = load_iris()
X,y = iris.data,iris.target
col = iris.target_names
train_x, valid_x, train_y, valid_y = train_test_split(X, y, test_size=0.3, random_state=1) # 分训练集和验证集
parameters = {
'max_depth': [5, 10, 15, 20, 25],
'learning_rate': [0.01, 0.02, 0.05, 0.1, 0.15],
'n_estimators': [500, 1000, 2000, 3000, 5000],
'min_child_weight': [0, 2, 5, 10, 20],
'max_delta_step': [0, 0.2, 0.6, 1, 2],
'subsample': [0.6, 0.7, 0.8, 0.85, 0.95],
'colsample_bytree': [0.5, 0.6, 0.7, 0.8, 0.9],
'reg_alpha': [0, 0.25, 0.5, 0.75, 1],
'reg_lambda': [0.2, 0.4, 0.6, 0.8, 1],
'scale_pos_weight': [0.2, 0.4, 0.6, 0.8, 1]

}

xlf = xgb.XGBClassifier(max_depth=10,
learning_rate=0.01,
n_estimators=2000,
silent=True,
objective='multi:softmax',
num_class=3 ,
nthread=-1,
gamma=0,
min_child_weight=1,
max_delta_step=0,
subsample=0.85,
colsample_bytree=0.7,
colsample_bylevel=1,
reg_alpha=0,
reg_lambda=1,
scale_pos_weight=1,
seed=0,
missing=None)

gs = GridSearchCV(xlf, param_grid=parameters, scoring='accuracy', cv=3)
gs.fit(train_x, train_y)

print("Best score: %0.3f" % gs.best_score_)
print("Best parameters set: %s" % gs.best_params_ )

Best score: 0.933
Best parameters set: {‘max_depth’: 5}

8. LightGBM算法

LightGBM也是像XGBoost一样,是一类集成算法,他跟XGBoost总体来说是一样的,算法本质上与Xgboost没有出入,只是在XGBoost的基础上进行了优化,因此就不对原理进行重复介绍,在这里我们来看看几种算法的差别:

  • 优化速度和内存使用
    • 降低了计算每个分割增益的成本。
    • 使用直方图减法进一步提高速度。
    • 减少内存使用。
    • 减少并行学习的计算成本。
  • 稀疏优化
    • 用离散的bin替换连续的值。如果#bins较小,则可以使用较小的数据类型(例如uint8_t)来存储训练数据 。
    • 无需存储其他信息即可对特征数值进行预排序 。
  • 精度优化
    • 使用叶子数为导向的决策树建立算法而不是树的深度导向。

    • 分类特征的编码方式的优化

    • 通信网络的优化

    • 并行学习的优化

    • GPU支持

      LightGBM的优点:

  1)更快的训练效率

  2)低内存使用

  3)更高的准确率

  4)支持并行化学习

  5)可以处理大规模数据

1.速度对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-W562LSSA-1623946035318)(./速度对比.png)]
2.准确率对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4JVvKjX-1623946035319)(./准确率对比.png)]
3.内存使用量对比:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-glXaoZd6-1623946035320)(./内存使用量.png)]

LightGBM参数说明:
推荐文档1:https://lightgbm.apachecn.org/#/docs/6
推荐文档2:https://lightgbm.readthedocs.io/en/latest/Parameters.html

1.核心参数:(括号内名称是别名)

  • objective(objective,app ,application):默认regression,用于设置损失函数
    • 回归问题:
      • L2损失:regression(regression_l2,l2,mean_squared_error,mse,l2_root,root_mean_squared_error,rmse)
      • L1损失:regression_l1(l1, mean_absolute_error, mae)
      • 其他损失:huber,fair,poisson,quantile,mape,gamma,tweedie
    • 二分类问题:二进制对数损失分类(或逻辑回归):binary
    • 多类别分类:
      • softmax目标函数: multiclass(softmax)
      • One-vs-All 目标函数:multiclassova(multiclass_ova,ova,ovr)
    • 交叉熵:
      • 用于交叉熵的目标函数(具有可选的线性权重):cross_entropy(xentropy)
      • 交叉熵的替代参数化:cross_entropy_lambda(xentlambda)
  • boosting :默认gbdt,设置提升类型,选项有gbdt,rf,dart,goss,别名:boosting_type,boost
    • gbdt(gbrt):传统的梯度提升决策树
    • rf(random_forest):随机森林
    • dart:多个加性回归树的DROPOUT方法 Dropouts meet Multiple Additive Regression Trees,参见:https://arxiv.org/abs/1505.01866
    • goss:基于梯度的单边采样 Gradient-based One-Side Sampling
  • data(train,train_data,train_data_file,data_filename):用于训练的数据或数据file
  • valid (test,valid_data,valid_data_file,test_data,test_data_file,valid_filenames):验证/测试数据的路径,LightGBM将输出这些数据的指标
  • num_iterations:默认=100,类型= INT
  • n_estimators:提升迭代次数,*LightGBM构造用于多类分类问题的树num_class * num_iterations*
  • learning_rate(shrinkage_rate,eta) :收缩率,默认=0.1
  • num_leaves(num_leaf,max_leaves,max_leaf) :默认=31,一棵树上的最大叶子数
  • tree_learner (tree,tree_type,tree_learner_type):默认=serial,可选:serial,feature,data,voting
    • serial:单台机器的 tree learner
    • feature:特征并行的 tree learner
    • data:数据并行的 tree learner
    • voting:投票并行的 tree learner
  • num_threads(num_thread, nthread):LightGBM 的线程数,为了更快的速度, 将此设置为真正的 CPU 内核数, 而不是线程的数量 (大多数 CPU 使用超线程来使每个 CPU 内核生成 2 个线程),当你的数据集小的时候不要将它设置的过大 (比如, 当数据集有 10,000 行时不要使用 64 线程),对于并行学习, 不应该使用全部的 CPU 内核, 因为这会导致网络性能不佳。
  • device(device_type):默认cpu,为树学习选择设备, 你可以使用 GPU 来获得更快的学习速度,可选cpu, gpu。
  • seed (random_seed,random_state):与其他种子相比,该种子具有较低的优先级,这意味着如果您明确设置其他种子,它将被覆盖。

2.用于控制模型学习过程的参数:

  • max_depth:限制树模型的最大深度. 这可以在 #data 小的情况下防止过拟合. 树仍然可以通过 leaf-wise 生长。
  • min_data_in_leaf: 默认=20,一个叶子上数据的最小数量. 可以用来处理过拟合。
  • min_sum_hessian_in_leaf(min_sum_hessian_per_leaf, min_sum_hessian, min_hessian):默认=1e-3,一个叶子上的最小 hessian 和. 类似于 min_data_in_leaf, 可以用来处理过拟合.
  • feature_fraction:default=1.0,如果 feature_fraction 小于 1.0, LightGBM 将会在每次迭代中随机选择部分特征. 例如, 如果设置为 0.8, 将会在每棵树训练之前选择 80% 的特征,可以用来加速训练,可以用来处理过拟合。
  • feature_fraction_seed:默认=2,feature_fraction 的随机数种子。
  • bagging_fraction(sub_row, subsample):默认=1,不进行重采样的情况下随机选择部分数据
  • bagging_freq(subsample_freq):bagging 的频率, 0 意味着禁用 bagging. k 意味着每 k 次迭代执行bagging
  • bagging_seed(bagging_fraction_seed) :默认=3,bagging 随机数种子。
  • early_stopping_round(early_stopping_rounds, early_stopping):默认=0,如果一个验证集的度量在 early_stopping_round 循环中没有提升, 将停止训练
  • lambda_l1(reg_alpha):L1正则化系数
  • lambda_l2(reg_lambda):L2正则化系数
  • min_split_gain(min_gain_to_split):执行切分的最小增益,默认=0.
  • cat_smooth:默认=10,用于分类特征,可以降低噪声在分类特征中的影响, 尤其是对数据很少的类别

3.度量参数:

  • metric:default={l2 for regression}, {binary_logloss for binary classification}, {ndcg for lambdarank}, type=multi-enum, options=l1, l2, ndcg, auc, binary_logloss, binary_error …
    • l1, absolute loss, alias=mean_absolute_error, mae
    • l2, square loss, alias=mean_squared_error, mse
    • l2_root, root square loss, alias=root_mean_squared_error, rmse
    • quantile, Quantile regression
    • huber, Huber loss
    • fair, Fair loss
    • poisson, Poisson regression
    • ndcg, NDCG
    • map, MAP
    • auc, AUC
    • binary_logloss, log loss
    • binary_error, 样本: 0 的正确分类, 1 错误分类
    • multi_logloss, mulit-class 损失日志分类
    • multi_error, error rate for mulit-class 出错率分类
    • xentropy, cross-entropy (与可选的线性权重), alias=cross_entropy
    • xentlambda, “intensity-weighted” 交叉熵, alias=cross_entropy_lambda
    • kldiv, Kullback-Leibler divergence, alias=kullback_leibler
    • 支持多指标, 使用 , 分隔
  • train_metric(training_metric, is_training_metric):默认=False,如果你需要输出训练的度量结果则设置 true

4.GPU 参数:

  • gpu_device_id:default为-1, 这个default意味着选定平台上的设备。

LightGBM与网格搜索结合调参:
参考代码:https://blog.csdn.net/u012735708/article/details/83749703

import lightgbm as lgb
from sklearn import metrics
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split

canceData=load_breast_cancer()
X=canceData.data
y=canceData.target
X_train,X_test,y_train,y_test=train_test_split(X,y,random_state=0,test_size=0.2)

### 数据转换
print('数据转换')
lgb_train = lgb.Dataset(X_train, y_train, free_raw_data=False)
lgb_eval = lgb.Dataset(X_test, y_test, reference=lgb_train,free_raw_data=False)

### 设置初始参数--不含交叉验证参数
print('设置参数')
params = {
'boosting_type': 'gbdt',
'objective': 'binary',
'metric': 'auc',
'nthread':4,
'learning_rate':0.1
}

### 交叉验证(调参)
print('交叉验证')
max_auc = float('0')
best_params = {}

# 准确率
print("调参1:提高准确率")
for num_leaves in range(5,100,5):
for max_depth in range(3,8,1):
params['num_leaves'] = num_leaves
params['max_depth'] = max_depth

cv_results = lgb.cv(
params,
lgb_train,
seed=1,
nfold=5,
metrics=['auc'],
early_stopping_rounds=10,
verbose_eval=True
)

mean_auc = pd.Series(cv_results['auc-mean']).max()
boost_rounds = pd.Series(cv_results['auc-mean']).idxmax()

if mean_auc >= max_auc:
max_auc = mean_auc
best_params['num_leaves'] = num_leaves
best_params['max_depth'] = max_depth
if 'num_leaves' and 'max_depth' in best_params.keys():
params['num_leaves'] = best_params['num_leaves']
params['max_depth'] = best_params['max_depth']

# 过拟合
print("调参2:降低过拟合")
for max_bin in range(5,256,10):
for min_data_in_leaf in range(1,102,10):
params['max_bin'] = max_bin
params['min_data_in_leaf'] = min_data_in_leaf

cv_results = lgb.cv(
params,
lgb_train,
seed=1,
nfold=5,
metrics=['auc'],
early_stopping_rounds=10,
verbose_eval=True
)

mean_auc = pd.Series(cv_results['auc-mean']).max()
boost_rounds = pd.Series(cv_results['auc-mean']).idxmax()

if mean_auc >= max_auc:
max_auc = mean_auc
best_params['max_bin']= max_bin
best_params['min_data_in_leaf'] = min_data_in_leaf
if 'max_bin' and 'min_data_in_leaf' in best_params.keys():
params['min_data_in_leaf'] = best_params['min_data_in_leaf']
params['max_bin'] = best_params['max_bin']

print("调参3:降低过拟合")
for feature_fraction in [0.6,0.7,0.8,0.9,1.0]:
for bagging_fraction in [0.6,0.7,0.8,0.9,1.0]:
for bagging_freq in range(0,50,5):
params['feature_fraction'] = feature_fraction
params['bagging_fraction'] = bagging_fraction
params['bagging_freq'] = bagging_freq

cv_results = lgb.cv(
params,
lgb_train,
seed=1,
nfold=5,
metrics=['auc'],
early_stopping_rounds=10,
verbose_eval=True
)

mean_auc = pd.Series(cv_results['auc-mean']).max()
boost_rounds = pd.Series(cv_results['auc-mean']).idxmax()

if mean_auc >= max_auc:
max_auc=mean_auc
best_params['feature_fraction'] = feature_fraction
best_params['bagging_fraction'] = bagging_fraction
best_params['bagging_freq'] = bagging_freq

if 'feature_fraction' and 'bagging_fraction' and 'bagging_freq' in best_params.keys():
params['feature_fraction'] = best_params['feature_fraction']
params['bagging_fraction'] = best_params['bagging_fraction']
params['bagging_freq'] = best_params['bagging_freq']


print("调参4:降低过拟合")
for lambda_l1 in [1e-5,1e-3,1e-1,0.0,0.1,0.3,0.5,0.7,0.9,1.0]:
for lambda_l2 in [1e-5,1e-3,1e-1,0.0,0.1,0.4,0.6,0.7,0.9,1.0]:
params['lambda_l1'] = lambda_l1
params['lambda_l2'] = lambda_l2
cv_results = lgb.cv(
params,
lgb_train,
seed=1,
nfold=5,
metrics=['auc'],
early_stopping_rounds=10,
verbose_eval=True
)

mean_auc = pd.Series(cv_results['auc-mean']).max()
boost_rounds = pd.Series(cv_results['auc-mean']).idxmax()

if mean_auc >= max_auc:
max_auc=mean_auc
best_params['lambda_l1'] = lambda_l1
best_params['lambda_l2'] = lambda_l2
if 'lambda_l1' and 'lambda_l2' in best_params.keys():
params['lambda_l1'] = best_params['lambda_l1']
params['lambda_l2'] = best_params['lambda_l2']

print("调参5:降低过拟合2")
for min_split_gain in [0.0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9,1.0]:
params['min_split_gain'] = min_split_gain

cv_results = lgb.cv(
params,
lgb_train,
seed=1,
nfold=5,
metrics=['auc'],
early_stopping_rounds=10,
verbose_eval=True
)

mean_auc = pd.Series(cv_results['auc-mean']).max()
boost_rounds = pd.Series(cv_results['auc-mean']).idxmax()

if mean_auc >= max_auc:
max_auc=mean_auc

best_params['min_split_gain'] = min_split_gain
if 'min_split_gain' in best_params.keys():
params['min_split_gain'] = best_params['min_split_gain']

print(best_params)

{‘bagging_fraction’: 0.7,
‘bagging_freq’: 30,
‘feature_fraction’: 0.8,
‘lambda_l1’: 0.1,
‘lambda_l2’: 0.0,
‘max_bin’: 255,
‘max_depth’: 4,
‘min_data_in_leaf’: 81,
‘min_split_gain’: 0.1,
‘num_leaves’: 10}

9. 结语

本章中,我们主要探讨了基于Boosting方式的集成方法,其中主要讲解了基于错误率驱动的Adaboost,基于残差改进的提升树,基于梯度提升的GBDT,基于泰勒二阶近似的Xgboost以及LightGBM。在实际的比赛或者工程中,基于Boosting的集成学习方式是非常有效且应用非常广泛的。更多的学习有待读者更深入阅读文献,包括原作者论文以及论文复现等。下一章我们即将探讨另一种集成学习方式:Stacking集成学习方式,这种集成方式虽然没有Boosting应用广泛,但是在比赛中或许能让你的模型更加出众。

本章作业:
本章在最后介绍LightGBM的时候并没有详细介绍它的原理以及它与XGBoost的不一样的地方,希望读者好好看看别的文章分享,总结LigntGBM与XGBoost的不同,然后使用一个具体的案例体现两者的不同。
参考链接: https://blog.csdn.net/weixin_30279315/article/details/95504220

]]>
+ + + + <h1 id="XGBoost算法"><a href="#XGBoost算法" class="headerlink" title="XGBoost算法"></a>XGBoost算法</h1><p>XGBoost是陈天奇等人开发的一个开源机器学习项目,高效地实现了GBDT算法并进行了算法和工程上的许多改进,被广泛应用在Kaggle竞赛及其他许多机器学习竞赛中并取得了不错的成绩。<strong>XGBoost本质上还是一个GBDT,但是力争把速度和效率发挥到极致,所以叫X (Extreme) GBoosted,</strong> 包括前面说过,两者都是boosting方法。XGBoost是一个优化的分布式梯度增强库,旨在实现高效,灵活和便携。 它在Gradient Boosting框架下实现机器学习算法。 XGBoost提供了<strong>并行树提升</strong>(也称为GBDT,GBM),可以快速准确地解决许多数据科学问题。 相同的代码在主要的分布式环境(Hadoop,SGE,MPI)上运行,并且可以解决超过数十亿个样例的问题。XGBoost利用了核外计算并且能够使数据科学家在一个主机上处理数亿的样本数据。最终,将这些技术进行结合来做一个端到端的系统以最少的集群系统来扩展到更大的数据集上。Xgboost<strong>以CART决策树为子模型</strong>,通过Gradient Tree Boosting实现多棵CART树的集成学习,得到最终模型。下面我们来看看XGBoost的最终模型构建:</p> + + + + + + + + + +
+ + + 集成学习专题——GBDT + + https://jackyin.space/2021/06/17/%E9%9B%86%E6%88%90%E5%AD%A6%E4%B9%A0%E4%B8%93%E9%A2%98%E2%80%94%E2%80%94GBDT/ + 2021-06-17T15:59:00.000Z + 2024-10-09T08:43:45.344Z + + 梯度提升决策树(GBDT)

(1) 基于残差学习的提升树算法:
在前面的学习过程中,我们一直讨论的都是分类树,比如Adaboost算法,并没有涉及回归的例子。在上一小节我们提到了一个加法模型+前向分步算法的框架,那能否使用这个框架解决回归的例子呢?答案是肯定的。接下来我们来探讨下如何使用加法模型+前向分步算法的框架实现回归问题。
在使用加法模型+前向分步算法的框架解决问题之前,我们需要首先确定框架内使用的基函数是什么,在这里我们使用决策树分类器。前面第二章我们已经学过了回归树的基本原理,树算法最重要是寻找最佳的划分点,分类树用纯度来判断最佳划分点使用信息增益(ID3算法),信息增益比(C4.5算法),基尼系数(CART分类树)。但是在回归树中的样本标签是连续数值,可划分点包含了所有特征的所有可取的值。所以再使用熵之类的指标不再合适,取而代之的是平方误差,它能很好的评判拟合程度。 基函数确定了以后,我们需要确定每次提升的标准是什么。回想Adaboost算法,在Adaboost算法内使用了分类错误率修正样本权重以及计算每个基本分类器的权重,那回归问题没有分类错误率可言,也就没办法在这里的回归问题使用了,因此我们需要另辟蹊径。模仿分类错误率,我们用每个样本的残差表示每次使用基函数预测时没有解决的那部分问题。因此,我们可以得出如下算法:

输入数据集$T=\left{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right}, x_{i} \in \mathcal{X} \subseteq \mathbf{R}^{n}, y_{i} \in \mathcal{Y} \subseteq \mathbf{R}$,输出最终的提升树$f_{M}(x)$

  • 初始化$f_0(x) = 0$

  • 对m = 1,2,…,M:

    • 计算每个样本的残差:$r_{m i}=y_{i}-f_{m-1}\left(x_{i}\right), \quad i=1,2, \cdots, N$
    • 拟合残差$r_{mi}$学习一棵回归树,得到$T\left(x ; \Theta_{m}\right)$
    • 更新$f_{m}(x)=f_{m-1}(x)+T\left(x ; \Theta_{m}\right)$
  • 得到最终的回归问题的提升树:$f_{M}(x)=\sum_{m=1}^{M} T\left(x ; \Theta_{m}\right)$

    下面我们用一个实际的案例来使用这个算法:(案例来源:李航老师《统计学习方法》)
    训练数据如下表,学习这个回归问题的提升树模型,考虑只用树桩作为基函数。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6RIHgryn-1623945003185)(./1.png)]
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    至此,我们已经能够建立起依靠加法模型+前向分步算法的框架解决回归问题的算法,叫提升树算法。那么,这个算法还是否有提升的空间呢?
    (2) 梯度提升决策树算法(GBDT):
    提升树利用加法模型和前向分步算法实现学习的过程,当损失函数为平方损失和指数损失时,每一步优化是相当简单的,也就是我们前面探讨的提升树算法和Adaboost算法。但是对于一般的损失函数而言,往往每一步的优化不是那么容易,针对这一问题,我们得分析问题的本质,也就是是什么导致了在一般损失函数条件下的学习困难。对比以下损失函数:
    $$
    \begin{array}{l|l|l}
    \hline \text { Setting } & \text { Loss Function } & -\partial L\left(y_{i}, f\left(x_{i}\right)\right) / \partial f\left(x_{i}\right) \
    \hline \text { Regression } & \frac{1}{2}\left[y_{i}-f\left(x_{i}\right)\right]^{2} & y_{i}-f\left(x_{i}\right) \
    \hline \text { Regression } & \left|y_{i}-f\left(x_{i}\right)\right| & \operatorname{sign}\left[y_{i}-f\left(x_{i}\right)\right] \
    \hline \text { Regression } & \text { Huber } & y_{i}-f\left(x_{i}\right) \text { for }\left|y_{i}-f\left(x_{i}\right)\right| \leq \delta_{m} \
    & & \delta_{m} \operatorname{sign}\left[y_{i}-f\left(x_{i}\right)\right] \text { for }\left|y_{i}-f\left(x_{i}\right)\right|>\delta_{m} \
    & & \text { where } \delta_{m}=\alpha \text { th-quantile }\left{\left|y_{i}-f\left(x_{i}\right)\right|\right} \
    \hline \text { Classification } & \text { Deviance } & k \text { th component: } I\left(y_{i}=\mathcal{G}{k}\right)-p{k}\left(x_{i}\right) \
    \hline
    \end{array}
    $$
    观察Huber损失函数:
    $$
    L_{\delta}(y, f(x))=\left{\begin{array}{ll}
    \frac{1}{2}(y-f(x))^{2} & \text { for }|y-f(x)| \leq \delta \
    \delta|y-f(x)|-\frac{1}{2} \delta^{2} & \text { otherwise }
    \end{array}\right.
    $$
    针对上面的问题,Freidman提出了梯度提升算法(gradient boosting),这是利用最速下降法的近似方法,利用损失函数的负梯度在当前模型的值$-\left[\frac{\partial L\left(y, f\left(x_{i}\right)\right)}{\partial f\left(x_{i}\right)}\right]{f(x)=f{m-1}(x)}$作为回归问题提升树算法中的残差的近似值,拟合回归树。与其说负梯度作为残差的近似值,不如说残差是负梯度的一种特例。
    以下开始具体介绍梯度提升算法:
    输入训练数据集$T=\left{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right}, x_{i} \in \mathcal{X} \subseteq \mathbf{R}^{n}, y_{i} \in \mathcal{Y} \subseteq \mathbf{R}$和损失函数$L(y, f(x))$,输出回归树$\hat{f}(x)$

  • 初始化$f_{0}(x)=\arg \min {c} \sum{i=1}^{N} L\left(y_{i}, c\right)$

  • 对于m=1,2,…,M:

    • 对i = 1,2,…,N计算:$r_{m i}=-\left[\frac{\partial L\left(y_{i}, f\left(x_{i}\right)\right)}{\partial f\left(x_{i}\right)}\right]{f(x)=f{m-1}(x)}$
    • 对$r_{mi}$拟合一个回归树,得到第m棵树的叶结点区域$R_{m j}, j=1,2, \cdots, J$
    • 对j=1,2,…J,计算:$c_{m j}=\arg \min {c} \sum{x_{i} \in R_{m j}} L\left(y_{i}, f_{m-1}\left(x_{i}\right)+c\right)$
    • 更新$f_{m}(x)=f_{m-1}(x)+\sum_{j=1}^{J} c_{m j} I\left(x \in R_{m j}\right)$
  • 得到回归树:$\hat{f}(x)=f_{M}(x)=\sum_{m=1}^{M} \sum_{j=1}^{J} c_{m j} I\left(x \in R_{m j}\right)$

下面,我们来使用一个具体的案例来说明GBDT是如何运作的(案例来源:https://blog.csdn.net/zpalyq110/article/details/79527653 ):
下面的表格是数据:
在这里插入图片描述

学习率:learning_rate=0.1,迭代次数:n_trees=5,树的深度:max_depth=3
平方损失的负梯度为:
$$
-\left[\frac{\left.\partial L\left(y, f\left(x_{i}\right)\right)\right)}{\partial f\left(x_{i}\right)}\right]{f(x)=f{t-1}(x)}=y-f\left(x_{i}\right)
$$
$c=(1.1+1.3+1.7+1.8)/4=1.475,f_{0}(x)=c=1.475$
在这里插入图片描述

学习决策树,分裂结点:
在这里插入图片描述

在这里插入图片描述

对于左节点,只有0,1两个样本,那么根据下表我们选择年龄7进行划分:
在这里插入图片描述

对于右节点,只有2,3两个样本,那么根据下表我们选择年龄30进行划分:
在这里插入图片描述

在这里插入图片描述

因此根据$\Upsilon_{j 1}=\underbrace{\arg \min }{\Upsilon} \sum{x_{i} \in R_{j 1}} L\left(y_{i}, f_{0}\left(x_{i}\right)+\Upsilon\right)$:
$$
\begin{array}{l}
\left(x_{0} \in R_{11}\right), \quad \Upsilon_{11}=-0.375 \
\left(x_{1} \in R_{21}\right), \quad \Upsilon_{21}=-0.175 \
\left(x_{2} \in R_{31}\right), \quad \Upsilon_{31}=0.225 \
\left(x_{3} \in R_{41}\right), \quad \Upsilon_{41}=0.325
\end{array}
$$
这里其实和上面初始化学习器是一个道理,平方损失,求导,令导数等于零,化简之后得到每个叶子节点的参数$\Upsilon$,其实就是标签值的均值。
最后得到五轮迭代:
在这里插入图片描述

最后的强学习器为:$f(x)=f_{5}(x)=f_{0}(x)+\sum_{m=1}^{5} \sum_{j=1}^{4} \Upsilon_{j m} I\left(x \in R_{j m}\right)$。
其中:
$$
\begin{array}{ll}
f_{0}(x)=1.475 & f_{2}(x)=0.0205 \
f_{3}(x)=0.1823 & f_{4}(x)=0.1640 \
f_{5}(x)=0.1476
\end{array}
$$
预测结果为:
$$
f(x)=1.475+0.1 *(0.2250+0.2025+0.1823+0.164+0.1476)=1.56714
$$
为什么要用学习率呢?这是Shrinkage的思想,如果每次都全部加上(学习率为1)很容易一步学到位导致过拟合。

下面我们来使用sklearn来使用GBDT:

from sklearn.metrics import mean_squared_error
from sklearn.datasets import make_friedman1
from sklearn.ensemble import GradientBoostingRegressor
'''
GradientBoostingRegressor参数解释:
loss:{‘ls’, ‘lad’, ‘huber’, ‘quantile’}, default=’ls’:‘ls’ 指最小二乘回归. ‘lad’ (最小绝对偏差) 是仅基于输入变量的顺序信息的高度鲁棒的损失函数。. ‘huber’ 是两者的结合. ‘quantile’允许分位数回归(用于alpha指定分位数)
learning_rate:学习率缩小了每棵树的贡献learning_rate。在learning_rate和n_estimators之间需要权衡。
n_estimators:要执行的提升次数。
subsample:用于拟合各个基础学习者的样本比例。如果小于1.0,则将导致随机梯度增强。subsample与参数n_estimators。选择会导致方差减少和偏差增加。subsample < 1.0
criterion:{'friedman_mse','mse','mae'},默认='friedman_mse':“ mse”是均方误差,“ mae”是平均绝对误差。默认值“ friedman_mse”通常是最好的,因为在某些情况下它可以提供更好的近似值。
min_samples_split:拆分内部节点所需的最少样本数
min_samples_leaf:在叶节点处需要的最小样本数。
min_weight_fraction_leaf:在所有叶节点处(所有输入样本)的权重总和中的最小加权分数。如果未提供sample_weight,则样本的权重相等。
max_depth:各个回归模型的最大深度。最大深度限制了树中节点的数量。调整此参数以获得最佳性能;最佳值取决于输入变量的相互作用。
min_impurity_decrease:如果节点分裂会导致杂质的减少大于或等于该值,则该节点将被分裂。
min_impurity_split:提前停止树木生长的阈值。如果节点的杂质高于阈值,则该节点将分裂
max_features{‘auto’, ‘sqrt’, ‘log2’},int或float:寻找最佳分割时要考虑的功能数量:

如果为int,则max_features在每个分割处考虑特征。

如果为float,max_features则为小数,并在每次拆分时考虑要素。int(max_features * n_features)

如果“auto”,则max_features=n_features。

如果是“ sqrt”,则max_features=sqrt(n_features)。

如果为“ log2”,则为max_features=log2(n_features)。

如果没有,则max_features=n_features。
'''

X, y = make_friedman1(n_samples=1200, random_state=0, noise=1.0)
X_train, X_test = X[:200], X[200:]
y_train, y_test = y[:200], y[200:]
reg = GradientBoostingRegressor(n_estimators=100,
learning_rate=0.1,max_depth=1, random_state=0, loss='ls')
est = reg.fit(X_train, y_train)
mean_squared_error(y_test, est.predict(X_test))
from sklearn.datasets import make_regression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.model_selection import train_test_split
X, y = make_regression(random_state=0)
X_train, X_test, y_train, y_test = train_test_split(
X, y, random_state=0)
reg = GradientBoostingRegressor(random_state=0)
reg.fit(X_train, y_train)
reg.score(X_test, y_test)

GradientBoostingRegressor与GradientBoostingClassifier函数的各个参数的参考文档:

]]>
+ + + + <h2 id="梯度提升决策树-GBDT"><a href="#梯度提升决策树-GBDT" class="headerlink" title="梯度提升决策树(GBDT)"></a>梯度提升决策树(GBDT)</h2><p>(1) 基于残差学习的提升树算法:<br>在前面的学习过程中,我们一直讨论的都是分类树,比如Adaboost算法,并没有涉及回归的例子。在上一小节我们提到了一个加法模型+前向分步算法的框架,那能否使用这个框架解决回归的例子呢?答案是肯定的。接下来我们来探讨下如何使用加法模型+前向分步算法的框架实现回归问题。<br>在使用加法模型+前向分步算法的框架解决问题之前,我们需要首先确定框架内使用的基函数是什么,在这里我们使用决策树分类器。前面第二章我们已经学过了回归树的基本原理,<strong>树算法最重要是寻找最佳的划分点,分类树用纯度来判断最佳划分点使用信息增益(ID3算法),信息增益比(C4.5算法),基尼系数(CART分类树)。但是在回归树中的样本标签是连续数值,可划分点包含了所有特征的所有可取的值。所以再使用熵之类的指标不再合适,取而代之的是平方误差,它能很好的评判拟合程度。</strong> 基函数确定了以后,我们需要确定每次提升的标准是什么。回想Adaboost算法,在Adaboost算法内使用了分类错误率修正样本权重以及计算每个基本分类器的权重,那回归问题没有分类错误率可言,也就没办法在这里的回归问题使用了,因此我们需要另辟蹊径。模仿分类错误率,我们用每个样本的残差表示每次使用基函数预测时没有解决的那部分问题。因此,我们可以得出如下算法: </p> + + + + + + + + + +
+ + + 集成学习专题——adaboost原理和sklearn实现 + + https://jackyin.space/2021/06/17/%E9%9B%86%E6%88%90%E5%AD%A6%E4%B9%A0%E4%B8%93%E9%A2%98%E2%80%94%E2%80%94adaboost%E5%8E%9F%E7%90%86%E5%92%8Csklearn%E5%AE%9E%E7%8E%B0/ + 2021-06-17T15:15:00.000Z + 2024-10-09T08:43:45.344Z + + 1. 导论

在前面的学习中,我们探讨了一系列简单而实用的回归和分类模型,同时也探讨了如何使用集成学习家族中的Bagging思想去优化最终的模型。Bagging思想的实质是:通过Bootstrap 的方式对全样本数据集进行抽样得到抽样子集,对不同的子集使用同一种基本模型进行拟合,然后投票得出最终的预测。我们也从前面的探讨知道:Bagging主要通过降低方差的方式减少预测误差。那么,本章介绍的Boosting是与Bagging截然不同的思想,Boosting方法是使用同一组数据集进行反复学习,得到一系列简单模型,然后组合这些模型构成一个预测性能十分强大的机器学习模型。 显然,Boosting思想提高最终的预测效果是通过不断减少偏差的形式,与Bagging有着本质的不同。在Boosting这一大类方法中,笔者主要介绍两类常用的Boosting方式:Adaptive Boosting 和 Gradient Boosting 以及它们的变体Xgboost、LightGBM以及Catboost。

2. Boosting方法的基本思路

在正式介绍Boosting思想之前,我想先介绍两个例子:
第一个例子:不知道大家有没有做过错题本,我们将每次测验的错的题目记录在错题本上,不停的翻阅,直到我们完全掌握(也就是能够在考试中能够举一反三)。
第二个例子:对于一个复杂任务来说,将多个专家的判断进行适当的综合所作出的判断,要比其中任何一个专家单独判断要好。实际上这是一种“三个臭皮匠顶个诸葛亮的道理”。
这两个例子都说明Boosting的道理,也就是不错地重复学习达到最终的要求。
Boosting的提出与发展离不开Valiant和 Kearns的努力,历史上正是Valiant和 Kearns提出了”强可学习”和”弱可学习”的概念。那什么是”强可学习”和”弱可学习”呢?在概率近似正确PAC学习的框架下:

  • 弱学习:识别错误率小于1/2(即准确率仅比随机猜测略高的学习算法)
  • 强学习:识别准确率很高并能在多项式时间内完成的学习算法

非常有趣的是,在PAC 学习的框架下,强可学习和弱可学习是等价的,也就是说一个概念是强可学习的充分必要条件是这个概念是弱可学习的。这样一来,问题便是:在学习中,如果已经发现了弱可学习算法,能否将他提升至强可学习算法。因为,弱可学习算法比强可学习算法容易得多。提升方法就是从弱学习算法出发,反复学习,得到一系列弱分类器(又称为基本分类器),然后通过一定的形式去组合这些弱分类器构成一个强分类器。大多数的Boosting方法都是通过改变训练数据集的概率分布(训练数据不同样本的权值),针对不同概率分布的数据调用弱分类算法学习一系列的弱分类器。
对于Boosting方法来说,有两个问题需要给出答案:第一个是每一轮学习应该如何改变数据的概率分布,第二个是如何将各个弱分类器组合起来。关于这两个问题,不同的Boosting算法会有不同的答案,我们接下来介绍一种最经典的Boosting算法—-Adaboost,我们需要理解Adaboost是怎么处理这两个问题以及为什么这么处理的。

3. Adaboost算法

Adaboost的基本原理

对于Adaboost来说,解决上述的两个问题的方式是:

  • 提高那些被前一轮分类器错误分类的样本的权重,而降低那些被正确分类的样本的权重。这样一来,那些在上一轮分类器中没有得到正确分类的样本,由于其权重的增大而在后一轮的训练中“备受关注”。
  • 各个弱分类器的组合是通过采取加权多数表决的方式,具体来说,加大分类错误率低的弱分类器的权重,因为这些分类器能更好地完成分类任务,而减小分类错误率较大的弱分类器的权重,使其在表决中起较小的作用。

现在,我们来具体介绍Adaboost算法:(参考李航老师的《统计学习方法》)
假设给定一个二分类的训练数据集:$T=\left{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right}$ ,其中每个样本点由特征与类别组成。特征$x_{i} \in \mathcal{X} \subseteq \mathbf{R}^{n}$,类别$y_{i} \in \mathcal{Y}={-1,+1}$,$\mathcal{X}$是特征空间,$ \mathcal{Y}$是类别集合,输出最终分类器$G(x)$。Adaboost算法如下:
(1) 初始化训练数据的分布:$D_{1}=\left(w_{11}, \cdots, w_{1 i}, \cdots, w_{1 N}\right), \quad w_{1 i}=\frac{1}{N}, \quad i=1,2, \cdots, N$
(2) 对于m=1,2,…,M

  • 使用具有权值分布$D_m$的训练数据集进行学习,得到基本分类器:$G_{m}(x): \mathcal{X} \rightarrow{-1,+1}$
  • 计算$G_m(x)$在训练集上的分类误差率$e_{m}=\sum_{i=1}^{N} P\left(G_{m}\left(x_{i}\right) \neq y_{i}\right)=\sum_{i=1}^{N} w_{m i} I\left(G_{m}\left(x_{i}\right) \neq y_{i}\right)$
  • 计算$G_m(x)$的系数$\alpha_{m}=\frac{1}{2} \log \frac{1-e_{m}}{e_{m}}$,这里的log是自然对数ln
  • 更新训练数据集的权重分布
    $$
    \begin{array}{c}
    D_{m+1}=\left(w_{m+1,1}, \cdots, w_{m+1, i}, \cdots, w_{m+1, N}\right) \
    w_{m+1, i}=\frac{w_{m i}}{Z_{m}} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right), \quad i=1,2, \cdots, N
    \end{array}
    $$ 这里的$Z_m$是规范化因子,使得$D_{m+1}$称为概率分布,$Z_{m}=\sum_{i=1}^{N} w_{m i} \exp \left(-\alpha_{m} y_{i} G_{m}\left(x_{i}\right)\right)$

(3) 构建基本分类器的线性组合$f(x)=\sum_{m=1}^{M} \alpha_{m} G_{m}(x)$,得到最终的分类器

$$
\begin{aligned}
G(x) &=\operatorname{sign}(f(x)) \
&=\operatorname{sign}\left(\sum_{m=1}^{M} \alpha_{m} G_{m}(x)\right)
\end{aligned}
$$

下面对Adaboost算法做如下说明:
对于步骤(1),假设训练数据的权值分布是均匀分布,是为了使得第一次没有先验信息的条件下每个样本在基本分类器的学习中作用一样。
对于步骤(2),每一次迭代产生的基本分类器$G_m(x)$在加权训练数据集上的分类错误率$\begin{aligned}e_{m} &=\sum_{i=1}^{N} P\left(G_{m}\left(x_{i}\right) \neq y_{i}\right) =\sum_{G_{m}\left(x_{i}\right) \neq y_{i}} w_{m i}\end{aligned}$代表了在$G_m(x)$中分类错误的样本权重和,这点直接说明了权重分布$D_m$与$G_m(x)$的分类错误率$e_m$有直接关系。同时,在步骤(2)中,计算基本分类器$G_m(x)$的系数$\alpha_m$,$\alpha_{m}=\frac{1}{2} \log \frac{1-e_{m}}{e_{m}}$,它表示了$G_m(x)$在最终分类器的重要性程度,$\alpha_m$的取值由基本分类器$G_m(x)$的分类错误率有直接关系,当$e_{m} \leqslant \frac{1}{2}$时,$\alpha_{m} \geqslant 0$,并且$\alpha_m$随着$e_m$的减少而增大,因此分类错误率越小的基本分类器在最终分类器的作用越大!
**最重要的,对于步骤(2)中的样本权重的更新: **
$$
w_{m+1, i}=\left{\begin{array}{ll}
\frac{w_{m i}}{Z_{m}} \mathrm{e}^{-\alpha_{m}}, & G_{m}\left(x_{i}\right)=y_{i} \
\frac{w_{m i}}{Z_{m}} \mathrm{e}^{\alpha_{m}}, & G_{m}\left(x_{i}\right) \neq y_{i}
\end{array}\right.
$$
因此,从上式可以看到:被基本分类器$G_m(x)$错误分类的样本的权重扩大,被正确分类的样本权重减少,二者相比相差$\mathrm{e}^{2 \alpha_{m}}=\frac{1-e_{m}}{e_{m}}$倍。
对于步骤(3),线性组合$f(x)$实现了将M个基本分类器的加权表决,系数$\alpha_m$标志了基本分类器$G_m(x)$的重要性,值得注意的是:所有的$\alpha_m$之和不为1。$f(x)$的符号决定了样本x属于哪一类。

下面,我们使用一组简单的数据来手动计算Adaboost算法的过程:(例子来源:http://www.csie.edu.tw)

训练数据如下表,假设基本分类器的形式是一个分割$x<v$或$x>v$表示,阈值v由该基本分类器在训练数据集上分类错误率$e_m$最低确定。
$$
\begin{array}{ccccccccccc}
\hline \text { 序号 } & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 \
\hline x & 0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 \
y & 1 & 1 & 1 & -1 & -1 & -1 & 1 & 1 & 1 & -1 \
\hline
\end{array}
$$
解:
初始化样本权值分布
$$
\begin{aligned}
D_{1} &=\left(w_{11}, w_{12}, \cdots, w_{110}\right) \
w_{1 i} &=0.1, \quad i=1,2, \cdots, 10
\end{aligned}
$$
对m=1:

  • 在权值分布$D_1$的训练数据集上,遍历每个结点并计算分类误差率$e_m$,阈值取v=2.5时分类误差率最低,那么基本分类器为:
    $$
    G_{1}(x)=\left{\begin{array}{ll}
    1, & x<2.5 \
  • 1, & x>2.5
    \end{array}\right.
    $$
  • $G_1(x)$在训练数据集上的误差率为$e_{1}=P\left(G_{1}\left(x_{i}\right) \neq y_{i}\right)=0.3$。
  • 计算$G_1(x)$的系数:$\alpha_{1}=\frac{1}{2} \log \frac{1-e_{1}}{e_{1}}=0.4236$
  • 更新训练数据的权值分布:
    $$
    \begin{aligned}
    D_{2}=&\left(w_{21}, \cdots, w_{2 i}, \cdots, w_{210}\right) \
    w_{2 i}=& \frac{w_{1 i}}{Z_{1}} \exp \left(-\alpha_{1} y_{i} G_{1}\left(x_{i}\right)\right), \quad i=1,2, \cdots, 10 \
    D_{2}=&(0.07143,0.07143,0.07143,0.07143,0.07143,0.07143,\
    &0.16667,0.16667,0.16667,0.07143) \
    f_{1}(x) &=0.4236 G_{1}(x)
    \end{aligned}
    $$

对于m=2:

  • 在权值分布$D_2$的训练数据集上,遍历每个结点并计算分类误差率$e_m$,阈值取v=8.5时分类误差率最低,那么基本分类器为:
    $$
    G_{2}(x)=\left{\begin{array}{ll}
    1, & x<8.5 \

  • 1, & x>8.5
    \end{array}\right.
    $$

  • $G_2(x)$在训练数据集上的误差率为$e_2 = 0.2143$

  • 计算$G_2(x)$的系数:$\alpha_2 = 0.6496$

  • 更新训练数据的权值分布:
    $$
    \begin{aligned}
    D_{3}=&(0.0455,0.0455,0.0455,0.1667,0.1667,0.1667\
    &0.1060,0.1060,0.1060,0.0455) \
    f_{2}(x) &=0.4236 G_{1}(x)+0.6496 G_{2}(x)
    \end{aligned}
    $$

    对m=3:

  • 在权值分布$D_3$的训练数据集上,遍历每个结点并计算分类误差率$e_m$,阈值取v=5.5时分类误差率最低,那么基本分类器为:
    $$
    G_{3}(x)=\left{\begin{array}{ll}
    1, & x>5.5 \

  • 1, & x<5.5
    \end{array}\right.
    $$

  • $G_3(x)$在训练数据集上的误差率为$e_3 = 0.1820$

  • 计算$G_3(x)$的系数:$\alpha_3 = 0.7514$

  • 更新训练数据的权值分布:
    $$
    D_{4}=(0.125,0.125,0.125,0.102,0.102,0.102,0.065,0.065,0.065,0.125)
    $$

    于是得到:$f_{3}(x)=0.4236 G_{1}(x)+0.6496 G_{2}(x)+0.7514 G_{3}(x)$,分类器$\operatorname{sign}\left[f_{3}(x)\right]$在训练数据集上的误分类点的个数为0。
    于是得到最终分类器为:$G(x)=\operatorname{sign}\left[f_{3}(x)\right]=\operatorname{sign}\left[0.4236 G_{1}(x)+0.6496 G_{2}(x)+0.7514 G_{3}(x)\right]$

下面,我们使用sklearn对Adaboost算法进行建模:

本次案例我们使用一份UCI的机器学习库里的开源数据集:葡萄酒数据集,该数据集可以在 ( https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data )上获得。该数据集包含了178个样本和13个特征,从不同的角度对不同的化学特性进行描述,我们的任务是根据这些数据预测红酒属于哪一个类别。(案例来源《python机器学习(第二版》)

# 引入数据科学相关工具包:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
%matplotlib inline
import seaborn as sns
# 加载训练数据:         
wine = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data",header=None)
wine.columns = ['Class label', 'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash','Magnesium', 'Total phenols','Flavanoids', 'Nonflavanoid phenols',
'Proanthocyanins','Color intensity', 'Hue','OD280/OD315 of diluted wines','Proline']
# 数据查看:
print("Class labels",np.unique(wine["Class label"]))
wine.head()

下面对数据做简单解读:

  • Class label:分类标签
  • Alcohol:酒精
  • Malic acid:苹果酸
  • Ash:灰
  • Alcalinity of ash:灰的碱度
  • Magnesium:镁
  • Total phenols:总酚
  • Flavanoids:黄酮类化合物
  • Nonflavanoid phenols:非黄烷类酚类
  • Proanthocyanins:原花青素
  • Color intensity:色彩强度
  • Hue:色调
  • OD280/OD315 of diluted wines:稀释酒OD280 OD350
  • Proline:脯氨酸
# 数据预处理
# 仅仅考虑2,3类葡萄酒,去除1类
wine = wine[wine['Class label']!=1]
y = wine['Class label'].values
X = wine[['Alcohol','OD280/OD315 of diluted wines']].values
# 将分类标签变成二进制编码:
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
y = le.fit_transform(y)

# 按8:2分割训练集和测试集
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test = train_test_split(X,y,test_size=0.2,random_state=1,stratify=y) # stratify参数代表了按照y的类别等比例抽样

使用单一决策树建模

from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier(criterion='entropy',random_state=1,max_depth=1)
from sklearn.metrics import accuracy_score
tree = tree.fit(X_train,y_train)
y_train_pred = tree.predict(X_train)
y_test_pred = tree.predict(X_test)
tree_train = accuracy_score(y_train,y_train_pred)
tree_test = accuracy_score(y_test,y_test_pred)
print('Decision tree train/test accuracies %.3f/%.3f' % (tree_train,tree_test))

使用sklearn实现Adaboost(基分类器为决策树)

# 使用sklearn实现Adaboost(基分类器为决策树)
'''
AdaBoostClassifier相关参数:
base_estimator:基本分类器,默认为DecisionTreeClassifier(max_depth=1)
n_estimators:终止迭代的次数
learning_rate:学习率
algorithm:训练的相关算法,{'SAMME','SAMME.R'},默认='SAMME.R'
random_state:随机种子
'''
from sklearn.ensemble import AdaBoostClassifier
adaboost = AdaBoostClassifier(base_estimator=tree,n_estimators=500,learning_rate=0.1,random_state=1)
adaboost = adaboost.fit(X_train,y_train)
y_train_pred = adaboost.predict(X_train)
y_test_pred = adaboost.predict(X_test)
ada_train = accuracy_score(y_train,y_train_pred)
ada_test = accuracy_score(y_test,y_test_pred)
print('Adaboost train/test accuracies %.3f/%.3f' % (ada_train,ada_test))

结果分析:单层决策树似乎对训练数据欠拟合,而Adaboost模型正确地预测了训练数据的所有分类标签,而且与单层决策树相比,Adaboost的测试性能也略有提高。然而,为什么模型在训练集和测试集的性能相差这么大呢?我们使用图像来简单说明下这个道理!

# 画出单层决策树与Adaboost的决策边界:
x_min = X_train[:, 0].min() - 1
x_max = X_train[:, 0].max() + 1
y_min = X_train[:, 1].min() - 1
y_max = X_train[:, 1].max() + 1
# 生成网格矩阵
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,sharex='col',sharey='row',figsize=(12, 6))
for idx, clf, tt in zip([0, 1],[tree, adaboost],['Decision tree', 'Adaboost']):
clf.fit(X_train, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
axarr[idx].scatter(X_train[y_train==0, 0],X_train[y_train==0, 1],c='blue', marker='^')
axarr[idx].scatter(X_train[y_train==1, 0],X_train[y_train==1, 1],c='red', marker='o')
axarr[idx].set_title(tt)

在这里插入图片描述

从上面的决策边界图可以看到:Adaboost模型的决策边界比单层决策树的决策边界要复杂的多。也就是说,Adaboost试图用增加模型复杂度而降低偏差的方式去减少总误差,但是过程中引入了方差,可能出现过拟合,因此在训练集和测试集之间的性能存在较大的差距,这就简单地回答的刚刚问题。
值的注意的是:与单个分类器相比,Adaboost等Boosting模型增加了计算的复杂度,在实践中需要仔细思考是否愿意为预测性能的相对改善而增加计算成本,而且Boosting方式无法做到现在流行的并行计算的方式进行训练,因为每一步迭代都要基于上一部的基本分类器。

4. 前向分步算法

回看Adaboost的算法内容,我们需要通过计算M个基本分类器,每个分类器的错误率、样本权重以及模型权重。我们可以认为:Adaboost每次学习单一分类器以及单一分类器的参数(权重)。接下来,我们抽象出Adaboost算法的整体框架逻辑,构建集成学习的一个非常重要的框架—-前向分步算法,有了这个框架,我们不仅可以解决分类问题,也可以解决回归问题。
(1) 加法模型:
在Adaboost模型中,我们把每个基本分类器合成一个复杂分类器的方法是每个基本分类器的加权和,即:$f(x)=\sum_{m=1}^{M} \beta_{m} b\left(x ; \gamma_{m}\right)$,其中,$b\left(x ; \gamma_{m}\right)$为即基本分类器,$\gamma_{m}$为基本分类器的参数,$\beta_m$为基本分类器的权重,显然这与第二章所学的加法模型。为什么这么说呢?大家把$b(x ; \gamma_{m})$看成是即函数即可。
在给定训练数据以及损失函数$L(y, f(x))$的条件下,学习加法模型$f(x)$就是:
$$
\min {\beta{m}, \gamma_{m}} \sum_{i=1}^{N} L\left(y_{i}, \sum_{m=1}^{M} \beta_{m} b\left(x_{i} ; \gamma_{m}\right)\right)
$$
通常这是一个复杂的优化问题,很难通过简单的凸优化的相关知识进行解决。前向分步算法可以用来求解这种方式的问题,它的基本思路是:因为学习的是加法模型,如果从前向后,每一步只优化一个基函数及其系数,逐步逼近目标函数,那么就可以降低优化的复杂度。具体而言,每一步只需要优化:
$$
\min {\beta, \gamma} \sum{i=1}^{N} L\left(y_{i}, \beta b\left(x_{i} ; \gamma\right)\right)
$$
(2) 前向分步算法:
给定数据集$T=\left{\left(x_{1}, y_{1}\right),\left(x_{2}, y_{2}\right), \cdots,\left(x_{N}, y_{N}\right)\right}$,$x_{i} \in \mathcal{X} \subseteq \mathbf{R}^{n}$,$y_{i} \in \mathcal{Y}={+1,-1}$。损失函数$L(y, f(x))$,基函数集合${b(x ; \gamma)}$,我们需要输出加法模型$f(x)$。

  • 初始化:$f_{0}(x)=0$
  • 对m = 1,2,…,M:
    • (a) 极小化损失函数:
      $$
      \left(\beta_{m}, \gamma_{m}\right)=\arg \min {\beta, \gamma} \sum{i=1}^{N} L\left(y_{i}, f_{m-1}\left(x_{i}\right)+\beta b\left(x_{i} ; \gamma\right)\right)
      $$
      得到参数$\beta_{m}$与$\gamma_{m}$
    • (b) 更新:
      $$
      f_{m}(x)=f_{m-1}(x)+\beta_{m} b\left(x ; \gamma_{m}\right)
      $$
  • 得到加法模型:
    $$
    f(x)=f_{M}(x)=\sum_{m=1}^{M} \beta_{m} b\left(x ; \gamma_{m}\right)
    $$

这样,前向分步算法将同时求解从m=1到M的所有参数$\beta_{m}$,$\gamma_{m}$的优化问题简化为逐次求解各个$\beta_{m}$,$\gamma_{m}$的问题。
(3) 前向分步算法与Adaboost的关系:
由于这里不是我们的重点,我们主要阐述这里的结论,不做相关证明,具体的证明见李航老师的《统计学习方法》第八章的3.2节。Adaboost算法是前向分步算法的特例,Adaboost算法是由基本分类器组成的加法模型,损失函数为指数损失函数。

]]>
+ + + + <h1 id="1-导论"><a href="#1-导论" class="headerlink" title="1. 导论"></a>1. 导论</h1><p>在前面的学习中,我们探讨了一系列简单而实用的回归和分类模型,同时也探讨了如何使用集成学习家族中的Bagging思想去优化最终的模型。Bagging思想的实质是:通过Bootstrap 的方式对全样本数据集进行抽样得到抽样子集,对不同的子集使用同一种基本模型进行拟合,然后投票得出最终的预测。我们也从前面的探讨知道:Bagging主要通过降低方差的方式减少预测误差。<strong>那么,本章介绍的Boosting是与Bagging截然不同的思想,Boosting方法是使用同一组数据集进行反复学习,得到一系列简单模型,然后组合这些模型构成一个预测性能十分强大的机器学习模型。</strong> 显然,Boosting思想提高最终的预测效果是通过不断减少偏差的形式,与Bagging有着本质的不同。在Boosting这一大类方法中,笔者主要介绍两类常用的Boosting方式:Adaptive Boosting 和 Gradient Boosting 以及它们的变体Xgboost、LightGBM以及Catboost。</p> + + + + + + + + + +
+ + + 集成学习专题——voting&bagging + + https://jackyin.space/2021/06/16/%E9%9B%86%E6%88%90%E5%AD%A6%E4%B9%A0%E4%B8%93%E9%A2%98%E2%80%94%E2%80%94voting-bagging/ + 2021-06-16T15:55:00.000Z + 2024-10-09T08:43:45.344Z + + 投票法的思路

投票法是集成学习中常用的技巧,可以帮助我们提高模型的泛化能力,减少模型的错误率。举个例子,在航空航天领域,每个零件发出的电信号都对航空器的成功发射起到重要作用。如果我们有一个二进制形式的信号:

11101100100111001011011011011

在传输过程中第二位发生了翻转

10101100100111001011011011011

这导致的结果可能是致命的。一个常用的纠错方法是重复多次发送数据,并以少数服从多数的方法确定正确的传输数据。一般情况下,错误总是发生在局部,因此融合多个数据是降低误差的一个好方法,这就是投票法的基本思路。

对于回归模型来说,投票法最终的预测结果是多个其他回归模型预测结果的平均值。

对于分类模型,硬投票法的预测结果是多个模型预测结果中出现次数最多的类别,软投票对各类预测结果的概率进行求和,最终选取概率之和最大的类标签。

投票法的原理分析

投票法是一种遵循少数服从多数原则的集成学习模型,通过多个模型的集成降低方差,从而提高模型的鲁棒性。在理想情况下,投票法的预测效果应当优于任何一个基模型的预测效果。

投票法在回归模型与分类模型上均可使用:

  • 回归投票法:预测结果是所有模型预测结果的平均值。
  • 分类投票法:预测结果是所有模型种出现最多的预测结果。

分类投票法又可以被划分为硬投票与软投票:

  • 硬投票:预测结果是所有投票结果最多出现的类。
  • 软投票:预测结果是所有投票结果中概率加和最大的类。

下面我们使用一个例子说明硬投票:

对于某个样本:

模型 1 的预测结果是 类别 A

模型 2 的预测结果是 类别 B

模型 3 的预测结果是 类别 B

有2/3的模型预测结果是B,因此硬投票法的预测结果是B

同样的例子说明软投票:

对于某个样本:

模型 1 的预测结果是 类别 A 的概率为 99%

模型 2 的预测结果是 类别 A 的概率为 49%

模型 3 的预测结果是 类别 A 的概率为 49%

最终对于类别A的预测概率的平均是 (99 + 49 + 49) / 3 = 65.67%,因此软投票法的预测结果是A。

从这个例子我们可以看出,软投票法与硬投票法可以得出完全不同的结论。相对于硬投票,软投票法考虑到了预测概率这一额外的信息,因此可以得出比硬投票法更加准确的预测结果。

在投票法中,我们还需要考虑到不同的基模型可能产生的影响。理论上,基模型可以是任何已被训练好的模型。但在实际应用上,想要投票法产生较好的结果,需要满足两个条件:

  • 基模型之间的效果不能差别过大。当某个基模型相对于其他基模型效果过差时,该模型很可能成为噪声。
  • 基模型之间应该有较小的同质性。例如在基模型预测效果近似的情况下,基于树模型与线性模型的投票,往往优于两个树模型或两个线性模型。

当投票合集中使用的模型能预测出清晰的类别标签时,适合使用硬投票。当投票集合中使用的模型能预测类别的概率时,适合使用软投票。软投票同样可以用于那些本身并不预测类成员概率的模型,只要他们可以输出类似于概率的预测分数值(例如支持向量机、k-最近邻和决策树)。

投票法的局限性在于,它对所有模型的处理是一样的,这意味着所有模型对预测的贡献是一样的。如果一些模型在某些情况下很好,而在其他情况下很差,这是使用投票法时需要考虑到的一个问题。

投票法的案例分析(基于sklearn,介绍pipe管道的使用以及voting的使用)

Sklearn中提供了 VotingRegressorVotingClassifier 两个投票方法。 这两种模型的操作方式相同,并采用相同的参数。使用模型需要提供一个模型列表,列表中每个模型采用Tuple的结构表示,第一个元素代表名称,第二个元素代表模型,需要保证每个模型必须拥有唯一的名称。

例如这里,我们定义两个模型:

models = [('lr',LogisticRegression()),('svm',SVC())]
ensemble = VotingClassifier(estimators=models)

有时某些模型需要一些预处理操作,我们可以为他们定义Pipeline完成模型预处理工作:

models = [('lr',LogisticRegression()),('svm',make_pipeline(StandardScaler(),SVC()))]
ensemble = VotingClassifier(estimators=models)

模型还提供了voting参数让我们选择软投票或者硬投票:

models = [('lr',LogisticRegression()),('svm',SVC())]
ensemble = VotingClassifier(estimators=models, voting='soft')

下面我们使用一个完整的例子演示投票法的使用:

首先我们创建一个1000个样本,20个特征的随机数据集:

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=2)
# summarize the dataset
print(X.shape, y.shape)

我们使用多个KNN模型作为基模型演示投票法,其中每个模型采用不同的邻居值K参数:

# get a voting ensemble of models
def get_voting():
# define the base models
models = list()
models.append(('knn1', KNeighborsClassifier(n_neighbors=1)))
models.append(('knn3', KNeighborsClassifier(n_neighbors=3)))
models.append(('knn5', KNeighborsClassifier(n_neighbors=5)))
models.append(('knn7', KNeighborsClassifier(n_neighbors=7)))
models.append(('knn9', KNeighborsClassifier(n_neighbors=9)))
# define the voting ensemble
ensemble = VotingClassifier(estimators=models, voting='hard')
return ensemble

然后,我们可以创建一个模型列表来评估投票带来的提升,包括KNN模型配置的每个独立版本和硬投票模型。下面的get_models()函数可以为我们创建模型列表进行评估。

# get a list of models to evaluate
def get_models():
models = dict()
models['knn1'] = KNeighborsClassifier(n_neighbors=1)
models['knn3'] = KNeighborsClassifier(n_neighbors=3)
models['knn5'] = KNeighborsClassifier(n_neighbors=5)
models['knn7'] = KNeighborsClassifier(n_neighbors=7)
models['knn9'] = KNeighborsClassifier(n_neighbors=9)
models['hard_voting'] = get_voting()
return models

下面的evaluate_model()函数接收一个模型实例,并以分层10倍交叉验证三次重复的分数列表的形式返回。

# evaluate a give model using cross-validation
def evaluate_model(model, X, y):
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
return scores

然后,我们可以报告每个算法的平均性能,还可以创建一个箱形图和须状图来比较每个算法的精度分数分布。

# define dataset
X, y = get_dataset()
# get the models to evaluate
models = get_models()
# evaluate the models and store results
results, names = list(), list()
for name, model in models.items():
scores = evaluate_model(model, X, y)
results.append(scores)
names.append(name)
print('>%s %.3f (%.3f)' % (name, mean(scores), std(scores)))
# plot model performance for comparison
pyplot.boxplot(results, labels=names, showmeans=True)
pyplot.show()

我们得到的结果如下:

>knn1 0.873 (0.030)
>knn3 0.889 (0.038)
>knn5 0.895 (0.031)
>knn7 0.899 (0.035)
>knn9 0.900 (0.033)
>hard_voting 0.902 (0.034)

显然投票的效果略大于任何一个基模型。

Box Plot of Hard Voting Ensemble Compared to Standalone Models for Binary Classification

通过箱形图我们可以看到硬投票方法对交叉验证整体预测结果分布带来的提升。

bagging的思路

与投票法不同的是,Bagging不仅仅集成模型最后的预测结果,同时采用一定策略来影响基模型训练,保证基模型可以服从一定的假设。 在上一章中我们提到,希望各个模型之间具有较大的差异性,而在实际操作中的模型却往往是同质的,因此一个简单的思路是通过不同的采样增加模型的差异性

bagging的原理分析

Bagging的核心在于自助采样(bootstrap)这一概念,即有放回的从数据集中进行采样,也就是说,同样的一个样本可能被多次进行采样。 一个自助采样的小例子是我们希望估计全国所有人口年龄的平均值,那么我们可以在全国所有人口中随机抽取不同的集合(这些集合可能存在交集),计算每个集合的平均值,然后将所有平均值的均值作为估计值。

首先我们随机取出一个样本放入采样集合中,再把这个样本放回初始数据集,重复K次采样,最终我们可以获得一个大小为K的样本集合。同样的方法, 我们可以采样出T个含K个样本的采样集合,然后基于每个采样集合训练出一个基学习器,再将这些基学习器进行结合,这就是Bagging的基本流程。

对回归问题的预测是通过预测取平均值来进行的。对于分类问题的预测是通过对预测取多数票预测来进行的。Bagging方法之所以有效,是因为每个模型都是在略微不同的训练数据集上拟合完成的,这又使得每个基模型之间存在略微的差异,使每个基模型拥有略微不同的训练能力。

Bagging同样是一种降低方差的技术,因此它在不剪枝决策树、神经网络等易受样本扰动的学习器上效果更加明显。在实际的使用中,加入列采样的Bagging技术对高维小样本往往有神奇的效果。

bagging的案例分析(基于sklearn,介绍随机森林的相关理论以及实例)

Sklearn为我们提供了 BaggingRegressorBaggingClassifier 两种Bagging方法的API,我们在这里通过一个完整的例子演示Bagging在分类问题上的具体应用。这里两种方法的默认基模型是树模型。

我们创建一个含有1000个样本20维特征的随机分类数据集:

# test classification dataset
from sklearn.datasets import make_classification
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# summarize the dataset
print(X.shape, y.shape)

我们将使用重复的分层k-fold交叉验证来评估该模型,一共重复3次,每次有10个fold。我们将评估该模型在所有重复交叉验证中性能的平均值和标准差。

# evaluate bagging algorithm for classification
from numpy import mean
from numpy import std
from sklearn.datasets import make_classification
from sklearn.model_selection import cross_val_score
from sklearn.model_selection import RepeatedStratifiedKFold
from sklearn.ensemble import BaggingClassifier
# define dataset
X, y = make_classification(n_samples=1000, n_features=20, n_informative=15, n_redundant=5, random_state=5)
# define the model
model = BaggingClassifier()
# evaluate the model
cv = RepeatedStratifiedKFold(n_splits=10, n_repeats=3, random_state=1)
n_scores = cross_val_score(model, X, y, scoring='accuracy', cv=cv, n_jobs=-1, error_score='raise')
# report performance
print('Accuracy: %.3f (%.3f)' % (mean(n_scores), std(n_scores)))

最终模型的效果是Accuracy: 0.856 标准差0.037

]]>
+ + + + <h2 id="投票法的思路"><a href="#投票法的思路" class="headerlink" title="投票法的思路"></a>投票法的思路</h2><p><strong>投票法是集成学习中常用的技巧,可以帮助我们提高模型的泛化能力,减少模型的错误率。</strong>举个例子,在航空航天领域,每个零件发出的电信号都对航空器的成功发射起到重要作用。如果我们有一个二进制形式的信号:</p> +<p>11101100100111001011011011011</p> +<p>在传输过程中第二位发生了翻转</p> +<p>10101100100111001011011011011</p> +<p>这导致的结果可能是致命的。一个常用的纠错方法是重复多次发送数据,并以少数服从多数的方法确定正确的传输数据。一般情况下,错误总是发生在局部,因此融合多个数据是降低误差的一个好方法,这就是投票法的基本思路。</p> +<p>对于回归模型来说,投票法最终的预测结果是多个其他回归模型预测结果的平均值。</p> +<p>对于分类模型,<strong>硬投票法</strong>的预测结果是多个模型预测结果中出现次数最多的类别,<strong>软投票</strong>对各类预测结果的概率进行求和,最终选取概率之和最大的类标签。</p> + + + + + + + + + +
+ + + 数据结构与算法——二分 + + https://jackyin.space/2021/06/15/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95%E2%80%94%E2%80%94%E4%BA%8C%E5%88%86/ + 2021-06-15T13:48:00.000Z + 2024-10-09T08:43:45.316Z + + 数据结构与算法——二分

最近leetcode每日一题经常出二分的题目,正好对前段时间学过的二分进行一些总结,首先这里要明确的一点是,二分的本质并不是单调性,而是通过某种条件将整个区间划分成满足条件和不满足条件的两端即可进行二分查找。
在二分这个专题,主要有两种类型的划分方式,一种是整数划分,一种是浮点数划分,前一种一般是我们最熟悉的二分查找的题型,也是出题比较灵活考的比较多的一种,后一种主要是为控制实数精度而设置的浮点数二分法(建议用doublefloat有时候会出现精度丢失)。

整数二分

这里我们拿一道经典例题来给出我们二分的两个十分精妙的模板。AcWing789. 数的范围

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while(l < r)
{
int mid = l + r >> 1; // 如果写r=mid则这里不需要+1
if(check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1;
}
return l; //退出时 l与r相等
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
while(l < r)
{
int mid = l + r + 1 >> 1;
if(check(mid)) l = mid;
else r = mid - 1;
}
return l;
}

浮点数二分

浮点数二分考的比较少,主要是实现对于高精度答案的控制。AcWing 790. 数的三次方根
这里有个小bug需要提醒一下我们以求二次方根为例,我们可以知道,$x=0.01$时,$\sqrt{x}=0.1>x$,所以当我们把二分的区间设置成$[0,x]$时,我们则无法找到答案,所以设置区间的时候我们最好可以设置大一点的区间,或者设置成$[0,\max(1,x)]$
在这里插入图片描述

bool check(double x) {/* ... */} // 检查x是否满足某种性质

double bsearch_3(double l, double r)
{
const double eps = 1e-8; // eps 表示精度,取决于题目对精度的要求
while(r - l > eps)
{
double mid = (l + r) / 2; // 对于浮点数二分则不需要考虑+1的问题
if(check(mid)) r = mid;
else l = mid;
}
return l;
}

STL

做题当中手写二分的题其实比较少,基本上记忆上述模板就能解决所以的问题,同时我们在日常做题的时候,为了方便,我们通常是使用STL当中的函数来实现二分,且支持vector,map,set等操作,还有结构体大小比较,这里就有三个一定要记住的API。头文件引入:#include<algorithm>
binary_search
功能:二分查找某个元素是否出现。
返回值:在数组中以二分法检索的方式查找,若在数组(要求数组元素非递减)中查找到indx元素则真,若查找不到则返回值为假。
用法实例:
a.数组用法

int a[100]= {4,10,11,30,69,70,96,100};
int b=binary_search(a,a+9,4);//查找成功,返回1
cout<<"在数组中查找元素4,结果为:"<<b<<endl;

b.vector用法

vector<int> res = {1,2,3};
cout<<binary_search(res.begin(),res.end(),3)<<endl;

lower_bound
功能:查找非递减序列[first,last) 内第一个大于或等于某个元素的位置。
返回值:如果找到返回找到元素的地址否则返回数组边界的下一个元素的地址。(这样不注意的话会越界,小心)
用法实例:

int a[100]= {4,10,11,30,69,70,96,100};
int d=lower_bound(a,a+9,10)-a;
cout<<"在数组中查找第一个大于等于10的元素位置,结果为:"<<d<<endl;
int e=lower_bound(a,a+9,101)-a;
cout<<"在数组中查找第一个大于等于101的元素位置,结果为:"<<e<<endl;

b.vector用法

vector<int> res = {1,2,3};
vector<int>::iterator it = lower_bound(res.begin(),res.end(),3);//返回迭代器的位置
//如果不存在,迭代器的位置会返回res.end()
if(it==res.end()) cout<<"不存在"<<endl;
else cout<<"求出下标:"<<(it - res.begin())<<endl;
//也可以添加偏移量
vector<int>::iterator it = lower_bound(res.begin()+1,res.end(),3);

upper_bound

功能:查找非递减序列[first,last) 内第一个大于某个元素的位置。

返回值:如果找到返回找到元素的地址,否则返回数组边界的下一个元素的地址。(同样这样不注意的话会越界,小心)
用法实例:

int a[100]= {4,10,11,30,69,70,96,100};
int d=upper_bound(a,a+9,10)-a;
cout<<"在数组中查找第一个大于等于10的元素位置,结果为:"<<d<<endl;
int e=upper_bound(a,a+9,101)-a;
cout<<"在数组中查找第一个大于等于101的元素位置,结果为:"<<e<<endl;

b.vector用法

vector<int> res = {1,2,3};
vector<int>::iterator it = upper_bound(res.begin(),res.end(),3);//返回迭代器的位置
//如果不存在,迭代器的位置会返回res.end()
if(it==res.end()) cout<<"不存在"<<endl;
else cout<<"求出下标:"<<(it - res.begin())<<endl;
//也可以添加偏移量
vector<int>::iterator it = upper_bound(res.begin()+1,res.end(),3);

经典例题

这里我顺便给出这两天的每日一题的解题方案,里面还涉及到了一个防止溢出的二分处理trick。
猜数字大小
在这里插入图片描述

/** 
* Forward declaration of guess API.
* @param num your guess
* @return -1 if num is lower than the guess number
* 1 if num is higher than the guess number
* otherwise return 0
* int guess(int num);
*/

class Solution {
public:
int guessNumber(int n) {
int l = 1;
int r = n;
while(l<r)
{
int mid = l + (r - l >> 1);//防止溢出
if(guess(mid)<=0)
r = mid;
else
l = mid + 1;
}
return r;
}
};

山脉数组的峰顶索引
在这里插入图片描述

class Solution {
public:
int peakIndexInMountainArray(vector<int>& arr) {
int l = 0;
int r = arr.size() - 1;
while(l<r)
{
int mid = l + r >> 1;
if(arr[mid]>arr[mid+1]) r = mid;
else l = mid+1;
}
return l;
}
};

这是三叶姐姐的二分经典题型汇总,大家也可以参考一下。
在这里插入图片描述

]]>
+ + + + <h2 id="数据结构与算法——二分"><a href="#数据结构与算法——二分" class="headerlink" title="数据结构与算法——二分"></a>数据结构与算法——二分</h2><p>最近leetcode每日一题经常出二分的题目,正好对前段时间学过的二分进行一些总结,首先这里要明确的一点是,<strong>二分的本质并不是单调性,而是通过某种条件将整个区间划分成满足条件和不满足条件的两端即可进行二分查找。</strong><br>在二分这个专题,主要有两种类型的划分方式,一种是整数划分,一种是浮点数划分,前一种一般是我们最熟悉的二分查找的题型,也是出题比较灵活考的比较多的一种,后一种主要是为控制实数精度而设置的浮点数二分法(建议用<code>double</code>,<code>float</code>有时候会出现精度丢失)。</p> + + + + + + + +
+ + + 数据结构与刷题——链表 + + https://jackyin.space/2021/06/13/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E5%88%B7%E9%A2%98%E2%80%94%E2%80%94%E9%93%BE%E8%A1%A8/ + 2021-06-13T07:49:00.000Z + 2024-10-09T08:43:45.316Z + + 数据结构与刷题——链表

在这里插入图片描述

在这里插入图片描述

单链表代码模板

代码实现单链表的方法有很多种,但是对于acm刷题来说,我们通常使用的是静态链表的方式,这样代码运行速度更快,防止被卡时间。

const int N = 100010;
int head; // 头指针
int e[N]; // e[i]表示第i个节点的
int ne[N];// 第i个节点的next指针,表示当前节点的直接后继的节点编号
int idx;//记录已经存储了多少个节点

void init()
{
head = -1;//用-1表示空节点
idx = 0;
}

//在第k个节点后面插入一个新节点,节点的值为x
void insert(int k,int x)
{
e[idx] = x;
ne[idx] = ne[k];
ne[k] = idx++;
}

// 删除第k+1个节点,即将将该节点的指针指向他的下一个元素
void delete_node(int k)
{
ne[k] = ne[ne[k]];
}

void delete_head()
{
head = ne[head];
}

//遍历过程
for(int i = head; i!=-1;i = ne[i])
{
cout<<e[i]<<endl;
}

双链表

在实际的代码编写过程当中,我们也是直接使用静态链表来设置双链表,我们首先设置0号点和1号点为左右边界head,tail。之后我们就只需要在这两者之间插入节点构造双链表。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

const int N = 100010;
int e[N];
int l[N];
int r[N];
int idx;

//初始化直接初始化出左右端点的下标,从而避免边界问题
void init()
{
//初始化的左右别搞反了
r[0] = 1;
l[1] = 0;
idx =2;
}

// 在k节点的右侧插入一个x,其实也相当于左侧插入节点
void add(int k,int x)
{
e[idx] = x;
//操作新节点的左右指针
r[idx] = r[k];
l[idx] = k;
//再操作原数组的节点
l[r[k]] = idx;
r[k] = idx++;
}

void remove(int k)
{
l[r[k]] = l[k]; //右节点的左侧,指向左节点
r[l[k]] = r[k]; //左节点的右侧,指向右节点
}

经典例题

以上两种实现方式都是通过静态链表实现的,主要是来自y总的AcWing经典例题。
AcWing826. 单链表
AcWing827. 双链表
使用指针的实现方式,在leetcode当中用的比较多,这里给大家补充一些leetcode中出现的链表类型的题目,主要涉及到链表的遍历,双指针算法,和一些小技巧,高阶一点的题目会涉及到树和递归的问题。
我做的主要是leetcode上程序员面试经典和剑指offer的例题,不过个人感觉这些题也大部分涵盖了链表题型的大部分考法,而且题解也十分详细。
在这里插入图片描述
在这里插入图片描述

]]>
+ + + + <h2 id="数据结构与刷题——链表"><a href="#数据结构与刷题——链表" class="headerlink" title="数据结构与刷题——链表"></a>数据结构与刷题——链表</h2><p><img src="https://img-blog.csdnimg.cn/20210607085716429.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0phY2tfX19F,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p> + + + + + + + +
+ + + 数据结构与算法基础——快速排序与归并排序 + + https://jackyin.space/2021/06/06/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95%E5%9F%BA%E7%A1%80%E2%80%94%E2%80%94%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F%E4%B8%8E%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/ + 2021-06-06T12:33:00.000Z + 2024-10-09T08:43:45.316Z + + 前言

最近在复习数据结构,顺便整理之前刷题的一些模板和技巧,希望对大家都有帮助,博客会侧重讲解的是OJ代码实现,理论部分偏少但也会写一些自己的理解。
在之前大二上数据结构的时候我也有写过一个关于排序的专题介绍数据结构复习——内部排序

快速排序

快速排序主要就是通过选取一个基准点,将一个区间内的数分成大于和小于两个部分,然后对左右区间再进行上述操作,直到子区间的长度为空为止。快速排序是不稳定的排序,如果需要变成稳定排序通过双关键字排序即可,通过下标控制绝对大小就能得到稳定的排序结果。
快速排序分三步走:

  • 确定分界点
  • 调整左右区间
  • 递归处理左右子区间

在代码实现当中,我们一般选取中间分位点会比较好,这样划分的区间比较平均。在遍历的过程当中每次调整区间的时间是$O(n)$,而区间递归的深度类似二叉树是$O(logn)$
在最好情况下,对于递归型的算法,我们利用主定理公式来计算快速排序时间复杂度得到$O(nlogn)$
$$
T(n) = 2 T\left(\frac{n}{2}\right)+\Theta(n)
$$
当然在最坏情况下,也就是数组是有序或者逆序的情况下,我们如果选择左右端点作为基准点,那么整个算法就相当于冒泡排序,递归的层数也就变成了$n$,则最坏时间复杂度为$O(n^2)$

代码实现

void quick_sort(int[] q,int l,int r)
{
if(l>=r) return;
// 1.确定分界点
int i = l - 1, j = r + 1, mid = q[l + r >> 1];
// 2.调整左右区间
while(i<j)
{
do i++; while(q[i]<mid);
do j--; while(q[j]>mid);
if(i<j) swap(q[i],q[j]);
}
//3.递归处理左右子区间
quick_sort(l,j);
quick_sort(j+1,r);
}

经典例题

洛谷P1177 【模板】快速排序

归并排序

归并排序也是基于分治的思想,每次将区间对半分,逐步递归合并有序化子区间,最终实现所有的左右区间的有序归并,但是跟快速排序不同的是,我们需要开一个辅助数组来存储有序的部分,所以时间复杂度为$O(nlogn)$。归并排序是稳定的排序,在元素相等情况下我们总是放入数组下标较小的元素。
归并排序分三步走:

  • 确定分界点
  • 递归处理子序列
  • 合并有序序列

olor_FFFFFF,t_70)

代码实现

const int N=100010;
int a[N],tmp[N];
void merge_sort(int q[],int l,int r)
{
if(l>=r)
return;
//确定分界点
int mid = l + r >> 1;

//递归处理子序列
merge_sort(q,l,mid);
merge_sort(q,mid+1,r);

//合并有序序列
int k = l,i = l,j = mid + 1;
while(i <= mid && j <= r)
{
if(q[i]<=q[j])// 取等号,保证归并排序的稳定性
tmp[k++]=q[i++];
else
tmp[k++]=q[j++];
}

while(i<=mid)
tmp[k++]=q[i++];
while(j<=r)
tmp[k++]=q[j++];

for(i=l;i<=r;i++)
q[i]=tmp[i];
}

经典例题

AcWing 787. 归并排序
AcWing 788. 逆序对的数量

排序相关时间复杂度整理

在这里插入图片描述

]]>
+ + + + <h2 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h2><p>最近在复习数据结构,顺便整理之前刷题的一些模板和技巧,希望对大家都有帮助,博客会侧重讲解的是OJ代码实现,理论部分偏少但也会写一些自己的理解。<br>在之前大二上数据结构的时候我也有写过一个关于排序的专题介绍<a href="https://blog.csdn.net/Jack___E/article/details/102875285?spm=1001.2014.3001.5502" target="_blank" rel="noopener">数据结构复习——内部排序</a></p> + + + + + + + +
+ + + EfficientNet论文解读和pytorch代码实现 + + https://jackyin.space/2021/05/09/EfficientNet%E8%AE%BA%E6%96%87%E8%A7%A3%E8%AF%BB%E5%92%8Cpytorch%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0/ + 2021-05-09T09:44:00.000Z + 2024-10-09T08:43:45.228Z + + EfficientNet论文解读和pytorch代码实现

传送门

论文地址:https://arxiv.org/pdf/1905.11946.pdf
官方github:https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet
github参考:https://github.com/qubvel/efficientnet
github参考:https://github.com/lukemelas/EfficientNet-PyTorch

摘要

谷歌的文章总是能让我印象深刻,不管从实验上还是论文的书写上都让人十分的佩服,不得不说这确实是一个非常creative的公司!
Convolutional Neural Networks (ConvNets) are commonly developed at a fixed resource budget, and then scaled up for better accuracy if more resources are available. In this paper, we systematically study model scaling and identify that carefully balancing network depth, width, and resolution can lead to better performance. Based on this observation, we propose a new scaling method that uniformly scales all dimensions of depth/width/resolution using a simple yet highly effective compound coefficient. We demonstrate the effectiveness of this method on scaling up MobileNets and ResNet.
卷积神经网络通常是在固定的资源预算下进行计算和发展的,如果有更多可用的资源,模型能通过缩放和扩展获得更好的效果,本文系统研究(工作量很充足)了模型缩放,并且证明了细致地平衡网络的深度,宽度,和分辨率能够得到更好的效果,基于这个观点,我们提出了一个新的尺度缩放的方法,我们提出了一个新的尺度缩放的方法即:使用一个简单且高效的复合系数统一地缩放所有网络层的深度/宽度/分辨率的维度。我们证明了该方法在扩大MobileNets和ResNet方面的有效性。

To go even further, we use neural architecture search to design a new baseline network and scale it up to obtain a family of models, called EfficientNets, which achieve much better accuracy and efficiency than previous ConvNets. In particular, our EfficientNet-B7 achieves state-of-the-art 84.3% top-1 accuracy on ImageNet, while being 8.4x smaller and 6.1x faster on inference than the best existing ConvNet. Our EfficientNets also transfer well and achieve state-of-the-art accuracy on CIFAR-100 (91.7%), Flowers (98.8%), and 3 other transfer learning datasets, with an order of magnitude fewer parameters. Source code is athttps://github.com/tensorflow/tpu/tree/
master/models/official/efficientnet.

更进一步,我们使用神经网络结构搜索设计了一个新的baseline网络架构并且对其进行缩放得到了一组模型,我们把他叫做EfficientNets。EfficientNets相比之前的ConvNets,有着更好的准确率和更高的效率。在ImageNet上达到了最好的水平即top-1准确率84.4%/top-5准确率97.1%,然而却比已有的最好的ConvNet模型小了8.4倍并且推理时间快了6.1倍。我们的EfficientNet迁移学习的效果也好,达到了最好的准确率水平CIFAR-100(91.7%),Flowers(98.8%),和其他3个迁移学习数据集合,参数少了一个数量级(with an order of magnitude fewer parameters)

论文思想

在之前的一些工作当中,我们可以看到,有的会通过增加网络的width即增加卷积核的个数(从而增大channels)来提升网络的性能,有的会通过增加网络的深度即使用更多的层结构来提升网络的性能,有的会通过增加输入网络的分辨率来提升网络的性能。而在Efficientnet当中则重新探究了这个问题,并提出了一种组合条件这三者的网络结构,同时量化了这三者的指标。
在这里插入图片描述

The intuition is that deeper ConvNet can capture richer and more complex features, and generalize well on new tasks. However, deeper networks are also more difficult to train due to the vanishing gradient problem
增加网络的深度depth能够得到更加丰富、复杂的特征并且能够在其他新任务中很好的泛化性能。但是,由于逐渐消失的梯度问题,更深层的网络也更难以训练。

wider networks tend to be able to capture more fine-grained features and are easier to train. However, extremely wide but shallow networks tend to have difficulties in capturing higher level features
with更广的网络往往能够捕获更多细粒度的功能,并且更易于训练。但是,极其宽泛但较浅的网络在捕获更高级别的特征时往往会遇到困难

With higher resolution input images, ConvNets can potentially capture more fine-grained pattern,but the accuracy gain diminishes for very high resolutions
使用更高分辨率的输入图像,ConvNets可以捕获更细粒度的图案,但对于非常高分辨率的图片,准确度会降低。

作者在论文中对整个网络的运算过程和复合扩展方法进行了抽象:
首先定义了每一层卷积网络为$\mathcal{F}{i}\left(X{i}\right)$,而$X_i$是输入张量,$Y_i$是输出张量,而tensor的形状是$<H_i,W_i,C_i>$
整个卷积网络由 k 个卷积层组成,可以表示为$\mathcal{N}=\mathcal{F}{k} \odot \ldots \odot \mathcal{F}{2} \odot \mathcal{F}{1}\left(X{1}\right)=\bigodot_{j=1 \ldots k} \mathcal{F}{j}\left(X{1}\right)$
从而得到我们的整个卷积网络:
$$
\mathcal{N}=\bigodot_{i=1 \ldots s} \mathcal{F}{i}^{L{i}}\left(X_{\left\langle H_{i}, W_{i}, C_{i}\right\rangle}\right)
$$

下标 i(从 1 到 s) 表示的是 stage 的序号,$\mathcal{F}{i}^{L{i}}$表示第 i 个 stage ,它表示卷积层 $\mathcal{F}{i}$重复了${L{i}}$ 次。

为了探究$d , r , w$这三个因子对最终准确率的影响,则将$d , r , w$加入到公式中,我们可以得到抽象化后的优化问题(在指定资源限制下),其中$s.t.$代表限制条件:
在这里插入图片描述

  • $d$用来缩放深度$\widehat{L}_i $。
  • $r$用来缩放分辨率即影响$\widehat{H}_i$以及$\widehat{W}_i$。
  • $w$就是用来缩放特征矩阵的channels即 $\widehat{C}_i$。
  • target_memory为memory限制
  • target_flops为FLOPs限制
    在这里插入图片描述
    Bigger networks with larger width, depth, or resolution tend to achieve higher accuracy, but the accuracy gain quickly saturate after reaching 80%, demonstrating the limitation of single dimension scaling
    具有较大宽度,深度或分辨率的较大网络往往会实现较高的精度,但是精度增益在达到80%后会迅速饱和,这表明了单维缩放的局限性

    compound scaling method

    In this paper, we propose a new compound scaling method, which use a compound coefficient φ to uniformly scales network width, depth, and resolution in a principled way:
    在本文中,我们提出了一种新的复合缩放方法,该方法使用一个统一的复合系数$\phi$对网络的宽度,深度和分辨率进行均匀缩放。
    在这里插入图片描述
    其中$\alpha,\beta,\gamma$是通过一个小格子搜索的方法决定的常量。通常来说,$\phi$是一个用户指定的系数来控制有多少的额外资源能够用于模型的缩放,$\alpha,\beta,\gamma$指明了怎么支配这些额外的资源分别到网络的宽度,深度,和分辨率上。尤其是,一个标准卷积操作的运算量的比例是$d,w^2,r^2$双倍的网络深度将带来双倍的运算量,但是双倍的网络宽度或分辨率将会增加运算为4倍。因为卷积操作通常在ConvNets中占据绝大部分计算量,通过3式来缩放ConvNet大约将增加$(\alpha,\beta^2,\gamma^2)$运算量。

我们限制$\alpha \cdot \beta^{2} \cdot \gamma^{2} \approx 2$所以对于任意给定的$\phi$值,我们总共的运算量将大约增加$2^{\phi}$

网络结构

文中给出了Efficientnet-B0的基准框架,在Efficientnet当中,我们所使用的激活函数是swish激活函数,整个网络分为了9个stage,在第2到第8stage是一直在堆叠MBConv结构,表格当中MBConv结构后面的数字(1或6)表示的就是MBConv中第一个1x1的卷积层会将输入特征矩阵的channels扩充为n倍。Channels表示通过该Stage后输出特征矩阵的Channels。
在这里插入图片描述

MBConv结构

MBConv的结构相对来说还是十分好理解的,这里是我自己画的一张结构图。
在这里插入图片描述
MBConv结构主要由一个1x1的expand conv(升维作用,包含BN和Swish激活函数)提升维度的倍率正是之前网络结构中看到的1和6,一个KxK的卷积深度可分离卷积Depthwise Conv(包含BN和Swish)k的具体值可看EfficientNet-B0的网络框架主要有3x3和5x5两种情况,一个SE模块,一个1x1的pointer conv降维作用,包含BN),一个Droupout层构成,一般情况下都添加上了残差边模块Shortcut,从而得到输出特征矩阵。
首先关于深度可分离卷积的概念是是我们需要了解的,相当于将卷积的过程拆成运算和合并两个过程,分别对应depthwise和point两个过程,这里给一个参考连接给大家就不在详细描述了Depthwise卷积与Pointwise卷积
在这里插入图片描述
1.由于该模块最初是用tensorflow来实现的与pytorch有一些小差别,所以在使用pytorch实现的时候我们最好将tensorflow当中的samepadding操作重新实现一下
2.在batchnormal时候的动量设置也是有一些不一样的,论文当中设置的batch_norm_momentum=0.99,在pytorch当中需要先执行1-momentum再设为参数与tensorflow不同。

# Batch norm parameters
momentum= 1 - batch_norm_momentum # pytorch's difference from tensorflow
eps= batch_norm_epsilon
nn.BatchNorm2d(num_features=out_channels, momentum=momentum, eps=eps)
class Conv2dSamePadding(nn.Conv2d):
"""2D Convolutions like TensorFlow, for a dynamic image size.
The padding is operated in forward function by calculating dynamically.
"""

# Tips for 'SAME' mode padding.
# Given the following:
# i: width or height
# s: stride
# k: kernel size
# d: dilation
# p: padding
# Output after Conv2d:
# o = floor((i+p-((k-1)*d+1))/s+1)
# If o equals i, i = floor((i+p-((k-1)*d+1))/s+1),
# => p = (i-1)*s+((k-1)*d+1)-i

def __init__(self, in_channels, out_channels, kernel_size,padding=0, stride=1, dilation=1,
groups=1, bias=True, padding_mode = 'zeros'):
super().__init__(in_channels, out_channels, kernel_size, stride, padding, dilation, groups, bias)
self.stride = self.stride if len(self.stride) == 2 else [self.stride[0]] * 2

def forward(self, x):
ih, iw = x.size()[-2:] # input
kh, kw = self.weight.size()[-2:] # because kernel size equals to weight size
sh, sw = self.stride # stride

# change the output size according to stride
oh, ow = math.ceil(ih/sh), math.ceil(iw/sw) # output
"""
kernel effective receptive field size: (kernel_size-1) x dilation + 1
"""
pad_h = max((oh - 1) * self.stride[0] + (kh - 1) * self.dilation[0] + 1 - ih, 0)
pad_w = max((ow - 1) * self.stride[1] + (kw - 1) * self.dilation[1] + 1 - iw, 0)

if pad_h > 0 or pad_w > 0:
x = F.pad(x, [pad_w // 2, pad_w - pad_w // 2, pad_h // 2, pad_h - pad_h // 2])

return F.conv2d(x, self.weight, self.bias, self.stride, self.padding, self.dilation, self.groups)

MBConvBlock模块结构

class ConvBNActivation(nn.Module):
"""Convolution BN Activation"""
def __init__(self,in_channels,out_channels,kernel_size,stride=1,groups=1,
bias=False,momentum=0.01,eps=1e-3,active=False):
super().__init__()
self.layer=nn.Sequential(
Conv2dSamePadding(in_channels,out_channels,kernel_size=kernel_size,
stride=stride,groups=groups, bias=bias),
nn.BatchNorm2d(num_features=out_channels, momentum=momentum, eps=eps)
)
self.active=active
self.swish = Swish()

def forward(self, x):
x = self.layer(x)
if self.active:
x=self.swish(x)
return x




class MBConvBlock(nn.Module):
def __init__(self,in_channels,out_channels,kernel_size,stride,
expand_ratio=1, momentum=0.01,eps=1e-3,
drop_connect_ratio=0.2,training=True,
se_ratio=0.25,skip=True, image_size=None):
super().__init__()
self.expand_ratio = expand_ratio
self.se_ratio = se_ratio
self.has_se = (se_ratio is not None) and (0 < se_ratio <= 1)
self.skip = skip and stride == 1 and in_channels == out_channels

# 1x1 convolution channels expansion phase
expand_channels = in_channels * self.expand_ratio # number of output channels

if self.expand_ratio != 1:
self.expand_conv = ConvBNActivation(in_channels=in_channels,out_channels=expand_channels,
momentum=momentum,eps=eps,
kernel_size=1,bias=False,active=False)

# Depthwise convolution phase
self.depthwise_conv = ConvBNActivation(in_channels=expand_channels,out_channels=expand_channels,
momentum=momentum,eps=eps,
kernel_size=kernel_size,stride=stride,groups=expand_channels,bias=False,active=False)

# Squeeze and Excitation module
if self.has_se:
sequeeze_channels = max(1,int(expand_channels*self.se_ratio))
self.se = SEModule(expand_channels,sequeeze_channels)

# Pointwise convolution phase
self.project_conv = ConvBNActivation(expand_channels,out_channels,momentum=momentum,eps=eps,
kernel_size=1,bias=False,active=True)

self.drop_connect = DropConnect(drop_connect_ratio,training)

def forward(self,x):
input_x = x
if self.expand_ratio != 1:
x = self.expand_conv(x)
x = self.depthwise_conv(x)
if self.has_se:
x = self.se(x)
x = self.project_conv(x)
if self.skip:
x = self.drop_connect(x)
x = x + input_x
return x

SE模块

SE模块是通道注意力模块,该模块能够关注channel之间的关系,可以让模型自主学习到不同channel特征的重要程度。由一个全局平均池化,两个全连接层组成。第一个全连接层的节点个数是输入该MBConv特征矩阵channels的1/4 ,且使用Swish激活函数。第二个全连接层的节点个数等于Depthwise Conv层输出的特征矩阵channels,且使用Sigmoid激活函数,这里引用一下别人画好的示意图。
在这里插入图片描述
在这里插入图片描述

class SEModule(nn.Module):
"""Squeeze and Excitation module for channel attention"""
def __init__(self,in_channels,squeezed_channels):
super().__init__()
self.global_avg_pool = nn.AdaptiveAvgPool2d(1)
self.sequential = nn.Sequential(
nn.Conv2d(in_channels,squeezed_channels,1), # use 1x1 convolution instead of linear
Swish(),
nn.Conv2d(squeezed_channels,in_channels,1),
nn.Sigmoid()
)

def forward(self,x):
x= self.global_avg_pool(x)
y = self.sequential(x)
return x * y

swish激活函数

Swish是Google提出的一种新型激活函数,其原始公式为:f(x)=x * sigmod(x),变形Swish-B激活函数的公式则为f(x)=x * sigmod(b * x),其拥有不饱和,光滑,非单调性的特征,Google在论文中的多项测试表明Swish以及Swish-B激活函数的性能即佳,在不同的数据集上都表现出了要优于当前最佳激活函数的性能。
$$f(x)=x \cdot \operatorname{sigmoid}(\beta x)$$
其中$\beta$是个常数或可训练的参数,Swish 具备无上界有下界、平滑、非单调的特性。

class Swish(nn.Module):
""" swish activation function"""
def forward(self,x):
return x * torch.sigmoid(x)

droupout代码实现

class DropConnect(nn.Module):
"""Drop Connection"""
def __init__(self,ratio,training):
super().__init__()
assert 0 <= ratio <= 1
self.keep_prob = 1 - ratio
self.training=training

def forward(self,x):
if not self.training:
return x
batch_size = x.shape[0]

random_tensor = self.keep_prob
random_tensor += torch.rand([batch_size,1,1,1],dtype=x.dtype,device=x.device)
# generate binary_tensor mask according to probability (p for 0, 1-p for 1)
binary_tensor = torch.floor(random_tensor)

output = x / self.keep_prob * binary_tensor
return output

总结

这里我们只给出了b0结构的代码实现,对于其他结构的实现过程就是在b0的基础上对wdith,depth,resolution都通过倍率因子统一缩放,这个部分在这个博客里面有详细的介绍EfficientNet(B0-B7)参数设置
在本文中,我们系统地研究了ConvNet的缩放比例,分析了各因素对网络结构的影响,并确定仔细平衡网络的宽度,深度和分辨率,这是目前网络训练最重要但缺乏研究的部分,也是我们无法获得更好的准确性和效率忽略的一个部分。为解决此问题,本文作者提出了一种简单而高效的复合缩放方法,通过一个倍率因子统一缩放各部分比例并添加上通道注意力机制和残差模块,从而改善网络架构得到SOTA的效果,同时对模型各成分因子进行量化十分具有创新性。

参考连接
EfficientNet网络详解
神经网络学习小记录50——Pytorch EfficientNet模型的复现详解
论文翻译
令人拍案叫绝的EfficientNet和EfficientDet
swish激活函数
Depthwise卷积与Pointwise卷积
CV领域常用的注意力机制模块(SE、CBAM)
Global Average Pooling

]]>
+ + + + <h2 id="EfficientNet论文解读和pytorch代码实现"><a href="#EfficientNet论文解读和pytorch代码实现" class="headerlink" title="EfficientNet论文解读和pytorch代码实现"></a>EfficientNet论文解读和pytorch代码实现</h2><h2 id="传送门"><a href="#传送门" class="headerlink" title="传送门"></a>传送门</h2><blockquote> +<p>论文地址:<a href="https://arxiv.org/pdf/1905.11946.pdf" target="_blank" rel="noopener">https://arxiv.org/pdf/1905.11946.pdf</a><br>官方github:<a href="https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet" target="_blank" rel="noopener">https://github.com/tensorflow/tpu/tree/master/models/official/efficientnet</a><br>github参考:<a href="https://github.com/qubvel/efficientnet" target="_blank" rel="noopener">https://github.com/qubvel/efficientnet</a><br>github参考:<a href="https://github.com/lukemelas/EfficientNet-PyTorch" target="_blank" rel="noopener">https://github.com/lukemelas/EfficientNet-PyTorch</a></p> +</blockquote> +<h2 id="摘要"><a href="#摘要" class="headerlink" title="摘要"></a>摘要</h2><p>谷歌的文章总是能让我印象深刻,不管从实验上还是论文的书写上都让人十分的佩服,不得不说这确实是一个非常creative的公司!<br><code>Convolutional Neural Networks (ConvNets) are commonly developed at a fixed resource budget, and then scaled up for better accuracy if more resources are available. In this paper, we systematically study model scaling and identify that carefully balancing network depth, width, and resolution can lead to better performance. Based on this observation, we propose a new scaling method that uniformly scales all dimensions of depth/width/resolution using a simple yet highly effective compound coefficient. We demonstrate the effectiveness of this method on scaling up MobileNets and ResNet. </code><br>卷积神经网络通常是在固定的资源预算下进行计算和发展的,如果有更多可用的资源,模型能通过缩放和扩展获得更好的效果,本文<strong>系统研究(工作量很充足)</strong>了模型缩放,并且证明了<strong>细致地平衡网络的深度,宽度,和分辨率能够得到更好的效果</strong>,基于这个观点,我们提出了一个新的尺度缩放的方法,我们提出了一个新的尺度缩放的方法即:<strong>使用一个简单且高效的复合系数统一地缩放所有网络层的深度/宽度/分辨率的维度</strong>。我们证明了该方法在扩大MobileNets和ResNet方面的有效性。</p> + + + + + + + +
+ + + yolov1-3论文解析 + + https://jackyin.space/2021/04/22/yolov1-3%E8%AE%BA%E6%96%87%E8%A7%A3%E6%9E%90/ + 2021-04-22T02:20:00.000Z + 2024-10-09T08:43:45.288Z + + yolov1-3论文解析

最近在看经典目标检测算法yolo的思想,为了更好的了解yolo系列的相关文章,我从最初版本的论文思想开始看的,之后有时间会把yolov4和yolov5再认真看看,目前来说yolov3的spp版本是使用得最为广泛的一种,整体上来说yolo的设计思想还是很有创造性的数学也比较严谨。

yolov1论文思想

物体检测主流的算法框架大致分为one-stage与two-stage。two-stage算法代表有R-CNN系列,one-stage算法代表有Yolo系列。按笔者理解,two-stage算法将步骤一与步骤二分开执行,输入图像先经过候选框生成网络(例如faster rcnn中的RPN网络),再经过分类网络;one-stage算法将步骤一与步骤二同时执行,输入图像只经过一个网络,生成的结果中同时包含位置与类别信息。two-stage与one-stage相比,精度高,但是计算量更大,所以运算较慢。

We present YOLO, a new approach to object detection. Prior work on object detection repurposes classifiers to perform detection. Instead, we frame object detection as a regression problem to spatially separated bounding boxes and associated class probabilities.

yolo相比其他R-CNN等方法最大的一个不同就是他将这个识别和定位的过程转化成了一个空间定位并分类的回归问题,这也是他为什么能够利用网络进行端到端直接同时预测的重要原因。

yolo的特点

1.YOLO速度非常快。由于我们的检测是当做一个回归问题,不需要很复杂的流程。在测试的时候我们只需将一个新的图片输入网络来检测物体。
First, YOLO is extremely fast. Since we frame detection as a regression problem we don’t need a complex pipeline
2.Yolo会基于整张图片信息进行预测,与基于滑动窗口和候选区域的方法不同,在训练和测试期间YOLO可以看到整个图像,所以它隐式地记录了分类类别的上下文信息及它的全貌
Second, YOLO reasons globally about the image when making predictions Unlike sliding window and region proposal-based techniques, YOLO sees the entire image during training and test time so it implicitly encodes contextual information about classes as well as their appearance
3.第三,YOLO能学习到目标的泛化表征。作者尝试了用自然图片数据集进行训练,用艺术画作品进行预测,Yolo的检测效果更佳。
Third, YOLO learns generalizable representations of objects. Since YOLO is highly generalizable it is less likely to break down when applied to new domains or unexpected inputs

backbone-darknet

在这里插入图片描述
yolov1这块的话,由于是比较早期的网络所以在设计时没有使用batchnormal,激活函数上采用leaky relu,输入图像大小为448x448,经过许多卷积层与池化层,变为7x7x1024张量,最后经过两层全连接层,输出张量维度为7x7x30。除了最后一层的输出使用了线性激活函数,其他层全部使用Leaky Relu激活函数。
$$\phi(x)= \begin{cases}
x,& \text{if x>0} \
0.1x,& \text{otherwise}
\end{cases}$$

输出维度

yolov1最精髓的地方应该就是他的输出维度,论文当中有放出这样一张图片,看完以后我们能对yolo算法的特点有更加深刻的理解。在上图的backbone当中我们可以看到的是
在这里插入图片描述yolo的输出相当于把原图片分割成了$S \times S$个区域,然后对预测目标标定他的boundingbox,boundingbox由中心点的坐标,长宽以及物体的置信分数组成$x,y,w,h,confidence$,图中的$B$表示的是boundingbox的个数。置信分数在yolo当中是这样定义的:$Pr(Object)IOU_{pred}^{truth}$对于$Pr(Object)=1 \text{ if detect object else 0}$,其实置信分数就是boudingbox与groundtruth之间的IOU,并对每个小网格对应的$C$个类别都预测出他的条件概率:$Pr(Class_i|Object)$。
在推理时,我们可以得到当前网格对于每个类别的预测置信分数:$$Pr(Class_i)*IOU_{pred}^{truth} = Pr(Class_i|Object)*Pr(Object)*IOU_{pred}^{truth}$$
这样一种严谨的条件概率的方式得到我们的最终概率是十分可行和合适的。
YOLO imposes strong spatial constraints on bounding box predictions since each grid cell only predicts two boxes and can only have one class. This spatial constraint limits the number of nearby objects that our model can predict. Our model struggles with small objects that appear in groups, such as flocks of birds.
*
不过在原论文当中也有提到的一点是:YOLO给边界框预测强加空间约束,因为每个网格单元只预测两个框和只能有一个类别。这个空间约束限制了我们的模型可以预测的邻近目标的数量。我们的模型难以预测群组中出现的小物体(比如鸟群)。**

损失函数

在损失函数方面,由于公式比较长所以就直接截图过来了,损失函数的设计放方面作者也考虑的比较周全,
在这里插入图片描述
预测框的中心点$(x,y)$。预测框的宽高$w,h$,其中$\mathbb{1}_{i j}^{\text {obj }}$为控制函数,在标签中包含物体的那些格点处,该值为 1 ,若格点不含有物体,该值为 0

在计算损失函数的时候作者最开始使用的是最简单的平方损失函数来计算检测,因为它是计算简单且容易优化的,但是它并不完全符合我们最大化平均精度的目标,原因如下:
It weights localization error equally with classification error which may not be ideal.
1.它对定位错误的权重与分类错误的权重相等,这可能不是理想的选择。
Also, in every image many grid cells do not contain any object. This pushes the “confidence” scores of those cells towards zero, often overpowering the gradient from cells that do contain objects. This can lead to model instability, causing training to diverge early on.
而且,在每个图像中,许多网格单元不包含任何对象。这就把这些网格的置信度分数推到零,往往超过了包含对象的网格的梯度。2.这可能导致模型不稳定,导致训练早期发散难以训练。

解决方案:增加边界框坐标预测的损失,并且减少了不包含对象的框的置信度预测的损失。我们使用两个参数来实现这一点。$\lambda_{coord}=5,\lambda_{noobj}=0.5$,其实这也是yolo面临的一个样本数目不均衡的典型例子。主要目的是让含有物体的格点,在损失函数中的权重更大,让模型更加注重含有物体的格点所造成的损失。
我们的损失函数则只会对那些有真实物体所属的格点进行损失计算,若该格点不包含物体,那么预测数值不对损失函数造成影响。

这里对$w,h$在损失函数中的处理分别取了根号,原因在于,如果不取根号,损失函数往往更倾向于调整尺寸比较大的预测框。例如,20个像素点的偏差,对于800x600的预测框几乎没有影响,此时的IOU数值还是很大,但是对于30x40的预测框影响就很大。取根号是为了尽可能的消除大尺寸框与小尺寸框之间的差异。

预测框的置信度$C_i$。当该格点不含有物体时,该置信度的标签为0;若含有物体时,该置信度的标签为预测框与真实物体框的IOU数值(。
物体类别概率$P_i$,对应的类别位置,该标签数值为1,其余位置为0,与分类网络相同。

yolov2:Better, Faster, Stronger

yolov2的论文里面其实更多的是对训练数据集的组合和扩充,然后再添加了很多计算机视觉方面新出的trick,然后达到了性能的提升。同时yolov2方面所使用的trick也是现在计算机视觉常用的方法,我认为这些都是我们需要好好掌握的,同时也是面试和kaggle上都经常使用的一些方法。

Batch Normalization

BN是由Google于2015年提出,论文是《Batch Normalization_ Accelerating Deep Network Training by Reducing Internal Covariate Shift》,这是一个深度神经网络训练的技巧,主要是让数据的分布变得一致,从而使得训练深层网络模型更加容易和稳定。
这里有一些相关的链接可以参考一下

https://www.cnblogs.com/itmorn/p/11241236.html
https://zhuanlan.zhihu.com/p/24810318
https://zhuanlan.zhihu.com/p/93643523
莫烦python
李宏毅yyds

算法具体过程:
在这里插入图片描述

这里要提一下这个$\gamma和\beta$是可训练参数,维度等于张量的通道数,主要是为了在反向传播更新网络时使得标准化后的数据分布与原始数据尽可能保持一直,从而很好的抽象和保留整个batch的数据分布。

Batch Normalization的作用:
将这些输入值或卷积网络的张量在batch维度上进行类似标准化的操作,将其放缩到合适的范围,加快模型训练时的收敛速度,使得模型训练过程更加稳定,避免梯度爆炸或者梯度消失,并且起到一定的正则化作用。

High Resolution Classifier

在Yolov1中,网络的backbone部分会在ImageNet数据集上进行预训练,训练时网络输入图像的分辨率为224x224。在v2中,将分类网络在输入图片分辨率为448x448的ImageNet数据集上训练10个epoch,再使用检测数据集(例如coco)进行微调。高分辨率预训练使mAP提高了大约4%。

Convolutional With Anchor Boxes

predicts these offsets at every location in a feature map
Predicting offsets instead of coordinates simplifies the problem and makes it easier for the network to learn.
第一篇解读v1时提到,每个格点预测两个矩形框,在计算loss时,只让与ground truth最接近的框产生loss数值,而另一个框不做修正。这样规定之后,作者发现两个框在物体的大小、长宽比、类别上逐渐有了分工。在v2中,神经网络不对预测矩形框的宽高的绝对值进行预测,而是预测与Anchor框的偏差(offset),每个格点指定n个Anchor框。在训练时,最接近ground truth的框产生loss,其余框不产生loss。在引入Anchor Box操作后,mAP由69.5下降至69.2,原因在于,每个格点预测的物体变多之后,召回率大幅上升,准确率有所下降,总体mAP略有下降。

Dimension Clusters

Instead of choosing priors by hand, we run k-means clustering on the training set bounding boxes to automatically find good priors.
这里算是作者数据处理上的一个创新点,这里作者提到之前的工作当中先Anchor Box都是认为设定的比例和大小,而这里作者时采用无监督的方式将训练数据集中的矩形框全部拿出来,用kmeans聚类得到先验框的宽和高。使用(1-IOU)数值作为两个矩形框的的距离函数,这个处理也十分的聪明。
$$
d(\text { box }, \text { centroid })=1-\operatorname{IOU}(\text { box }, \text { centroid })
$$
在这里插入图片描述

Direct location prediction

Yolo中的位置预测方法是预测的左上角的格点坐标预测偏移量。网络预测输出要素图中每个单元格的5个边界框。网络为每个边界框预测$t_x,t_y,t_h,t_w和t_o$这5个坐标。如果单元格从图像的左上角偏移了$(c_x,c_y)$并且先验边界框的宽度和高度为$p_w,p_h$,则预测对应于:
$$
\begin{array}{l}
x=\left(t_{x} * w_{a}\right)-x_{a} \
y=\left(t_{y} * h_{a}\right)-y_{a}
\end{array}
$$
在这里插入图片描述
$$
\begin{aligned}
b_{x} &=\sigma\left(t_{x}\right)+c_{x} \
b_{y} &=\sigma\left(t_{y}\right)+c_{y} \
b_{w} &=p_{w} e^{t_{w}} \
b_{h} &=p_{h} e^{t_{h}} \
\operatorname{Pr}(\text { object }) * I O U(b, \text { object }) &=\sigma\left(t_{o}\right)
\end{aligned}
$$
由于我们约束位置预测,参数化更容易学习,使得网络更稳定使用维度集群以及直接预测边界框中心位置使YOLO比具有anchor box的版本提高了近5%的mAP。

Fine-Grained Features

在2626的特征图,经过卷积层等,变为1313的特征图后,作者认为损失了很多细粒度的特征,导致小尺寸物体的识别效果不佳,所以在此加入了passthrough层
传递层通过将相邻特征堆叠到不同的通道而不是堆叠到空间位置,将较高分辨率特征与低分辨率特征相连,类似于ResNet中的标识映射。这将26×26×512特征映射转换为13×13×2048特征映射,其可以与原始特征连接。
在这里插入图片描述

Multi-Scale Training

我觉得这个也是yolo为什么性能提升的一个很重要的点,解决了yolo1当中对于多个小物体检测的问题。
原始的YOLO使用448×448的输入分辨率。添加anchor box后,我们将分辨率更改为416×416。然而,由于我们的模型只使用卷积层和池化层,相比yolo1删除了全连接层,它可以在运行中调整大小(应该是使用了1x1卷积不过我没看代码)。我们希望YOLOv2能够在不同大小的图像上运行,因此我们将其训练到模型中。
instead of fixing the input image size we change the network every few iterations. Every 10 batches our network randomly chooses a new image dimension size.
不固定输入图像的大小,我们每隔几次迭代就更改网络。在每10个batch之后,我们的网络就会随机resize成{320, 352, …, 608}中的一种。不同的输入,最后产生的格点数不同,比如输入图片是320320,那么输出格点是1010,如果每个格点的先验框个数设置为5,那么总共输出500个预测结果;如果输入图片大小是608608,输出格点就是1919,共1805个预测结果。
YOLO’s convolutional layers downsample the image by a factor of 32 so by using an input image of 416 we get an output feature map of 13 × 13.
We do this because we want an odd number of locations in our feature map so there is a single center cell.
关于416×416也是有说法的,主要是下采样是32的倍数,而且最后的输出是13x13是奇数然后会有一个中心点更加易于目标检测。
这种训练方法迫使网络学习在各种输入维度上很好地预测。这意味着相同的网络可以预测不同分辨率的检测。
关于yolov2最大的一个提升还有一个原因就是WordTree组合数据集的训练方法,不过这里我就不再赘述,可以看参考资料有详细介绍,这里主要讲网络和思路

yolov3论文改进

yolov3的论文改进就有很多方面了,而且yolov3-spp的网络效果很不错,和yolov4,yolov5的效果差别也不是特别大,这也是为什么yolov3网络被广泛应用的原因之一。

backbone:Darknet-53

相比yolov1的网络,在网络上有了很大的改进,借鉴了Resnet、Densenet、FPN的做法结合了当前网络中十分有效的
在这里插入图片描述
1.Yolov3中,全卷积,对于输入图片尺寸没有特别限制,可通过调节卷积步长控制输出特征图的尺寸。
2.Yolov3借鉴了金字塔特征图思想,小尺寸特征图用于检测大尺寸物体,而大尺寸特征图检测小尺寸物体。特征图的输出维度为$N \times N \times (3 \times (4+1+80))$, NxN为输出特征图格点数,一共3个Anchor框,每个框有4维预测框数值 $t_x,t_y,t_w,t_h$ ,1维预测框置信度,80维物体类别数。所以第一层特征图的输出维度为8x8x255
3.Yolov3总共输出3个特征图,第一个特征图下采样32倍,第二个特征图下采样16倍,第三个下采样8倍。每个特征图进行一次3X3、步长为2的卷积,然后保存该卷积layer,再进行一次1X1的卷积和一次3X3的卷积,并把这个结果加上layer作为最后的结果。三个特征层进行5次卷积处理,处理完后一部分用于输出该特征层对应的预测结果,一部分用于进行反卷积UmSampling2d后与其它特征层进行结合。
4.concat和resiual加操作,借鉴DenseNet将特征图按照通道维度直接进行拼接,借鉴Resnet添加残差边,缓解了在深度神经网络中增加深度带来的梯度消失问题。
5.上采样层(upsample):作用是将小尺寸特征图通过插值等方法,生成大尺寸图像。例如使用最近邻插值算法,将88的图像变换为1616。上采样层不改变特征图的通道数。

对于yolo3的模型来说,网络最后输出的内容就是三个特征层每个网格点对应的预测框及其种类,即三个特征层分别对应着图片被分为不同size的网格后,每个网格点上三个先验框对应的位置、置信度及其种类。然后对输出进行解码,解码过程也就是yolov2上面的Direct location prediction方法一样,每个网格点加上它对应的x_offset和y_offset,加完后的结果就是预测框的中心,然后再利用 先验框和h、w结合 计算出预测框的长和宽。这样就能得到整个预测框的位置了。

CIoU loss

在yolov3当中我们使用的不再是传统的IoU loss,而是一个非常优秀的loss设计,整个发展过程也可以多了解了解IoU->GIoU->DIoU->CIoU,完整的考虑了重合面积,中心点距离,长宽比
$$CIoU=IoU-(\frac{\rho(b,b^{gt}}{c^2}+\alpha v))$$
$$v=\frac{4}{\pi^2}(\arctan\frac{w^{gt}}{h^{gt}}-\arctan\frac{w}{h})^2$$
$$\alpha = \frac{v}{(1-IoU)+v}$$
其中, $b$ , $b^{gt}$ 分别代表了预测框和真实框的中心点,且 $\rho$代表的是计算两个中心点间的欧式距离。 [公式] 代表的是能够同时包含预测框和真实框的最小闭包区域的对角线距离。
在介绍CIoU之前,我们可以先介绍一下DIoU loss
在这里插入图片描述
其实这两项就是我们的DIoU
$$DIoU = IoU-(\frac{\rho(b,b^{gt}}{c^2})$$
则我们可以提出DIoU loss函数
$$
L_{\text {DIoU }}=1-D I o U \
0 \leq L_{\text {DloU}} \leq 2
$$
DloU损失能够直接最小化两个boxes之间的距离,因此收敛速度更快。
而我们的CIoU则比DIoU考虑更多的东西,也就是长宽比即最后一项。而$v$用来度量长宽比的相似性,$\alpha$是权重
在损失函数这块,有知乎大佬写了一下,其实就是对yolov1上的损失函数进行了一下变形。
在这里插入图片描述

Spatial Pyramid Pooling

在yolov3的spp版本中使用了spp模块,实现了不同尺度的特征融合,spp模块最初来源于何凯明大神的论文SPP-net,主要用来解决输入图像尺寸不统一的问题,而目前的图像预处理操作中,resize,crop等都会造成一定程度的图像失真,因此影响了最终的精度。SPP模块,使用固定分块的池化操作,可以对不同尺寸的输入实现相同大小的输出,因此能够避免这一问题。
同时SPP模块中不同大小特征的融合,有利于待检测图像中目标大小差异较大的情况,也相当于增大了多重感受野吧,尤其是对于yolov3一般针对的复杂多目标图像。
在yolov3的darknet53输出到第一个特征图计算之前我们插入了一个spp模块。
在这里插入图片描述
SPP的这几个模块stride=1,而且会对外补padding,所以最后的输出特征图大小是一致的,然后在深度方向上进行concatenate,使得深度增大了4倍。
在这里插入图片描述
在这里插入图片描述
可以看出随着输入网络尺度的增大,spp的效果会更好。多个spp的效果增大也就是spp3和spp1的效果是差不多的,为了保证推理速度就只使用了一个spp

Mosaic图像增强

在yolov3-spp包括yolov4当中我们都使用了mosaic数据增强,有点类似cutmix。cutmix是合并两张图片进行预测,mosaic数据增强利用了四张图片,对四张图片进行拼接,每一张图片都有其对应的框框,将四张图片拼接之后就获得一张新的图片,同时也获得这张图片对应的框框,然后我们将这样一张新的图片传入到神经网络当中去学习,相当于一下子传入四张图片进行学习了。论文中说这极大丰富了检测物体的背景,且在标准化BN计算的时候一下子会计算四张图片的数据。
在这里插入图片描述
作用:增加数据的多样性,增加目标个数,BN能一次性归一化多张图片组合的分布,会更加接近原数据的分布。

focal loss

最后我们提一下focal loss,虽然在原论文当中作者说focal loss效果反而下降了,但是我认为还是有必要了解一下何凯明的这篇bestpaper。作者提出focal loss的出发点也是希望one-stage detector可以达到two-stage detector的准确率,同时不影响原有的速度。作者认为造成这种情况的原因是样本的类别不均衡导致的
对于二分类的CrossEntropy,我们有如下表示方法:
$$
\mathrm{CE}(p, y)=\left{\begin{array}{ll}
-\log (p) & \text { if } y=1 \
-\log (1-p) & \text { otherwise. }
\end{array}\right.
$$
我们定义$p_t$:
$$
p_{\mathrm{t}}=\left{\begin{array}{ll}
p & \text { if } y=1 \
1-p & \text { otherwise }
\end{array}\right.
$$
则重写交叉熵
$$
\operatorname{CE}(n, y)=C E(p_t)=-\log (p_t)
$$
接着我们提出改进思路就是在计算CE时添加了一个平衡因子,是一个可训练的参数
$$
\mathrm{CE}\left(p_{\mathrm{t}}\right)=-\alpha_{\mathrm{t}} \log \left(p_{\mathrm{t}}\right)
$$
其中
$$
\alpha_{\mathrm{t}}=\left{\begin{array}{ll}
\alpha_{\mathrm{t}} & \text { if } y=1 \
1-\alpha_{\mathrm{t}} & \text { otherwise }
\end{array}\right.
$$
相当于给正负样本加上权重,负样本出现的频次多,那么就降低负样本的权重,正样本数量少,就相对提高正样本的权重。因此可以通过设定a的值来控制正负样本对总的loss的共享权重。a取比较小的值来降低负样本(多的那类样本)的权重。
但是何凯明认为这个还是不能完全解决样本不平衡的问题,虽然这个平衡因子可以控制正负样本的权重,但是没法控制容易分类和难分类样本的权重

As our experiments will show, the large class imbalance encountered during training of dense detectors overwhelms the cross entropy loss. Easily classified negatives comprise the majority of the loss and dominate the gradient. While
α balances the importance of positive/negative examples, it does not differentiate between easy/hard examples. Instead, we propose to reshape the loss function to down-weight easy examples and thus focus training on hard negatives

于是提出了一种新的损失函数Focal Loss
$$
\mathrm{FL}\left(p_{\mathrm{t}}\right)=-\left(1-p_{\mathrm{t}}\right)^{\gamma} \log \left(p_{\mathrm{t}}\right)
$$
在这里插入图片描述

focal loss的两个重要性质

1、当一个样本被分错的时候,pt是很小的,那么调制因子(1-Pt)接近1,损失不被影响;当Pt→1,因子(1-Pt)接近0,那么分的比较好的(well-classified)样本的权值就被调低了。因此调制系数就趋于1,也就是说相比原来的loss是没有什么大的改变的。当pt趋于1的时候(此时分类正确而且是易分类样本),调制系数趋于0,也就是对于总的loss的贡献很小。

2、当γ=0的时候,focal loss就是传统的交叉熵损失,当γ增加的时候,调制系数也会增加。 专注参数γ平滑地调节了易分样本调低权值的比例。γ增大能增强调制因子的影响,实验发现γ取2最好。直觉上来说,调制因子减少了易分样本的损失贡献,拓宽了样例接收到低损失的范围。当γ一定的时候,比如等于2,一样easy example(pt=0.9)的loss要比标准的交叉熵loss小100+倍,当pt=0.968时,要小1000+倍,但是对于hard example(pt < 0.5),loss最多小了4倍。这样的话hard example的权重相对就提升了很多。这样就增加了那些误分类的重要性

focal loss的两个性质算是核心,其实就是用一个合适的函数去度量难分类和易分类样本对总的损失的贡献。

然后作者又提出了最终的focal loss形式
$$
\mathrm{FL}\left(p_{\mathrm{t}}\right)=-\alpha_{\mathrm{t}}\left(1-p_{\mathrm{t}}\right)^{\gamma} \log \left(p_{\mathrm{t}}\right)
$$
$$
F L(p)\left{\begin{array}{ll}
-\alpha(1-p)^{\gamma} \log (p) & \text { if } y=1 \
-(1-\alpha) p^{\gamma} \log (1-p) & \text { otherwise }
\end{array}\right.
$$
这样既能调整正负样本的权重,又能控制难易分类样本的权重
在实验中a的选择范围也很广,一般而言当γ增加的时候,a需要减小一点(实验中γ=2,a=0.25的效果最好)

总结

yolo和yolov2的严谨数学推理和网络相结合的做法令人十分惊艳,而yolov3相比之前的两个版本不管是在数据处理还是网络性质上都有很大的改变,也使用了很多流行的tirck来实现目标检测,基本上结合了很多cv领域的精髓,博客中有很多部分由于时间关系没有太细讲,其实每个部分都可以去原论文中找到很多可以学习的地方,之后有时候会补上yolov4和yolov5的讲解,后面的网络添加了注意力机制模块效果应该是更加work的。

参考文献

yolov3-spp
focal loss
batch normal
IoU系列
yolov1论文翻译
yolo1-3三部曲
Bubbliiiing的教程里
还有很多但是没找到之后会补上的

]]>
+ + + + <h2 id="yolov1-3论文解析"><a href="#yolov1-3论文解析" class="headerlink" title="yolov1-3论文解析"></a>yolov1-3论文解析</h2><p>最近在看经典目标检测算法yolo的思想,为了更好的了解yolo系列的相关文章,我从最初版本的论文思想开始看的,之后有时间会把yolov4和yolov5再认真看看,目前来说yolov3的spp版本是使用得最为广泛的一种,整体上来说yolo的设计思想还是很有创造性的数学也比较严谨。</p> + + + + + + + +
+ + + MTCNN论文和pytorch代码解读 + + https://jackyin.space/2021/04/12/MTCNN%E8%AE%BA%E6%96%87%E5%92%8Cpytorch%E4%BB%A3%E7%A0%81%E8%A7%A3%E8%AF%BB/ + 2021-04-12T00:39:00.000Z + 2024-10-09T08:43:45.243Z + + MTCNN人脸检测和pytorch代码实现解读

传送门

论文地址:https://arxiv.org/ftp/arxiv/papers/1604/1604.02878.pdf
我的论文笔记:https://khany.top/file/paper/mtcnn.pdf
本文csdn链接:https://blog.csdn.net/Jack___E/article/details/115601474
github参考:https://github.com/Sierkinhane/mtcnn-pytorch
github参考:https://github.com/GitHberChen/MTCNN_Pytorch

abstract

abstract—Face detection and alignment in unconstrained environment are challenging due to various poses, illuminations and occlusions. Recent studies show that deep learning approaches can achieve impressive performance on these two tasks. In this paper, we propose a deep cascaded multi-task framework which exploits the inherent correlation between detection and alignment
to boost up their performance. In particular, our framework leverages a cascaded architecture with three stages of carefully designed deep convolutional networks to predict face and landmark location in a coarse-to-fine manner. In addition, we propose a new online hard sample mining strategy that further improves the performance in practice. Our method achieves superior accuracy over the state-of-the-art techniques on the challenging FDDB and WIDER FACE benchmarks for face detection, and AFLW benchmark for face alignment, while keeps real time performance.

在无约束条件的环境下进行人脸检测和校准人脸检测和校准是非常具挑战性的,因为你要考虑复杂的姿势,光照因素以及面部遮挡问题的影响,最近的研究表明,使用深度学习的方法能够在这两项任务上有不错的效果。本文作者探索和研究了人脸检测和校准之间的内在联系,提出了一个深层级的多任务框架有效提升了网络的性能。我们的深层级联合架构包含三个阶段的卷积神经网络从粗略到细致逐步实现人脸检测和面部特征点标记。此外,我们还提出了一种新的线上进行困难样本的预测的策略可以在实际使用过程中有效提升网络的性能。我们的方法目前在FDDB和WIDER FACE人脸检测任务和AFLW面部对准任务上超越了最佳模型方法的性能标准,同时该模型具有不错的实时检测效果。

my English is not so well,if there are some mistakes in translations, please contact me in blog comments.

简介

人脸检测和脸部校准任务对于很多面部任务和应用来说都是十分重要的,比如说人脸识别,人脸表情分析。不过在现实生活当中,面部特征时常会因为一些遮挡物,强烈的光照对比,复杂的姿势发生很大的变化,这使得这些任务变得具有很大挑战性。Viola和Jones 提出的级联人脸检测器利用Haar特征和AdaBoost训练级联分类器,实现了具有实时效率的良好性能。 然而,也有相当一部分的工作表明,这种分类器可能在现实生活的应用中效果显着降低,即使具有更高级的特征和分类器。,之后人们又提出了DPM的方式,这些年来基于CNN的一些解决方案也层出不穷,基于CNN的方案主要是为了识别出面部的一些特征来实现。作者认为这种方式其实是需要花费更多的时间来对面部进行校准来训练同时还忽略了面部的重要特征点位置和边框问题。
对于人脸校准的话目前也有大致的两个方向:一个是基于回归的方法还有一个就是基于模板拟合的方式进行,主要是对特征识别起到一个辅助的工作。
作者认为关于人脸识别和面部对准这两个任务其实是有内在关联的,而目前大多数的方法则忽略了这一点,所以本文所提出的方案就是将这两者都结合起来,构建出一个三阶段的模型实现一个端到端的人脸检测并校准面部特征点的过程。
第一阶段:通过浅层CNN快速生成候选窗口。
第二阶段:通过more complex的CNN拒绝大量非面部窗口来细化窗口。
第三阶段:使用more powerful的CNN再次细化结果并输出五个面部标志位置。

方法

Image pyramid图像金字塔

在进入stage-1之前,作者先构建了一组多尺度的图像金字塔缩放,这一块要理解起来还是有一点费力的,这里我们需要了解的是在训练网络的过程当中,作者都是把WIDER FACE的图片随机剪切成12x12size的大小进行单尺度训练的,不能满足任意大小的人脸检测,所以为了检测到不同尺寸的人脸,所以在推理时需要先生成图像金字塔生成一组不同scale的图像输入P-net进行来实现人脸的检测,同时也这是为什么P-net要使用FCN的原因。
在这里插入图片描述

def calculateScales(img):
min_face_size = 20 # 最小的人脸尺寸
width, height = img.size
min_length = min(height, width)
min_detection_size = 12
factor = 0.707 # sqrt(0.5)
scales = []
m = min_detection_size / min_face_size
min_length *= m
factor_count = 0
# 图像尺寸缩小到不大于min_detection_size
while min_length > min_detection_size:
scales.append(m * factor ** factor_count)
min_length *= factor
factor_count += 1

$$\text{length} =\text{length} \times (\frac{\text{min detection size}}{\text{min face size}} )\times factor^{count} $$
$\text{here we define in our code:} factor=\frac{1}{\sqrt{2}}, \text{min face size}=20,\text{min detection size}=12$

min_face_size和factor对推理过程会产生什么样的影响?
min_face_size越大,factor越小,图像最短边就越快缩放到接近min_detect_size,从而生成图像金字塔的耗时就越短,同时各尺度的跨度也更大。因此,加大min_face_size、减小factor能加速图像金字塔的生成,但同时也更易造成漏检。

Stage 1 P-Net(Proposal Network)

这是一个全卷积网络,也就是说这个网络可以兼容任意大小的输入,他的整个网络其实十分简单,该层的作用主要是为了获得人脸检测的大量候选框,这一层我们最大的作用就是要尽可能的提升recall,然后在获得许多候选框后再使用非极大抑制的方法合并高度重叠的候选区域。
在这里插入图片描述
P-Net的示意图当中我们也可以看到的是作者输入12x12大小最终的output为一个1x1x2的face label classification概率和一个1x1x4的boudingbox(左上角和右下角的坐标)以及一个1x1x10的landmark(双眼,鼻子,左右嘴角的坐标)
注意虽然这里作者举例是12x12的图片大小,但是他的意思并不是说这个P-Net的图片输入大小必须是12,我们可以知道这个网络是FCN,这就意味着不同输入的大小都是可以输入其中的,最后我们所得到的featuremap$[m \times n \times (2+4+10) ]$每一个小像素点映射到输入图像所在的12x12区域是否包含人脸的分类结果,候选框左上和右下基准点以及landmark,然后根据图像金字塔的我们再根据scale和resize的逆过程将其映射到原图像上

P-net structure

class P_Net(nn.Module):
def __init__(self):
super(P_Net, self).__init__()
self.pre_layer = nn.Sequential(
# 12x12x3
nn.Conv2d(3, 10, kernel_size=3, stride=1), # conv1
nn.PReLU(), # PReLU1
# 10x10x10
nn.MaxPool2d(kernel_size=2, stride=2), # pool1
# 5x5x10
nn.Conv2d(10, 16, kernel_size=3, stride=1), # conv2
# 3x3x16
nn.PReLU(), # PReLU2
nn.Conv2d(16, 32, kernel_size=3, stride=1), # conv3
# 1x1x32
nn.PReLU() # PReLU3
)
# detection
self.conv4_1 = nn.Conv2d(32, 1, kernel_size=1, stride=1)
# bounding box regresion
self.conv4_2 = nn.Conv2d(32, 4, kernel_size=1, stride=1)
# landmark localization
self.conv4_3 = nn.Conv2d(32, 10, kernel_size=1, stride=1)
# weight initiation with xavier
self.apply(weights_init)

def forward(self, x):
x = self.pre_layer(x)
det = torch.sigmoid(self.conv4_1(x))
box = self.conv4_2(x)
landmark = self.conv4_3(x)
# det:[,2,1,1], box:[,4,1,1], landmark:[,10,1,1]
return det, box, landmark

这里要提一下nn.PReLU(),有点类似Leaky ReLU,可以看下面的博客深入了解一下
在这里插入图片描述

https://blog.csdn.net/qq_23304241/article/details/80300149
https://blog.csdn.net/shuzfan/article/details/51345832

然后在P-Net之后我们通过非极大抑制的方法和将所有的boudingbox都修正为框的最长边为边长的正方形框主要是避免后面的Rnet在resize的时候因为尺寸原因出现信息的损失。
在这里插入图片描述

Non-Maximum Suppression非极大抑制

其实关于非极大抑制这个trick最初是在目标检测任务当中提出的来的,其思想是搜素局部最大值,抑制极大值,主要用在目标检测当中,最传统的非极大抑制所采用的评价指标就是交并比IoU(intersection-over-union)即两个groud truth和bounding box的交集部分除以它们的并集.
在这里插入图片描述
$$IoU = \frac{area(C) \cap area(G)}{area(C) \cup area(G)}$$

def IoU(box, boxes):
"""Compute IoU between detect box and gt boxes

Parameters:
----------
box: numpy array , shape (5, ): x1, y1, x2, y2, score
input box
boxes: numpy array, shape (n, 4): x1, y1, x2, y2
input ground truth boxes

Returns:
-------
ovr: numpy.array, shape (n, )
IoU
"""
box_area = (box[2] - box[0] + 1) * (box[3] - box[1] + 1)
area = (boxes[:, 2] - boxes[:, 0] + 1) * (boxes[:, 3] - boxes[:, 1] + 1)
xx1 = np.maximum(box[0], boxes[:, 0])
xx2 = np.minimum(box[2], boxes[:, 2])
yy1 = np.maximum(box[1], boxes[:, 1])
yy2 = np.minimum(box[3], boxes[:, 3])

# compute the width and height of the bounding box
w = np.maximum(0, xx2 - xx1 + 1)
h = np.maximum(0, yy2 - yy1 + 1)

inter = w * h
ovr = np.true_divide(inter,(box_area + area - inter))
#ovr = inter / (box_area + area - inter)
return ovr

使用非极大抑制的前提是,我们已经得到了一组候选框和对应label的置信分数,以及groud truth的信息,通过设定阈值来删除重合度较高的候选框。
算法流程如下:

  • 根据置信度得分进行排序
  • 选择置信度最高的比边界框添加到最终输出列表中,将其从边界框列表中删除
  • 计算所有边界框的面积
  • 计算置信度最高的边界框与其它候选框的IoU。
  • 删除IoU大于阈值的边界框
  • 重复上述过程,直至边界框列表为空。
def nms(dets,threshod,mode="Union"):
"""
greedily select boxes with high confidence
keep boxes overlap <= thresh
rule out overlap > thresh
:param dets: [[x1, y1, x2, y2 score]]
:param threshod: retain overlap <= thresh
:return: indexes to keep
"""
x1 = dets[:,0]
y1 = dets[;,1]
x2 = dets[:,2]
y2 = dets[:,3]

scores = dets[:,4]

areas = (x2 - x1 + 1) * (y2 - y1 + 1)
order = areas.argsort()[::-1] # reverse

keep=[]

while order.size()>0:
i = order[0]
keep.append(i)
# A & B left top position
xx1 = np.maximun(x1[i],x1[order[1,:]])
yy1 = np.maximun(y1[i],y1[order[1,:]])
# A & B right down position
xx2 = np.minimum(x2[i],x2[order[1,:]])
yy2 = np.minimum(y2[i], y2[order[1:]])

w = np.maximum(0.0, xx2 - xx1 + 1)
h = np.maximum(0.0, yy2 - yy1 + 1)

inter = w * h

# cacaulate the IOU between box which have largest score with other boxes
if mode == "Union":
# area[i]: the area of largest score
ovr = inter / (areas[i] + areas[order[1:]] - inter)
elif mode == "Minimum":
ovr = inter / np.minimum(areas[i], areas[order[1:]])
# delete the IoU that higher than threshod
inds = np.where(ovr <= threshod)[0]
order = order[inds + 1] # +1: eliminates the first element in order

return keep

边框修正

以最大边作为边长将矩形修正为正方形,同时包含的信息也更多,以免在后面resize输入下一个网络时减少信息的损失。

def convert_to_square(bboxes):
"""
Convert bounding boxes to a square form.
"""
# 将矩形对称扩大为正方形
square_bboxes = np.zeros_like(bboxes)
x1, y1, x2, y2 = [bboxes[:, i] for i in range(4)]
h = y2 - y1 + 1.0
w = x2 - x1 + 1.0
max_side = np.maximum(h, w)
square_bboxes[:, 0] = x1 + w * 0.5 - max_side * 0.5
square_bboxes[:, 1] = y1 + h * 0.5 - max_side * 0.5
square_bboxes[:, 2] = square_bboxes[:, 0] + max_side - 1.0
square_bboxes[:, 3] = square_bboxes[:, 1] + max_side - 1.0
return square_bboxes

Stage 2 R-Net(Refine Network)

R-net的输入是固定的,必须是24x24,所以对于P-net产生的大量boundingbox我们需要先进行resize然后再输入R-Net,在论文中我们了解到该网络层的作用主要是对大量的boundingbox进行有效过滤,获得更加精细的候选框。
在这里插入图片描述

R-net structure

class R_Net(nn.Module):
def __init__(self):
super(R_Net, self).__init__()
self.pre_layer = nn.Sequential(
# 24x24x3
nn.Conv2d(3, 28, kernel_size=3, stride=1), # conv1
nn.PReLU(), # prelu1
# 22x22x28
nn.MaxPool2d(kernel_size=3, stride=2), # pool1
# 10x10x28
nn.Conv2d(28, 48, kernel_size=3, stride=1), # conv2
nn.PReLU(), # prelu2
# 8x8x48
nn.MaxPool2d(kernel_size=3, stride=2), # pool2
# 3x3x48
nn.Conv2d(48, 64, kernel_size=2, stride=1), # conv3
# 2x2x64
nn.PReLU() # prelu3
)
# 2x2x64
self.conv4 = nn.Linear(64 * 2 * 2, 128) # conv4
# 128
self.prelu4 = nn.PReLU() # prelu4
# detection
self.conv5_1 = nn.Linear(128, 1)
# bounding box regression
self.conv5_2 = nn.Linear(128, 4)
# lanbmark localization
self.conv5_3 = nn.Linear(128, 10)
# weight initiation weih xavier
self.apply(weights_init)

def forward(self, x):
x = self.pre_layer(x)
x = x.view(x.size(0), -1)
x = self.conv4(x)
x = self.prelu4(x)
det = torch.sigmoid(self.conv5_1(x))
box = self.conv5_2(x)
landmark = self.conv5_3(x)
return det, box, landmark

然后在P-Net之后我们通过非极大抑制的方法和将所有的boudingbox都修正为框的最长边为边长的正方形框也是避免后面的Onet在resize的时候出现因为尺寸原因出现信息的损失。
在这里插入图片描述

Stage 3 O-Net(Output?[作者未指出命名] Network)

在这里插入图片描述
Onet与Rnet工作流程类似。只不过输入的尺寸变成了48x48,对于R-net当中的框再次进行处理,得到的网络结构的输出则是最终的label classfication,boundingbox,landmark。
O-net structure

class O_Net(nn.Module):
def __init__(self):
super(O_Net, self).__init__()
self.pre_layer = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, stride=1), # conv1
nn.PReLU(), # prelu1
nn.MaxPool2d(kernel_size=3, stride=2), # pool1
nn.Conv2d(32, 64, kernel_size=3, stride=1), # conv2
nn.PReLU(), # prelu2
nn.MaxPool2d(kernel_size=3, stride=2), # pool2
nn.Conv2d(64, 64, kernel_size=3, stride=1), # conv3
nn.PReLU(), # prelu3
nn.MaxPool2d(kernel_size=2, stride=2), # pool3
nn.Conv2d(64, 128, kernel_size=2, stride=1), # conv4
nn.PReLU() # prelu4
)
self.conv5 = nn.Linear(128 * 2 * 2, 256) # conv5
self.prelu5 = nn.PReLU() # prelu5
# detection
self.conv6_1 = nn.Linear(256, 1)
# bounding box regression
self.conv6_2 = nn.Linear(256, 4)
# lanbmark localization
self.conv6_3 = nn.Linear(256, 10)
# weight initiation weih xavier
self.apply(weights_init)

def forward(self, x):
x = self.pre_layer(x)
x = x.view(x.size(0), -1)
x = self.conv5(x)
x = self.prelu5(x)
# detection
det = torch.sigmoid(self.conv6_1(x))
box = self.conv6_2(x)
landmark = self.conv6_3(x)
return det, box, landmark

在这里插入图片描述
注意,其实在之前的两个网络当中我们也预测了landmark的位置,只是在论文的图示当中没有展示而已,从作者描述的网络结构图的输出当中是详细指出了landmarkposition的卷积块的

损失函数

在研究完网络结构以后我们可以来看看这个mtcnn模型的一个损失函数,作者将损失函数分为了3个部分:Face classification、Bounding box regression、Facial landmark localization。

Face classification

对于第一部分的损失就是用的是最常用的交叉熵损失函数,就本质上来说人脸识别还是一个二分类问题,这里就使用Cross Entropy是最简单也是最合适的选择。
$$L_i^{det} = -(y_i^{det} \log(p_i) + (1-y_i^det)(1-\log(p_i)))$$
$p_i$是预测为face的可能性,$y_i^{det}$指的是真实标签也就是groud truth label

Bounding box regression

对于目标边界框的损失来说,对于每一个候选框我们都需要对与他最接近的真实目标边界框进行比较,the bounding box$(left, top, height, and width)$
$$L_i^{box} = ||y_j^{box}-y_i^{box} ||_2^2$$

Facial landmark localization

而对于boundingbox和landmark来说整个框的调整过程其实可以看作是一个连续的变化过程,固使用的是欧氏距离回归损失计算方法。比较的是各个点的坐标与真实面部关键点坐标的差异。
$$L_i^{landmark} = ||y_j^{landmark}-y_i^{landmark} ||_2^2$$

total loss

最终我们得到的损失函数是有上述这三部分加权而成
$$\min{\sum_{i=1}^{N}{\sum_{j \in {det,box,landmark}} \alpha_j \beta_i^j L_i^j}}$$
其中$\alpha_j$表示权重,$\beta_i^j$表示第i个样本的类型,也可以说是第i个样本在任务j中是否需要贡献loss,如果不存在人脸即label为0时则无需计算loss。
对于不同的网络我们所设置的权重是不一样的
in P-net & R-net(在这两层我们更注重classification的识别)
$$alpha_{det}=1, alpha_{box}=0.5,alpha_{landmark}=0.5$$
in O-net(在这层我们提高了对于注意关键点的预测精度)
$$alpha_{det}=1, alpha_{box}=0.5,alpha_{landmark}=1 $$
文中也有提到,采用的是随机梯度下降优化器进行的训练。

OHEM(Online Hard Example Mining)

作者对于困难样本的在线预测所做的trick也比较简单,就是挑选损失最大的前70%作为困难样本,在反向传播时仅使用这70%困难样本产生的损失,这样就剔除了很容易预测的easy sample对训练结果的影响,不过在我参考的这两个版本的代码里面似乎没有这么做。

实验

实验这块的话也比较充分,验证了每个修改部分对于实验结果的有效性验证,主要是讲述了实验过程对于训练数据集的处理和划分,验证了在线硬样本挖掘的有效性,联合检测和校准的有效性,分别评估了face detection和lanmark的贡献,面部检测评估,面部校准评估以及与SOTA的对比,这一块的话就没有细看了,分享的网站也有详细解释,论文原文也写了。
在这里插入图片描述
在这里插入图片描述

总结

这篇论文是中科院深圳先进技术研究院的乔宇老师团队所作,2016ECCV,看完这篇文章的话给我的感觉的话就是idea和实现过程包括实验都是很充分的,创新点这块的话主要是挖掘了人脸特征关键点和目标检测的一些联系,结合了人脸检测和对准两个任务来进行人脸检测,相比其他经典的目标检测网络如yolov3,R-CNN系列,在网络和损失函数上的创新确实略有不足,但是也让我收到了一些启发,看似几个简单的model和常见的loss联合,在对数据进行有效处理的基础上也是可以实现达到十分不错的效果的,不过这个方案的话在训练的时候其实是很花费时间的,毕竟需要对于不同scale的图片都进行输入训练,然后就是这种输入输出的结构其实还是存在一些局限性的,对于图像检测框和关键点的映射我个人觉得也比较繁杂或者说浪费了一些时间,毕竟是一篇2016年的论文之后应该会有更好的实现方式。

参考资料

参考链接: https://zhuanlan.zhihu.com/p/337690783
参考链接:https://zhuanlan.zhihu.com/p/60199964?utm_source=qq&utm_medium=social&utm_oi=1221207556791963648
参考链接: https://blog.csdn.net/weixin_44791964/article/details/103530206
参考链接:https://blog.csdn.net/qq_34714751/article/details/85536669
参考链接:https://www.bilibili.com/video/BV1fJ411C7AJ?from=search&seid=2691296178499711503

]]>
+ + + + <h1 id="MTCNN人脸检测和pytorch代码实现解读"><a href="#MTCNN人脸检测和pytorch代码实现解读" class="headerlink" title="MTCNN人脸检测和pytorch代码实现解读"></a>MTCNN人脸检测和pytorch代码实现解读</h1><h2 id="传送门"><a href="#传送门" class="headerlink" title="传送门"></a>传送门</h2><blockquote> +<p>论文地址:<a href="https://arxiv.org/ftp/arxiv/papers/1604/1604.02878.pdf" target="_blank" rel="noopener">https://arxiv.org/ftp/arxiv/papers/1604/1604.02878.pdf</a><br>我的论文笔记:<a href="https://khany.top/file/paper/mtcnn.pdf" target="_blank" rel="noopener">https://khany.top/file/paper/mtcnn.pdf</a><br>本文csdn链接:<a href="https://blog.csdn.net/Jack___E/article/details/115601474" target="_blank" rel="noopener">https://blog.csdn.net/Jack___E/article/details/115601474</a><br>github参考:<a href="https://github.com/Sierkinhane/mtcnn-pytorch" target="_blank" rel="noopener">https://github.com/Sierkinhane/mtcnn-pytorch</a><br>github参考:<a href="https://github.com/GitHberChen/MTCNN_Pytorch" target="_blank" rel="noopener">https://github.com/GitHberChen/MTCNN_Pytorch</a></p> +</blockquote> +<h2 id="abstract"><a href="#abstract" class="headerlink" title="abstract"></a>abstract</h2> + + + + + + + +
+ + + docker镜像操作 + + https://jackyin.space/2021/02/25/docker%E9%95%9C%E5%83%8F%E6%93%8D%E4%BD%9C/ + 2021-02-24T16:03:00.000Z + 2024-10-09T08:43:45.257Z + + commit镜像

在这里插入图片描述

数据卷操作实战:mysql同步

mysql运行容器,需要做数据挂载,安装启动mysql是需要配置密码的这一点要注意,所以要去docker hub官方文档上面去看官方配置

docker pull mysql:5.7

docker运行,docker run的常用参数这里我们再次回顾一下

-d 后台运行
-p 端口映射
-v 卷挂载
-e 环境配置
--name 环境名字

通过docker hub我们找到了官方的命令:docker run --name some-mysql -e MYSQL_ROOT_PASSWORD=my-secret-pw -d mysql:tag,在修改一下得到我们最终的输入命令

docker run -d -p 3310:3306 -v /home/mysql/conf:/etc/mysql/conf.d -v /home/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=12345678 --name mysql01 mysql:5.7
CREATE DATABASE test_db;

在这里插入图片描述

在这里插入图片描述
删除这个镜像后数据则依旧保存下来了
在这里插入图片描述

具名/匿名挂载

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
大多数情况下,为了方便,我们会使用具名挂载
在这里插入图片描述

Dockerfile

Dockerfile就是用来构建docker镜像的文件,命令脚本,通过这个脚本可以生成镜像。
构建步骤

  1. 编写一个Dockerfile

  2. docker build 构建成为一个镜像

  3. docker run 运行镜像

  4. docker push 发布镜像(DockerHub,阿里云镜像)

    这里我们可以先看看Docker Hub官方是怎么做的
    在这里插入图片描述
    在这里插入图片描述
    官方镜像是比较基础的,有很多命令和功能都省去了,所以我们通常需要在基础的镜像上来构建我们自己的镜像
    在这里插入图片描述

Dockerfile命令

常用命令用法
FROM基础镜像,一切从这开始构建
MAINTAINER镜像是谁写的,姓名+邮箱
RUN镜像构建的时候需要运行的命令
ADD添加内容,如tomcat压缩包
WORKDIR镜像的工作目录
VOLUME挂载的目录
CMD指定这个容器启动时要运行的命令,只有最后一个会生效,可被替代
ENTRYPOINT指定这个容器启动时要运行的命令,可以追加命令
ONBUILD当构建一个被继承DockerFile这个时候就会执行ONBUILD命令
COPY类似ADD将文件拷贝到镜像当中
ENV构建的时候设置环境变量

在这里插入图片描述

创建一个自己的centos

Dockerfile中99%的镜像都来自于这个scratch镜像,然后配置需要的软件和配置来进行构建。

mkdir dockerfile
cd dockerfile
vim mydockerfile-centos

编写mydockerfile-centos

FROM centos
MAINTAINER khan<khany@foxmail.com>
ENV MYPATH /usr/local
WORKDIR $MYPATH
RUN yum -y install vim
RUN yum -y install net-tools
EXPOSE 80
CMD echo $MYPATH
CMD echo "---end---"
CMD /bin/bash

然后我们进入docker build,注意后面一定要有一个.号

docker build -f mydockerfile-centos  -t mycentos:1.0 .

然后我们通过docker run -it mycentos:1.0 命令进入我们自己创建的镜像测试运行我们新安装的包和命令是否能正常运行。
在这里插入图片描述
我们可以通过 docker history +容器名称/容器id看到这个容器的构建过程。
在这里插入图片描述

CMD和ENTRYPOINT区别

在这里插入图片描述

dockerfile-cmd-test:

FROM centos
CMD ["ls","-a"]

dockerfile-entrypoint-test:

FROM centos
ENTRYPOINT ["ls","-a"]

执行命令 docker run 容器名称 -l在CMD下会报错,命令会被后面追加的-l替代,而-l并不是有效的linux命令,所以报错,而ENTRYPOINT则是可以追加的则该命令会变为ls -al
在这里插入图片描述

发布镜像

发布到Docker Hub

  1. 地址 https://hub.docker.com/ 注册自己的账号
  2. 确定这个账号可以登录
  3. 在我们服务器上提交自己的镜像
  4. 登录成功,通过push命令提交镜像,记得注意添加版本号
    在这里插入图片描述
    这里出了一点小问题:

在build自己的镜像的时候添加tag时必须在前面加上自己的dockerhub的username,然后再push就可以了
在这里插入图片描述

docker tag 镜像id YOUR_DOCKERHUB_NAME/firstimage
docker push YOUR_DOCKERHUB_NAME/firstimage

在这里插入图片描述
提交成功,可以在docker hub上找到你提交的镜像
在这里插入图片描述

阿里云镜像提交

在阿里云的容器镜像服务里面,创建一个新的镜像仓库,然后就会有详细的教学,做法与docker hub基本一致,提交成功能在镜像版本当中查看到,这里就不再重复讲解了。
在这里插入图片描述

Docker镜像操作过程总结

在这里插入图片描述
在这里插入图片描述

参考链接:【狂神说Java】Docker最新超详细版教程通俗易懂

]]>
+ + + + <h2 id="commit镜像"><a href="#commit镜像" class="headerlink" title="commit镜像"></a>commit镜像</h2><p><img src="https://img-blog.csdnimg.cn/20210224162521454.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0phY2tfX19F,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p> +<h2 id="数据卷操作实战:mysql同步"><a href="#数据卷操作实战:mysql同步" class="headerlink" title="数据卷操作实战:mysql同步"></a>数据卷操作实战:mysql同步</h2><p><strong>mysql运行容器,需要做数据挂载,安装启动mysql是需要配置密码的这一点要注意,所以要去docker hub官方文档上面去看官方配置</strong></p> +<figure class="highlight powershell"><table><tr><td class="code"><pre><code class="hljs powershell">docker pull mysql:<span class="hljs-number">5.7</span><br></code></pre></td></tr></table></figure> + +<p>docker运行,docker run的常用参数这里我们再次回顾一下</p> +<figure class="highlight powershell"><table><tr><td class="code"><pre><code class="hljs powershell"><span class="hljs-literal">-d</span> 后台运行<br><span class="hljs-literal">-p</span> 端口映射<br><span class="hljs-literal">-v</span> 卷挂载<br><span class="hljs-literal">-e</span> 环境配置<br>-<span class="hljs-literal">-name</span> 环境名字<br></code></pre></td></tr></table></figure> + + + + + + + +
+ + + docker常用命令 + + https://jackyin.space/2021/02/24/docker%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/ + 2021-02-24T07:30:00.000Z + 2024-10-09T08:43:45.257Z + + Docker 常用命令

帮助命令

docker version #显示docker版本信息
docker info #显示docker的系统信息,包括镜像和容器的数量
docker 命令 --help # 帮助命令

镜像命令

1.docker images查看所有本地的主机镜像

docker images显示字段解释
REPOSITORY镜像的仓库源
TAG镜像的标签
IMAGE ID镜像的id
CREATED镜像的创建时间
SIZE镜像的大小
(base) [root@iZuf69rye0flkbn4kbxrobZ ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest bf756fb1ae65 13 months ago 13.3kB
(base) [root@iZuf69rye0flkbn4kbxrobZ ~]# docker images --help

Usage: docker images [OPTIONS] [REPOSITORY[:TAG]]

List images

Options:
-a, --all Show all images
-q, --quiet Only show image IDs

在这里插入图片描述
2.docker search命令搜索镜像
搜索镜像可以去docker hub网站上直接搜索,也可以通过命令行来搜索,通过万能帮助命令能更快的看到他的一些用法,这两种方法结果是一样的
在这里插入图片描述
在这里插入图片描述

我们也可以通过--filter来进行条件筛选
比如docker search mysql --filter=STARS=3000

(base) [root@iZuf69rye0flkbn4kbxrobZ ~]# docker search mysql --filter=STARS=3000
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 10538 [OK]
mariadb MariaDB is a community-developed fork of MyS… 3935 [OK]

3.docker pull下载镜像
这个命令其实信息量很大,这也是docker高明的地方,关于指定版本下载一定要是docker hub官网上面支持和提供的版本
在这里插入图片描述
我这里使用了

docker pull mysql
docker pull mysql:5.7

在这里插入图片描述
4.docker rmi删除镜像
删除可以通过REPOSITORY来删,也可以通过IMAGE ID来删除
在这里插入图片描述

容器命令

说明:我们有了镜像才可以创建容器,linux,下载一个centos镜像来测试学习

docker pull centos

1.新建容器并启动
通过docker run命令进入下载的centos容器里面后我们可以发现的是,我们的rootname不一样了
在这里插入图片描述在这里插入图片描述

2.列出所有运行的容器
docker ps命令
在这里插入图片描述
3.exit退出命令

exit #直接容器停止并退出
Ctrl + P + Q #容器不停止并退出

在执行exit命令后,我们看到rootname又变回来了
在这里插入图片描述

4.删除容器

docker rm 容器id #删除指定的容器,不能删除正在运行的容器,如果要强制删除,需要使用 rm -f
docker rm $(docker ps -aq) #删除全部的容器
docker ps -a -q|xargs docker rm #删除全部容器

5.启动和停止容器
在这里插入图片描述

日志元数据进程查看


在这里插入图片描述
1.docker top 容器id查看容器中的进程

在这里插入图片描述
2.docker inspect 容器id查看元数据

3.进入当前正在运行的容器

方式1: docker exec -it 容器id bashshell并可通过ps -ef查看容器当中的进程

方式2:docker attach 容器id进入容器,如果当前有正在执行的容器则会直接进入到当前正在执行的进程当中

在这里插入图片描述

从容器内拷贝到主机上

即使容器已经停止也是可以进行拷贝的

docker cp 容器id:容器内路径 目的主机路径

在这里插入图片描述

docker部署nginx

$ docker search nginx
$ docker pull nginx
$ docker run -d --name nginx01 -p 8083:80 nginx
$ docker ps
$ curl localhost:8083

docker stop 后则无法再访问
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

portainer可视化管理

docker run -d -p 8088:9000 --restart=always -v /var/run/docker.sock:/var/run/docker.sock --privileged=true portainer/portainer

在这里插入图片描述
进入后选择local模式,然后就能看到这个版面了
在这里插入图片描述
参考链接:
【狂神说Java】Docker最新超详细版教程通俗易懂

]]>
+ + + + <h1 id="Docker-常用命令"><a href="#Docker-常用命令" class="headerlink" title="Docker 常用命令"></a>Docker 常用命令</h1><h2 id="帮助命令"><a href="#帮助命令" class="headerlink" title="帮助命令"></a>帮助命令</h2><figure class="highlight bash"><table><tr><td class="code"><pre><code class="hljs bash">docker version <span class="hljs-comment">#显示docker版本信息</span><br>docker info <span class="hljs-comment">#显示docker的系统信息,包括镜像和容器的数量</span><br>docker 命令 --<span class="hljs-built_in">help</span> <span class="hljs-comment"># 帮助命令</span><br></code></pre></td></tr></table></figure> + +<h2 id="镜像命令"><a href="#镜像命令" class="headerlink" title="镜像命令"></a>镜像命令</h2><p><strong>1.<code>docker images</code>查看所有本地的主机镜像</strong></p> +<table> +<thead> +<tr> +<th align="left">docker images显示字段</th> +<th align="left">解释</th> +</tr> +</thead> +<tbody><tr> +<td align="left">REPOSITORY</td> +<td align="left">镜像的仓库源</td> +</tr> +<tr> +<td align="left">TAG</td> +<td align="left">镜像的标签</td> +</tr> +<tr> +<td align="left">IMAGE ID</td> +<td align="left">镜像的id</td> +</tr> +<tr> +<td align="left">CREATED</td> +<td align="left">镜像的创建时间</td> +</tr> +<tr> +<td align="left">SIZE</td> +<td align="left">镜像的大小</td> +</tr> +</tbody></table> + + + + + + + +
+ + + docker安装和简易原理 + + https://jackyin.space/2021/02/24/docker%E5%AE%89%E8%A3%85%E5%92%8C%E7%AE%80%E6%98%93%E5%8E%9F%E7%90%86/ + 2021-02-24T04:53:00.000Z + 2024-10-09T08:43:45.257Z + + docker安装和简易原理

最近参加了阿里云datawhale天池的一个比赛里面需要用docker进行提交,所以借此机会学习了一下docker,b站上有个很好的视频【狂神说Java】Docker最新超详细版教程通俗易懂

docker基本组成

在这里插入图片描述

在这里插入图片描述

docker安装

centos7安装
先查看centos版本,新版本的docker都只支持centos7以上

(base) [root@iZuf69rye0flkbn4kbxrobZ ~]# cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

然后我们的操作均按照帮助文档进行操作即可
dockerCentos安装

# 卸载旧版本
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine

# 安装
sudo yum install -y yum-utils

#配置镜像,官方是国外的很慢,这里我们使用阿里云镜像
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

# 推荐使用这个
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

#更新yum
yum makecache fast

# 安装相关的包
sudo yum install docker-ce docker-ce-cli containerd.io

Start Docker

sudo systemctl start docker

使用docker version查看是否安装成功
在这里插入图片描述
sudo docker run hello-world在这里插入图片描述

使用docker images 查看所安装的所有镜像
在这里插入图片描述

Uninstall Docker Engine

1.Uninstall the Docker Engine, CLI, and Containerd packages:

sudo yum remove docker-ce docker-ce-cli containerd.io

2.删除默认工作目录和资源

$ sudo rm -rf /var/lib/docker

阿里云镜像加速器

这一块的话推荐天池的一个docker学习赛
登录阿里云找到容器服务,并创建新容器,然后找到里面的镜像加速器对centos进行配置。
在这里插入图片描述

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://fdm7vcvf.mirror.aliyuncs.com"]
}
EOF

sudo systemctl daemon-reload

sudo systemctl restart docker

回归Hello World镜像的运行过程

在这里插入图片描述

底层原理

Docker是什么工作的?
Docker是一个Client - Server结构的系统,Docker的守护进行运行在主机上。通过Socket从客户端访问!DockerServer接收到Docker-Client的指令,就会执行这个命令!
在这里插入图片描述
docker为什么比虚拟机快?
参考链接

在这里插入图片描述
在这里插入图片描述

]]>
+ + + + <h2 id="docker安装和简易原理"><a href="#docker安装和简易原理" class="headerlink" title="docker安装和简易原理"></a>docker安装和简易原理</h2><p>最近参加了阿里云datawhale天池的一个比赛里面需要用docker进行提交,所以借此机会学习了一下docker,b站上有个很好的视频<a href="https://www.bilibili.com/video/BV1og4y1q7M4?p=6" target="_blank" rel="noopener">【狂神说Java】Docker最新超详细版教程通俗易懂</a></p> +<h2 id="docker基本组成"><a href="#docker基本组成" class="headerlink" title="docker基本组成"></a>docker基本组成</h2><p><img src="https://img-blog.csdnimg.cn/20210224124633537.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0phY2tfX19F,size_16,color_FFFFFF,t_70" alt="在这里插入图片描述"></p> + + + + + + + +
+ +
diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 00000000..d833360a --- /dev/null +++ b/categories/index.html @@ -0,0 +1,775 @@ + + + + + + + + + categories | khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/content.json b/content.json new file mode 100644 index 00000000..a5394f68 --- /dev/null +++ b/content.json @@ -0,0 +1 @@ +[{"title":"ubuntu22.04 日常化","date":"2024-10-09T10:17:37.000Z","path":"2024/10/09/ubuntu22-04-日常化/","tags":[{"name":"linux","slug":"linux","permalink":"https://jackyin.space/tags/linux/"}]},{"title":"Never Stop Thinking","date":"2024-06-09T07:51:56.000Z","path":"2024/06/09/Never-Stop-Thinking(1)/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"Dynamicgo 支持 Protobuf 动态反射","date":"2023-12-27T08:57:00.000Z","path":"2023/12/27/Dynamicgo-支持-Protobuf-动态反射/","tags":[{"name":"Go","slug":"Go","permalink":"https://jackyin.space/tags/Go/"}]},{"title":"既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子","date":"2022-03-30T16:41:32.000Z","path":"2022/03/31/既往不恋,纵情向前,江湖再见——22岁那年,在北京的日子/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"菜鸡的算法岗日常实习面经总结","date":"2022-01-08T12:06:00.000Z","path":"2022/01/08/菜鸡的算法岗日常实习面经总结/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"},{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"回首向来萧瑟处,归去,也无风雨也无晴|2021年终总结","date":"2022-01-08T12:04:00.000Z","path":"2022/01/08/回首向来萧瑟处,归去,也无风雨也无晴|2021年终总结/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"PAT笔记","date":"2021-10-16T06:19:00.000Z","path":"2021/10/16/PAT笔记/","tags":[{"name":"数据结构","slug":"数据结构","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"}]},{"title":"集成学习专题——Xgboost&LightGBM","date":"2021-06-17T16:11:00.000Z","path":"2021/06/18/集成学习专题——Xgboost-LightGBM/","tags":[{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"},{"name":"机器学习","slug":"机器学习","permalink":"https://jackyin.space/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"}]},{"title":"集成学习专题——GBDT","date":"2021-06-17T15:59:00.000Z","path":"2021/06/17/集成学习专题——GBDT/","tags":[{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"},{"name":"机器学习","slug":"机器学习","permalink":"https://jackyin.space/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"}]},{"title":"集成学习专题——adaboost原理和sklearn实现","date":"2021-06-17T15:15:00.000Z","path":"2021/06/17/集成学习专题——adaboost原理和sklearn实现/","tags":[{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"},{"name":"机器学习","slug":"机器学习","permalink":"https://jackyin.space/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"}]},{"title":"集成学习专题——voting&bagging","date":"2021-06-16T15:55:00.000Z","path":"2021/06/16/集成学习专题——voting-bagging/","tags":[{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"},{"name":"机器学习","slug":"机器学习","permalink":"https://jackyin.space/tags/%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/"}]},{"title":"数据结构与算法——二分","date":"2021-06-15T13:48:00.000Z","path":"2021/06/15/数据结构与算法——二分/","tags":[{"name":"数据结构","slug":"数据结构","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"}]},{"title":"数据结构与刷题——链表","date":"2021-06-13T07:49:00.000Z","path":"2021/06/13/数据结构与刷题——链表/","tags":[{"name":"数据结构","slug":"数据结构","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"}]},{"title":"数据结构与算法基础——快速排序与归并排序","date":"2021-06-06T12:33:00.000Z","path":"2021/06/06/数据结构与算法基础——快速排序与归并排序/","tags":[{"name":"数据结构","slug":"数据结构","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/"}]},{"title":"EfficientNet论文解读和pytorch代码实现","date":"2021-05-09T09:44:00.000Z","path":"2021/05/09/EfficientNet论文解读和pytorch代码实现/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"}]},{"title":"yolov1-3论文解析","date":"2021-04-22T02:20:00.000Z","path":"2021/04/22/yolov1-3论文解析/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"}]},{"title":"MTCNN论文和pytorch代码解读","date":"2021-04-12T00:39:00.000Z","path":"2021/04/12/MTCNN论文和pytorch代码解读/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"}]},{"title":"docker镜像操作","date":"2021-02-24T16:03:00.000Z","path":"2021/02/25/docker镜像操作/","tags":[{"name":"docker","slug":"docker","permalink":"https://jackyin.space/tags/docker/"}]},{"title":"docker常用命令","date":"2021-02-24T07:30:00.000Z","path":"2021/02/24/docker常用命令/","tags":[{"name":"docker","slug":"docker","permalink":"https://jackyin.space/tags/docker/"}]},{"title":"docker安装和简易原理","date":"2021-02-24T04:53:00.000Z","path":"2021/02/24/docker安装和简易原理/","tags":[{"name":"docker","slug":"docker","permalink":"https://jackyin.space/tags/docker/"}]},{"title":"datawhale语义分割-Task4 评价函数与损失函数","date":"2021-02-23T06:55:00.000Z","path":"2021/02/23/datawhale语义分割-Task4-评价函数与损失函数/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"datawhale语义分割-Task3 语义分割模型发展","date":"2021-02-23T05:39:00.000Z","path":"2021/02/23/datawhale语义分割-Task3-语义分割模型发展/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"datawhale-语义分割task2数据扩增","date":"2021-02-22T11:04:00.000Z","path":"2021/02/22/datawhale-语义分割task2数据扩增/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"datawhale阿里云天池语义分割比赛-Task1 赛题理解和baseline代码","date":"2021-02-20T13:44:00.000Z","path":"2021/02/20/datawhale阿里云天池语义分割比赛-Task1-赛题理解和baseline代码/","tags":[{"name":"计算机视觉","slug":"计算机视觉","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E8%A7%86%E8%A7%89/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"datawhale-pandas缺失数据处理","date":"2021-01-20T12:55:00.000Z","path":"2021/01/20/datawhale-pandas缺失数据处理/","tags":[{"name":"pandas","slug":"pandas","permalink":"https://jackyin.space/tags/pandas/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"datawhale-pandas数据分析预备","date":"2020-12-21T04:40:31.000Z","path":"2020/12/21/datawhale-pandas数据分析预备/","tags":[{"name":"pandas","slug":"pandas","permalink":"https://jackyin.space/tags/pandas/"},{"name":"datawhale","slug":"datawhale","permalink":"https://jackyin.space/tags/datawhale/"}]},{"title":"信号量机制经典例子","date":"2020-11-05T16:27:36.000Z","path":"2020/11/06/信号量机制经典例子/","tags":[{"name":"操作系统","slug":"操作系统","permalink":"https://jackyin.space/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"}]},{"title":"数据库复习题","date":"2020-11-01T11:16:40.000Z","path":"2020/11/01/数据库复习题/","tags":[{"name":"数据库系统","slug":"数据库系统","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/"}]},{"title":"人人都是产品经理读后感","date":"2020-10-13T09:16:09.000Z","path":"2020/10/13/人人都是产品经理读后感/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"中断异常与系统调用","date":"2020-10-03T14:51:56.000Z","path":"2020/10/03/中断异常与系统调用/","tags":[{"name":"操作系统","slug":"操作系统","permalink":"https://jackyin.space/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"}]},{"title":"操作系统的运行机制和体系结构","date":"2020-10-03T13:37:16.000Z","path":"2020/10/03/操作系统的运行机制和体系结构/","tags":[{"name":"操作系统","slug":"操作系统","permalink":"https://jackyin.space/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"}]},{"title":"js基础——关于对象","date":"2020-10-02T08:03:30.000Z","path":"2020/10/02/js基础——关于对象/","tags":[{"name":"web基础","slug":"web基础","permalink":"https://jackyin.space/tags/web%E5%9F%BA%E7%A1%80/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://jackyin.space/tags/JavaScript/"}]},{"title":"编译原理第二章——文法分类","date":"2020-10-02T01:35:22.000Z","path":"2020/10/02/编译原理第二章——文法分类/","tags":[{"name":"编译原理","slug":"编译原理","permalink":"https://jackyin.space/tags/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86/"}]},{"title":"SQL语句————数据定义","date":"2020-09-29T15:38:18.000Z","path":"2020/09/29/SQL语句————数据定义/","tags":[{"name":"数据库系统","slug":"数据库系统","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/"}]},{"title":"js基础——数组对象(Array object)","date":"2020-09-29T12:11:24.000Z","path":"2020/09/29/js基础——数组对象-Array-object/","tags":[{"name":"web基础","slug":"web基础","permalink":"https://jackyin.space/tags/web%E5%9F%BA%E7%A1%80/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://jackyin.space/tags/JavaScript/"}]},{"title":"js基础——函数","date":"2020-09-27T07:55:13.000Z","path":"2020/09/27/js基础——函数/","tags":[{"name":"web基础","slug":"web基础","permalink":"https://jackyin.space/tags/web%E5%9F%BA%E7%A1%80/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://jackyin.space/tags/JavaScript/"}]},{"title":"js基础——数据类型与基本逻辑语句","date":"2020-09-26T07:57:00.000Z","path":"2020/09/26/js基础——数据类型与基本逻辑语句/","tags":[{"name":"web基础","slug":"web基础","permalink":"https://jackyin.space/tags/web%E5%9F%BA%E7%A1%80/"},{"name":"JavaScript","slug":"JavaScript","permalink":"https://jackyin.space/tags/JavaScript/"}]},{"title":"htmlcss回顾","date":"2020-09-24T13:15:00.000Z","path":"2020/09/24/htmlcss回顾/","tags":[{"name":"web基础","slug":"web基础","permalink":"https://jackyin.space/tags/web%E5%9F%BA%E7%A1%80/"}]},{"title":"进程","date":"2020-09-21T15:41:53.000Z","path":"2020/09/21/进程/","tags":[{"name":"操作系统","slug":"操作系统","permalink":"https://jackyin.space/tags/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F/"}]},{"title":"Business Intelligence(BI) System介绍","date":"2020-09-13T12:12:18.000Z","path":"2020/09/13/Business-Intelligence-BI-System介绍/","tags":[{"name":"数据库系统","slug":"数据库系统","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/"}]},{"title":"并发控制机制的必要性","date":"2020-09-10T16:01:25.000Z","path":"2020/09/11/并发控制机制的必要性/","tags":[{"name":"数据库系统","slug":"数据库系统","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/"}]},{"title":"数据库E-R图介绍","date":"2020-09-10T14:37:19.000Z","path":"2020/09/10/数据库E-R图介绍/","tags":[{"name":"数据库系统","slug":"数据库系统","permalink":"https://jackyin.space/tags/%E6%95%B0%E6%8D%AE%E5%BA%93%E7%B3%BB%E7%BB%9F/"}]},{"title":"java的String常用操作","date":"2020-09-09T12:02:38.000Z","path":"2020/09/09/java的String常用操作/","tags":[{"name":"Java","slug":"Java","permalink":"https://jackyin.space/tags/Java/"}]},{"title":"matlab简单微分方程求解","date":"2020-07-16T15:36:00.000Z","path":"2020/07/16/matlab简单微分方程求解/","tags":[{"name":"数学建模","slug":"数学建模","permalink":"https://jackyin.space/tags/%E6%95%B0%E5%AD%A6%E5%BB%BA%E6%A8%A1/"}]},{"title":"模拟退火matlab实现(TSP为例)","date":"2020-07-15T03:38:00.000Z","path":"2020/07/15/模拟退火matlab实现(TSP为例)/","tags":[{"name":"数学建模","slug":"数学建模","permalink":"https://jackyin.space/tags/%E6%95%B0%E5%AD%A6%E5%BB%BA%E6%A8%A1/"}]},{"title":"python实现遗传算法","date":"2020-07-12T13:56:00.000Z","path":"2020/07/12/python实现遗传算法/","tags":[{"name":"数学建模","slug":"数学建模","permalink":"https://jackyin.space/tags/%E6%95%B0%E5%AD%A6%E5%BB%BA%E6%A8%A1/"}]},{"title":"Hexo博客搭建","date":"2020-07-10T15:01:00.000Z","path":"2020/07/10/Hexo博客搭建/","tags":[{"name":"Hexo","slug":"Hexo","permalink":"https://jackyin.space/tags/Hexo/"}]},{"title":"人到大二人生迷茫(专业教育被迫写文)","date":"2020-07-09T12:15:00.000Z","path":"2020/07/09/人到大二人生迷茫(专业教育被迫写文)/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]},{"title":"计算机组成原理——编码","date":"2020-03-15T10:43:00.000Z","path":"2020/03/15/编码/","tags":[{"name":"计算机组成原理","slug":"计算机组成原理","permalink":"https://jackyin.space/tags/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/"}]},{"title":"King Back","date":"2020-01-19T04:31:00.000Z","path":"2020/01/19/King Back/","tags":[{"name":"youth","slug":"youth","permalink":"https://jackyin.space/tags/youth/"}]}] \ No newline at end of file diff --git a/fonts/default-skin.b257fa.svg b/fonts/default-skin.b257fa.svg new file mode 100644 index 00000000..9d5f0c6a --- /dev/null +++ b/fonts/default-skin.b257fa.svg @@ -0,0 +1 @@ +default-skin 2 \ No newline at end of file diff --git a/fonts/iconfont.16acc2.ttf b/fonts/iconfont.16acc2.ttf new file mode 100644 index 00000000..bcc77994 Binary files /dev/null and b/fonts/iconfont.16acc2.ttf differ diff --git a/fonts/iconfont.45d7ee.svg b/fonts/iconfont.45d7ee.svg new file mode 100644 index 00000000..59c4f5bf --- /dev/null +++ b/fonts/iconfont.45d7ee.svg @@ -0,0 +1,201 @@ + + + + +Created by FontForge 20120731 at Sun Jul 9 01:44:08 2017 + By admin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/iconfont.8c627f.woff b/fonts/iconfont.8c627f.woff new file mode 100644 index 00000000..d044ffbf Binary files /dev/null and b/fonts/iconfont.8c627f.woff differ diff --git a/fonts/iconfont.b322fa.eot b/fonts/iconfont.b322fa.eot new file mode 100644 index 00000000..a3ffe871 Binary files /dev/null and b/fonts/iconfont.b322fa.eot differ diff --git a/fonts/tooltip.4004ff.svg b/fonts/tooltip.4004ff.svg new file mode 100644 index 00000000..252cb39b --- /dev/null +++ b/fonts/tooltip.4004ff.svg @@ -0,0 +1,6 @@ + + + + + diff --git a/images/pasted-0.png b/images/pasted-0.png new file mode 100644 index 00000000..73c2634f Binary files /dev/null and b/images/pasted-0.png differ diff --git a/img/default-skin.png b/img/default-skin.png new file mode 100644 index 00000000..441c502c Binary files /dev/null and b/img/default-skin.png differ diff --git a/img/preloader.gif b/img/preloader.gif new file mode 100644 index 00000000..b8faa697 Binary files /dev/null and b/img/preloader.gif differ diff --git a/img/scrollbar_arrow.png b/img/scrollbar_arrow.png new file mode 100644 index 00000000..81bba972 Binary files /dev/null and b/img/scrollbar_arrow.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..545f6349 --- /dev/null +++ b/index.html @@ -0,0 +1,1525 @@ + + + + + + + + + khan's study and life blog - 学习站 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ + + +
+ +
+
+
+ + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+ + + +
+
+

tag:

+ + +
+
    +

    + 缺失模块。
    1、请确保node版本大于6.2
    2、在博客根目录(注意不是yilia根目录)执行以下命令:
    npm i hexo-generator-json-content --save

    + 3、在根目录_config.yml里添加配置: +

    +  jsonContent:
    +    meta: false
    +    pages: false
    +    posts:
    +      title: true
    +      date: true
    +      path: true
    +      text: false
    +      raw: false
    +      content: false
    +      slug: false
    +      updated: false
    +      comments: false
    +      link: false
    +      permalink: false
    +      excerpt: false
    +      categories: false
    +      tags: true
    +
    +

    +
  • + +

    + + +

    +

    + + +

    +
  • +
+
+ + + +
+ + + +
+ + + +
+ + + +
+ + + + + +
+ +
在日落大道的你与我握手 <br /> 发觉太想和你闯遍这地球
+ +
+ +
+ +
+ + +
+ + + + + + + + + \ No newline at end of file diff --git a/live2d-widget-old/LICENSE b/live2d-widget-old/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/live2d-widget-old/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/live2d-widget-old/README.html b/live2d-widget-old/README.html new file mode 100644 index 00000000..a258ee5d --- /dev/null +++ b/live2d-widget-old/README.html @@ -0,0 +1,67 @@ +

Live2D Widget






+

特性 Feature

在网页中添加 Live2D 看板娘。兼容 PJAX,支持无刷新加载。
Add Live2D widget to web page. Compatible with PJAX.

+

警告:本项目使用了大量 ES6 语法,且依赖于 WebGL。不支持 IE 11 等老旧浏览器。
WARNING: This project does not support legacy browsers such as IE 11.

+

示例 Demo

米米的博客的左下角可查看效果。

+



+

这个仓库中也提供了两个 Demo,即

+ +

依赖 Dependencies

本插件需要 Font Awesome 4.7.0 支持,请确保相关样式表已在页面中加载,例如在 <head> 中加入:
Font Awesome 4.7.0 is required for this plugin. You can add this to <head>:

+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome/css/font-awesome.min.css">
+
+

否则无法正常显示。(如果网页中已经加载了 Font Awesome,就不要重复加载了)

+

使用 Usage

将这一行代码加入 <head><body>,即可展现出效果:

+
<script src="https://cdn.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>
+
+

如果网站启用了 PJAX,由于看板娘不必每页刷新,因此要注意将相关脚本放到 PJAX 刷新区域之外。

+

换句话说,如果你是小白,或者只需要最基础的功能,就只用把这一行代码,连同前面加载 Font Awesome 的一行代码,一起放到 html 的 <head> 中即可。
对于用各种模版引擎(例如 Nunjucks,Jinja 或者 PHP)生成的页面,也要自行修改,方法类似,只是可能略为麻烦。以 Hexo 为例,需要在主题相关的 ejs 或 njk 模版中正确配置路径,才可以加载。

+

但是!我们强烈推荐自己进行配置,否则很多功能是不完整的,并且可能产生问题!
如果你有兴趣自己折腾的话,请看下面的详细说明。

+

Using CDN

要自定义有关内容,可以把这个仓库 Fork 一份,然后进行修改。这时,使用方法对应地变为

+
<script src="https://cdn.jsdelivr.net/gh/username/live2d-widget@latest/autoload.js"></script>
+
+

username 替换为你的 GitHub 用户名即可。

+

Self-host

你也可以直接把这些文件放到服务器上,而不是通过 CDN 加载。

+
    +
  • 如果你能够通过 ssh 访问你的主机,请把整个仓库克隆到服务器上。执行:
    cd /path/to/your/webroot
    +# Clone this repository
    +git clone https://github.com/stevenjoezhang/live2d-widget.git
    +
    +
  • +
  • 如果你的主机无法用 ssh 连接(例如一般的虚拟主机),请选择 Download ZIP,然后通过 ftp 等方式上传到主机上,再解压到网站的目录下。
  • +
  • 如果你是通过 Hexo 等工具部署的静态博客,请在本地开命令行进入博客目录,例如 source 下与 _posts 同级的目录,然后再执行前述的 git clone 命令。重新部署博客时,相关文件就会自动上传到对应的路径下。
  • +
+

这样,整个项目就可以通过你的服务器 IP 或者域名从公网访问了。不妨试试能否正常地通过浏览器打开 autoload.jslive2d.min.js 等文件,并确认这些文件的内容是正确的,没有出现乱码。
一切正常的话,接下来修改一些配置就行了。(需要通过服务器上的文本编辑器修改;你也可以先在本地完成这一步骤,再上传到服务器上)
修改 autoload.js 中的常量 live2d_pathlive2d-widget 这一文件夹在公网上的路径。比如说,如果你能够通过

+
https://www.example.com/path/to/live2d-widget/live2d.min.js
+
+

访问到 live2d.min.js,那么就把 live2d_path 的值修改为

+
https://www.example.com/path/to/live2d-widget/
+
+

路径末尾的 / 一定要加上。具体可以参考 autoload.js 内的注释。
完成后,在你要添加看板娘的界面加入

+
<script src="https://www.example.com/path/to/live2d-widget/autoload.js"></script>
+
+

就可以加载了。

+

目录结构 Files

    +
  • waifu-tips.json 中包含了触发条件(selector,选择器)和触发时显示的文字(text);
  • +
  • waifu.css 是看板娘的样式表。
  • +
+

源文件是对 Hexo 的 NexT 主题有效的,为了适用于你自己的网页,可能需要自行修改,或增加新内容。
警告:作者不对包括但不限于 waifu-tips.jsonwaifu-tips.js 文件中的内容负责,请自行确保它们是合适的。

+

如果有任何疑问,欢迎提 Issue。如果有任何修改建议,欢迎提 Pull Request。

+

鸣谢 Credits

+

感谢 BrowserStack 容许我们在真实的浏览器中测试此项目。
Thanks to BrowserStack for allowing us to test this project in real browsers.

+

代码自这篇博文魔改而来:
https://www.fghrsh.net/post/123.html

+

点击看板娘的纸飞机按钮时,会出现一个彩蛋,这来自于 WebsiteAsteroids

+

更多 More

更多内容可以参考:
https://imjad.cn/archives/lab/add-dynamic-poster-girl-with-live2d-to-your-blog-02
https://github.com/xiazeyu/live2d-widget.js
https://github.com/summerscar/live2dDemo

+

还可以自行搭建后端 API,并增加模型(需要修改的内容比较多,此处不再赘述):
https://github.com/fghrsh/live2d_api
https://github.com/xiazeyu/live2d-widget-models
https://github.com/xiaoski/live2d_models_collection

+

除此之外,还有桌面版本:
https://github.com/amorist/platelet
https://github.com/akiroz/Live2D-Widget

+

许可证 License

Released under the GNU General Public License v3
http://www.gnu.org/licenses/gpl-3.0.html

+

本仓库中涉及的所有 Live2D 模型、图片、动作数据等版权均属于其原作者,仅供研究学习,不得用于商业用途。

+

Live2D 官方网站:
https://www.live2d.com/en/
https://live2d.github.io

+

Live2D Cubism Core は Live2D Proprietary Software License で提供しています。
https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_en.html
Live2D Cubism Components は Live2D Open Software License で提供しています。
http://www.live2d.com/eula/live2d-open-software-license-agreement_en.html

+
+

The terms and conditions do prohibit modification, but obfuscating in live2d.min.js would not be considered illegal modification.

+
+

https://community.live2d.com/discussion/140/webgl-developer-licence-and-javascript-question

+

更新 Update

2018年10月31日,由 fghrsh 提供的原 API 停用,请更新至新地址。参考文章:
https://www.fghrsh.net/post/170.html

+

2020年1月1日起,本项目不再依赖于 jQuery。

diff --git a/live2d-widget-old/assets/browserstack.svg b/live2d-widget-old/assets/browserstack.svg new file mode 100644 index 00000000..846f6d36 --- /dev/null +++ b/live2d-widget-old/assets/browserstack.svg @@ -0,0 +1 @@ +bs \ No newline at end of file diff --git a/live2d-widget-old/assets/screenshot-1.png b/live2d-widget-old/assets/screenshot-1.png new file mode 100644 index 00000000..8ac6f90b Binary files /dev/null and b/live2d-widget-old/assets/screenshot-1.png differ diff --git a/live2d-widget-old/assets/screenshot-2.png b/live2d-widget-old/assets/screenshot-2.png new file mode 100644 index 00000000..542ed432 Binary files /dev/null and b/live2d-widget-old/assets/screenshot-2.png differ diff --git a/live2d-widget-old/assets/screenshot-3.png b/live2d-widget-old/assets/screenshot-3.png new file mode 100644 index 00000000..62834245 Binary files /dev/null and b/live2d-widget-old/assets/screenshot-3.png differ diff --git a/live2d-widget-old/autoload.js b/live2d-widget-old/autoload.js new file mode 100644 index 00000000..498caf0d --- /dev/null +++ b/live2d-widget-old/autoload.js @@ -0,0 +1,75 @@ +// 注意:live2d_path 参数应使用绝对路径 +const live2d_path = "/live2d-widget/"; +//const live2d_path = "/live2d-widget/"; + +// 封装异步加载资源的方法 +function loadExternalResource(url, type) { + return new Promise((resolve, reject) => { + let tag; + + if (type === "css") { + tag = document.createElement("link"); + tag.rel = "stylesheet"; + tag.href = url; + } + else if (type === "js") { + tag = document.createElement("script"); + tag.src = url; + } + if (tag) { + tag.onload = () => resolve(url); + tag.onerror = () => reject(url); + document.head.appendChild(tag); + } + }); +} + +// Promise.all([ +// loadExternalResource(live2d_path + "waifu.css", "css"), +// loadExternalResource(live2d_path + "live2d.min.js", "js"), +// loadExternalResource(live2d_path + "waifu-tips.js", "js") +// ]).then(() => { +// initWidget({ +// waifuPath: live2d_path + "waifu-tips.json", +// apiPath: "https://live2d.fghrsh.net/api/", +// //cdnPath: "https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/" +// }); +// }); + +// 加载 waifu.css live2d.min.js waifu-tips.js +if (screen.width >= 768) { + Promise.all([ + loadExternalResource(live2d_path + "waifu.css", "css"), + loadExternalResource(live2d_path + "live2d.min.js", "js"), + loadExternalResource(live2d_path + "waifu-tips.js", "js") + ]).then(() => { + initWidget({ + waifuPath: live2d_path + "waifu-tips.json", + apiPath: "https://live2d.fghrsh.net/api/", + //cdnPath: "https://cdn.jsdelivr.net/gh/fghrsh/live2d_api/" + }); + }); +} +// initWidget 第一个参数为 waifu-tips.json 的路径,第二个参数为 API 地址 +// API 后端可自行搭建,参考 https://github.com/fghrsh/live2d_api +// 初始化看板娘会自动加载指定目录下的 waifu-tips.json + +console.log(` + く__,.ヘヽ. / ,ー、 〉 + \ ', !-─‐-i / /´ + /`ー' L//`ヽ、 + / /, /| , , ', + イ / /-‐/ i L_ ハ ヽ! i + レ ヘ 7イ`ト レ'ァ-ト、!ハ| | + !,/7 '0' ´0iソ| | + |.从" _ ,,,, / |./ | + レ'| i>.、,,__ _,.イ / .i | + レ'| | / k_7_/レ'ヽ, ハ. | + | |/i 〈|/ i ,.ヘ | i | + .|/ / i: ヘ! \ | + kヽ>、ハ _,.ヘ、 /、! + !'〈//`T´', \ `'7'ーr' + レ'ヽL__|___i,___,ンレ|ノ + ト-,/ |___./ + 'ー' !_,.: +`); diff --git a/live2d-widget-old/live2d.min.js b/live2d-widget-old/live2d.min.js new file mode 100644 index 00000000..8255ab22 --- /dev/null +++ b/live2d-widget-old/live2d.min.js @@ -0,0 +1 @@ +!function(t){function i(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,i),o.l=!0,o.exports}var e={};i.m=t,i.c=e,i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},i.p="",i(i.s=4)}([function(t,i,e){"use strict";function r(){this.live2DModel=null,this.modelMatrix=null,this.eyeBlink=null,this.physics=null,this.pose=null,this.debugMode=!1,this.initialized=!1,this.updating=!1,this.alpha=1,this.accAlpha=0,this.lipSync=!1,this.lipSyncValue=0,this.accelX=0,this.accelY=0,this.accelZ=0,this.dragX=0,this.dragY=0,this.startTimeMSec=null,this.mainMotionManager=new h,this.expressionManager=new h,this.motions={},this.expressions={},this.isTexLoaded=!1}function o(){AMotion.prototype.constructor.call(this),this.paramList=new Array}function n(){this.id="",this.type=-1,this.value=null}function s(){this.nextBlinkTime=null,this.stateStartTime=null,this.blinkIntervalMsec=null,this.eyeState=g.STATE_FIRST,this.blinkIntervalMsec=4e3,this.closingMotionMsec=100,this.closedMotionMsec=50,this.openingMotionMsec=150,this.closeIfZero=!0,this.eyeID_L="PARAM_EYE_L_OPEN",this.eyeID_R="PARAM_EYE_R_OPEN"}function _(){this.tr=new Float32Array(16),this.identity()}function a(t,i){_.prototype.constructor.call(this),this.width=t,this.height=i}function h(){MotionQueueManager.prototype.constructor.call(this),this.currentPriority=null,this.reservePriority=null,this.super=MotionQueueManager.prototype}function l(){this.physicsList=new Array,this.startTimeMSec=UtSystem.getUserTimeMSec()}function $(){this.lastTime=0,this.lastModel=null,this.partsGroups=new Array}function u(t){this.paramIndex=-1,this.partsIndex=-1,this.link=null,this.id=t}function p(){this.EPSILON=.01,this.faceTargetX=0,this.faceTargetY=0,this.faceX=0,this.faceY=0,this.faceVX=0,this.faceVY=0,this.lastTimeSec=0}function f(){_.prototype.constructor.call(this),this.screenLeft=null,this.screenRight=null,this.screenTop=null,this.screenBottom=null,this.maxLeft=null,this.maxRight=null,this.maxTop=null,this.maxBottom=null,this.max=Number.MAX_VALUE,this.min=0}function c(){}var d=0;r.prototype.getModelMatrix=function(){return this.modelMatrix},r.prototype.setAlpha=function(t){t>.999&&(t=1),t<.001&&(t=0),this.alpha=t},r.prototype.getAlpha=function(){return this.alpha},r.prototype.isInitialized=function(){return this.initialized},r.prototype.setInitialized=function(t){this.initialized=t},r.prototype.isUpdating=function(){return this.updating},r.prototype.setUpdating=function(t){this.updating=t},r.prototype.getLive2DModel=function(){return this.live2DModel},r.prototype.setLipSync=function(t){this.lipSync=t},r.prototype.setLipSyncValue=function(t){this.lipSyncValue=t},r.prototype.setAccel=function(t,i,e){this.accelX=t,this.accelY=i,this.accelZ=e},r.prototype.setDrag=function(t,i){this.dragX=t,this.dragY=i},r.prototype.getMainMotionManager=function(){return this.mainMotionManager},r.prototype.getExpressionManager=function(){return this.expressionManager},r.prototype.loadModelData=function(t,i){var e=c.getPlatformManager();this.debugMode&&e.log("Load model : "+t);var r=this;e.loadLive2DModel(t,function(t){if(r.live2DModel=t,r.live2DModel.saveParam(),0!=Live2D.getError())return void console.error("Error : Failed to loadModelData().");r.modelMatrix=new a(r.live2DModel.getCanvasWidth(),r.live2DModel.getCanvasHeight()),r.modelMatrix.setWidth(2),r.modelMatrix.setCenterPosition(0,0),i(r.live2DModel)})},r.prototype.loadTexture=function(t,i,e){d++;var r=c.getPlatformManager();this.debugMode&&r.log("Load Texture : "+i);var o=this;r.loadTexture(this.live2DModel,t,i,function(){d--,0==d&&(o.isTexLoaded=!0),"function"==typeof e&&e()})},r.prototype.loadMotion=function(t,i,e){var r=c.getPlatformManager();this.debugMode&&r.log("Load Motion : "+i);var o=null,n=this;r.loadBytes(i,function(i){o=Live2DMotion.loadMotion(i),null!=t&&(n.motions[t]=o),e(o)})},r.prototype.loadExpression=function(t,i,e){var r=c.getPlatformManager();this.debugMode&&r.log("Load Expression : "+i);var n=this;r.loadBytes(i,function(i){null!=t&&(n.expressions[t]=o.loadJson(i)),"function"==typeof e&&e()})},r.prototype.loadPose=function(t,i){var e=c.getPlatformManager();this.debugMode&&e.log("Load Pose : "+t);var r=this;try{e.loadBytes(t,function(t){r.pose=$.load(t),"function"==typeof i&&i()})}catch(t){console.warn(t)}},r.prototype.loadPhysics=function(t){var i=c.getPlatformManager();this.debugMode&&i.log("Load Physics : "+t);var e=this;try{i.loadBytes(t,function(t){e.physics=l.load(t)})}catch(t){console.warn(t)}},r.prototype.hitTestSimple=function(t,i,e){if(null===this.live2DModel)return!1;var r=this.live2DModel.getDrawDataIndex(t);if(r<0)return!1;for(var o=this.live2DModel.getTransformedPoints(r),n=this.live2DModel.getCanvasWidth(),s=0,_=this.live2DModel.getCanvasHeight(),a=0,h=0;hs&&(s=l),$<_&&(_=$),$>a&&(a=$)}var u=this.modelMatrix.invertTransformX(i),p=this.modelMatrix.invertTransformY(e);return n<=u&&u<=s&&_<=p&&p<=a},r.prototype.hitTestSimpleCustom=function(t,i,e,r){return null!==this.live2DModel&&(e>=t[0]&&e<=i[0]&&r<=t[1]&&r>=i[1])},o.prototype=new AMotion,o.EXPRESSION_DEFAULT="DEFAULT",o.TYPE_SET=0,o.TYPE_ADD=1,o.TYPE_MULT=2,o.loadJson=function(t){var i=new o,e=c.getPlatformManager(),r=e.jsonParseFromBytes(t);if(i.setFadeIn(parseInt(r.fade_in)>0?parseInt(r.fade_in):1e3),i.setFadeOut(parseInt(r.fade_out)>0?parseInt(r.fade_out):1e3),null==r.params)return i;var s=r.params,_=s.length;i.paramList=[];for(var a=0;a<_;a++){var h=s[a],l=h.id.toString(),$=parseFloat(h.val),u=o.TYPE_ADD,p=null!=h.calc?h.calc.toString():"add";if((u="add"===p?o.TYPE_ADD:"mult"===p?o.TYPE_MULT:"set"===p?o.TYPE_SET:o.TYPE_ADD)==o.TYPE_ADD){var f=null==h.def?0:parseFloat(h.def);$-=f}else if(u==o.TYPE_MULT){var f=null==h.def?1:parseFloat(h.def);0==f&&(f=1),$/=f}var d=new n;d.id=l,d.type=u,d.value=$,i.paramList.push(d)}return i},o.prototype.updateParamExe=function(t,i,e,r){for(var n=this.paramList.length-1;n>=0;--n){var s=this.paramList[n];s.type==o.TYPE_ADD?t.addToParamFloat(s.id,s.value,e):s.type==o.TYPE_MULT?t.multParamFloat(s.id,s.value,e):s.type==o.TYPE_SET&&t.setParamFloat(s.id,s.value,e)}},s.prototype.calcNextBlink=function(){return UtSystem.getUserTimeMSec()+Math.random()*(2*this.blinkIntervalMsec-1)},s.prototype.setInterval=function(t){this.blinkIntervalMsec=t},s.prototype.setEyeMotion=function(t,i,e){this.closingMotionMsec=t,this.closedMotionMsec=i,this.openingMotionMsec=e},s.prototype.updateParam=function(t){var i,e=UtSystem.getUserTimeMSec(),r=0;switch(this.eyeState){case g.STATE_CLOSING:r=(e-this.stateStartTime)/this.closingMotionMsec,r>=1&&(r=1,this.eyeState=g.STATE_CLOSED,this.stateStartTime=e),i=1-r;break;case g.STATE_CLOSED:r=(e-this.stateStartTime)/this.closedMotionMsec,r>=1&&(this.eyeState=g.STATE_OPENING,this.stateStartTime=e),i=0;break;case g.STATE_OPENING:r=(e-this.stateStartTime)/this.openingMotionMsec,r>=1&&(r=1,this.eyeState=g.STATE_INTERVAL,this.nextBlinkTime=this.calcNextBlink()),i=r;break;case g.STATE_INTERVAL:this.nextBlinkTime=t)&&(!(this.currentPriority>=t)&&(this.reservePriority=t,!0))},h.prototype.setReservePriority=function(t){this.reservePriority=t},h.prototype.updateParam=function(t){var i=MotionQueueManager.prototype.updateParam.call(this,t);return this.isFinished()&&(this.currentPriority=0),i},h.prototype.startMotionPrio=function(t,i){return i==this.reservePriority&&(this.reservePriority=0),this.currentPriority=i,this.startMotion(t,!1)},l.load=function(t){for(var i=new l,e=c.getPlatformManager(),r=e.jsonParseFromBytes(t),o=r.physics_hair,n=o.length,s=0;s=0)break;r=n,o=t.getPartsOpacity(s),o+=e/.5,o>1&&(o=1)}}r<0&&(r=0,o=1);for(var n=0;n.15&&(a=1-.15/(1-o)),h>a&&(h=a),t.setPartsOpacity(s,h)}}},$.prototype.copyOpacityOtherParts=function(t,i){for(var e=0;eo)&&(l*=o/u,$*=o/u,u=o),this.faceVX+=l,this.faceVY+=$;var f=.5*(Math.sqrt(o*o+16*o*_-8*o*_)-o),c=Math.sqrt(this.faceVX*this.faceVX+this.faceVY*this.faceVY);c>f&&(this.faceVX*=f/c,this.faceVY*=f/c),this.faceX+=this.faceVX,this.faceY+=this.faceVY}},f.prototype=new _,f.prototype.getMaxScale=function(){return this.max},f.prototype.getMinScale=function(){return this.min},f.prototype.setMaxScale=function(t){this.max=t},f.prototype.setMinScale=function(t){this.min=t},f.prototype.isMaxScale=function(){return this.getScaleX()==this.max},f.prototype.isMinScale=function(){return this.getScaleX()==this.min},f.prototype.adjustTranslate=function(t,i){this.tr[0]*this.maxLeft+(this.tr[12]+t)>this.screenLeft&&(t=this.screenLeft-this.tr[0]*this.maxLeft-this.tr[12]),this.tr[0]*this.maxRight+(this.tr[12]+t)this.screenBottom&&(i=this.screenBottom-this.tr[5]*this.maxBottom-this.tr[13]);var e=[1,0,0,0,0,1,0,0,0,0,1,0,t,i,0,1];_.mul(e,this.tr,this.tr)},f.prototype.adjustScale=function(t,i,e){var r=e*this.tr[0];r0&&(e=this.min/this.tr[0]):r>this.max&&this.tr[0]>0&&(e=this.max/this.tr[0]);var o=[1,0,0,0,0,1,0,0,0,0,1,0,t,i,0,1],n=[e,0,0,0,0,e,0,0,0,0,1,0,0,0,0,1],s=[1,0,0,0,0,1,0,0,0,0,1,0,-t,-i,0,1];_.mul(s,this.tr,this.tr),_.mul(n,this.tr,this.tr),_.mul(o,this.tr,this.tr)},f.prototype.setScreenRect=function(t,i,e,r){this.screenLeft=t,this.screenRight=i,this.screenTop=r,this.screenBottom=e},f.prototype.setMaxScreenRect=function(t,i,e,r){this.maxLeft=t,this.maxRight=i,this.maxTop=r,this.maxBottom=e},f.prototype.getScreenLeft=function(){return this.screenLeft},f.prototype.getScreenRight=function(){return this.screenRight},f.prototype.getScreenBottom=function(){return this.screenBottom},f.prototype.getScreenTop=function(){return this.screenTop},f.prototype.getMaxLeft=function(){return this.maxLeft},f.prototype.getMaxRight=function(){return this.maxRight},f.prototype.getMaxBottom=function(){return this.maxBottom},f.prototype.getMaxTop=function(){return this.maxTop},c.platformManager=null,c.getPlatformManager=function(){return c.platformManager},c.setPlatformManager=function(t){c.platformManager=t},t.exports={L2DTargetPoint:p,Live2DFramework:c,L2DViewMatrix:f,L2DPose:$,L2DPartsParam:u,L2DPhysics:l,L2DMotionManager:h,L2DModelMatrix:a,L2DMatrix44:_,EYE_STATE:g,L2DEyeBlink:s,L2DExpressionParam:n,L2DExpressionMotion:o,L2DBaseModel:r}},function(t,i,e){"use strict";var r={DEBUG_LOG:!1,DEBUG_MOUSE_LOG:!1,DEBUG_DRAW_HIT_AREA:!1,DEBUG_DRAW_ALPHA_MODEL:!1,VIEW_MAX_SCALE:2,VIEW_MIN_SCALE:.8,VIEW_LOGICAL_LEFT:-1,VIEW_LOGICAL_RIGHT:1,VIEW_LOGICAL_MAX_LEFT:-2,VIEW_LOGICAL_MAX_RIGHT:2,VIEW_LOGICAL_MAX_BOTTOM:-2,VIEW_LOGICAL_MAX_TOP:2,PRIORITY_NONE:0,PRIORITY_IDLE:1,PRIORITY_SLEEPY:2,PRIORITY_NORMAL:3,PRIORITY_FORCE:4,MOTION_GROUP_IDLE:"idle",MOTION_GROUP_SLEEPY:"sleepy",MOTION_GROUP_TAP_BODY:"tap_body",MOTION_GROUP_FLICK_HEAD:"flick_head",MOTION_GROUP_PINCH_IN:"pinch_in",MOTION_GROUP_PINCH_OUT:"pinch_out",MOTION_GROUP_SHAKE:"shake",HIT_AREA_HEAD:"head",HIT_AREA_BODY:"body"};t.exports=r},function(t,i,e){"use strict";function r(t){n=t}function o(){return n}Object.defineProperty(i,"__esModule",{value:!0}),i.setContext=r,i.getContext=o;var n=void 0},function(t,i,e){"use strict";function r(){}r.matrixStack=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],r.depth=0,r.currentMatrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],r.tmp=new Array(16),r.reset=function(){this.depth=0},r.loadIdentity=function(){for(var t=0;t<16;t++)this.currentMatrix[t]=t%5==0?1:0},r.push=function(){var t=(this.depth,16*(this.depth+1));this.matrixStack.lengthe.left&&i.y>e.top)return i;var o=t.x-i.x,n=t.y-i.y,s=r(o,n);i.xat.frameBuffers.length&&(this.curFrameNo=this.getMaskRenderTexture()),this.tmpModelToViewMatrix=new R,this.tmpMatrix2=new R,this.tmpMatrixForMask=new R,this.tmpMatrixForDraw=new R,this.CHANNEL_COLORS=new Array;var i=new A;i=new A,i.r=0,i.g=0,i.b=0,i.a=1,this.CHANNEL_COLORS.push(i),i=new A,i.r=1,i.g=0,i.b=0,i.a=0,this.CHANNEL_COLORS.push(i),i=new A,i.r=0,i.g=1,i.b=0,i.a=0,this.CHANNEL_COLORS.push(i),i=new A,i.r=0,i.g=0,i.b=1,i.a=0,this.CHANNEL_COLORS.push(i);for(var e=0;eG._$T7){t._$NP|=i._$4s;throw new lt("_$gi _$C _$li , _$n0 _$_ version _$li ( SDK : "+G._$T7+" < _$f0 : "+r+" )@_$SS#loadModel()\n")}var h=o._$nP();if(r>=G._$s7){var l=o._$9T(),$=o._$9T();if(-30584!=l||-30584!=$)throw t._$NP|=i._$0s,new lt("_$gi _$C _$li , _$0 _$6 _$Ui.")}t._$KS(h);var u=t.getModelContext();u.setDrawParam(t.getDrawParam()),u.init()}catch(t){_._$Rb(t)}},i.prototype._$KS=function(t){this._$MT=t},i.prototype.getModelImpl=function(){return null==this._$MT&&(this._$MT=new p,this._$MT._$zP()),this._$MT},i.prototype.getCanvasWidth=function(){return null==this._$MT?0:this._$MT.getCanvasWidth()},i.prototype.getCanvasHeight=function(){return null==this._$MT?0:this._$MT.getCanvasHeight()},i.prototype.getParamFloat=function(t){return"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),this._$5S.getParamFloat(t)},i.prototype.setParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)*(1-e)+i*e)},i.prototype.addToParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)+i*e)},i.prototype.multParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)*(1+(i-1)*e))},i.prototype.getParamIndex=function(t){return this._$5S.getParamIndex(u.getID(t))},i.prototype.loadParam=function(){this._$5S.loadParam()},i.prototype.saveParam=function(){this._$5S.saveParam()},i.prototype.init=function(){this._$5S.init()},i.prototype.update=function(){this._$5S.update()},i.prototype._$Rs=function(){return _._$li("_$60 _$PT _$Rs()"),-1},i.prototype._$Ds=function(t){_._$li("_$60 _$PT _$SS#_$Ds() \n")},i.prototype._$K2=function(){},i.prototype.draw=function(){},i.prototype.getModelContext=function(){return this._$5S},i.prototype._$s2=function(){return this._$NP},i.prototype._$P7=function(t,i,e,r){var o=-1,n=0,s=this;if(0!=e)if(1==t.length){var _=t[0],a=0!=s.getParamFloat(_),h=i[0],l=s.getPartsOpacity(h),$=e/r;a?(l+=$)>1&&(l=1):(l-=$)<0&&(l=0),s.setPartsOpacity(h,l)}else{for(var u=0;u=0)break;o=u;var h=i[u];n=s.getPartsOpacity(h),n+=e/r,n>1&&(n=1)}}o<0&&(console.log("No _$wi _$q0/ _$U default[%s]",t[0]),o=0,n=1,s.loadParam(),s.setParamFloat(t[o],n),s.saveParam());for(var u=0;u.15&&(f=1-.15/(1-n)),c>f&&(c=f),s.setPartsOpacity(h,c)}}}else for(var u=0;u=this._$5S._$aS.length)return null;var i=this._$5S._$aS[t];return null!=i&&i.getType()==W._$wb&&i instanceof $t?i.getIndexArray():null},e.CHANNEL_COUNT=4,e.RENDER_TEXTURE_USE_MIPMAP=!1,e.NOT_USED_FRAME=-100,e.prototype._$L7=function(){if(this.tmpModelToViewMatrix&&(this.tmpModelToViewMatrix=null),this.tmpMatrix2&&(this.tmpMatrix2=null),this.tmpMatrixForMask&&(this.tmpMatrixForMask=null),this.tmpMatrixForDraw&&(this.tmpMatrixForDraw=null),this.tmpBoundsOnModel&&(this.tmpBoundsOnModel=null),this.CHANNEL_COLORS){for(var t=this.CHANNEL_COLORS.length-1;t>=0;--t)this.CHANNEL_COLORS.splice(t,1);this.CHANNEL_COLORS=[]}this.releaseShader()},e.prototype.releaseShader=function(){for(var t=at.frameBuffers.length,i=0;i0){var n=i.gl.getParameter(i.gl.FRAMEBUFFER_BINDING),s=new Array(4);s[0]=0,s[1]=0,s[2]=i.gl.canvas.width,s[3]=i.gl.canvas.height,i.gl.viewport(0,0,at.clippingMaskBufferSize,at.clippingMaskBufferSize),this.setupLayoutBounds(e),i.gl.bindFramebuffer(i.gl.FRAMEBUFFER,at.frameBuffers[this.curFrameNo].framebuffer),i.gl.clearColor(0,0,0,0),i.gl.clear(i.gl.COLOR_BUFFER_BIT);for(var r=0;rr?e:r,n=o,s=o,_=0,a=0,h=i.clippedDrawContextList.length,l=0;l_&&(_=S),v>a&&(a=v)}}if(n==o)i.allClippedDrawRect.x=0,i.allClippedDrawRect.y=0,i.allClippedDrawRect.width=0,i.allClippedDrawRect.height=0,i.isUsing=!1;else{var L=_-n,M=a-s;i.allClippedDrawRect.x=n,i.allClippedDrawRect.y=s,i.allClippedDrawRect.width=L,i.allClippedDrawRect.height=M,i.isUsing=!0}},e.prototype.setupLayoutBounds=function(t){var i=t/e.CHANNEL_COUNT,r=t%e.CHANNEL_COUNT;i=~~i,r=~~r;for(var o=0,n=0;n=1)return 1;var p=r,f=p*p;return l*(p*f)+$*f+u*p+0},s.prototype._$a0=function(){},s.prototype.setFadeIn=function(t){this._$dP=t},s.prototype.setFadeOut=function(t){this._$eo=t},s.prototype._$pT=function(t){this._$V0=t},s.prototype.getFadeOut=function(){return this._$eo},s.prototype._$4T=function(){return this._$eo},s.prototype._$mT=function(){return this._$V0},s.prototype.getDurationMSec=function(){return-1},s.prototype.getLoopDurationMSec=function(){return-1},s.prototype.updateParam=function(t,i){if(i._$AT&&!i._$9L){var e=w.getUserTimeMSec();if(i._$z2<0){i._$z2=e,i._$bs=e;var r=this.getDurationMSec();i._$Do<0&&(i._$Do=r<=0?-1:i._$z2+r)}var o=this._$V0;o=o*(0==this._$dP?1:ht._$r2((e-i._$bs)/this._$dP))*(0==this._$eo||i._$Do<0?1:ht._$r2((i._$Do-e)/this._$eo)),0<=o&&o<=1||console.log("### assert!! ### "),this.updateParamExe(t,e,o,i),i._$Do>0&&i._$Do0?console.log("\n"):e%8==0&&e>0&&console.log(" "),console.log("%02X ",255&t[e]);console.log("\n")},_._$nr=function(t,i,e){console.log("%s\n",t);for(var r=i.length,o=0;o=0;--r){this._$lL[r]._$oP(t,this)}this._$oo(t,e),this._$M2=this._$Yb(),this._$9b=(this._$M2-this._$ks)/e,this._$ks=this._$M2}for(var r=this._$qP.length-1;r>=0;--r){this._$qP[r]._$YS(t,this)}this._$iT=i},f.prototype._$oo=function(t,i){i<.033&&(i=.033);var e=1/i;this.p1.vx=(this.p1.x-this.p1._$s0)*e,this.p1.vy=(this.p1.y-this.p1._$70)*e,this.p1.ax=(this.p1.vx-this.p1._$7L)*e,this.p1.ay=(this.p1.vy-this.p1._$HL)*e,this.p1.fx=this.p1.ax*this.p1._$p,this.p1.fy=this.p1.ay*this.p1._$p,this.p1._$xT();var r,o,n=-Math.atan2(this.p1.y-this.p2.y,this.p1.x-this.p2.x),s=Math.cos(n),_=Math.sin(n),a=9.8*this.p2._$p,h=this._$Db*Lt._$bS,l=a*Math.cos(n-h);r=l*_,o=l*s;var $=-this.p1.fx*_*_,u=-this.p1.fy*_*s,p=-this.p2.vx*this._$L2,f=-this.p2.vy*this._$L2;this.p2.fx=r+$+p,this.p2.fy=o+u+f,this.p2.ax=this.p2.fx/this.p2._$p,this.p2.ay=this.p2.fy/this.p2._$p,this.p2.vx+=this.p2.ax*i,this.p2.vy+=this.p2.ay*i,this.p2.x+=this.p2.vx*i,this.p2.y+=this.p2.vy*i;var c=Math.sqrt((this.p1.x-this.p2.x)*(this.p1.x-this.p2.x)+(this.p1.y-this.p2.y)*(this.p1.y-this.p2.y));this.p2.x=this.p1.x+this._$Fo*(this.p2.x-this.p1.x)/c,this.p2.y=this.p1.y+this._$Fo*(this.p2.y-this.p1.y)/c,this.p2.vx=(this.p2.x-this.p2._$s0)*e,this.p2.vy=(this.p2.y-this.p2._$70)*e,this.p2._$xT()},c.prototype._$xT=function(){this._$s0=this.x,this._$70=this.y,this._$7L=this.vx,this._$HL=this.vy},d.prototype._$oP=function(t,i){},g.prototype=new d,g.prototype._$oP=function(t,i){var e=this.scale*t.getParamFloat(this._$wL),r=i.getPhysicsPoint1();switch(this._$tL){default:case f.Src.SRC_TO_X:r.x=r.x+(e-r.x)*this._$V0;break;case f.Src.SRC_TO_Y:r.y=r.y+(e-r.y)*this._$V0;break;case f.Src.SRC_TO_G_ANGLE:var o=i._$qr();o+=(e-o)*this._$V0,i._$pr(o)}},y.prototype._$YS=function(t,i){},T.prototype=new y,T.prototype._$YS=function(t,i){switch(this._$YP){default:case f.Target.TARGET_FROM_ANGLE:t.setParamFloat(this._$wL,this.scale*i._$5r(),this._$V0);break;case f.Target.TARGET_FROM_ANGLE_V:t.setParamFloat(this._$wL,this.scale*i._$Cs(),this._$V0)}},f.Src=function(){},f.Src.SRC_TO_X="SRC_TO_X",f.Src.SRC_TO_Y="SRC_TO_Y",f.Src.SRC_TO_G_ANGLE="SRC_TO_G_ANGLE",f.Target=function(){},f.Target.TARGET_FROM_ANGLE="TARGET_FROM_ANGLE",f.Target.TARGET_FROM_ANGLE_V="TARGET_FROM_ANGLE_V",P.prototype.init=function(t){this._$fL=t._$fL,this._$gL=t._$gL,this._$B0=t._$B0,this._$z0=t._$z0,this._$qT=t._$qT,this.reflectX=t.reflectX,this.reflectY=t.reflectY},P.prototype._$F0=function(t){this._$fL=t._$_T(),this._$gL=t._$_T(),this._$B0=t._$_T(),this._$z0=t._$_T(),this._$qT=t._$_T(),t.getFormatVersion()>=G.LIVE2D_FORMAT_VERSION_V2_10_SDK2&&(this.reflectX=t._$po(),this.reflectY=t._$po())},P.prototype._$e=function(){};var It=function(){};It._$ni=function(t,i,e,r,o,n,s,_,a){var h=s*n-_*o;if(0==h)return null;var l,$=((t-e)*n-(i-r)*o)/h;return l=0!=o?(t-e-$*s)/o:(i-r-$*_)/n,isNaN(l)&&(l=(t-e-$*s)/o,isNaN(l)&&(l=(i-r-$*_)/n),isNaN(l)&&(console.log("a is NaN @UtVector#_$ni() "),console.log("v1x : "+o),console.log("v1x != 0 ? "+(0!=o)))),null==a?new Array(l,$):(a[0]=l,a[1]=$,a)},S.prototype._$8P=function(){return this.x+.5*this.width},S.prototype._$6P=function(){return this.y+.5*this.height},S.prototype._$EL=function(){return this.x+this.width},S.prototype._$5T=function(){return this.y+this.height},S.prototype._$jL=function(t,i,e,r){this.x=t,this.y=i,this.width=e,this.height=r},S.prototype._$jL=function(t){this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height},S.prototype.contains=function(t,i){return this.x<=this.x&&this.y<=this.y&&this.x<=this.x+this.width&&this.y<=this.y+this.height},S.prototype.expand=function(t,i){this.x-=t,this.y-=i,this.width+=2*t,this.height+=2*i},v._$Z2=function(t,i,e,r){var o=i._$Q2(t,e),n=t._$vs(),s=t._$Tr();if(i._$zr(n,s,o),o<=0)return r[n[0]];if(1==o){var _=r[n[0]],a=r[n[1]],h=s[0];return _+(a-_)*h|0}if(2==o){var _=r[n[0]],a=r[n[1]],l=r[n[2]],$=r[n[3]],h=s[0],u=s[1],p=_+(a-_)*h|0,f=l+($-l)*h|0;return p+(f-p)*u|0}if(3==o){var c=r[n[0]],d=r[n[1]],g=r[n[2]],y=r[n[3]],m=r[n[4]],T=r[n[5]],P=r[n[6]],S=r[n[7]],h=s[0],u=s[1],v=s[2],_=c+(d-c)*h|0,a=g+(y-g)*h|0,l=m+(T-m)*h|0,$=P+(S-P)*h|0,p=_+(a-_)*u|0,f=l+($-l)*u|0;return p+(f-p)*v|0}if(4==o){var L=r[n[0]],M=r[n[1]],E=r[n[2]],A=r[n[3]],I=r[n[4]],w=r[n[5]],x=r[n[6]],O=r[n[7]],D=r[n[8]],R=r[n[9]],b=r[n[10]],F=r[n[11]],C=r[n[12]],N=r[n[13]],B=r[n[14]],U=r[n[15]],h=s[0],u=s[1],v=s[2],G=s[3],c=L+(M-L)*h|0,d=E+(A-E)*h|0,g=I+(w-I)*h|0,y=x+(O-x)*h|0,m=D+(R-D)*h|0,T=b+(F-b)*h|0,P=C+(N-C)*h|0,S=B+(U-B)*h|0,_=c+(d-c)*u|0,a=g+(y-g)*u|0,l=m+(T-m)*u|0,$=P+(S-P)*u|0,p=_+(a-_)*v|0,f=l+($-l)*v|0;return p+(f-p)*G|0}for(var Y=1<=G._$T7?(this.clipID=t._$nP(),this.clipIDList=this.convertClipIDForV2_11(this.clipID)):this.clipIDList=[],this._$MS(this._$Lb)},M.prototype.getClipIDList=function(){return this.clipIDList},M.prototype.init=function(t){},M.prototype._$Nr=function(t,i){if(i._$IS[0]=!1,i._$Us=v._$Z2(t,this._$GS,i._$IS,this._$Lb),at._$Zs);else if(i._$IS[0])return;i._$7s=v._$br(t,this._$GS,i._$IS,this._$mS)},M.prototype._$2b=function(t,i){},M.prototype.getDrawDataID=function(){return this._$gP},M.prototype._$j2=function(t){this._$gP=t},M.prototype.getOpacity=function(t,i){return i._$7s},M.prototype._$zS=function(t,i){return i._$Us},M.prototype._$MS=function(t){for(var i=t.length-1;i>=0;--i){var e=t[i];eM._$R2&&(M._$R2=e)}},M.prototype.getTargetBaseDataID=function(){return this._$dr},M.prototype._$gs=function(t){this._$dr=t},M.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},M.prototype.preDraw=function(t,i,e){},M.prototype.draw=function(t,i,e){},M.prototype.getType=function(){},M.prototype._$B2=function(t,i,e){},E._$ps=32,E.CLIPPING_PROCESS_NONE=0,E.CLIPPING_PROCESS_OVERWRITE_ALPHA=1,E.CLIPPING_PROCESS_MULTIPLY_ALPHA=2,E.CLIPPING_PROCESS_DRAW=3,E.CLIPPING_PROCESS_CLEAR_ALPHA=4,E.prototype.setChannelFlagAsColor=function(t,i){this.CHANNEL_COLORS[t]=i},E.prototype.getChannelFlagAsColor=function(t){return this.CHANNEL_COLORS[t]},E.prototype._$ZT=function(){},E.prototype._$Uo=function(t,i,e,r,o,n,s){},E.prototype._$Rs=function(){return-1},E.prototype._$Ds=function(t){},E.prototype.setBaseColor=function(t,i,e,r){t<0?t=0:t>1&&(t=1),i<0?i=0:i>1&&(i=1),e<0?e=0:e>1&&(e=1),r<0?r=0:r>1&&(r=1),this._$lT=t,this._$C0=i,this._$tT=e,this._$WL=r},E.prototype._$WP=function(t){this.culling=t},E.prototype.setMatrix=function(t){for(var i=0;i<16;i++)this.matrix4x4[i]=t[i]},E.prototype._$IT=function(){return this.matrix4x4},E.prototype.setPremultipliedAlpha=function(t){this.premultipliedAlpha=t},E.prototype.isPremultipliedAlpha=function(){return this.premultipliedAlpha},E.prototype.setAnisotropy=function(t){this.anisotropy=t},E.prototype.getAnisotropy=function(){return this.anisotropy},E.prototype.getClippingProcess=function(){return this.clippingProcess},E.prototype.setClippingProcess=function(t){this.clippingProcess=t},E.prototype.setClipBufPre_clipContextForMask=function(t){this.clipBufPre_clipContextMask=t},E.prototype.getClipBufPre_clipContextMask=function(){return this.clipBufPre_clipContextMask},E.prototype.setClipBufPre_clipContextForDraw=function(t){this.clipBufPre_clipContextDraw=t},E.prototype.getClipBufPre_clipContextDraw=function(){return this.clipBufPre_clipContextDraw},I._$ur=-2,I._$c2=1,I._$_b=2,I.prototype._$F0=function(t){this._$kP=t._$nP(),this._$dr=t._$nP()},I.prototype.readV2_opacity=function(t){t.getFormatVersion()>=G.LIVE2D_FORMAT_VERSION_V2_10_SDK2&&(this._$mS=t._$Tb())},I.prototype.init=function(t){},I.prototype._$Nr=function(t,i){},I.prototype.interpolateOpacity=function(t,i,e,r){null==this._$mS?e.setInterpolatedOpacity(1):e.setInterpolatedOpacity(v._$br(t,i,r,this._$mS))},I.prototype._$2b=function(t,i){},I.prototype._$nb=function(t,i,e,r,o,n,s){},I.prototype.getType=function(){},I.prototype._$gs=function(t){this._$dr=t},I.prototype._$a2=function(t){this._$kP=t},I.prototype.getTargetBaseDataID=function(){return this._$dr},I.prototype.getBaseDataID=function(){return this._$kP},I.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},w._$W2=0,w._$CS=w._$W2,w._$Mo=function(){return!0},w._$XP=function(t){try{for(var i=getTimeMSec();getTimeMSec()-i=t.length)return!1;for(var o=i;o=0;--e){var r=this._$Ob[e].getParamIndex(i);if(r==x._$ds&&(r=t.getParamIndex(this._$Ob[e].getParamID())),t._$Xb(r))return!0}return!1},D.prototype._$Q2=function(t,i){for(var e,r,o=this._$Ob.length,n=t._$v2(),s=0,_=0;_U._$Qb&&console.log("err 23245\n");for(var o=this._$Ob.length,n=1,s=1,_=0,a=0;a=0;--n)e[n]=o[n]}else this.mult_fast(t,i,e,r)},R.prototype.mult_fast=function(t,i,e,r){r?(e[0]=t[0]*i[0]+t[4]*i[1]+t[8]*i[2],e[4]=t[0]*i[4]+t[4]*i[5]+t[8]*i[6],e[8]=t[0]*i[8]+t[4]*i[9]+t[8]*i[10],e[12]=t[0]*i[12]+t[4]*i[13]+t[8]*i[14]+t[12],e[1]=t[1]*i[0]+t[5]*i[1]+t[9]*i[2],e[5]=t[1]*i[4]+t[5]*i[5]+t[9]*i[6],e[9]=t[1]*i[8]+t[5]*i[9]+t[9]*i[10],e[13]=t[1]*i[12]+t[5]*i[13]+t[9]*i[14]+t[13],e[2]=t[2]*i[0]+t[6]*i[1]+t[10]*i[2],e[6]=t[2]*i[4]+t[6]*i[5]+t[10]*i[6],e[10]=t[2]*i[8]+t[6]*i[9]+t[10]*i[10],e[14]=t[2]*i[12]+t[6]*i[13]+t[10]*i[14]+t[14],e[3]=e[7]=e[11]=0,e[15]=1):(e[0]=t[0]*i[0]+t[4]*i[1]+t[8]*i[2]+t[12]*i[3],e[4]=t[0]*i[4]+t[4]*i[5]+t[8]*i[6]+t[12]*i[7],e[8]=t[0]*i[8]+t[4]*i[9]+t[8]*i[10]+t[12]*i[11],e[12]=t[0]*i[12]+t[4]*i[13]+t[8]*i[14]+t[12]*i[15],e[1]=t[1]*i[0]+t[5]*i[1]+t[9]*i[2]+t[13]*i[3],e[5]=t[1]*i[4]+t[5]*i[5]+t[9]*i[6]+t[13]*i[7],e[9]=t[1]*i[8]+t[5]*i[9]+t[9]*i[10]+t[13]*i[11],e[13]=t[1]*i[12]+t[5]*i[13]+t[9]*i[14]+t[13]*i[15],e[2]=t[2]*i[0]+t[6]*i[1]+t[10]*i[2]+t[14]*i[3],e[6]=t[2]*i[4]+t[6]*i[5]+t[10]*i[6]+t[14]*i[7],e[10]=t[2]*i[8]+t[6]*i[9]+t[10]*i[10]+t[14]*i[11],e[14]=t[2]*i[12]+t[6]*i[13]+t[10]*i[14]+t[14]*i[15],e[3]=t[3]*i[0]+t[7]*i[1]+t[11]*i[2]+t[15]*i[3],e[7]=t[3]*i[4]+t[7]*i[5]+t[11]*i[6]+t[15]*i[7],e[11]=t[3]*i[8]+t[7]*i[9]+t[11]*i[10]+t[15]*i[11],e[15]=t[3]*i[12]+t[7]*i[13]+t[11]*i[14]+t[15]*i[15])},R.prototype.translate=function(t,i,e){this.m[12]=this.m[0]*t+this.m[4]*i+this.m[8]*e+this.m[12],this.m[13]=this.m[1]*t+this.m[5]*i+this.m[9]*e+this.m[13],this.m[14]=this.m[2]*t+this.m[6]*i+this.m[10]*e+this.m[14],this.m[15]=this.m[3]*t+this.m[7]*i+this.m[11]*e+this.m[15]},R.prototype.scale=function(t,i,e){this.m[0]*=t,this.m[4]*=i,this.m[8]*=e,this.m[1]*=t,this.m[5]*=i,this.m[9]*=e,this.m[2]*=t,this.m[6]*=i,this.m[10]*=e,this.m[3]*=t,this.m[7]*=i,this.m[11]*=e},R.prototype.rotateX=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[4];this.m[4]=r*i+this.m[8]*e,this.m[8]=r*-e+this.m[8]*i,r=this.m[5],this.m[5]=r*i+this.m[9]*e,this.m[9]=r*-e+this.m[9]*i,r=this.m[6],this.m[6]=r*i+this.m[10]*e,this.m[10]=r*-e+this.m[10]*i,r=this.m[7],this.m[7]=r*i+this.m[11]*e,this.m[11]=r*-e+this.m[11]*i},R.prototype.rotateY=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[0];this.m[0]=r*i+this.m[8]*-e,this.m[8]=r*e+this.m[8]*i,r=this.m[1],this.m[1]=r*i+this.m[9]*-e,this.m[9]=r*e+this.m[9]*i,r=m[2],this.m[2]=r*i+this.m[10]*-e,this.m[10]=r*e+this.m[10]*i,r=m[3],this.m[3]=r*i+this.m[11]*-e,this.m[11]=r*e+this.m[11]*i},R.prototype.rotateZ=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[0];this.m[0]=r*i+this.m[4]*e,this.m[4]=r*-e+this.m[4]*i,r=this.m[1],this.m[1]=r*i+this.m[5]*e,this.m[5]=r*-e+this.m[5]*i,r=this.m[2],this.m[2]=r*i+this.m[6]*e,this.m[6]=r*-e+this.m[6]*i,r=this.m[3],this.m[3]=r*i+this.m[7]*e,this.m[7]=r*-e+this.m[7]*i},b.prototype=new et,b._$tP=new Object,b._$27=function(){b._$tP.clear()},b.getID=function(t){var i=b._$tP[t];return null==i&&(i=new b(t),b._$tP[t]=i),i},b.prototype._$3s=function(){return new b},F._$kS=-1,F._$pS=0,F._$hb=1,F.STATE_IDENTITY=0,F._$gb=1,F._$fo=2,F._$go=4,F.prototype.transform=function(t,i,e){var r,o,n,s,_,a,h=0,l=0;switch(this._$hi){default:return;case F._$go|F._$fo|F._$gb:for(r=this._$7,o=this._$H,n=this._$k,s=this._$f,_=this._$g,a=this._$w;--e>=0;){var $=t[h++],u=t[h++];i[l++]=r*$+o*u+n,i[l++]=s*$+_*u+a}return;case F._$go|F._$fo:for(r=this._$7,o=this._$H,s=this._$f,_=this._$g;--e>=0;){var $=t[h++],u=t[h++];i[l++]=r*$+o*u,i[l++]=s*$+_*u}return;case F._$go|F._$gb:for(o=this._$H,n=this._$k,s=this._$f,a=this._$w;--e>=0;){var $=t[h++];i[l++]=o*t[h++]+n,i[l++]=s*$+a}return;case F._$go:for(o=this._$H,s=this._$f;--e>=0;){var $=t[h++];i[l++]=o*t[h++],i[l++]=s*$}return;case F._$fo|F._$gb:for(r=this._$7,n=this._$k,_=this._$g,a=this._$w;--e>=0;)i[l++]=r*t[h++]+n,i[l++]=_*t[h++]+a;return;case F._$fo:for(r=this._$7,_=this._$g;--e>=0;)i[l++]=r*t[h++],i[l++]=_*t[h++];return;case F._$gb:for(n=this._$k,a=this._$w;--e>=0;)i[l++]=t[h++]+n,i[l++]=t[h++]+a;return;case F.STATE_IDENTITY:return void(t==i&&h==l||w._$jT(t,h,i,l,2*e))}},F.prototype.update=function(){0==this._$H&&0==this._$f?1==this._$7&&1==this._$g?0==this._$k&&0==this._$w?(this._$hi=F.STATE_IDENTITY,this._$Z=F._$pS):(this._$hi=F._$gb,this._$Z=F._$hb):0==this._$k&&0==this._$w?(this._$hi=F._$fo,this._$Z=F._$kS):(this._$hi=F._$fo|F._$gb,this._$Z=F._$kS):0==this._$7&&0==this._$g?0==this._$k&&0==this._$w?(this._$hi=F._$go,this._$Z=F._$kS):(this._$hi=F._$go|F._$gb,this._$Z=F._$kS):0==this._$k&&0==this._$w?(this._$hi=F._$go|F._$fo,this._$Z=F._$kS):(this._$hi=F._$go|F._$fo|F._$gb,this._$Z=F._$kS)},F.prototype._$RT=function(t){this._$IT(t);var i=t[0],e=t[2],r=t[1],o=t[3],n=Math.sqrt(i*i+r*r),s=i*o-e*r;0==n?at._$so&&console.log("affine._$RT() / rt==0"):(t[0]=n,t[1]=s/n,t[2]=(r*o+i*e)/s,t[3]=Math.atan2(r,i))},F.prototype._$ho=function(t,i,e,r){var o=new Float32Array(6),n=new Float32Array(6);t._$RT(o),i._$RT(n);var s=new Float32Array(6);s[0]=o[0]+(n[0]-o[0])*e,s[1]=o[1]+(n[1]-o[1])*e,s[2]=o[2]+(n[2]-o[2])*e,s[3]=o[3]+(n[3]-o[3])*e,s[4]=o[4]+(n[4]-o[4])*e,s[5]=o[5]+(n[5]-o[5])*e,r._$CT(s)},F.prototype._$CT=function(t){var i=Math.cos(t[3]),e=Math.sin(t[3]);this._$7=t[0]*i,this._$f=t[0]*e,this._$H=t[1]*(t[2]*i-e),this._$g=t[1]*(t[2]*e+i),this._$k=t[4],this._$w=t[5],this.update()},F.prototype._$IT=function(t){t[0]=this._$7,t[1]=this._$f,t[2]=this._$H,t[3]=this._$g,t[4]=this._$k,t[5]=this._$w},C.prototype=new s,C._$cs="VISIBLE:",C._$ar="LAYOUT:",C._$Co=0,C._$D2=[],C._$1T=1,C.loadMotion=function(t){var i=new C,e=[0],r=t.length;i._$yT=0;for(var o=0;o=0){var a=new B;O.startsWith(t,s,C._$cs)?(a._$RP=B._$hs,a._$4P=new String(t,s,_-s)):O.startsWith(t,s,C._$ar)?(a._$4P=new String(t,s+7,_-s-7),O.startsWith(t,s+7,"ANCHOR_X")?a._$RP=B._$xs:O.startsWith(t,s+7,"ANCHOR_Y")?a._$RP=B._$us:O.startsWith(t,s+7,"SCALE_X")?a._$RP=B._$qs:O.startsWith(t,s+7,"SCALE_Y")?a._$RP=B._$Ys:O.startsWith(t,s+7,"X")?a._$RP=B._$ws:O.startsWith(t,s+7,"Y")&&(a._$RP=B._$Ns)):(a._$RP=B._$Fr,a._$4P=new String(t,s,_-s)),i.motions.push(a);var h=0;for(C._$D2.clear(),o=_+1;o0){C._$D2.push(l),h++;var $=e[0];if($i._$yT&&(i._$yT=h)}}}else{for(var s=o,_=-1;o=0)for(_==s+4&&"f"==t[s+1]&&"p"==t[s+2]&&"s"==t[s+3]&&(u=!0),o=_+1;o0&&u&&5=l?l-1:s];t.setParamFloat($,u)}else if(B._$ws<=h._$RP&&h._$RP<=B._$Ys);else{var p=t.getParamFloat($),f=h._$I0[s>=l?l-1:s],c=h._$I0[s+1>=l?l-1:s+1],d=f+(c-f)*_,g=p+(d-p)*e;t.setParamFloat($,g)}}s>=this._$yT&&(this._$E?(r._$z2=i,this.loopFadeIn&&(r._$bs=i)):r._$9L=!0)},C.prototype._$r0=function(){return this._$E},C.prototype._$aL=function(t){this._$E=t},C.prototype.isLoopFadeIn=function(){return this.loopFadeIn},C.prototype.setLoopFadeIn=function(t){this.loopFadeIn=t},N.prototype.clear=function(){this.size=0},N.prototype.add=function(t){if(this._$P.length<=this.size){var i=new Float32Array(2*this.size);w._$jT(this._$P,0,i,0,this.size),this._$P=i}this._$P[this.size++]=t},N.prototype._$BL=function(){var t=new Float32Array(this.size);return w._$jT(this._$P,0,t,0,this.size),t},B._$Fr=0,B._$hs=1,B._$ws=100,B._$Ns=101,B._$xs=102,B._$us=103,B._$qs=104,B._$Ys=105,U._$Ms=1,U._$Qs=2,U._$i2=0,U._$No=2,U._$do=U._$Ms,U._$Ls=!0,U._$1r=5,U._$Qb=65,U._$J=1e-4,U._$FT=.001,U._$Ss=3,G._$o7=6,G._$S7=7,G._$s7=8,G._$77=9,G.LIVE2D_FORMAT_VERSION_V2_10_SDK2=10,G.LIVE2D_FORMAT_VERSION_V2_11_SDK2_1=11,G._$T7=G.LIVE2D_FORMAT_VERSION_V2_11_SDK2_1,G._$Is=-2004318072,G._$h0=0,G._$4L=23,G._$7P=33,G._$uT=function(t){console.log("_$bo :: _$6 _$mo _$E0 : %d\n",t)},G._$9o=function(t){if(t<40)return G._$uT(t),null;if(t<50)return G._$uT(t),null;if(t<60)return G._$uT(t),null;if(t<100)switch(t){case 65:return new Z;case 66:return new D;case 67:return new x;case 68:return new z;case 69:return new P;case 70:return new $t;default:return G._$uT(t),null}else if(t<150)switch(t){case 131:return new st;case 133:return new tt;case 136:return new p;case 137:return new ot;case 142:return new j}return G._$uT(t),null},Y._$HP=0,Y._$_0=!0;Y._$V2=-1,Y._$W0=-1,Y._$jr=!1,Y._$ZS=!0,Y._$tr=-1e6,Y._$lr=1e6,Y._$is=32,Y._$e=!1,Y.prototype.getDrawDataIndex=function(t){for(var i=this._$aS.length-1;i>=0;--i)if(null!=this._$aS[i]&&this._$aS[i].getDrawDataID()==t)return i;return-1},Y.prototype.getDrawData=function(t){if(t instanceof b){if(null==this._$Bo){this._$Bo=new Object;for(var i=this._$aS.length,e=0;e0&&this.release();for(var t=this._$Ri.getModelImpl(),i=t._$Xr(),r=i.length,o=new Array,n=new Array,s=0;s=0)&&(this._$3S.push(m),this._$db.push(n[s]),o[s]=null,y=!0)}}if(!y)break}var P=t._$E2();if(null!=P){var S=P._$1s();if(null!=S)for(var v=S.length,s=0;s=0;i--)this._$Js[i]=Y._$jr;return this._$QT=!1,Y._$e&&_.dump("_$eL"),!1},Y.prototype.preDraw=function(t){null!=this.clipManager&&(t._$ZT(),this.clipManager.setupClip(this,t))},Y.prototype.draw=function(t){if(null==this._$Ws)return void _._$li("call _$Ri.update() before _$Ri.draw() ");var i=this._$Ws.length;t._$ZT();for(var e=0;e=0;--i)if(this._$pb[i]==t)return i;return this._$02(t,0,Y._$tr,Y._$lr)},Y.prototype._$BS=function(t){return this.getBaseDataIndex(t)},Y.prototype.getBaseDataIndex=function(t){for(var i=this._$3S.length-1;i>=0;--i)if(null!=this._$3S[i]&&this._$3S[i].getBaseDataID()==t)return i;return-1},Y.prototype._$UT=function(t,i){var e=new Float32Array(i);return w._$jT(t,0,e,0,t.length),e},Y.prototype._$02=function(t,i,e,r){if(this._$qo>=this._$pb.length){var o=this._$pb.length,n=new Array(2*o);w._$jT(this._$pb,0,n,0,o),this._$pb=n,this._$_2=this._$UT(this._$_2,2*o),this._$vr=this._$UT(this._$vr,2*o),this._$Rr=this._$UT(this._$Rr,2*o),this._$Or=this._$UT(this._$Or,2*o);var s=new Array;w._$jT(this._$Js,0,s,0,o),this._$Js=s}return this._$pb[this._$qo]=t,this._$_2[this._$qo]=i,this._$vr[this._$qo]=i,this._$Rr[this._$qo]=e,this._$Or[this._$qo]=r,this._$Js[this._$qo]=Y._$ZS,this._$qo++},Y.prototype._$Zo=function(t,i){this._$3S[t]=i},Y.prototype.setParamFloat=function(t,i){ithis._$Or[t]&&(i=this._$Or[t]),this._$_2[t]=i},Y.prototype.loadParam=function(){var t=this._$_2.length;t>this._$fs.length&&(t=this._$fs.length),w._$jT(this._$fs,0,this._$_2,0,t)},Y.prototype.saveParam=function(){var t=this._$_2.length;t>this._$fs.length&&(this._$fs=new Float32Array(t)),w._$jT(this._$_2,0,this._$fs,0,t)},Y.prototype._$v2=function(){return this._$co},Y.prototype._$WS=function(){return this._$QT},Y.prototype._$Xb=function(t){return this._$Js[t]==Y._$ZS},Y.prototype._$vs=function(){return this._$Es},Y.prototype._$Tr=function(){return this._$ZP},Y.prototype.getBaseData=function(t){return this._$3S[t]},Y.prototype.getParamFloat=function(t){return this._$_2[t]},Y.prototype.getParamMax=function(t){return this._$Or[t]},Y.prototype.getParamMin=function(t){return this._$Rr[t]},Y.prototype.setPartsOpacity=function(t,i){this._$Hr[t].setPartsOpacity(i)},Y.prototype.getPartsOpacity=function(t){return this._$Hr[t].getPartsOpacity()},Y.prototype.getPartsDataIndex=function(t){for(var i=this._$F2.length-1;i>=0;--i)if(null!=this._$F2[i]&&this._$F2[i]._$p2()==t)return i;return-1},Y.prototype._$q2=function(t){return this._$db[t]},Y.prototype._$C2=function(t){return this._$8b[t]},Y.prototype._$Bb=function(t){return this._$Hr[t]},Y.prototype._$5s=function(t,i){for(var e=this._$Ws.length,r=t,o=0;o0;)n+=i;return r},k._$C=function(t){var i=null,e=null;try{i=t instanceof Array?t:new _$Xs(t,8192),e=new _$js;for(var r,o=new Int8Array(1e3);(r=i.read(o))>0;)e.write(o,0,r);return e._$TS()}finally{null!=t&&t.close(),null!=e&&(e.flush(),e.close())}},V.prototype._$T2=function(){return w.getUserTimeMSec()+Math._$10()*(2*this._$Br-1)},V.prototype._$uo=function(t){this._$Br=t},V.prototype._$QS=function(t,i,e){this._$Dr=t,this._$Cb=i,this._$mr=e},V.prototype._$7T=function(t){var i,e=w.getUserTimeMSec(),r=0;switch(this._$_L){case STATE_CLOSING:r=(e-this._$bb)/this._$Dr,r>=1&&(r=1,this._$_L=wt.STATE_CLOSED,this._$bb=e),i=1-r;break;case STATE_CLOSED:r=(e-this._$bb)/this._$Cb,r>=1&&(this._$_L=wt.STATE_OPENING,this._$bb=e),i=0;break;case STATE_OPENING:r=(e-this._$bb)/this._$mr,r>=1&&(r=1,this._$_L=wt.STATE_INTERVAL,this._$12=this._$T2()),i=r;break;case STATE_INTERVAL:this._$12.9?at.EXPAND_W:0;this.gl.drawElements(a,e,r,o,n,h,this.transform,_)}},X.prototype._$Rs=function(){throw new Error("_$Rs")},X.prototype._$Ds=function(t){throw new Error("_$Ds")},X.prototype._$K2=function(){for(var t=0;t=0;--i){var e=t[i];eW._$R2&&(W._$R2=e)}},W._$or=function(){return W._$52},W._$Pr=function(){return W._$R2},W.prototype._$F0=function(t){this._$gP=t._$nP(),this._$dr=t._$nP(),this._$GS=t._$nP(),this._$qb=t._$6L(),this._$Lb=t._$cS(),this._$mS=t._$Tb(),t.getFormatVersion()>=G._$T7?(this.clipID=t._$nP(),this.clipIDList=this.convertClipIDForV2_11(this.clipID)):this.clipIDList=null,W._$Sb(this._$Lb)},W.prototype.getClipIDList=function(){return this.clipIDList},W.prototype._$Nr=function(t,i){if(i._$IS[0]=!1,i._$Us=v._$Z2(t,this._$GS,i._$IS,this._$Lb),at._$Zs);else if(i._$IS[0])return;i._$7s=v._$br(t,this._$GS,i._$IS,this._$mS)},W.prototype._$2b=function(t){},W.prototype.getDrawDataID=function(){return this._$gP},W.prototype._$j2=function(t){this._$gP=t},W.prototype.getOpacity=function(t,i){return i._$7s},W.prototype._$zS=function(t,i){return i._$Us},W.prototype.getTargetBaseDataID=function(){return this._$dr},W.prototype._$gs=function(t){this._$dr=t},W.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},W.prototype.getType=function(){},j._$42=0,j.prototype._$1b=function(){return this._$3S},j.prototype.getDrawDataList=function(){return this._$aS},j.prototype._$F0=function(t){this._$NL=t._$nP(),this._$aS=t._$nP(),this._$3S=t._$nP()},j.prototype._$kr=function(t){t._$Zo(this._$3S),t._$xo(this._$aS),this._$3S=null,this._$aS=null},q.prototype=new i,q.loadModel=function(t){var e=new q;return i._$62(e,t),e},q.loadModel=function(t){var e=new q;return i._$62(e,t),e},q._$to=function(){return new q},q._$er=function(t){var i=new _$5("../_$_r/_$t0/_$Ri/_$_P._$d");if(0==i.exists())throw new _$ls("_$t0 _$_ _$6 _$Ui :: "+i._$PL());for(var e=["../_$_r/_$t0/_$Ri/_$_P.512/_$CP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$vP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$EP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$pP._$1"],r=q.loadModel(i._$3b()),o=0;o=0){var h=new B;O.startsWith(t,_,J._$cs)?(h._$RP=B._$hs,h._$4P=O.createString(t,_,a-_)):O.startsWith(t,_,J._$ar)?(h._$4P=O.createString(t,_+7,a-_-7),O.startsWith(t,_+7,"ANCHOR_X")?h._$RP=B._$xs:O.startsWith(t,_+7,"ANCHOR_Y")?h._$RP=B._$us:O.startsWith(t,_+7,"SCALE_X")?h._$RP=B._$qs:O.startsWith(t,_+7,"SCALE_Y")?h._$RP=B._$Ys:O.startsWith(t,_+7,"X")?h._$RP=B._$ws:O.startsWith(t,_+7,"Y")&&(h._$RP=B._$Ns)):(h._$RP=B._$Fr,h._$4P=O.createString(t,_,a-_)),i.motions.push(h);var l=0,$=[];for(o=a+1;o0){$.push(u),l++;var p=e[0];if(pi._$yT&&(i._$yT=l)}}}else{for(var _=o,a=-1;o=0)for(a==_+4&&"f"==Q(t,_+1)&&"p"==Q(t,_+2)&&"s"==Q(t,_+3)&&(f=!0),o=a+1;o0&&f&&5=l?l-1:s];t.setParamFloat($,u)}else if(B._$ws<=h._$RP&&h._$RP<=B._$Ys);else{var p,f=t.getParamIndex($),c=t.getModelContext(),d=c.getParamMax(f),g=c.getParamMin(f),y=.4*(d-g),m=c.getParamFloat(f),T=h._$I0[s>=l?l-1:s],P=h._$I0[s+1>=l?l-1:s+1];p=Ty||T>P&&T-P>y?T:T+(P-T)*_;var S=m+(p-m)*e;t.setParamFloat($,S)}}s>=this._$yT&&(this._$E?(r._$z2=i,this.loopFadeIn&&(r._$bs=i)):r._$9L=!0),this._$eP=e},J.prototype._$r0=function(){return this._$E},J.prototype._$aL=function(t){this._$E=t},J.prototype._$S0=function(){return this._$D0},J.prototype._$U0=function(t){this._$D0=t},J.prototype.isLoopFadeIn=function(){return this.loopFadeIn},J.prototype.setLoopFadeIn=function(t){this.loopFadeIn=t},N.prototype.clear=function(){this.size=0},N.prototype.add=function(t){if(this._$P.length<=this.size){var i=new Float32Array(2*this.size);w._$jT(this._$P,0,i,0,this.size),this._$P=i}this._$P[this.size++]=t},N.prototype._$BL=function(){var t=new Float32Array(this.size);return w._$jT(this._$P,0,t,0,this.size),t},B._$Fr=0,B._$hs=1,B._$ws=100,B._$Ns=101,B._$xs=102,B._$us=103,B._$qs=104,B._$Ys=105,Z.prototype=new I,Z._$gT=new Array,Z.prototype._$zP=function(){this._$GS=new D,this._$GS._$zP()},Z.prototype._$F0=function(t){I.prototype._$F0.call(this,t),this._$A=t._$6L(),this._$o=t._$6L(),this._$GS=t._$nP(),this._$Eo=t._$nP(),I.prototype.readV2_opacity.call(this,t)},Z.prototype.init=function(t){var i=new K(this),e=(this._$o+1)*(this._$A+1);return null!=i._$Cr&&(i._$Cr=null),i._$Cr=new Float32Array(2*e),null!=i._$hr&&(i._$hr=null),this._$32()?i._$hr=new Float32Array(2*e):i._$hr=null,i},Z.prototype._$Nr=function(t,i){var e=i;if(this._$GS._$Ur(t)){var r=this._$VT(),o=Z._$gT;o[0]=!1,v._$Vr(t,this._$GS,o,r,this._$Eo,e._$Cr,0,2),i._$Ib(o[0]),this.interpolateOpacity(t,this._$GS,i,o)}},Z.prototype._$2b=function(t,i){var e=i;if(e._$hS(!0),this._$32()){var r=this.getTargetBaseDataID();if(e._$8r==I._$ur&&(e._$8r=t.getBaseDataIndex(r)),e._$8r<0)at._$so&&_._$li("_$L _$0P _$G :: %s",r),e._$hS(!1);else{var o=t.getBaseData(e._$8r),n=t._$q2(e._$8r);if(null!=o&&n._$yo()){var s=n.getTotalScale();e.setTotalScale_notForClient(s);var a=n.getTotalOpacity();e.setTotalOpacity(a*e.getInterpolatedOpacity()),o._$nb(t,n,e._$Cr,e._$hr,this._$VT(),0,2),e._$hS(!0)}else e._$hS(!1)}}else e.setTotalOpacity(e.getInterpolatedOpacity())},Z.prototype._$nb=function(t,i,e,r,o,n,s){var _=i,a=null!=_._$hr?_._$hr:_._$Cr;Z.transformPoints_sdk2(e,r,o,n,s,a,this._$o,this._$A)},Z.transformPoints_sdk2=function(i,e,r,o,n,s,_,a){for(var h,l,$,u=r*n,p=0,f=0,c=0,d=0,g=0,y=0,m=!1,T=o;T=1){var b=s[2*(0+a*M)],F=s[2*(0+a*M)+1],C=p-2*c+1*g,N=f-2*d+1*y,x=p+3*g,O=f+3*y,D=p-2*c+3*g,R=f-2*d+3*y,B=.5*(v- -2),U=.5*(L-1);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else{var G=0|S;G==a&&(G=a-1);var B=.5*(v- -2),U=S-G,Y=G/a,k=(G+1)/a,b=s[2*(0+G*M)],F=s[2*(0+G*M)+1],x=s[2*(0+(G+1)*M)],O=s[2*(0+(G+1)*M)+1],C=p-2*c+Y*g,N=f-2*d+Y*y,D=p-2*c+k*g,R=f-2*d+k*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(1<=v)if(L<=0){var D=s[2*(_+0*M)],R=s[2*(_+0*M)+1],x=p+3*c,O=f+3*d,C=p+1*c-2*g,N=f+1*d-2*y,b=p+3*c-2*g,F=f+3*d-2*y,B=.5*(v-1),U=.5*(L- -2);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L>=1){var C=s[2*(_+a*M)],N=s[2*(_+a*M)+1],b=p+3*c+1*g,F=f+3*d+1*y,D=p+1*c+3*g,R=f+1*d+3*y,x=p+3*c+3*g,O=f+3*d+3*y,B=.5*(v-1),U=.5*(L-1);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else{var G=0|S;G==a&&(G=a-1);var B=.5*(v-1),U=S-G,Y=G/a,k=(G+1)/a,C=s[2*(_+G*M)],N=s[2*(_+G*M)+1],D=s[2*(_+(G+1)*M)],R=s[2*(_+(G+1)*M)+1],b=p+3*c+Y*g,F=f+3*d+Y*y,x=p+3*c+k*g,O=f+3*d+k*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L<=0){var V=0|P;V==_&&(V=_-1);var B=P-V,U=.5*(L- -2),X=V/_,z=(V+1)/_,D=s[2*(V+0*M)],R=s[2*(V+0*M)+1],x=s[2*(V+1+0*M)],O=s[2*(V+1+0*M)+1],C=p+X*c-2*g,N=f+X*d-2*y,b=p+z*c-2*g,F=f+z*d-2*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L>=1){var V=0|P;V==_&&(V=_-1);var B=P-V,U=.5*(L-1),X=V/_,z=(V+1)/_,C=s[2*(V+a*M)],N=s[2*(V+a*M)+1],b=s[2*(V+1+a*M)],F=s[2*(V+1+a*M)+1],D=p+X*c+3*g,R=f+X*d+3*y,x=p+z*c+3*g,O=f+z*d+3*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else t.err.printf("_$li calc : %.4f , %.4f\t\t\t\t\t@@BDBoxGrid\n",v,L);else e[T]=p+v*c+L*g,e[T+1]=f+v*d+L*y}else l=P-(0|P),$=S-(0|S),h=2*((0|P)+(0|S)*(_+1)),l+$<1?(e[T]=s[h]*(1-l-$)+s[h+2]*l+s[h+2*(_+1)]*$,e[T+1]=s[h+1]*(1-l-$)+s[h+3]*l+s[h+2*(_+1)+1]*$):(e[T]=s[h+2*(_+1)+2]*(l-1+$)+s[h+2*(_+1)]*(1-l)+s[h+2]*(1-$),e[T+1]=s[h+2*(_+1)+3]*(l-1+$)+s[h+2*(_+1)+1]*(1-l)+s[h+3]*(1-$))}},Z.prototype.transformPoints_sdk1=function(t,i,e,r,o,n,s){for(var _,a,h,l,$,u,p,f=i,c=this._$o,d=this._$A,g=o*s,y=null!=f._$hr?f._$hr:f._$Cr,m=n;m1&&(_=1),a<0?a=0:a>1&&(a=1),_*=c,a*=d,h=0|_,l=0|a,h>c-1&&(h=c-1),l>d-1&&(l=d-1),u=_-h,p=a-l,$=2*(h+l*(c+1))):(_=e[m]*c,a=e[m+1]*d,u=_-(0|_),p=a-(0|a),$=2*((0|_)+(0|a)*(c+1))),u+p<1?(r[m]=y[$]*(1-u-p)+y[$+2]*u+y[$+2*(c+1)]*p,r[m+1]=y[$+1]*(1-u-p)+y[$+3]*u+y[$+2*(c+1)+1]*p):(r[m]=y[$+2*(c+1)+2]*(u-1+p)+y[$+2*(c+1)]*(1-u)+y[$+2]*(1-p),r[m+1]=y[$+2*(c+1)+3]*(u-1+p)+y[$+2*(c+1)+1]*(1-u)+y[$+3]*(1-p))},Z.prototype._$VT=function(){return(this._$o+1)*(this._$A+1)},Z.prototype.getType=function(){return I._$_b},K.prototype=new _t,tt._$42=0,tt.prototype._$zP=function(){this._$3S=new Array,this._$aS=new Array},tt.prototype._$F0=function(t){this._$g0=t._$8L(),this.visible=t._$8L(),this._$NL=t._$nP(),this._$3S=t._$nP(),this._$aS=t._$nP()},tt.prototype.init=function(t){var i=new it(this);return i.setPartsOpacity(this.isVisible()?1:0),i},tt.prototype._$6o=function(t){if(null==this._$3S)throw new Error("_$3S _$6 _$Wo@_$6o");this._$3S.push(t)},tt.prototype._$3o=function(t){if(null==this._$aS)throw new Error("_$aS _$6 _$Wo@_$3o");this._$aS.push(t)},tt.prototype._$Zo=function(t){this._$3S=t},tt.prototype._$xo=function(t){this._$aS=t},tt.prototype.isVisible=function(){return this.visible},tt.prototype._$uL=function(){return this._$g0},tt.prototype._$KP=function(t){this.visible=t},tt.prototype._$ET=function(t){this._$g0=t},tt.prototype.getBaseData=function(){return this._$3S},tt.prototype.getDrawData=function(){return this._$aS},tt.prototype._$p2=function(){return this._$NL},tt.prototype._$ob=function(t){this._$NL=t},tt.prototype.getPartsID=function(){return this._$NL},tt.prototype._$MP=function(t){this._$NL=t},it.prototype=new $,it.prototype.getPartsOpacity=function(){return this._$VS},it.prototype.setPartsOpacity=function(t){this._$VS=t},et._$L7=function(){u._$27(),yt._$27(),b._$27(),l._$27()},et.prototype.toString=function(){return this.id},rt.prototype._$F0=function(t){},ot.prototype._$1s=function(){return this._$4S},ot.prototype._$zP=function(){this._$4S=new Array},ot.prototype._$F0=function(t){this._$4S=t._$nP()},ot.prototype._$Ks=function(t){this._$4S.push(t)},nt.tr=new gt,nt._$50=new gt,nt._$Ti=new Array(0,0),nt._$Pi=new Array(0,0),nt._$B=new Array(0,0),nt.prototype._$lP=function(t,i,e,r){this.viewport=new Array(t,i,e,r)},nt.prototype._$bL=function(){this.context.save();var t=this.viewport;null!=t&&(this.context.beginPath(),this.context._$Li(t[0],t[1],t[2],t[3]),this.context.clip())},nt.prototype._$ei=function(){this.context.restore()},nt.prototype.drawElements=function(t,i,e,r,o,n,s,a){try{o!=this._$Qo&&(this._$Qo=o,this.context.globalAlpha=o);for(var h=i.length,l=t.width,$=t.height,u=this.context,p=this._$xP,f=this._$uP,c=this._$6r,d=this._$3r,g=nt.tr,y=nt._$Ti,m=nt._$Pi,T=nt._$B,P=0;P.02?nt.expandClip(t,i,e,r,l,$,u,p,f,c):nt.clipWithTransform(t,null,o,n,s,_,a,h)},nt.expandClip=function(t,i,e,r,o,n,s,_,a,h){var l=s-o,$=_-n,u=a-o,p=h-n,f=l*p-$*u>0?e:-e,c=-$,d=l,g=a-s,y=h-_,m=-y,T=g,P=Math.sqrt(g*g+y*y),S=-p,v=u,L=Math.sqrt(u*u+p*p),M=o-f*c/r,E=n-f*d/r,A=s-f*c/r,I=_-f*d/r,w=s-f*m/P,x=_-f*T/P,O=a-f*m/P,D=h-f*T/P,R=o+f*S/L,b=n+f*v/L,F=a+f*S/L,C=h+f*v/L,N=nt._$50;return null!=i._$P2(N)&&(nt.clipWithTransform(t,N,M,E,A,I,w,x,O,D,F,C,R,b),!0)},nt.clipWithTransform=function(t,i,e,r,o,n,s,a){if(arguments.length<7)return void _._$li("err : @LDGL.clip()");if(!(arguments[1]instanceof gt))return void _._$li("err : a[0] is _$6 LDTransform @LDGL.clip()");var h=nt._$B,l=i,$=arguments;if(t.beginPath(),l){l._$PS($[2],$[3],h),t.moveTo(h[0],h[1]);for(var u=4;u<$.length;u+=2)l._$PS($[u],$[u+1],h),t.lineTo(h[0],h[1])}else{t.moveTo($[2],$[3]);for(var u=4;u<$.length;u+=2)t.lineTo($[u],$[u+1])}t.clip()},nt.createCanvas=function(t,i){var e=document.createElement("canvas");return e.setAttribute("width",t),e.setAttribute("height",i),e||_._$li("err : "+e),e},nt.dumpValues=function(){for(var t="",i=0;i1?1:.5-.5*Math.cos(t*Lt.PI_F)},lt._$fr=-1,lt.prototype.toString=function(){return this._$ib},$t.prototype=new W,$t._$42=0,$t._$Os=30,$t._$ms=0,$t._$ns=1,$t._$_s=2,$t._$gT=new Array,$t.prototype._$_S=function(t){this._$LP=t},$t.prototype.getTextureNo=function(){return this._$LP},$t.prototype._$ZL=function(){return this._$Qi},$t.prototype._$H2=function(){return this._$JP},$t.prototype.getNumPoints=function(){return this._$d0},$t.prototype.getType=function(){return W._$wb},$t.prototype._$B2=function(t,i,e){var r=i,o=null!=r._$hr?r._$hr:r._$Cr;switch(U._$do){default:case U._$Ms:throw new Error("_$L _$ro ");case U._$Qs:for(var n=this._$d0-1;n>=0;--n)o[n*U._$No+4]=e}},$t.prototype._$zP=function(){this._$GS=new D,this._$GS._$zP()},$t.prototype._$F0=function(t){W.prototype._$F0.call(this,t),this._$LP=t._$6L(),this._$d0=t._$6L(),this._$Yo=t._$6L();var i=t._$nP();this._$BP=new Int16Array(3*this._$Yo);for(var e=3*this._$Yo-1;e>=0;--e)this._$BP[e]=i[e];if(this._$Eo=t._$nP(),this._$Qi=t._$nP(),t.getFormatVersion()>=G._$s7){if(this._$JP=t._$6L(),0!=this._$JP){if(0!=(1&this._$JP)){var r=t._$6L();null==this._$5P&&(this._$5P=new Object),this._$5P._$Hb=parseInt(r)}0!=(this._$JP&$t._$Os)?this._$6s=(this._$JP&$t._$Os)>>1:this._$6s=$t._$ms,0!=(32&this._$JP)&&(this.culling=!1)}}else this._$JP=0},$t.prototype.init=function(t){var i=new ut(this),e=this._$d0*U._$No,r=this._$32();switch(null!=i._$Cr&&(i._$Cr=null),i._$Cr=new Float32Array(e),null!=i._$hr&&(i._$hr=null),i._$hr=r?new Float32Array(e):null,U._$do){default:case U._$Ms:if(U._$Ls)for(var o=this._$d0-1;o>=0;--o){var n=o<<1;this._$Qi[n+1]=1-this._$Qi[n+1]}break;case U._$Qs:for(var o=this._$d0-1;o>=0;--o){var n=o<<1,s=o*U._$No,_=this._$Qi[n],a=this._$Qi[n+1];i._$Cr[s]=_,i._$Cr[s+1]=a,i._$Cr[s+4]=0,r&&(i._$hr[s]=_,i._$hr[s+1]=a,i._$hr[s+4]=0)}}return i},$t.prototype._$Nr=function(t,i){var e=i;if(this!=e._$GT()&&console.log("### assert!! ### "),this._$GS._$Ur(t)&&(W.prototype._$Nr.call(this,t,e),!e._$IS[0])){var r=$t._$gT;r[0]=!1,v._$Vr(t,this._$GS,r,this._$d0,this._$Eo,e._$Cr,U._$i2,U._$No)}},$t.prototype._$2b=function(t,i){try{this!=i._$GT()&&console.log("### assert!! ### ");var e=!1;i._$IS[0]&&(e=!0);var r=i;if(!e&&(W.prototype._$2b.call(this,t),this._$32())){var o=this.getTargetBaseDataID();if(r._$8r==W._$ur&&(r._$8r=t.getBaseDataIndex(o)),r._$8r<0)at._$so&&_._$li("_$L _$0P _$G :: %s",o);else{var n=t.getBaseData(r._$8r),s=t._$q2(r._$8r);null==n||s._$x2()?r._$AT=!1:(n._$nb(t,s,r._$Cr,r._$hr,this._$d0,U._$i2,U._$No),r._$AT=!0),r.baseOpacity=s.getTotalOpacity()}}}catch(t){throw t}},$t.prototype.draw=function(t,i,e){if(this!=e._$GT()&&console.log("### assert!! ### "),!e._$IS[0]){var r=e,o=this._$LP;o<0&&(o=1);var n=this.getOpacity(i,r)*e._$VS*e.baseOpacity,s=null!=r._$hr?r._$hr:r._$Cr;t.setClipBufPre_clipContextForDraw(e.clipBufPre_clipContext),t._$WP(this.culling),t._$Uo(o,3*this._$Yo,this._$BP,s,this._$Qi,n,this._$6s,r)}},$t.prototype.dump=function(){console.log(" _$yi( %d ) , _$d0( %d ) , _$Yo( %d ) \n",this._$LP,this._$d0,this._$Yo),console.log(" _$Oi _$di = { ");for(var t=0;tstartMotion() / start _$K _$3 (m%d)\n",r,e._$sr));if(null==t)return-1;e=new dt,e._$w0=t,this.motions.push(e);var n=e._$sr;return this._$eb&&_._$Ji("MotionQueueManager[size:%2d]->startMotion() / new _$w0 (m%d)\n",r,n),n},ct.prototype.updateParam=function(t){try{for(var i=!1,e=0;eupdateParam() / _$T0 _$w0 (m%d)\n",this.motions.length-1,r._$sr),this.motions.splice(e,1),e--)):(this.motions=this.motions.splice(e,1),e--)}else this.motions.splice(e,1),e--}return i}catch(t){return _._$li(t),!0}},ct.prototype.isFinished=function(t){if(arguments.length>=1){for(var i=0;i.9&&at.EXPAND_W,this.gl);if(null==this.gl)throw new Error("gl is null");var h=1*this._$C0*n,l=1*this._$tT*n,$=1*this._$WL*n,u=this._$lT*n;if(null!=this.clipBufPre_clipContextMask){a.frontFace(a.CCW),a.useProgram(this.shaderProgram),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc),a.vertexAttribPointer(this.a_position_Loc,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc,1),a.enableVertexAttribArray(this.a_texCoord_Loc),a.vertexAttribPointer(this.a_texCoord_Loc,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_matrix_Loc,!1,this.getClipBufPre_clipContextMask().matrixForMask);var p=this.getClipBufPre_clipContextMask().layoutChannelNo,f=this.getChannelFlagAsColor(p);a.uniform4f(this.u_channelFlag,f.r,f.g,f.b,f.a);var c=this.getClipBufPre_clipContextMask().layoutBounds;a.uniform4f(this.u_baseColor_Loc,2*c.x-1,2*c.y-1,2*c._$EL()-1,2*c._$5T()-1),a.uniform1i(this.u_maskFlag_Loc,!0)}else if(null!=this.getClipBufPre_clipContextDraw()){a.useProgram(this.shaderProgramOff),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc_Off),a.vertexAttribPointer(this.a_position_Loc_Off,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc_Off,1),a.enableVertexAttribArray(this.a_texCoord_Loc_Off),a.vertexAttribPointer(this.a_texCoord_Loc_Off,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_clipMatrix_Loc_Off,!1,this.getClipBufPre_clipContextDraw().matrixForDraw),a.uniformMatrix4fv(this.u_matrix_Loc_Off,!1,this.matrix4x4),a.activeTexture(a.TEXTURE2),a.bindTexture(a.TEXTURE_2D,at.fTexture[this.glno]),a.uniform1i(this.s_texture1_Loc_Off,2);var p=this.getClipBufPre_clipContextDraw().layoutChannelNo,f=this.getChannelFlagAsColor(p);a.uniform4f(this.u_channelFlag_Loc_Off,f.r,f.g,f.b,f.a),a.uniform4f(this.u_baseColor_Loc_Off,h,l,$,u)}else a.useProgram(this.shaderProgram),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc),a.vertexAttribPointer(this.a_position_Loc,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc,1),a.enableVertexAttribArray(this.a_texCoord_Loc),a.vertexAttribPointer(this.a_texCoord_Loc,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_matrix_Loc,!1,this.matrix4x4),a.uniform4f(this.u_baseColor_Loc,h,l,$,u),a.uniform1i(this.u_maskFlag_Loc,!1);this.culling?this.gl.enable(a.CULL_FACE):this.gl.disable(a.CULL_FACE),this.gl.enable(a.BLEND);var d,g,y,m;if(null!=this.clipBufPre_clipContextMask)d=a.ONE,g=a.ONE_MINUS_SRC_ALPHA,y=a.ONE,m=a.ONE_MINUS_SRC_ALPHA;else switch(s){case $t._$ms:d=a.ONE,g=a.ONE_MINUS_SRC_ALPHA,y=a.ONE,m=a.ONE_MINUS_SRC_ALPHA;break;case $t._$ns:d=a.ONE,g=a.ONE,y=a.ZERO,m=a.ONE;break;case $t._$_s:d=a.DST_COLOR,g=a.ONE_MINUS_SRC_ALPHA,y=a.ZERO,m=a.ONE}a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD),a.blendFuncSeparate(d,g,y,m),this.anisotropyExt&&a.texParameteri(a.TEXTURE_2D,this.anisotropyExt.TEXTURE_MAX_ANISOTROPY_EXT,this.maxAnisotropy);var T=e.length;a.drawElements(a.TRIANGLES,T,a.UNSIGNED_SHORT,0),a.bindTexture(a.TEXTURE_2D,null)}},mt.prototype._$Rs=function(){throw new Error("_$Rs")},mt.prototype._$Ds=function(t){throw new Error("_$Ds")},mt.prototype._$K2=function(){for(var t=0;t=48){var r=G._$9o(t);return null!=r?(r._$F0(this),r):null}switch(t){case 1:return this._$bT();case 10:return new n(this._$6L(),!0);case 11:return new S(this._$mP(),this._$mP(),this._$mP(),this._$mP());case 12:return new S(this._$_T(),this._$_T(),this._$_T(),this._$_T());case 13:return new L(this._$mP(),this._$mP());case 14:return new L(this._$_T(),this._$_T());case 15:for(var o=this._$3L(),e=new Array(o),s=0;s>7-this._$hL++&1)},St.prototype._$zT=function(){0!=this._$hL&&(this._$hL=0)},vt.prototype._$wP=function(t,i,e){for(var r=0;rMath.PI;)e-=2*Math.PI;return e},Lt._$9=function(t){return Math.sin(t)},Lt.fcos=function(t){return Math.cos(t)},Mt.prototype._$u2=function(){return this._$IS[0]},Mt.prototype._$yo=function(){return this._$AT&&!this._$IS[0]},Mt.prototype._$GT=function(){return this._$e0},Et._$W2=0,Et.SYSTEM_INFO=null,Et.USER_AGENT=navigator.userAgent,Et.isIPhone=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone},Et.isIOS=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone||Et.SYSTEM_INFO._isIPad},Et.isAndroid=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isAndroid},Et.getOSVersion=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO.version},Et.getOS=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone||Et.SYSTEM_INFO._isIPad?"iOS":Et.SYSTEM_INFO._isAndroid?"Android":"_$Q0 OS"},Et.setup=function(){function t(t,i){for(var e=t.substring(i).split(/[ _,;\.]/),r=0,o=0;o<=2&&!isNaN(e[o]);o++){var n=parseInt(e[o]);if(n<0||n>999){_._$li("err : "+n+" @UtHtml5.setup()"),r=0;break}r+=n*Math.pow(1e3,2-o)}return r}var i,e=Et.USER_AGENT,r=Et.SYSTEM_INFO={userAgent:e};if((i=e.indexOf("iPhone OS "))>=0)r.os="iPhone",r._isIPhone=!0,r.version=t(e,i+"iPhone OS ".length);else if((i=e.indexOf("iPad"))>=0){if((i=e.indexOf("CPU OS"))<0)return void _._$li(" err : "+e+" @UtHtml5.setup()");r.os="iPad",r._isIPad=!0,r.version=t(e,i+"CPU OS ".length)}else(i=e.indexOf("Android"))>=0?(r.os="Android",r._isAndroid=!0,r.version=t(e,i+"Android ".length)):(r.os="-",r.version=-1)},window.UtSystem=w,window.UtDebug=_,window.LDTransform=gt,window.LDGL=nt,window.Live2D=at,window.Live2DModelWebGL=ft,window.Live2DModelJS=q,window.Live2DMotion=J,window.MotionQueueManager=ct,window.PhysicsHair=f,window.AMotion=s,window.PartsDataID=l,window.DrawDataID=b,window.BaseDataID=yt,window.ParamID=u,at.init();var At=!1}()}).call(i,e(7))},function(t,i){t.exports={import:function(){throw new Error("System.import cannot be used indirectly")}}},function(t,i,e){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(){this.models=[],this.count=-1,this.reloadFlg=!1,Live2D.init(),n.Live2DFramework.setPlatformManager(new _.default)}Object.defineProperty(i,"__esModule",{value:!0}),i.default=o;var n=e(0),s=e(9),_=r(s),a=e(10),h=r(a),l=e(1),$=r(l);o.prototype.createModel=function(){var t=new h.default;return this.models.push(t),t},o.prototype.changeModel=function(t,i){if(this.reloadFlg){this.reloadFlg=!1;this.releaseModel(0,t),this.createModel(),this.models[0].load(t,i)}},o.prototype.getModel=function(t){return t>=this.models.length?null:this.models[t]},o.prototype.releaseModel=function(t,i){this.models.length<=t||(this.models[t].release(i),delete this.models[t],this.models.splice(t,1))},o.prototype.numModels=function(){return this.models.length},o.prototype.setDrag=function(t,i){for(var e=0;e0){r.expressions={};for(var t=0;t +
+ +
+ + + + + + + +
+ `); + // https://stackoverflow.com/questions/24148403/trigger-css-transition-on-appended-element + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + + function randomSelection(obj) { + return Array.isArray(obj) ? obj[Math.floor(Math.random() * obj.length)] : obj; + } + // 检测用户活动状态,并在空闲时显示消息 + let userAction = false, + userActionTimer, + messageTimer, + messageArray = ["好久不见,日子过得好快呢……", "大坏蛋!你都多久没理人家了呀,嘤嘤嘤~", "嗨~快来逗我玩吧!", "拿小拳拳锤你胸口!", "记得把小家加入 Adblock 白名单哦!"]; + window.addEventListener("mousemove", () => userAction = true); + window.addEventListener("keydown", () => userAction = true); + setInterval(() => { + if (userAction) { + userAction = false; + clearInterval(userActionTimer); + userActionTimer = null; + } else if (!userActionTimer) { + userActionTimer = setInterval(() => { + showMessage(randomSelection(messageArray), 6000, 9); + }, 20000); + } + }, 1000); + + (function registerEventListener() { + document.querySelector("#waifu-tool .fa-comment").addEventListener("click", showHitokoto); + document.querySelector("#waifu-tool .fa-paper-plane").addEventListener("click", () => { + if (window.Asteroids) { + if (!window.ASTEROIDSPLAYERS) window.ASTEROIDSPLAYERS = []; + window.ASTEROIDSPLAYERS.push(new Asteroids()); + } else { + let script = document.createElement("script"); + script.src = "https://cdn.jsdelivr.net/gh/GalaxyMimi/CDN/asteroids.js"; + document.head.appendChild(script); + } + }); + document.querySelector("#waifu-tool .fa-user-circle").addEventListener("click", loadOtherModel); + document.querySelector("#waifu-tool .fa-street-view").addEventListener("click", loadRandModel); + document.querySelector("#waifu-tool .fa-camera-retro").addEventListener("click", () => { + showMessage("照好了嘛,是不是很可爱呢?", 6000, 9); + Live2D.captureName = "photo.png"; + Live2D.captureFrame = true; + }); + document.querySelector("#waifu-tool .fa-info-circle").addEventListener("click", () => { + open("https://github.com/stevenjoezhang/live2d-widget"); + }); + document.querySelector("#waifu-tool .fa-times").addEventListener("click", () => { + localStorage.setItem("waifu-display", Date.now()); + showMessage("愿你有一天能与重要的人重逢。", 2000, 11); + document.getElementById("waifu").style.bottom = "-500px"; + setTimeout(() => { + document.getElementById("waifu").style.display = "none"; + document.getElementById("waifu-toggle").classList.add("waifu-toggle-active"); + }, 3000); + }); + let devtools = () => {}; + console.log("%c", devtools); + devtools.toString = () => { + showMessage("哈哈,你打开了控制台,是想要看看我的小秘密吗?", 6000, 9); + }; + window.addEventListener("copy", () => { + showMessage("你都复制了些什么呀,转载要记得加上出处哦!", 6000, 9); + }); + window.addEventListener("visibilitychange", () => { + if (!document.hidden) showMessage("哇,你终于回来了~", 6000, 9); + }); + })(); + + (function welcomeMessage() { + let text; + if (location.pathname === "/") { // 如果是主页 + let now = new Date().getHours(); + if (now > 5 && now <= 7) text = "早上好!一日之计在于晨,美好的一天就要开始了。"; + else if (now > 7 && now <= 11) text = "上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"; + else if (now > 11 && now <= 13) text = "中午了,工作了一个上午,现在是午餐时间!"; + else if (now > 13 && now <= 17) text = "午后很容易犯困呢,今天的运动目标完成了吗?"; + else if (now > 17 && now <= 19) text = "傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"; + else if (now > 19 && now <= 21) text = "晚上好,今天过得怎么样?"; + else if (now > 21 && now <= 23) text = ["已经这么晚了呀,早点休息吧,晚安~", "深夜时要爱护眼睛呀!"]; + else text = "你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"; + } else if (document.referrer !== "") { + let referrer = new URL(document.referrer), + domain = referrer.hostname.split(".")[1]; + if (location.hostname === referrer.hostname) text = `欢迎阅读「${document.title.split(" - ")[0]}」`; + else if (domain === "baidu") text = `Hello!来自 百度搜索 的朋友
你是搜索 ${referrer.search.split("&wd=")[1].split("&")[0]} 找到的我吗?`; + else if (domain === "so") text = `Hello!来自 360搜索 的朋友
你是搜索 ${referrer.search.split("&q=")[1].split("&")[0]} 找到的我吗?`; + else if (domain === "google") text = `Hello!来自 谷歌搜索 的朋友
欢迎阅读「${document.title.split(" - ")[0]}」`; + else text = `Hello!来自 ${referrer.hostname} 的朋友`; + } else { + text = `欢迎阅读「${document.title.split(" - ")[0]}」`; + } + showMessage(text, 7000, 8); + })(); + + function showHitokoto() { + // 增加 hitokoto.cn 的 API + fetch("https://v1.hitokoto.cn") + .then(response => response.json()) + .then(result => { + let text = `这句一言来自 「${result.from}」,是 ${result.creator} 在 hitokoto.cn 投稿的。`; + showMessage(result.hitokoto, 6000, 9); + setTimeout(() => { + showMessage(text, 4000, 9); + }, 6000); + }); + } + + function showMessage(text, timeout, priority) { + if (!text || (sessionStorage.getItem("waifu-text") && sessionStorage.getItem("waifu-text") > priority)) return; + if (messageTimer) { + clearTimeout(messageTimer); + messageTimer = null; + } + text = randomSelection(text); + sessionStorage.setItem("waifu-text", priority); + let tips = document.getElementById("waifu-tips"); + tips.innerHTML = text; + tips.classList.add("waifu-tips-active"); + messageTimer = setTimeout(() => { + sessionStorage.removeItem("waifu-text"); + tips.classList.remove("waifu-tips-active"); + }, timeout); + } + + (function initModel() { + let modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (modelId === null) { + // 首次访问加载 指定模型 的 指定材质 + modelId = 1; // 模型 ID + modelTexturesId = 53; // 材质 ID + } + loadModel(modelId, modelTexturesId); + fetch(waifuPath) + .then(response => response.json()) + .then(result => { + result.mouseover.forEach(tips => { + window.addEventListener("mouseover", event => { + if (!event.target.matches(tips.selector)) return; + let text = randomSelection(tips.text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + }); + }); + result.click.forEach(tips => { + window.addEventListener("click", event => { + if (!event.target.matches(tips.selector)) return; + let text = randomSelection(tips.text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + }); + }); + result.seasons.forEach(tips => { + let now = new Date(), + after = tips.date.split("-")[0], + before = tips.date.split("-")[1] || after; + if ((after.split("/")[0] <= now.getMonth() + 1 && now.getMonth() + 1 <= before.split("/")[0]) && (after.split("/")[1] <= now.getDate() && now.getDate() <= before.split("/")[1])) { + let text = randomSelection(tips.text); + text = text.replace("{year}", now.getFullYear()); + //showMessage(text, 7000, true); + messageArray.push(text); + } + }); + }); + })(); + + async function loadModelList() { + let response = await fetch(`${cdnPath}model_list.json`); + let result = await response.json(); + modelList = result; + } + + async function loadModel(modelId, modelTexturesId, message) { + localStorage.setItem("modelId", modelId); + localStorage.setItem("modelTexturesId", modelTexturesId); + showMessage(message, 4000, 10); + if (useCDN) { + if (!modelList) await loadModelList(); + let target = randomSelection(modelList.models[modelId]); + loadlive2d("live2d", `${cdnPath}model/${target}/index.json`); + } else { + loadlive2d("live2d", `${apiPath}get/?id=${modelId}-${modelTexturesId}`); + console.log(`Live2D 模型 ${modelId}-${modelTexturesId} 加载完成`); + } + } + + async function loadRandModel() { + let modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (useCDN) { + if (!modelList) await loadModelList(); + let target = randomSelection(modelList.models[modelId]); + loadlive2d("live2d", `${cdnPath}model/${target}/index.json`); + showMessage("我的新衣服好看嘛?", 4000, 10); + } else { + // 可选 "rand"(随机), "switch"(顺序) + fetch(`${apiPath}rand_textures/?id=${modelId}-${modelTexturesId}`) + .then(response => response.json()) + .then(result => { + if (result.textures.id === 1 && (modelTexturesId === 1 || modelTexturesId === 0)) showMessage("我还没有其他衣服呢!", 4000, 10); + else loadModel(modelId, result.textures.id, "我的新衣服好看嘛?"); + }); + } + } + + async function loadOtherModel() { + let modelId = localStorage.getItem("modelId"); + if (useCDN) { + if (!modelList) await loadModelList(); + let index = (++modelId >= modelList.models.length) ? 0 : modelId; + loadModel(index, 0, modelList.messages[index]); + } else { + fetch(`${apiPath}switch/?id=${modelId}`) + .then(response => response.json()) + .then(result => { + loadModel(result.model.id, 0, result.model.message); + }); + } + } +} + +function initWidget(config, apiPath = "/") { + if (typeof config === "string") { + config = { + waifuPath: config, + apiPath + }; + } + document.body.insertAdjacentHTML("beforeend", `
+ 看板娘 +
`); + let toggle = document.getElementById("waifu-toggle"); + toggle.addEventListener("click", () => { + toggle.classList.remove("waifu-toggle-active"); + if (toggle.getAttribute("first-time")) { + loadWidget(config); + toggle.removeAttribute("first-time"); + } else { + localStorage.removeItem("waifu-display"); + document.getElementById("waifu").style.display = ""; + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + } + }); + if (localStorage.getItem("waifu-display") && Date.now() - localStorage.getItem("waifu-display") <= 86400000) { + toggle.setAttribute("first-time", true); + setTimeout(() => { + toggle.classList.add("waifu-toggle-active"); + }, 0); + } else { + loadWidget(config); + } +} diff --git a/live2d-widget-old/waifu-tips.json b/live2d-widget-old/waifu-tips.json new file mode 100644 index 00000000..3073eda3 --- /dev/null +++ b/live2d-widget-old/waifu-tips.json @@ -0,0 +1 @@ +{"mouseover":[{"selector":"#waifu #live2d","text":["干嘛呢你,快把手拿开~~","鼠…鼠标放错地方了!","你要干嘛呀?","喵喵喵?","怕怕(ノ≧∇≦)ノ","非礼呀!救命!","这样的话,只能使用武力了!","我要生气了哦","不要动手动脚的!","真…真的是不知羞耻!","Hentai!"]},{"selector":"#waifu-tool .fa-comment","text":["猜猜我要说些什么?","我从青蛙王子那里听到了不少人生经验。"]},{"selector":"#waifu-tool .fa-paper-plane","text":["要不要来玩飞机大战?","这个按钮上写着「不要点击」。","怎么,你想来和我玩个游戏?","听说这样可以蹦迪!"]},{"selector":"#waifu-tool .fa-user-circle","text":["你是不是不爱人家了呀,呜呜呜~","要见见我的姐姐嘛?","想要看我妹妹嘛?","要切换看板娘吗?"]},{"selector":"#waifu-tool .fa-street-view","text":["喜欢换装 PLAY 吗?","这次要扮演什么呢?","变装!","让我们看看接下来会发生什么!"]},{"selector":"#waifu-tool .fa-camera-retro","text":["你要给我拍照呀?一二三~茄子~","要不,我们来合影吧!","保持微笑就好了~"]},{"selector":"#waifu-tool .fa-info-circle","text":["想要知道更多关于我的事么?","这里记录着我搬家的历史呢。","你想深入了解我什么呢?"]},{"selector":"#waifu-tool .fa-times","text":["到了要说再见的时候了吗?","呜呜 QAQ 后会有期……","不要抛弃我呀……","我们,还能再见面吗……","哼,你会后悔的!"]},{"selector":".menu-item-home","text":["点击前往首页,想回到上一页可以使用浏览器的后退功能哦。","点它就可以回到首页啦!","回首页看看吧。"]},{"selector":".menu-item-about","text":["你想知道我家主人是谁吗?","这里有一些关于我家主人的秘密哦,要不要看看呢?","发现主人出没地点!"]},{"selector":".menu-item-tags","text":["点击就可以看文章的标签啦!","点击来查看所有标签哦。","快看看这里都有什么呢!"]},{"selector":".menu-item-categories","text":["文章都分类好啦~","点击来查看文章分类哦。","快看看这里都有什么呢!"]},{"selector":".menu-item-archives","text":["翻页比较麻烦吗,那就来看看文章归档吧。","文章目录都整理在这里啦!","快看看这里都有什么呢?"]},{"selector":".menu-item-friends","text":["这是我的朋友们哦ヾ(◍°∇°◍)ノ゙","要去大佬们的家看看吗?","要去拜访一下我的朋友们吗?"]},{"selector":".menu-item-search","text":["找不到想看的内容?搜索看看吧!","在找什么东西呢,需要帮忙吗?"]},{"selector":".site-author","text":["我家主人好看吗?","这是我家主人(*´∇`*)"]},{"selector":".site-state","text":["这是文章的统计信息~","要不要点进去看看?"]},{"selector":".feed-link a","text":["这里可以使用 RSS 订阅呢!","利用 feed 订阅器,就能快速知道博客有没有更新了呢。"]},{"selector":".cc-opacity, .post-copyright-author","text":["要记得规范转载哦。","所有文章均采用 CC BY-NC-SA 4.0 许可协议~","转载前要先注意下文章的版权协议呢。"]},{"selector":".links-of-author","text":["这里是主人的常驻地址哦。","这里有主人的联系方式!"]},{"selector":"#qrcode","text":["手机扫一下就能继续看,很方便呢~","扫一扫,打开新世界的大门!"]},{"selector":".fancybox img, img.medium-zoom-image","text":["点击图片可以放大呢!"]},{"selector":".highlight, .gist","text":["代码可以直接点击复制哟。","GitHub!我是新手!","PHP 是最好的语言!"]},{"selector":".container a[href^='http'], .nav-link .nav-text","text":["要去看看 {text} 么?","去 {text} 逛逛吧。","到 {text} 看看吧。"]},{"selector":"a[href^='mailto']","text":["邮件我会及时回复的!","点击就可以发送邮件啦~"]},{"selector":"a[href^='/tags/']","text":["要去看看 {text} 标签么?","点它可以查看此标签下的所有文章哟!"]},{"selector":"a[href^='/categories/']","text":["要去看看 {text} 分类么?","点它可以查看此分类下的所有文章哟!"]},{"selector":".post-title-link","text":["要看看 {text} 这篇文章吗?"]},{"selector":"a[rel='contents']","text":["点击来阅读全文哦。"]},{"selector":"a[itemprop='discussionUrl']","text":["要去看看评论吗?"]},{"selector":".back-to-top","text":["点它就可以回到顶部啦!","又回到最初的起点~","要回到开始的地方么?"]},{"selector":".reward-container","text":["我是不是棒棒哒~快给我点赞吧!","要打赏我嘛?好期待啊~","主人最近在吃土呢,很辛苦的样子,给他一些钱钱吧~"]},{"selector":"#wechat","text":["这是我的微信二维码~"]},{"selector":"#alipay","text":["这是我的支付宝哦!"]},{"selector":"#bitcoin","text":["这是我的比特币账号!"]},{"selector":"#needsharebutton-postbottom .btn","text":["好东西要让更多人知道才行哦。","觉得文章有帮助的话,可以分享给更多需要的朋友呢。"]},{"selector":".need-share-button_weibo","text":["微博?来分享一波喵!"]},{"selector":".need-share-button_wechat","text":["分享到微信吧!"]},{"selector":".need-share-button_douban","text":["分享到豆瓣好像也不错!"]},{"selector":".need-share-button_qqzone","text":["QQ 空间,一键转发,耶~"]},{"selector":".need-share-button_twitter","text":["Twitter?好像是不存在的东西?"]},{"selector":".need-share-button_facebook","text":["emmm…FB 好像也是不存在的东西?"]},{"selector":".post-nav-item a[rel='next']","text":["来看看下一篇文章吧。","点它可以看下一篇文章哦!","要翻到下一篇文章吗?"]},{"selector":".post-nav-item a[rel='prev']","text":["来看看上一篇文章吧。","点它可以看上一篇文章哦!","要翻到上一篇文章吗?"]},{"selector":".extend.next","text":["去下一页看看吧。","点它可以前进哦!","要翻到下一页吗?"]},{"selector":".extend.prev","text":["去上一页看看吧。","点它可以后退哦!","要翻到上一页吗?"]},{"selector":"input.vnick","text":["该怎么称呼你呢?","留下你的尊姓大名!"]},{"selector":".vmail","text":["留下你的邮箱,不然就是无头像人士了!","记得设置好 Gravatar 头像哦!","为了方便通知你最新消息,一定要留下邮箱!"]},{"selector":".vlink","text":["快快告诉我你的家在哪里,好让我去参观参观!"]},{"selector":".veditor","text":["想要去评论些什么吗?","要说点什么吗?","觉得博客不错?快来留言和主人交流吧!"]},{"selector":".vcontrol a","text":["你会不会熟练使用 Markdown 呀?","使用 Markdown 让评论更美观吧~"]},{"selector":".vemoji-btn","text":["要插入一个萌萌哒的表情吗?","要来一发表情吗?"]},{"selector":".vpreview-btn","text":["要预览一下你的发言吗?","快看看你的评论有多少负熵!"]},{"selector":".vsubmit","text":["评论没有审核,要对自己的发言负责哦~","要提交了吗,请耐心等待回复哦~"]},{"selector":".vcontent","text":["哇,快看看这个精彩评论!","如果有疑问,请尽快留言哦~"]}],"click":[{"selector":"#waifu #live2d","text":["是…是不小心碰到了吧…","萝莉控是什么呀?","你看到我的小熊了吗?","再摸的话我可要报警了!⌇●﹏●⌇","110 吗,这里有个变态一直在摸我(ó﹏ò。)","不要摸我了,我会告诉老婆来打你的!","干嘛动我呀!小心我咬你!","别摸我,有什么好摸的!"]},{"selector":".veditor","text":["要吐槽些什么呢?","一定要认真填写喵~","有什么想说的吗?"]},{"selector":".vsubmit","text":["输入验证码就可以提交评论啦~"]}],"seasons":[{"date":"01/01","text":"元旦了呢,新的一年又开始了,今年是{year}年~"},{"date":"02/14","text":"又是一年情人节,{year}年找到对象了嘛~"},{"date":"03/08","text":"今天是国际妇女节!"},{"date":"03/12","text":"今天是植树节,要保护环境呀!"},{"date":"04/01","text":"悄悄告诉你一个秘密~今天是愚人节,不要被骗了哦~"},{"date":"05/01","text":"今天是五一劳动节,计划好假期去哪里了吗~"},{"date":"06/01","text":"儿童节了呢,快活的时光总是短暂,要是永远长不大该多好啊…"},{"date":"09/03","text":"中国人民抗日战争胜利纪念日,铭记历史、缅怀先烈、珍爱和平、开创未来。"},{"date":"09/10","text":"教师节,在学校要给老师问声好呀~"},{"date":"10/01","text":"国庆节到了,为祖国母亲庆生!"},{"date":"11/05-11/12","text":"今年的双十一是和谁一起过的呢~"},{"date":"12/20-12/31","text":"这几天是圣诞节,主人肯定又去剁手买买买了~"}]} \ No newline at end of file diff --git a/live2d-widget-old/waifu.css b/live2d-widget-old/waifu.css new file mode 100644 index 00000000..e4a88d58 --- /dev/null +++ b/live2d-widget-old/waifu.css @@ -0,0 +1,312 @@ +#waifu-toggle { + background-color: #fa0; + border-radius: 5px; + bottom: 66px; + color: #fff; + cursor: pointer; + font-size: 12px; + left: 0; + margin-left: -100px; + padding: 5px 2px 5px 5px; + position: fixed; + transition: margin-left 1s; + width: 60px; + writing-mode: vertical-rl; +} + +#waifu-toggle.waifu-toggle-active { + margin-left: -50px; +} + +#waifu-toggle.waifu-toggle-active:hover { + margin-left: -30px; +} + +#waifu { + bottom: -10px; + right: 100px; + line-height: 0; + position: fixed; + transform: translateY(3px); + transition: transform .3s ease-in-out, bottom 3s ease-in-out; + z-index: 1; +} + +#waifu:hover { + transform: translateY(0); +} + +@media (max-width: 768px) { + #waifu { + display: none; + } +} + +#waifu-tips { + animation: shake 50s ease-in-out 5s infinite; + background-color: rgba(236, 217, 188, .5); + border: 1px solid rgba(224, 186, 140, .62); + border-radius: 12px; + box-shadow: 0 3px 15px 2px rgba(191, 158, 118, .2); + font-size: 14px; + line-height: 24px; + margin: -30px 20px; + min-height: 70px; + opacity: 0; + overflow: hidden; + padding: 5px 10px; + position: absolute; + text-overflow: ellipsis; + transition: opacity 1s; + width: 250px; + word-break: break-all; +} + +#waifu-tips.waifu-tips-active { + opacity: 1; + transition: opacity .2s; +} + +#waifu-tips span { + color: #0099cc; +} + +#waifu #live2d { + cursor: grab; + position: relative; + bottom: -10px; + height: 240px; + width: 240px; +} + +#waifu #live2d:active { + cursor: grabbing; +} + +#waifu-tool { + color: #aaa; + opacity: 0; + position: absolute; + right: 0px; + top: 10px; + transition: opacity 1s; +} + +#waifu:hover #waifu-tool { + opacity: 1; +} + +#waifu-tool span { + color: #5b6c7d; + cursor: pointer; + display: block; + line-height: 30px; + text-align: center; + transition: color .3s; +} + +#waifu-tool span:hover { + color: #0684bd; /* #34495e */ +} + +@keyframes shake { + 2% { + transform: translate(.5px, -1.5px) rotate(-.5deg); + } + + 4% { + transform: translate(.5px, 1.5px) rotate(1.5deg); + } + + 6% { + transform: translate(1.5px, 1.5px) rotate(1.5deg); + } + + 8% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 10% { + transform: translate(.5px, 2.5px) rotate(.5deg); + } + + 12% { + transform: translate(1.5px, 1.5px) rotate(.5deg); + } + + 14% { + transform: translate(.5px, .5px) rotate(.5deg); + } + + 16% { + transform: translate(-1.5px, -.5px) rotate(1.5deg); + } + + 18% { + transform: translate(.5px, .5px) rotate(1.5deg); + } + + 20% { + transform: translate(2.5px, 2.5px) rotate(1.5deg); + } + + 22% { + transform: translate(.5px, -1.5px) rotate(1.5deg); + } + + 24% { + transform: translate(-1.5px, 1.5px) rotate(-.5deg); + } + + 26% { + transform: translate(1.5px, .5px) rotate(1.5deg); + } + + 28% { + transform: translate(-.5px, -.5px) rotate(-.5deg); + } + + 30% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 32% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 34% { + transform: translate(2.5px, 2.5px) rotate(-.5deg); + } + + 36% { + transform: translate(.5px, -1.5px) rotate(.5deg); + } + + 38% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 40% { + transform: translate(-.5px, 2.5px) rotate(.5deg); + } + + 42% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 44% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 46% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 48% { + transform: translate(2.5px, -.5px) rotate(.5deg); + } + + 50% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 52% { + transform: translate(-.5px, 1.5px) rotate(.5deg); + } + + 54% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 56% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 58% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 60% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 62% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 64% { + transform: translate(-1.5px, 1.5px) rotate(1.5deg); + } + + 66% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 68% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 70% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 72% { + transform: translate(-.5px, -1.5px) rotate(1.5deg); + } + + 74% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 76% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 78% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 80% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 82% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 84% { + transform: translate(-.5px, .5px) rotate(1.5deg); + } + + 86% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 88% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 90% { + transform: translate(-1.5px, -.5px) rotate(-.5deg); + } + + 92% { + transform: translate(-1.5px, -1.5px) rotate(1.5deg); + } + + 94% { + transform: translate(.5px, .5px) rotate(-.5deg); + } + + 96% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 98% { + transform: translate(-1.5px, -1.5px) rotate(-.5deg); + } + + 0%, 100% { + transform: translate(0, 0) rotate(0); + } +} diff --git a/live2d-widget/LICENSE b/live2d-widget/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/live2d-widget/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/live2d-widget/README.html b/live2d-widget/README.html new file mode 100644 index 00000000..5e805077 --- /dev/null +++ b/live2d-widget/README.html @@ -0,0 +1,116 @@ +

Live2D Widget






+

特性 Feature

在网页中添加 Live2D 看板娘。兼容 PJAX,支持无刷新加载。
Add Live2D widget to web page. Compatible with PJAX.

+

+

(注:以上人物模型仅供展示之用,本仓库并不包含任何模型。)

+

你也可以查看示例网页:

+ +

使用 Usage

如果你是小白,或者只需要最基础的功能,那么只用将这一行代码加入 html 页面的 headbody 中,即可加载看板娘:

+
<script src="https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/autoload.js"></script>
+
+

添加代码的位置取决于你的网站的构建方式。例如,如果你使用的是 Hexo,那么需要在主题的模版文件中添加以上代码。对于用各种模版引擎生成的页面,修改方法类似。
如果网站启用了 PJAX,由于看板娘不必每页刷新,需要注意将该脚本放到 PJAX 刷新区域之外。

+

但是!我们强烈推荐自己进行配置,让看板娘更加适合你的网站!
如果你有兴趣自己折腾的话,请看下面的详细说明。

+

配置 Configuration

你可以对照 autoload.js 的源码查看可选的配置项目。autoload.js 会自动加载三个文件:waifu.csslive2d.min.jswaifu-tips.jswaifu-tips.js 会创建 initWidget 函数,这就是加载看板娘的主函数。initWidget 函数接收一个 Object 类型的参数,作为看板娘的配置。以下是配置选项:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
选项类型默认值说明
waifuPathstringhttps://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/waifu-tips.json看板娘资源路径,可自行修改
apiPathstringhttps://live2d.fghrsh.net/api/API 路径,可选参数
cdnPathstringhttps://fastly.jsdelivr.net/gh/fghrsh/live2d_api/CDN 路径,可选参数
toolsstring[]autoload.js加载的小工具按钮,可选参数
+

其中,apiPathcdnPath 两个参数设置其中一项即可。apiPath 是后端 API 的 URL,可以自行搭建,并增加模型(需要修改的内容比较多,此处不再赘述),可以参考 live2d_api。而 cdnPath 则是通过 jsDelivr 这样的 CDN 服务加载资源,更加稳定。

+

自定义 Customization

如果以上「配置」部分提供的选项还不足以满足你的需求,那么你可以自己进行修改。本仓库的目录结构如下:

+
    +
  • src/waifu-tips.js 包含了按钮和对话框的逻辑;
  • +
  • waifu-tips.js 是由 src/waifu-tips.js 自动打包生成的,不建议直接修改;
  • +
  • waifu-tips.json 中定义了触发条件(selector,CSS 选择器)和触发时显示的文字(text);
  • +
  • waifu.css 是看板娘的样式表。
  • +
+

waifu-tips.json 中默认的 CSS 选择器规则是对 Hexo 的 NexT 主题 有效的,为了适用于你自己的网页,可能需要自行修改,或增加新内容。
警告:waifu-tips.json 中的内容可能不适合所有年龄段,或不宜在工作期间访问。在使用时,请自行确保它们是合适的。

+

要在本地部署本项目的开发测试环境,你需要安装 Node.js 和 npm,然后执行以下命令:

+
git clone https://github.com/stevenjoezhang/live2d-widget.git
+npm install
+npm run build
+
+

如果有任何疑问,欢迎提 Issue。如果有任何修改建议,欢迎提 Pull Request。

+

部署 Deploy

在本地完成了修改后,你可以将修改后的项目部署在服务器上,或者通过 CDN 加载,以便在网页中使用。

+

Using CDN

要自定义有关内容,可以把这个仓库 Fork 一份,然后把修改后的内容通过 git push 到你的仓库中。这时,使用方法对应地变为

+
<script src="https://fastly.jsdelivr.net/gh/username/live2d-widget@latest/autoload.js"></script>
+
+

将此处的 username 替换为你的 GitHub 用户名。为了使 CDN 的内容正常刷新,需要创建新的 git tag 并推送至 GitHub 仓库中,否则此处的 @latest 仍然指向更新前的文件。此外 CDN 本身存在缓存,因此改动可能需要一定的时间生效。相关文档:

+ +

Self-host

你也可以直接把这些文件放到服务器上,而不是通过 CDN 加载。

+
    +
  • 如果你能够通过 ssh 连接你的主机,请把 Fork 并修改后的代码仓库克隆到服务器上。
  • +
  • 如果你的主机无法用 ssh 连接(例如一般的虚拟主机),请在本地修改好代码后,通过 ftp 等方式将文件上传到主机的网站的目录下。
  • +
  • 如果你是通过 Hexo 等工具部署的静态博客,请把本项目的代码放在博客源文件目录下(例如 source 目录)。重新部署博客时,相关文件就会自动上传到对应的路径下。为了避免这些文件被 Hexo 插件错误地修改,可能需要设置 skip_render
  • +
+

这样,整个项目就可以通过你的域名访问了。不妨试试能否正常地通过浏览器打开 autoload.jslive2d.min.js 等文件,并确认这些文件的内容是完整和正确的。
一切正常的话,接下来修改 autoload.js 中的常量 live2d_pathlive2d-widget 这一目录的 URL 即可。比如说,如果你能够通过

+
https://example.com/path/to/live2d-widget/live2d.min.js
+
+

访问到 live2d.min.js,那么就把 live2d_path 的值修改为

+
https://example.com/path/to/live2d-widget/
+
+

路径末尾的 / 一定要加上。
完成后,在你要添加看板娘的界面加入

+
<script src="https://example.com/path/to/live2d-widget/autoload.js"></script>
+
+

就可以加载了。

+

鸣谢 Thanks

BrowserStack Logo

+
+

感谢 BrowserStack 容许我们在真实的浏览器中测试此项目。
Thanks to BrowserStack for providing the infrastructure that allows us to test in real browsers!

+
+

+
+

感谢 jsDelivr 提供的 CDN 服务。
Thanks jsDelivr for providing public CDN service.

+
+

代码自这篇博文魔改而来:
https://www.fghrsh.net/post/123.html

+

感谢 一言 提供的语句接口。

+

点击看板娘的纸飞机按钮时,会出现一个彩蛋,这来自于 WebsiteAsteroids

+

更多 More

更多内容可以参考:
https://nocilol.me/archives/lab/add-dynamic-poster-girl-with-live2d-to-your-blog-02
https://github.com/xiazeyu/live2d-widget.js
https://github.com/summerscar/live2dDemo

+

关于后端 API 模型:
https://github.com/xiazeyu/live2d-widget-models
https://github.com/xiaoski/live2d_models_collection

+

除此之外,还有桌面版本:
https://github.com/amorist/platelet
https://github.com/akiroz/Live2D-Widget
https://github.com/zenghongtu/PPet
https://github.com/LikeNeko/L2dPetForMac

+

以及 Wallpaper Engine:
https://github.com/guansss/nep-live2d

+

许可证 License

Released under the GNU General Public License v3
http://www.gnu.org/licenses/gpl-3.0.html

+

本仓库并不包含任何模型,用作展示的所有 Live2D 模型、图片、动作数据等版权均属于其原作者,仅供研究学习,不得用于商业用途。

+

Live2D 官方网站:
https://www.live2d.com/en/
https://live2d.github.io

+

Live2D Cubism Core は Live2D Proprietary Software License で提供しています。
https://www.live2d.com/eula/live2d-proprietary-software-license-agreement_en.html
Live2D Cubism Components は Live2D Open Software License で提供しています。
http://www.live2d.com/eula/live2d-open-software-license-agreement_en.html

+
+

The terms and conditions do prohibit modification, but obfuscating in live2d.min.js would not be considered illegal modification.

+
+

https://community.live2d.com/discussion/140/webgl-developer-licence-and-javascript-question

+

更新 Update

2018年10月31日,由 fghrsh 提供的原 API 停用,请更新至新地址。参考文章:
https://www.fghrsh.net/post/170.html

+

2020年1月1日起,本项目不再依赖于 jQuery。

+

2022年11月1日起,本项目不再需要用户单独加载 Font Awesome。

diff --git a/live2d-widget/assets/screenshot-1.png b/live2d-widget/assets/screenshot-1.png new file mode 100644 index 00000000..8ac6f90b Binary files /dev/null and b/live2d-widget/assets/screenshot-1.png differ diff --git a/live2d-widget/assets/screenshot-2.png b/live2d-widget/assets/screenshot-2.png new file mode 100644 index 00000000..41497545 Binary files /dev/null and b/live2d-widget/assets/screenshot-2.png differ diff --git a/live2d-widget/assets/screenshot-3.png b/live2d-widget/assets/screenshot-3.png new file mode 100644 index 00000000..231f6a74 Binary files /dev/null and b/live2d-widget/assets/screenshot-3.png differ diff --git a/live2d-widget/autoload.js b/live2d-widget/autoload.js new file mode 100644 index 00000000..43198ac9 --- /dev/null +++ b/live2d-widget/autoload.js @@ -0,0 +1,78 @@ +// live2d_path 参数建议使用绝对路径 +// const live2d_path = "https://fastly.jsdelivr.net/gh/stevenjoezhang/live2d-widget@latest/"; +const live2d_path = "/live2d-widget/"; + +// 封装异步加载资源的方法 +function loadExternalResource(url, type) { + return new Promise((resolve, reject) => { + let tag; + + if (type === "css") { + tag = document.createElement("link"); + tag.rel = "stylesheet"; + tag.href = url; + } + else if (type === "js") { + tag = document.createElement("script"); + tag.src = url; + } + if (tag) { + tag.onload = () => resolve(url); + tag.onerror = () => reject(url); + document.head.appendChild(tag); + } + }); +} + + +Promise.all([ + loadExternalResource(live2d_path + "waifu.css", "css"), + loadExternalResource(live2d_path + "live2d.min.js", "js"), + loadExternalResource(live2d_path + "waifu-tips.js", "js") +]).then(() => { + // 配置选项的具体用法见 README.md + initWidget({ + waifuPath: live2d_path + "waifu-tips.json", + apiPath: "https://live2d.fghrsh.net/api/", + // cdnPath: "https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/", + tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"] + }); +}); + + +// 加载 waifu.css live2d.min.js waifu-tips.js +// if (screen.width >= 768) { +// Promise.all([ +// loadExternalResource(live2d_path + "waifu.css", "css"), +// loadExternalResource(live2d_path + "live2d.min.js", "js"), +// loadExternalResource(live2d_path + "waifu-tips.js", "js") +// ]).then(() => { +// // 配置选项的具体用法见 README.md +// initWidget({ +// waifuPath: live2d_path + "waifu-tips.json", +// apiPath: "https://live2d.fghrsh.net/api/", +// // cdnPath: "https://fastly.jsdelivr.net/gh/fghrsh/live2d_api/", +// tools: ["hitokoto", "asteroids", "switch-model", "switch-texture", "photo", "info", "quit"] +// }); +// }); +// } + +console.log(` + く__,.ヘヽ. / ,ー、 〉 + \ ', !-─‐-i / /´ + /`ー' L//`ヽ、 + / /, /| , , ', + イ / /-‐/ i L_ ハ ヽ! i + レ ヘ 7イ`ト レ'ァ-ト、!ハ| | + !,/7 '0' ´0iソ| | + |.从" _ ,,,, / |./ | + レ'| i>.、,,__ _,.イ / .i | + レ'| | / k_7_/レ'ヽ, ハ. | + | |/i 〈|/ i ,.ヘ | i | + .|/ / i: ヘ! \ | + kヽ>、ハ _,.ヘ、 /、! + !'〈//`T´', \ `'7'ーr' + レ'ヽL__|___i,___,ンレ|ノ + ト-,/ |___./ + 'ー' !_,.: +`); diff --git a/live2d-widget/demo/demo.html b/live2d-widget/demo/demo.html new file mode 100644 index 00000000..ddf85409 --- /dev/null +++ b/live2d-widget/demo/demo.html @@ -0,0 +1,35 @@ + + + + +Live2D 看板娘 / Demo + + + + + + + + + + diff --git a/live2d-widget/demo/login.html b/live2d-widget/demo/login.html new file mode 100644 index 00000000..4145327e --- /dev/null +++ b/live2d-widget/demo/login.html @@ -0,0 +1,289 @@ + + + + + +看板娘登陆平台 + + + + + + + + + + + + + + + + + + diff --git a/live2d-widget/live2d.min.js b/live2d-widget/live2d.min.js new file mode 100644 index 00000000..8915e1d0 --- /dev/null +++ b/live2d-widget/live2d.min.js @@ -0,0 +1 @@ +!function(t){function i(r){if(e[r])return e[r].exports;var o=e[r]={i:r,l:!1,exports:{}};return t[r].call(o.exports,o,o.exports,i),o.l=!0,o.exports}var e={};i.m=t,i.c=e,i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:r})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,i){return Object.prototype.hasOwnProperty.call(t,i)},i.p="",i(i.s=4)}([function(t,i,e){"use strict";function r(){this.live2DModel=null,this.modelMatrix=null,this.eyeBlink=null,this.physics=null,this.pose=null,this.debugMode=!1,this.initialized=!1,this.updating=!1,this.alpha=1,this.accAlpha=0,this.lipSync=!1,this.lipSyncValue=0,this.accelX=0,this.accelY=0,this.accelZ=0,this.dragX=0,this.dragY=0,this.startTimeMSec=null,this.mainMotionManager=new h,this.expressionManager=new h,this.motions={},this.expressions={},this.isTexLoaded=!1}function o(){AMotion.prototype.constructor.call(this),this.paramList=new Array}function n(){this.id="",this.type=-1,this.value=null}function s(){this.nextBlinkTime=null,this.stateStartTime=null,this.blinkIntervalMsec=null,this.eyeState=g.STATE_FIRST,this.blinkIntervalMsec=4e3,this.closingMotionMsec=100,this.closedMotionMsec=50,this.openingMotionMsec=150,this.closeIfZero=!0,this.eyeID_L="PARAM_EYE_L_OPEN",this.eyeID_R="PARAM_EYE_R_OPEN"}function _(){this.tr=new Float32Array(16),this.identity()}function a(t,i){_.prototype.constructor.call(this),this.width=t,this.height=i}function h(){MotionQueueManager.prototype.constructor.call(this),this.currentPriority=null,this.reservePriority=null,this.super=MotionQueueManager.prototype}function l(){this.physicsList=new Array,this.startTimeMSec=UtSystem.getUserTimeMSec()}function $(){this.lastTime=0,this.lastModel=null,this.partsGroups=new Array}function u(t){this.paramIndex=-1,this.partsIndex=-1,this.link=null,this.id=t}function p(){this.EPSILON=.01,this.faceTargetX=0,this.faceTargetY=0,this.faceX=0,this.faceY=0,this.faceVX=0,this.faceVY=0,this.lastTimeSec=0}function f(){_.prototype.constructor.call(this),this.screenLeft=null,this.screenRight=null,this.screenTop=null,this.screenBottom=null,this.maxLeft=null,this.maxRight=null,this.maxTop=null,this.maxBottom=null,this.max=Number.MAX_VALUE,this.min=0}function c(){}var d=0;r.prototype.getModelMatrix=function(){return this.modelMatrix},r.prototype.setAlpha=function(t){t>.999&&(t=1),t<.001&&(t=0),this.alpha=t},r.prototype.getAlpha=function(){return this.alpha},r.prototype.isInitialized=function(){return this.initialized},r.prototype.setInitialized=function(t){this.initialized=t},r.prototype.isUpdating=function(){return this.updating},r.prototype.setUpdating=function(t){this.updating=t},r.prototype.getLive2DModel=function(){return this.live2DModel},r.prototype.setLipSync=function(t){this.lipSync=t},r.prototype.setLipSyncValue=function(t){this.lipSyncValue=t},r.prototype.setAccel=function(t,i,e){this.accelX=t,this.accelY=i,this.accelZ=e},r.prototype.setDrag=function(t,i){this.dragX=t,this.dragY=i},r.prototype.getMainMotionManager=function(){return this.mainMotionManager},r.prototype.getExpressionManager=function(){return this.expressionManager},r.prototype.loadModelData=function(t,i){var e=c.getPlatformManager();this.debugMode&&e.log("Load model : "+t);var r=this;e.loadLive2DModel(t,function(t){if(r.live2DModel=t,r.live2DModel.saveParam(),0!=Live2D.getError())return void console.error("Error : Failed to loadModelData().");r.modelMatrix=new a(r.live2DModel.getCanvasWidth(),r.live2DModel.getCanvasHeight()),r.modelMatrix.setWidth(2),r.modelMatrix.setCenterPosition(0,0),i(r.live2DModel)})},r.prototype.loadTexture=function(t,i,e){d++;var r=c.getPlatformManager();this.debugMode&&r.log("Load Texture : "+i);var o=this;r.loadTexture(this.live2DModel,t,i,function(){d--,0==d&&(o.isTexLoaded=!0),"function"==typeof e&&e()})},r.prototype.loadMotion=function(t,i,e){var r=c.getPlatformManager();this.debugMode&&r.log("Load Motion : "+i);var o=null,n=this;r.loadBytes(i,function(i){o=Live2DMotion.loadMotion(i),null!=t&&(n.motions[t]=o),e(o)})},r.prototype.loadExpression=function(t,i,e){var r=c.getPlatformManager();this.debugMode&&r.log("Load Expression : "+i);var n=this;r.loadBytes(i,function(i){null!=t&&(n.expressions[t]=o.loadJson(i)),"function"==typeof e&&e()})},r.prototype.loadPose=function(t,i){var e=c.getPlatformManager();this.debugMode&&e.log("Load Pose : "+t);var r=this;try{e.loadBytes(t,function(t){r.pose=$.load(t),"function"==typeof i&&i()})}catch(t){console.warn(t)}},r.prototype.loadPhysics=function(t){var i=c.getPlatformManager();this.debugMode&&i.log("Load Physics : "+t);var e=this;try{i.loadBytes(t,function(t){e.physics=l.load(t)})}catch(t){console.warn(t)}},r.prototype.hitTestSimple=function(t,i,e){if(null===this.live2DModel)return!1;var r=this.live2DModel.getDrawDataIndex(t);if(r<0)return!1;for(var o=this.live2DModel.getTransformedPoints(r),n=this.live2DModel.getCanvasWidth(),s=0,_=this.live2DModel.getCanvasHeight(),a=0,h=0;hs&&(s=l),$<_&&(_=$),$>a&&(a=$)}var u=this.modelMatrix.invertTransformX(i),p=this.modelMatrix.invertTransformY(e);return n<=u&&u<=s&&_<=p&&p<=a},r.prototype.hitTestSimpleCustom=function(t,i,e,r){return null!==this.live2DModel&&(e>=t[0]&&e<=i[0]&&r<=t[1]&&r>=i[1])},o.prototype=new AMotion,o.EXPRESSION_DEFAULT="DEFAULT",o.TYPE_SET=0,o.TYPE_ADD=1,o.TYPE_MULT=2,o.loadJson=function(t){var i=new o,e=c.getPlatformManager(),r=e.jsonParseFromBytes(t);if(i.setFadeIn(parseInt(r.fade_in)>0?parseInt(r.fade_in):1e3),i.setFadeOut(parseInt(r.fade_out)>0?parseInt(r.fade_out):1e3),null==r.params)return i;var s=r.params,_=s.length;i.paramList=[];for(var a=0;a<_;a++){var h=s[a],l=h.id.toString(),$=parseFloat(h.val),u=o.TYPE_ADD,p=null!=h.calc?h.calc.toString():"add";if((u="add"===p?o.TYPE_ADD:"mult"===p?o.TYPE_MULT:"set"===p?o.TYPE_SET:o.TYPE_ADD)==o.TYPE_ADD){var f=null==h.def?0:parseFloat(h.def);$-=f}else if(u==o.TYPE_MULT){var f=null==h.def?1:parseFloat(h.def);0==f&&(f=1),$/=f}var d=new n;d.id=l,d.type=u,d.value=$,i.paramList.push(d)}return i},o.prototype.updateParamExe=function(t,i,e,r){for(var n=this.paramList.length-1;n>=0;--n){var s=this.paramList[n];s.type==o.TYPE_ADD?t.addToParamFloat(s.id,s.value,e):s.type==o.TYPE_MULT?t.multParamFloat(s.id,s.value,e):s.type==o.TYPE_SET&&t.setParamFloat(s.id,s.value,e)}},s.prototype.calcNextBlink=function(){return UtSystem.getUserTimeMSec()+Math.random()*(2*this.blinkIntervalMsec-1)},s.prototype.setInterval=function(t){this.blinkIntervalMsec=t},s.prototype.setEyeMotion=function(t,i,e){this.closingMotionMsec=t,this.closedMotionMsec=i,this.openingMotionMsec=e},s.prototype.updateParam=function(t){var i,e=UtSystem.getUserTimeMSec(),r=0;switch(this.eyeState){case g.STATE_CLOSING:r=(e-this.stateStartTime)/this.closingMotionMsec,r>=1&&(r=1,this.eyeState=g.STATE_CLOSED,this.stateStartTime=e),i=1-r;break;case g.STATE_CLOSED:r=(e-this.stateStartTime)/this.closedMotionMsec,r>=1&&(this.eyeState=g.STATE_OPENING,this.stateStartTime=e),i=0;break;case g.STATE_OPENING:r=(e-this.stateStartTime)/this.openingMotionMsec,r>=1&&(r=1,this.eyeState=g.STATE_INTERVAL,this.nextBlinkTime=this.calcNextBlink()),i=r;break;case g.STATE_INTERVAL:this.nextBlinkTime=t)&&(!(this.currentPriority>=t)&&(this.reservePriority=t,!0))},h.prototype.setReservePriority=function(t){this.reservePriority=t},h.prototype.updateParam=function(t){var i=MotionQueueManager.prototype.updateParam.call(this,t);return this.isFinished()&&(this.currentPriority=0),i},h.prototype.startMotionPrio=function(t,i){return i==this.reservePriority&&(this.reservePriority=0),this.currentPriority=i,this.startMotion(t,!1)},l.load=function(t){for(var i=new l,e=c.getPlatformManager(),r=e.jsonParseFromBytes(t),o=r.physics_hair,n=o.length,s=0;s=0)break;r=n,o=t.getPartsOpacity(s),o+=e/.5,o>1&&(o=1)}}r<0&&(r=0,o=1);for(var n=0;n.15&&(a=1-.15/(1-o)),h>a&&(h=a),t.setPartsOpacity(s,h)}}},$.prototype.copyOpacityOtherParts=function(t,i){for(var e=0;eo)&&(l*=o/u,$*=o/u,u=o),this.faceVX+=l,this.faceVY+=$;var f=.5*(Math.sqrt(o*o+16*o*_-8*o*_)-o),c=Math.sqrt(this.faceVX*this.faceVX+this.faceVY*this.faceVY);c>f&&(this.faceVX*=f/c,this.faceVY*=f/c),this.faceX+=this.faceVX,this.faceY+=this.faceVY}},f.prototype=new _,f.prototype.getMaxScale=function(){return this.max},f.prototype.getMinScale=function(){return this.min},f.prototype.setMaxScale=function(t){this.max=t},f.prototype.setMinScale=function(t){this.min=t},f.prototype.isMaxScale=function(){return this.getScaleX()==this.max},f.prototype.isMinScale=function(){return this.getScaleX()==this.min},f.prototype.adjustTranslate=function(t,i){this.tr[0]*this.maxLeft+(this.tr[12]+t)>this.screenLeft&&(t=this.screenLeft-this.tr[0]*this.maxLeft-this.tr[12]),this.tr[0]*this.maxRight+(this.tr[12]+t)this.screenBottom&&(i=this.screenBottom-this.tr[5]*this.maxBottom-this.tr[13]);var e=[1,0,0,0,0,1,0,0,0,0,1,0,t,i,0,1];_.mul(e,this.tr,this.tr)},f.prototype.adjustScale=function(t,i,e){var r=e*this.tr[0];r0&&(e=this.min/this.tr[0]):r>this.max&&this.tr[0]>0&&(e=this.max/this.tr[0]);var o=[1,0,0,0,0,1,0,0,0,0,1,0,t,i,0,1],n=[e,0,0,0,0,e,0,0,0,0,1,0,0,0,0,1],s=[1,0,0,0,0,1,0,0,0,0,1,0,-t,-i,0,1];_.mul(s,this.tr,this.tr),_.mul(n,this.tr,this.tr),_.mul(o,this.tr,this.tr)},f.prototype.setScreenRect=function(t,i,e,r){this.screenLeft=t,this.screenRight=i,this.screenTop=r,this.screenBottom=e},f.prototype.setMaxScreenRect=function(t,i,e,r){this.maxLeft=t,this.maxRight=i,this.maxTop=r,this.maxBottom=e},f.prototype.getScreenLeft=function(){return this.screenLeft},f.prototype.getScreenRight=function(){return this.screenRight},f.prototype.getScreenBottom=function(){return this.screenBottom},f.prototype.getScreenTop=function(){return this.screenTop},f.prototype.getMaxLeft=function(){return this.maxLeft},f.prototype.getMaxRight=function(){return this.maxRight},f.prototype.getMaxBottom=function(){return this.maxBottom},f.prototype.getMaxTop=function(){return this.maxTop},c.platformManager=null,c.getPlatformManager=function(){return c.platformManager},c.setPlatformManager=function(t){c.platformManager=t},t.exports={L2DTargetPoint:p,Live2DFramework:c,L2DViewMatrix:f,L2DPose:$,L2DPartsParam:u,L2DPhysics:l,L2DMotionManager:h,L2DModelMatrix:a,L2DMatrix44:_,EYE_STATE:g,L2DEyeBlink:s,L2DExpressionParam:n,L2DExpressionMotion:o,L2DBaseModel:r}},function(t,i,e){"use strict";var r={DEBUG_LOG:!1,DEBUG_MOUSE_LOG:!1,DEBUG_DRAW_HIT_AREA:!1,DEBUG_DRAW_ALPHA_MODEL:!1,VIEW_MAX_SCALE:2,VIEW_MIN_SCALE:.8,VIEW_LOGICAL_LEFT:-1,VIEW_LOGICAL_RIGHT:1,VIEW_LOGICAL_MAX_LEFT:-2,VIEW_LOGICAL_MAX_RIGHT:2,VIEW_LOGICAL_MAX_BOTTOM:-2,VIEW_LOGICAL_MAX_TOP:2,PRIORITY_NONE:0,PRIORITY_IDLE:1,PRIORITY_SLEEPY:2,PRIORITY_NORMAL:3,PRIORITY_FORCE:4,MOTION_GROUP_IDLE:"idle",MOTION_GROUP_SLEEPY:"sleepy",MOTION_GROUP_TAP_BODY:"tap_body",MOTION_GROUP_FLICK_HEAD:"flick_head",MOTION_GROUP_PINCH_IN:"pinch_in",MOTION_GROUP_PINCH_OUT:"pinch_out",MOTION_GROUP_SHAKE:"shake",HIT_AREA_HEAD:"head",HIT_AREA_BODY:"body"};t.exports=r},function(t,i,e){"use strict";function r(t){n=t}function o(){return n}Object.defineProperty(i,"__esModule",{value:!0}),i.setContext=r,i.getContext=o;var n=void 0},function(t,i,e){"use strict";function r(){}r.matrixStack=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],r.depth=0,r.currentMatrix=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],r.tmp=new Array(16),r.reset=function(){this.depth=0},r.loadIdentity=function(){for(var t=0;t<16;t++)this.currentMatrix[t]=t%5==0?1:0},r.push=function(){var t=(this.depth,16*(this.depth+1));this.matrixStack.lengthe.left&&i.y>e.top)return i;var o=t.x-i.x,n=t.y-i.y,s=r(o,n);i.xat.frameBuffers.length&&(this.curFrameNo=this.getMaskRenderTexture()),this.tmpModelToViewMatrix=new R,this.tmpMatrix2=new R,this.tmpMatrixForMask=new R,this.tmpMatrixForDraw=new R,this.CHANNEL_COLORS=new Array;var i=new A;i=new A,i.r=0,i.g=0,i.b=0,i.a=1,this.CHANNEL_COLORS.push(i),i=new A,i.r=1,i.g=0,i.b=0,i.a=0,this.CHANNEL_COLORS.push(i),i=new A,i.r=0,i.g=1,i.b=0,i.a=0,this.CHANNEL_COLORS.push(i),i=new A,i.r=0,i.g=0,i.b=1,i.a=0,this.CHANNEL_COLORS.push(i);for(var e=0;eG._$T7){t._$NP|=i._$4s;throw new lt("_$gi _$C _$li , _$n0 _$_ version _$li ( SDK : "+G._$T7+" < _$f0 : "+r+" )@_$SS#loadModel()\n")}var h=o._$nP();if(r>=G._$s7){var l=o._$9T(),$=o._$9T();if(-30584!=l||-30584!=$)throw t._$NP|=i._$0s,new lt("_$gi _$C _$li , _$0 _$6 _$Ui.")}t._$KS(h);var u=t.getModelContext();u.setDrawParam(t.getDrawParam()),u.init()}catch(t){_._$Rb(t)}},i.prototype._$KS=function(t){this._$MT=t},i.prototype.getModelImpl=function(){return null==this._$MT&&(this._$MT=new p,this._$MT._$zP()),this._$MT},i.prototype.getCanvasWidth=function(){return null==this._$MT?0:this._$MT.getCanvasWidth()},i.prototype.getCanvasHeight=function(){return null==this._$MT?0:this._$MT.getCanvasHeight()},i.prototype.getParamFloat=function(t){return"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),this._$5S.getParamFloat(t)},i.prototype.setParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)*(1-e)+i*e)},i.prototype.addToParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)+i*e)},i.prototype.multParamFloat=function(t,i,e){"number"!=typeof t&&(t=this._$5S.getParamIndex(u.getID(t))),arguments.length<3&&(e=1),this._$5S.setParamFloat(t,this._$5S.getParamFloat(t)*(1+(i-1)*e))},i.prototype.getParamIndex=function(t){return this._$5S.getParamIndex(u.getID(t))},i.prototype.loadParam=function(){this._$5S.loadParam()},i.prototype.saveParam=function(){this._$5S.saveParam()},i.prototype.init=function(){this._$5S.init()},i.prototype.update=function(){this._$5S.update()},i.prototype._$Rs=function(){return _._$li("_$60 _$PT _$Rs()"),-1},i.prototype._$Ds=function(t){_._$li("_$60 _$PT _$SS#_$Ds() \n")},i.prototype._$K2=function(){},i.prototype.draw=function(){},i.prototype.getModelContext=function(){return this._$5S},i.prototype._$s2=function(){return this._$NP},i.prototype._$P7=function(t,i,e,r){var o=-1,n=0,s=this;if(0!=e)if(1==t.length){var _=t[0],a=0!=s.getParamFloat(_),h=i[0],l=s.getPartsOpacity(h),$=e/r;a?(l+=$)>1&&(l=1):(l-=$)<0&&(l=0),s.setPartsOpacity(h,l)}else{for(var u=0;u=0)break;o=u;var h=i[u];n=s.getPartsOpacity(h),n+=e/r,n>1&&(n=1)}}o<0&&(console.log("No _$wi _$q0/ _$U default[%s]",t[0]),o=0,n=1,s.loadParam(),s.setParamFloat(t[o],n),s.saveParam());for(var u=0;u.15&&(f=1-.15/(1-n)),c>f&&(c=f),s.setPartsOpacity(h,c)}}}else for(var u=0;u=this._$5S._$aS.length)return null;var i=this._$5S._$aS[t];return null!=i&&i.getType()==W._$wb&&i instanceof $t?i.getIndexArray():null},e.CHANNEL_COUNT=4,e.RENDER_TEXTURE_USE_MIPMAP=!1,e.NOT_USED_FRAME=-100,e.prototype._$L7=function(){if(this.tmpModelToViewMatrix&&(this.tmpModelToViewMatrix=null),this.tmpMatrix2&&(this.tmpMatrix2=null),this.tmpMatrixForMask&&(this.tmpMatrixForMask=null),this.tmpMatrixForDraw&&(this.tmpMatrixForDraw=null),this.tmpBoundsOnModel&&(this.tmpBoundsOnModel=null),this.CHANNEL_COLORS){for(var t=this.CHANNEL_COLORS.length-1;t>=0;--t)this.CHANNEL_COLORS.splice(t,1);this.CHANNEL_COLORS=[]}this.releaseShader()},e.prototype.releaseShader=function(){for(var t=at.frameBuffers.length,i=0;i0){var n=i.gl.getParameter(i.gl.FRAMEBUFFER_BINDING),s=new Array(4);s[0]=0,s[1]=0,s[2]=i.gl.canvas.width,s[3]=i.gl.canvas.height,i.gl.viewport(0,0,at.clippingMaskBufferSize,at.clippingMaskBufferSize),this.setupLayoutBounds(e),i.gl.bindFramebuffer(i.gl.FRAMEBUFFER,at.frameBuffers[this.curFrameNo].framebuffer),i.gl.clearColor(0,0,0,0),i.gl.clear(i.gl.COLOR_BUFFER_BIT);for(var r=0;rr?e:r,n=o,s=o,_=0,a=0,h=i.clippedDrawContextList.length,l=0;l_&&(_=S),v>a&&(a=v)}}if(n==o)i.allClippedDrawRect.x=0,i.allClippedDrawRect.y=0,i.allClippedDrawRect.width=0,i.allClippedDrawRect.height=0,i.isUsing=!1;else{var L=_-n,M=a-s;i.allClippedDrawRect.x=n,i.allClippedDrawRect.y=s,i.allClippedDrawRect.width=L,i.allClippedDrawRect.height=M,i.isUsing=!0}},e.prototype.setupLayoutBounds=function(t){var i=t/e.CHANNEL_COUNT,r=t%e.CHANNEL_COUNT;i=~~i,r=~~r;for(var o=0,n=0;n=1)return 1;var p=r,f=p*p;return l*(p*f)+$*f+u*p+0},s.prototype._$a0=function(){},s.prototype.setFadeIn=function(t){this._$dP=t},s.prototype.setFadeOut=function(t){this._$eo=t},s.prototype._$pT=function(t){this._$V0=t},s.prototype.getFadeOut=function(){return this._$eo},s.prototype._$4T=function(){return this._$eo},s.prototype._$mT=function(){return this._$V0},s.prototype.getDurationMSec=function(){return-1},s.prototype.getLoopDurationMSec=function(){return-1},s.prototype.updateParam=function(t,i){if(i._$AT&&!i._$9L){var e=w.getUserTimeMSec();if(i._$z2<0){i._$z2=e,i._$bs=e;var r=this.getDurationMSec();i._$Do<0&&(i._$Do=r<=0?-1:i._$z2+r)}var o=this._$V0;o=o*(0==this._$dP?1:ht._$r2((e-i._$bs)/this._$dP))*(0==this._$eo||i._$Do<0?1:ht._$r2((i._$Do-e)/this._$eo)),0<=o&&o<=1||console.log("### assert!! ### "),this.updateParamExe(t,e,o,i),i._$Do>0&&i._$Do0?console.log("\n"):e%8==0&&e>0&&console.log(" "),console.log("%02X ",255&t[e]);console.log("\n")},_._$nr=function(t,i,e){console.log("%s\n",t);for(var r=i.length,o=0;o=0;--r){this._$lL[r]._$oP(t,this)}this._$oo(t,e),this._$M2=this._$Yb(),this._$9b=(this._$M2-this._$ks)/e,this._$ks=this._$M2}for(var r=this._$qP.length-1;r>=0;--r){this._$qP[r]._$YS(t,this)}this._$iT=i},f.prototype._$oo=function(t,i){i<.033&&(i=.033);var e=1/i;this.p1.vx=(this.p1.x-this.p1._$s0)*e,this.p1.vy=(this.p1.y-this.p1._$70)*e,this.p1.ax=(this.p1.vx-this.p1._$7L)*e,this.p1.ay=(this.p1.vy-this.p1._$HL)*e,this.p1.fx=this.p1.ax*this.p1._$p,this.p1.fy=this.p1.ay*this.p1._$p,this.p1._$xT();var r,o,n=-Math.atan2(this.p1.y-this.p2.y,this.p1.x-this.p2.x),s=Math.cos(n),_=Math.sin(n),a=9.8*this.p2._$p,h=this._$Db*Lt._$bS,l=a*Math.cos(n-h);r=l*_,o=l*s;var $=-this.p1.fx*_*_,u=-this.p1.fy*_*s,p=-this.p2.vx*this._$L2,f=-this.p2.vy*this._$L2;this.p2.fx=r+$+p,this.p2.fy=o+u+f,this.p2.ax=this.p2.fx/this.p2._$p,this.p2.ay=this.p2.fy/this.p2._$p,this.p2.vx+=this.p2.ax*i,this.p2.vy+=this.p2.ay*i,this.p2.x+=this.p2.vx*i,this.p2.y+=this.p2.vy*i;var c=Math.sqrt((this.p1.x-this.p2.x)*(this.p1.x-this.p2.x)+(this.p1.y-this.p2.y)*(this.p1.y-this.p2.y));this.p2.x=this.p1.x+this._$Fo*(this.p2.x-this.p1.x)/c,this.p2.y=this.p1.y+this._$Fo*(this.p2.y-this.p1.y)/c,this.p2.vx=(this.p2.x-this.p2._$s0)*e,this.p2.vy=(this.p2.y-this.p2._$70)*e,this.p2._$xT()},c.prototype._$xT=function(){this._$s0=this.x,this._$70=this.y,this._$7L=this.vx,this._$HL=this.vy},d.prototype._$oP=function(t,i){},g.prototype=new d,g.prototype._$oP=function(t,i){var e=this.scale*t.getParamFloat(this._$wL),r=i.getPhysicsPoint1();switch(this._$tL){default:case f.Src.SRC_TO_X:r.x=r.x+(e-r.x)*this._$V0;break;case f.Src.SRC_TO_Y:r.y=r.y+(e-r.y)*this._$V0;break;case f.Src.SRC_TO_G_ANGLE:var o=i._$qr();o+=(e-o)*this._$V0,i._$pr(o)}},y.prototype._$YS=function(t,i){},T.prototype=new y,T.prototype._$YS=function(t,i){switch(this._$YP){default:case f.Target.TARGET_FROM_ANGLE:t.setParamFloat(this._$wL,this.scale*i._$5r(),this._$V0);break;case f.Target.TARGET_FROM_ANGLE_V:t.setParamFloat(this._$wL,this.scale*i._$Cs(),this._$V0)}},f.Src=function(){},f.Src.SRC_TO_X="SRC_TO_X",f.Src.SRC_TO_Y="SRC_TO_Y",f.Src.SRC_TO_G_ANGLE="SRC_TO_G_ANGLE",f.Target=function(){},f.Target.TARGET_FROM_ANGLE="TARGET_FROM_ANGLE",f.Target.TARGET_FROM_ANGLE_V="TARGET_FROM_ANGLE_V",P.prototype.init=function(t){this._$fL=t._$fL,this._$gL=t._$gL,this._$B0=t._$B0,this._$z0=t._$z0,this._$qT=t._$qT,this.reflectX=t.reflectX,this.reflectY=t.reflectY},P.prototype._$F0=function(t){this._$fL=t._$_T(),this._$gL=t._$_T(),this._$B0=t._$_T(),this._$z0=t._$_T(),this._$qT=t._$_T(),t.getFormatVersion()>=G.LIVE2D_FORMAT_VERSION_V2_10_SDK2&&(this.reflectX=t._$po(),this.reflectY=t._$po())},P.prototype._$e=function(){};var It=function(){};It._$ni=function(t,i,e,r,o,n,s,_,a){var h=s*n-_*o;if(0==h)return null;var l,$=((t-e)*n-(i-r)*o)/h;return l=0!=o?(t-e-$*s)/o:(i-r-$*_)/n,isNaN(l)&&(l=(t-e-$*s)/o,isNaN(l)&&(l=(i-r-$*_)/n),isNaN(l)&&(console.log("a is NaN @UtVector#_$ni() "),console.log("v1x : "+o),console.log("v1x != 0 ? "+(0!=o)))),null==a?new Array(l,$):(a[0]=l,a[1]=$,a)},S.prototype._$8P=function(){return this.x+.5*this.width},S.prototype._$6P=function(){return this.y+.5*this.height},S.prototype._$EL=function(){return this.x+this.width},S.prototype._$5T=function(){return this.y+this.height},S.prototype._$jL=function(t,i,e,r){this.x=t,this.y=i,this.width=e,this.height=r},S.prototype._$jL=function(t){this.x=t.x,this.y=t.y,this.width=t.width,this.height=t.height},S.prototype.contains=function(t,i){return this.x<=this.x&&this.y<=this.y&&this.x<=this.x+this.width&&this.y<=this.y+this.height},S.prototype.expand=function(t,i){this.x-=t,this.y-=i,this.width+=2*t,this.height+=2*i},v._$Z2=function(t,i,e,r){var o=i._$Q2(t,e),n=t._$vs(),s=t._$Tr();if(i._$zr(n,s,o),o<=0)return r[n[0]];if(1==o){var _=r[n[0]],a=r[n[1]],h=s[0];return _+(a-_)*h|0}if(2==o){var _=r[n[0]],a=r[n[1]],l=r[n[2]],$=r[n[3]],h=s[0],u=s[1],p=_+(a-_)*h|0,f=l+($-l)*h|0;return p+(f-p)*u|0}if(3==o){var c=r[n[0]],d=r[n[1]],g=r[n[2]],y=r[n[3]],m=r[n[4]],T=r[n[5]],P=r[n[6]],S=r[n[7]],h=s[0],u=s[1],v=s[2],_=c+(d-c)*h|0,a=g+(y-g)*h|0,l=m+(T-m)*h|0,$=P+(S-P)*h|0,p=_+(a-_)*u|0,f=l+($-l)*u|0;return p+(f-p)*v|0}if(4==o){var L=r[n[0]],M=r[n[1]],E=r[n[2]],A=r[n[3]],I=r[n[4]],w=r[n[5]],x=r[n[6]],O=r[n[7]],D=r[n[8]],R=r[n[9]],b=r[n[10]],F=r[n[11]],C=r[n[12]],N=r[n[13]],B=r[n[14]],U=r[n[15]],h=s[0],u=s[1],v=s[2],G=s[3],c=L+(M-L)*h|0,d=E+(A-E)*h|0,g=I+(w-I)*h|0,y=x+(O-x)*h|0,m=D+(R-D)*h|0,T=b+(F-b)*h|0,P=C+(N-C)*h|0,S=B+(U-B)*h|0,_=c+(d-c)*u|0,a=g+(y-g)*u|0,l=m+(T-m)*u|0,$=P+(S-P)*u|0,p=_+(a-_)*v|0,f=l+($-l)*v|0;return p+(f-p)*G|0}for(var Y=1<=G._$T7?(this.clipID=t._$nP(),this.clipIDList=this.convertClipIDForV2_11(this.clipID)):this.clipIDList=[],this._$MS(this._$Lb)},M.prototype.getClipIDList=function(){return this.clipIDList},M.prototype.init=function(t){},M.prototype._$Nr=function(t,i){if(i._$IS[0]=!1,i._$Us=v._$Z2(t,this._$GS,i._$IS,this._$Lb),at._$Zs);else if(i._$IS[0])return;i._$7s=v._$br(t,this._$GS,i._$IS,this._$mS)},M.prototype._$2b=function(t,i){},M.prototype.getDrawDataID=function(){return this._$gP},M.prototype._$j2=function(t){this._$gP=t},M.prototype.getOpacity=function(t,i){return i._$7s},M.prototype._$zS=function(t,i){return i._$Us},M.prototype._$MS=function(t){for(var i=t.length-1;i>=0;--i){var e=t[i];eM._$R2&&(M._$R2=e)}},M.prototype.getTargetBaseDataID=function(){return this._$dr},M.prototype._$gs=function(t){this._$dr=t},M.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},M.prototype.preDraw=function(t,i,e){},M.prototype.draw=function(t,i,e){},M.prototype.getType=function(){},M.prototype._$B2=function(t,i,e){},E._$ps=32,E.CLIPPING_PROCESS_NONE=0,E.CLIPPING_PROCESS_OVERWRITE_ALPHA=1,E.CLIPPING_PROCESS_MULTIPLY_ALPHA=2,E.CLIPPING_PROCESS_DRAW=3,E.CLIPPING_PROCESS_CLEAR_ALPHA=4,E.prototype.setChannelFlagAsColor=function(t,i){this.CHANNEL_COLORS[t]=i},E.prototype.getChannelFlagAsColor=function(t){return this.CHANNEL_COLORS[t]},E.prototype._$ZT=function(){},E.prototype._$Uo=function(t,i,e,r,o,n,s){},E.prototype._$Rs=function(){return-1},E.prototype._$Ds=function(t){},E.prototype.setBaseColor=function(t,i,e,r){t<0?t=0:t>1&&(t=1),i<0?i=0:i>1&&(i=1),e<0?e=0:e>1&&(e=1),r<0?r=0:r>1&&(r=1),this._$lT=t,this._$C0=i,this._$tT=e,this._$WL=r},E.prototype._$WP=function(t){this.culling=t},E.prototype.setMatrix=function(t){for(var i=0;i<16;i++)this.matrix4x4[i]=t[i]},E.prototype._$IT=function(){return this.matrix4x4},E.prototype.setPremultipliedAlpha=function(t){this.premultipliedAlpha=t},E.prototype.isPremultipliedAlpha=function(){return this.premultipliedAlpha},E.prototype.setAnisotropy=function(t){this.anisotropy=t},E.prototype.getAnisotropy=function(){return this.anisotropy},E.prototype.getClippingProcess=function(){return this.clippingProcess},E.prototype.setClippingProcess=function(t){this.clippingProcess=t},E.prototype.setClipBufPre_clipContextForMask=function(t){this.clipBufPre_clipContextMask=t},E.prototype.getClipBufPre_clipContextMask=function(){return this.clipBufPre_clipContextMask},E.prototype.setClipBufPre_clipContextForDraw=function(t){this.clipBufPre_clipContextDraw=t},E.prototype.getClipBufPre_clipContextDraw=function(){return this.clipBufPre_clipContextDraw},I._$ur=-2,I._$c2=1,I._$_b=2,I.prototype._$F0=function(t){this._$kP=t._$nP(),this._$dr=t._$nP()},I.prototype.readV2_opacity=function(t){t.getFormatVersion()>=G.LIVE2D_FORMAT_VERSION_V2_10_SDK2&&(this._$mS=t._$Tb())},I.prototype.init=function(t){},I.prototype._$Nr=function(t,i){},I.prototype.interpolateOpacity=function(t,i,e,r){null==this._$mS?e.setInterpolatedOpacity(1):e.setInterpolatedOpacity(v._$br(t,i,r,this._$mS))},I.prototype._$2b=function(t,i){},I.prototype._$nb=function(t,i,e,r,o,n,s){},I.prototype.getType=function(){},I.prototype._$gs=function(t){this._$dr=t},I.prototype._$a2=function(t){this._$kP=t},I.prototype.getTargetBaseDataID=function(){return this._$dr},I.prototype.getBaseDataID=function(){return this._$kP},I.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},w._$W2=0,w._$CS=w._$W2,w._$Mo=function(){return!0},w._$XP=function(t){try{for(var i=getTimeMSec();getTimeMSec()-i=t.length)return!1;for(var o=i;o=0;--e){var r=this._$Ob[e].getParamIndex(i);if(r==x._$ds&&(r=t.getParamIndex(this._$Ob[e].getParamID())),t._$Xb(r))return!0}return!1},D.prototype._$Q2=function(t,i){for(var e,r,o=this._$Ob.length,n=t._$v2(),s=0,_=0;_U._$Qb&&console.log("err 23245\n");for(var o=this._$Ob.length,n=1,s=1,_=0,a=0;a=0;--n)e[n]=o[n]}else this.mult_fast(t,i,e,r)},R.prototype.mult_fast=function(t,i,e,r){r?(e[0]=t[0]*i[0]+t[4]*i[1]+t[8]*i[2],e[4]=t[0]*i[4]+t[4]*i[5]+t[8]*i[6],e[8]=t[0]*i[8]+t[4]*i[9]+t[8]*i[10],e[12]=t[0]*i[12]+t[4]*i[13]+t[8]*i[14]+t[12],e[1]=t[1]*i[0]+t[5]*i[1]+t[9]*i[2],e[5]=t[1]*i[4]+t[5]*i[5]+t[9]*i[6],e[9]=t[1]*i[8]+t[5]*i[9]+t[9]*i[10],e[13]=t[1]*i[12]+t[5]*i[13]+t[9]*i[14]+t[13],e[2]=t[2]*i[0]+t[6]*i[1]+t[10]*i[2],e[6]=t[2]*i[4]+t[6]*i[5]+t[10]*i[6],e[10]=t[2]*i[8]+t[6]*i[9]+t[10]*i[10],e[14]=t[2]*i[12]+t[6]*i[13]+t[10]*i[14]+t[14],e[3]=e[7]=e[11]=0,e[15]=1):(e[0]=t[0]*i[0]+t[4]*i[1]+t[8]*i[2]+t[12]*i[3],e[4]=t[0]*i[4]+t[4]*i[5]+t[8]*i[6]+t[12]*i[7],e[8]=t[0]*i[8]+t[4]*i[9]+t[8]*i[10]+t[12]*i[11],e[12]=t[0]*i[12]+t[4]*i[13]+t[8]*i[14]+t[12]*i[15],e[1]=t[1]*i[0]+t[5]*i[1]+t[9]*i[2]+t[13]*i[3],e[5]=t[1]*i[4]+t[5]*i[5]+t[9]*i[6]+t[13]*i[7],e[9]=t[1]*i[8]+t[5]*i[9]+t[9]*i[10]+t[13]*i[11],e[13]=t[1]*i[12]+t[5]*i[13]+t[9]*i[14]+t[13]*i[15],e[2]=t[2]*i[0]+t[6]*i[1]+t[10]*i[2]+t[14]*i[3],e[6]=t[2]*i[4]+t[6]*i[5]+t[10]*i[6]+t[14]*i[7],e[10]=t[2]*i[8]+t[6]*i[9]+t[10]*i[10]+t[14]*i[11],e[14]=t[2]*i[12]+t[6]*i[13]+t[10]*i[14]+t[14]*i[15],e[3]=t[3]*i[0]+t[7]*i[1]+t[11]*i[2]+t[15]*i[3],e[7]=t[3]*i[4]+t[7]*i[5]+t[11]*i[6]+t[15]*i[7],e[11]=t[3]*i[8]+t[7]*i[9]+t[11]*i[10]+t[15]*i[11],e[15]=t[3]*i[12]+t[7]*i[13]+t[11]*i[14]+t[15]*i[15])},R.prototype.translate=function(t,i,e){this.m[12]=this.m[0]*t+this.m[4]*i+this.m[8]*e+this.m[12],this.m[13]=this.m[1]*t+this.m[5]*i+this.m[9]*e+this.m[13],this.m[14]=this.m[2]*t+this.m[6]*i+this.m[10]*e+this.m[14],this.m[15]=this.m[3]*t+this.m[7]*i+this.m[11]*e+this.m[15]},R.prototype.scale=function(t,i,e){this.m[0]*=t,this.m[4]*=i,this.m[8]*=e,this.m[1]*=t,this.m[5]*=i,this.m[9]*=e,this.m[2]*=t,this.m[6]*=i,this.m[10]*=e,this.m[3]*=t,this.m[7]*=i,this.m[11]*=e},R.prototype.rotateX=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[4];this.m[4]=r*i+this.m[8]*e,this.m[8]=r*-e+this.m[8]*i,r=this.m[5],this.m[5]=r*i+this.m[9]*e,this.m[9]=r*-e+this.m[9]*i,r=this.m[6],this.m[6]=r*i+this.m[10]*e,this.m[10]=r*-e+this.m[10]*i,r=this.m[7],this.m[7]=r*i+this.m[11]*e,this.m[11]=r*-e+this.m[11]*i},R.prototype.rotateY=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[0];this.m[0]=r*i+this.m[8]*-e,this.m[8]=r*e+this.m[8]*i,r=this.m[1],this.m[1]=r*i+this.m[9]*-e,this.m[9]=r*e+this.m[9]*i,r=m[2],this.m[2]=r*i+this.m[10]*-e,this.m[10]=r*e+this.m[10]*i,r=m[3],this.m[3]=r*i+this.m[11]*-e,this.m[11]=r*e+this.m[11]*i},R.prototype.rotateZ=function(t){var i=Lt.fcos(t),e=Lt._$9(t),r=this.m[0];this.m[0]=r*i+this.m[4]*e,this.m[4]=r*-e+this.m[4]*i,r=this.m[1],this.m[1]=r*i+this.m[5]*e,this.m[5]=r*-e+this.m[5]*i,r=this.m[2],this.m[2]=r*i+this.m[6]*e,this.m[6]=r*-e+this.m[6]*i,r=this.m[3],this.m[3]=r*i+this.m[7]*e,this.m[7]=r*-e+this.m[7]*i},b.prototype=new et,b._$tP=new Object,b._$27=function(){b._$tP.clear()},b.getID=function(t){var i=b._$tP[t];return null==i&&(i=new b(t),b._$tP[t]=i),i},b.prototype._$3s=function(){return new b},F._$kS=-1,F._$pS=0,F._$hb=1,F.STATE_IDENTITY=0,F._$gb=1,F._$fo=2,F._$go=4,F.prototype.transform=function(t,i,e){var r,o,n,s,_,a,h=0,l=0;switch(this._$hi){default:return;case F._$go|F._$fo|F._$gb:for(r=this._$7,o=this._$H,n=this._$k,s=this._$f,_=this._$g,a=this._$w;--e>=0;){var $=t[h++],u=t[h++];i[l++]=r*$+o*u+n,i[l++]=s*$+_*u+a}return;case F._$go|F._$fo:for(r=this._$7,o=this._$H,s=this._$f,_=this._$g;--e>=0;){var $=t[h++],u=t[h++];i[l++]=r*$+o*u,i[l++]=s*$+_*u}return;case F._$go|F._$gb:for(o=this._$H,n=this._$k,s=this._$f,a=this._$w;--e>=0;){var $=t[h++];i[l++]=o*t[h++]+n,i[l++]=s*$+a}return;case F._$go:for(o=this._$H,s=this._$f;--e>=0;){var $=t[h++];i[l++]=o*t[h++],i[l++]=s*$}return;case F._$fo|F._$gb:for(r=this._$7,n=this._$k,_=this._$g,a=this._$w;--e>=0;)i[l++]=r*t[h++]+n,i[l++]=_*t[h++]+a;return;case F._$fo:for(r=this._$7,_=this._$g;--e>=0;)i[l++]=r*t[h++],i[l++]=_*t[h++];return;case F._$gb:for(n=this._$k,a=this._$w;--e>=0;)i[l++]=t[h++]+n,i[l++]=t[h++]+a;return;case F.STATE_IDENTITY:return void(t==i&&h==l||w._$jT(t,h,i,l,2*e))}},F.prototype.update=function(){0==this._$H&&0==this._$f?1==this._$7&&1==this._$g?0==this._$k&&0==this._$w?(this._$hi=F.STATE_IDENTITY,this._$Z=F._$pS):(this._$hi=F._$gb,this._$Z=F._$hb):0==this._$k&&0==this._$w?(this._$hi=F._$fo,this._$Z=F._$kS):(this._$hi=F._$fo|F._$gb,this._$Z=F._$kS):0==this._$7&&0==this._$g?0==this._$k&&0==this._$w?(this._$hi=F._$go,this._$Z=F._$kS):(this._$hi=F._$go|F._$gb,this._$Z=F._$kS):0==this._$k&&0==this._$w?(this._$hi=F._$go|F._$fo,this._$Z=F._$kS):(this._$hi=F._$go|F._$fo|F._$gb,this._$Z=F._$kS)},F.prototype._$RT=function(t){this._$IT(t);var i=t[0],e=t[2],r=t[1],o=t[3],n=Math.sqrt(i*i+r*r),s=i*o-e*r;0==n?at._$so&&console.log("affine._$RT() / rt==0"):(t[0]=n,t[1]=s/n,t[2]=(r*o+i*e)/s,t[3]=Math.atan2(r,i))},F.prototype._$ho=function(t,i,e,r){var o=new Float32Array(6),n=new Float32Array(6);t._$RT(o),i._$RT(n);var s=new Float32Array(6);s[0]=o[0]+(n[0]-o[0])*e,s[1]=o[1]+(n[1]-o[1])*e,s[2]=o[2]+(n[2]-o[2])*e,s[3]=o[3]+(n[3]-o[3])*e,s[4]=o[4]+(n[4]-o[4])*e,s[5]=o[5]+(n[5]-o[5])*e,r._$CT(s)},F.prototype._$CT=function(t){var i=Math.cos(t[3]),e=Math.sin(t[3]);this._$7=t[0]*i,this._$f=t[0]*e,this._$H=t[1]*(t[2]*i-e),this._$g=t[1]*(t[2]*e+i),this._$k=t[4],this._$w=t[5],this.update()},F.prototype._$IT=function(t){t[0]=this._$7,t[1]=this._$f,t[2]=this._$H,t[3]=this._$g,t[4]=this._$k,t[5]=this._$w},C.prototype=new s,C._$cs="VISIBLE:",C._$ar="LAYOUT:",C._$Co=0,C._$D2=[],C._$1T=1,C.loadMotion=function(t){var i=new C,e=[0],r=t.length;i._$yT=0;for(var o=0;o=0){var a=new B;O.startsWith(t,s,C._$cs)?(a._$RP=B._$hs,a._$4P=new String(t,s,_-s)):O.startsWith(t,s,C._$ar)?(a._$4P=new String(t,s+7,_-s-7),O.startsWith(t,s+7,"ANCHOR_X")?a._$RP=B._$xs:O.startsWith(t,s+7,"ANCHOR_Y")?a._$RP=B._$us:O.startsWith(t,s+7,"SCALE_X")?a._$RP=B._$qs:O.startsWith(t,s+7,"SCALE_Y")?a._$RP=B._$Ys:O.startsWith(t,s+7,"X")?a._$RP=B._$ws:O.startsWith(t,s+7,"Y")&&(a._$RP=B._$Ns)):(a._$RP=B._$Fr,a._$4P=new String(t,s,_-s)),i.motions.push(a);var h=0;for(C._$D2.clear(),o=_+1;o0){C._$D2.push(l),h++;var $=e[0];if($i._$yT&&(i._$yT=h)}}}else{for(var s=o,_=-1;o=0)for(_==s+4&&"f"==t[s+1]&&"p"==t[s+2]&&"s"==t[s+3]&&(u=!0),o=_+1;o0&&u&&5=l?l-1:s];t.setParamFloat($,u)}else if(B._$ws<=h._$RP&&h._$RP<=B._$Ys);else{var p=t.getParamFloat($),f=h._$I0[s>=l?l-1:s],c=h._$I0[s+1>=l?l-1:s+1],d=f+(c-f)*_,g=p+(d-p)*e;t.setParamFloat($,g)}}s>=this._$yT&&(this._$E?(r._$z2=i,this.loopFadeIn&&(r._$bs=i)):r._$9L=!0)},C.prototype._$r0=function(){return this._$E},C.prototype._$aL=function(t){this._$E=t},C.prototype.isLoopFadeIn=function(){return this.loopFadeIn},C.prototype.setLoopFadeIn=function(t){this.loopFadeIn=t},N.prototype.clear=function(){this.size=0},N.prototype.add=function(t){if(this._$P.length<=this.size){var i=new Float32Array(2*this.size);w._$jT(this._$P,0,i,0,this.size),this._$P=i}this._$P[this.size++]=t},N.prototype._$BL=function(){var t=new Float32Array(this.size);return w._$jT(this._$P,0,t,0,this.size),t},B._$Fr=0,B._$hs=1,B._$ws=100,B._$Ns=101,B._$xs=102,B._$us=103,B._$qs=104,B._$Ys=105,U._$Ms=1,U._$Qs=2,U._$i2=0,U._$No=2,U._$do=U._$Ms,U._$Ls=!0,U._$1r=5,U._$Qb=65,U._$J=1e-4,U._$FT=.001,U._$Ss=3,G._$o7=6,G._$S7=7,G._$s7=8,G._$77=9,G.LIVE2D_FORMAT_VERSION_V2_10_SDK2=10,G.LIVE2D_FORMAT_VERSION_V2_11_SDK2_1=11,G._$T7=G.LIVE2D_FORMAT_VERSION_V2_11_SDK2_1,G._$Is=-2004318072,G._$h0=0,G._$4L=23,G._$7P=33,G._$uT=function(t){console.log("_$bo :: _$6 _$mo _$E0 : %d\n",t)},G._$9o=function(t){if(t<40)return G._$uT(t),null;if(t<50)return G._$uT(t),null;if(t<60)return G._$uT(t),null;if(t<100)switch(t){case 65:return new Z;case 66:return new D;case 67:return new x;case 68:return new z;case 69:return new P;case 70:return new $t;default:return G._$uT(t),null}else if(t<150)switch(t){case 131:return new st;case 133:return new tt;case 136:return new p;case 137:return new ot;case 142:return new j}return G._$uT(t),null},Y._$HP=0,Y._$_0=!0;Y._$V2=-1,Y._$W0=-1,Y._$jr=!1,Y._$ZS=!0,Y._$tr=-1e6,Y._$lr=1e6,Y._$is=32,Y._$e=!1,Y.prototype.getDrawDataIndex=function(t){for(var i=this._$aS.length-1;i>=0;--i)if(null!=this._$aS[i]&&this._$aS[i].getDrawDataID()==t)return i;return-1},Y.prototype.getDrawData=function(t){if(t instanceof b){if(null==this._$Bo){this._$Bo=new Object;for(var i=this._$aS.length,e=0;e0&&this.release();for(var t=this._$Ri.getModelImpl(),i=t._$Xr(),r=i.length,o=new Array,n=new Array,s=0;s=0)&&(this._$3S.push(m),this._$db.push(n[s]),o[s]=null,y=!0)}}if(!y)break}var P=t._$E2();if(null!=P){var S=P._$1s();if(null!=S)for(var v=S.length,s=0;s=0;i--)this._$Js[i]=Y._$jr;return this._$QT=!1,Y._$e&&_.dump("_$eL"),!1},Y.prototype.preDraw=function(t){null!=this.clipManager&&(t._$ZT(),this.clipManager.setupClip(this,t))},Y.prototype.draw=function(t){if(null==this._$Ws)return void _._$li("call _$Ri.update() before _$Ri.draw() ");var i=this._$Ws.length;t._$ZT();for(var e=0;e=0;--i)if(this._$pb[i]==t)return i;return this._$02(t,0,Y._$tr,Y._$lr)},Y.prototype._$BS=function(t){return this.getBaseDataIndex(t)},Y.prototype.getBaseDataIndex=function(t){for(var i=this._$3S.length-1;i>=0;--i)if(null!=this._$3S[i]&&this._$3S[i].getBaseDataID()==t)return i;return-1},Y.prototype._$UT=function(t,i){var e=new Float32Array(i);return w._$jT(t,0,e,0,t.length),e},Y.prototype._$02=function(t,i,e,r){if(this._$qo>=this._$pb.length){var o=this._$pb.length,n=new Array(2*o);w._$jT(this._$pb,0,n,0,o),this._$pb=n,this._$_2=this._$UT(this._$_2,2*o),this._$vr=this._$UT(this._$vr,2*o),this._$Rr=this._$UT(this._$Rr,2*o),this._$Or=this._$UT(this._$Or,2*o);var s=new Array;w._$jT(this._$Js,0,s,0,o),this._$Js=s}return this._$pb[this._$qo]=t,this._$_2[this._$qo]=i,this._$vr[this._$qo]=i,this._$Rr[this._$qo]=e,this._$Or[this._$qo]=r,this._$Js[this._$qo]=Y._$ZS,this._$qo++},Y.prototype._$Zo=function(t,i){this._$3S[t]=i},Y.prototype.setParamFloat=function(t,i){ithis._$Or[t]&&(i=this._$Or[t]),this._$_2[t]=i},Y.prototype.loadParam=function(){var t=this._$_2.length;t>this._$fs.length&&(t=this._$fs.length),w._$jT(this._$fs,0,this._$_2,0,t)},Y.prototype.saveParam=function(){var t=this._$_2.length;t>this._$fs.length&&(this._$fs=new Float32Array(t)),w._$jT(this._$_2,0,this._$fs,0,t)},Y.prototype._$v2=function(){return this._$co},Y.prototype._$WS=function(){return this._$QT},Y.prototype._$Xb=function(t){return this._$Js[t]==Y._$ZS},Y.prototype._$vs=function(){return this._$Es},Y.prototype._$Tr=function(){return this._$ZP},Y.prototype.getBaseData=function(t){return this._$3S[t]},Y.prototype.getParamFloat=function(t){return this._$_2[t]},Y.prototype.getParamMax=function(t){return this._$Or[t]},Y.prototype.getParamMin=function(t){return this._$Rr[t]},Y.prototype.setPartsOpacity=function(t,i){this._$Hr[t].setPartsOpacity(i)},Y.prototype.getPartsOpacity=function(t){return this._$Hr[t].getPartsOpacity()},Y.prototype.getPartsDataIndex=function(t){for(var i=this._$F2.length-1;i>=0;--i)if(null!=this._$F2[i]&&this._$F2[i]._$p2()==t)return i;return-1},Y.prototype._$q2=function(t){return this._$db[t]},Y.prototype._$C2=function(t){return this._$8b[t]},Y.prototype._$Bb=function(t){return this._$Hr[t]},Y.prototype._$5s=function(t,i){for(var e=this._$Ws.length,r=t,o=0;o0;)n+=i;return r},k._$C=function(t){var i=null,e=null;try{i=t instanceof Array?t:new _$Xs(t,8192),e=new _$js;for(var r,o=new Int8Array(1e3);(r=i.read(o))>0;)e.write(o,0,r);return e._$TS()}finally{null!=t&&t.close(),null!=e&&(e.flush(),e.close())}},V.prototype._$T2=function(){return w.getUserTimeMSec()+Math._$10()*(2*this._$Br-1)},V.prototype._$uo=function(t){this._$Br=t},V.prototype._$QS=function(t,i,e){this._$Dr=t,this._$Cb=i,this._$mr=e},V.prototype._$7T=function(t){var i,e=w.getUserTimeMSec(),r=0;switch(this._$_L){case STATE_CLOSING:r=(e-this._$bb)/this._$Dr,r>=1&&(r=1,this._$_L=wt.STATE_CLOSED,this._$bb=e),i=1-r;break;case STATE_CLOSED:r=(e-this._$bb)/this._$Cb,r>=1&&(this._$_L=wt.STATE_OPENING,this._$bb=e),i=0;break;case STATE_OPENING:r=(e-this._$bb)/this._$mr,r>=1&&(r=1,this._$_L=wt.STATE_INTERVAL,this._$12=this._$T2()),i=r;break;case STATE_INTERVAL:this._$12.9?at.EXPAND_W:0;this.gl.drawElements(a,e,r,o,n,h,this.transform,_)}},X.prototype._$Rs=function(){throw new Error("_$Rs")},X.prototype._$Ds=function(t){throw new Error("_$Ds")},X.prototype._$K2=function(){for(var t=0;t=0;--i){var e=t[i];eW._$R2&&(W._$R2=e)}},W._$or=function(){return W._$52},W._$Pr=function(){return W._$R2},W.prototype._$F0=function(t){this._$gP=t._$nP(),this._$dr=t._$nP(),this._$GS=t._$nP(),this._$qb=t._$6L(),this._$Lb=t._$cS(),this._$mS=t._$Tb(),t.getFormatVersion()>=G._$T7?(this.clipID=t._$nP(),this.clipIDList=this.convertClipIDForV2_11(this.clipID)):this.clipIDList=null,W._$Sb(this._$Lb)},W.prototype.getClipIDList=function(){return this.clipIDList},W.prototype._$Nr=function(t,i){if(i._$IS[0]=!1,i._$Us=v._$Z2(t,this._$GS,i._$IS,this._$Lb),at._$Zs);else if(i._$IS[0])return;i._$7s=v._$br(t,this._$GS,i._$IS,this._$mS)},W.prototype._$2b=function(t){},W.prototype.getDrawDataID=function(){return this._$gP},W.prototype._$j2=function(t){this._$gP=t},W.prototype.getOpacity=function(t,i){return i._$7s},W.prototype._$zS=function(t,i){return i._$Us},W.prototype.getTargetBaseDataID=function(){return this._$dr},W.prototype._$gs=function(t){this._$dr=t},W.prototype._$32=function(){return null!=this._$dr&&this._$dr!=yt._$2o()},W.prototype.getType=function(){},j._$42=0,j.prototype._$1b=function(){return this._$3S},j.prototype.getDrawDataList=function(){return this._$aS},j.prototype._$F0=function(t){this._$NL=t._$nP(),this._$aS=t._$nP(),this._$3S=t._$nP()},j.prototype._$kr=function(t){t._$Zo(this._$3S),t._$xo(this._$aS),this._$3S=null,this._$aS=null},q.prototype=new i,q.loadModel=function(t){var e=new q;return i._$62(e,t),e},q.loadModel=function(t){var e=new q;return i._$62(e,t),e},q._$to=function(){return new q},q._$er=function(t){var i=new _$5("../_$_r/_$t0/_$Ri/_$_P._$d");if(0==i.exists())throw new _$ls("_$t0 _$_ _$6 _$Ui :: "+i._$PL());for(var e=["../_$_r/_$t0/_$Ri/_$_P.512/_$CP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$vP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$EP._$1","../_$_r/_$t0/_$Ri/_$_P.512/_$pP._$1"],r=q.loadModel(i._$3b()),o=0;o=0){var h=new B;O.startsWith(t,_,J._$cs)?(h._$RP=B._$hs,h._$4P=O.createString(t,_,a-_)):O.startsWith(t,_,J._$ar)?(h._$4P=O.createString(t,_+7,a-_-7),O.startsWith(t,_+7,"ANCHOR_X")?h._$RP=B._$xs:O.startsWith(t,_+7,"ANCHOR_Y")?h._$RP=B._$us:O.startsWith(t,_+7,"SCALE_X")?h._$RP=B._$qs:O.startsWith(t,_+7,"SCALE_Y")?h._$RP=B._$Ys:O.startsWith(t,_+7,"X")?h._$RP=B._$ws:O.startsWith(t,_+7,"Y")&&(h._$RP=B._$Ns)):(h._$RP=B._$Fr,h._$4P=O.createString(t,_,a-_)),i.motions.push(h);var l=0,$=[];for(o=a+1;o0){$.push(u),l++;var p=e[0];if(pi._$yT&&(i._$yT=l)}}}else{for(var _=o,a=-1;o=0)for(a==_+4&&"f"==Q(t,_+1)&&"p"==Q(t,_+2)&&"s"==Q(t,_+3)&&(f=!0),o=a+1;o0&&f&&5=l?l-1:s];t.setParamFloat($,u)}else if(B._$ws<=h._$RP&&h._$RP<=B._$Ys);else{var p,f=t.getParamIndex($),c=t.getModelContext(),d=c.getParamMax(f),g=c.getParamMin(f),y=.4*(d-g),m=c.getParamFloat(f),T=h._$I0[s>=l?l-1:s],P=h._$I0[s+1>=l?l-1:s+1];p=Ty||T>P&&T-P>y?T:T+(P-T)*_;var S=m+(p-m)*e;t.setParamFloat($,S)}}s>=this._$yT&&(this._$E?(r._$z2=i,this.loopFadeIn&&(r._$bs=i)):r._$9L=!0),this._$eP=e},J.prototype._$r0=function(){return this._$E},J.prototype._$aL=function(t){this._$E=t},J.prototype._$S0=function(){return this._$D0},J.prototype._$U0=function(t){this._$D0=t},J.prototype.isLoopFadeIn=function(){return this.loopFadeIn},J.prototype.setLoopFadeIn=function(t){this.loopFadeIn=t},N.prototype.clear=function(){this.size=0},N.prototype.add=function(t){if(this._$P.length<=this.size){var i=new Float32Array(2*this.size);w._$jT(this._$P,0,i,0,this.size),this._$P=i}this._$P[this.size++]=t},N.prototype._$BL=function(){var t=new Float32Array(this.size);return w._$jT(this._$P,0,t,0,this.size),t},B._$Fr=0,B._$hs=1,B._$ws=100,B._$Ns=101,B._$xs=102,B._$us=103,B._$qs=104,B._$Ys=105,Z.prototype=new I,Z._$gT=new Array,Z.prototype._$zP=function(){this._$GS=new D,this._$GS._$zP()},Z.prototype._$F0=function(t){I.prototype._$F0.call(this,t),this._$A=t._$6L(),this._$o=t._$6L(),this._$GS=t._$nP(),this._$Eo=t._$nP(),I.prototype.readV2_opacity.call(this,t)},Z.prototype.init=function(t){var i=new K(this),e=(this._$o+1)*(this._$A+1);return null!=i._$Cr&&(i._$Cr=null),i._$Cr=new Float32Array(2*e),null!=i._$hr&&(i._$hr=null),this._$32()?i._$hr=new Float32Array(2*e):i._$hr=null,i},Z.prototype._$Nr=function(t,i){var e=i;if(this._$GS._$Ur(t)){var r=this._$VT(),o=Z._$gT;o[0]=!1,v._$Vr(t,this._$GS,o,r,this._$Eo,e._$Cr,0,2),i._$Ib(o[0]),this.interpolateOpacity(t,this._$GS,i,o)}},Z.prototype._$2b=function(t,i){var e=i;if(e._$hS(!0),this._$32()){var r=this.getTargetBaseDataID();if(e._$8r==I._$ur&&(e._$8r=t.getBaseDataIndex(r)),e._$8r<0)at._$so&&_._$li("_$L _$0P _$G :: %s",r),e._$hS(!1);else{var o=t.getBaseData(e._$8r),n=t._$q2(e._$8r);if(null!=o&&n._$yo()){var s=n.getTotalScale();e.setTotalScale_notForClient(s);var a=n.getTotalOpacity();e.setTotalOpacity(a*e.getInterpolatedOpacity()),o._$nb(t,n,e._$Cr,e._$hr,this._$VT(),0,2),e._$hS(!0)}else e._$hS(!1)}}else e.setTotalOpacity(e.getInterpolatedOpacity())},Z.prototype._$nb=function(t,i,e,r,o,n,s){var _=i,a=null!=_._$hr?_._$hr:_._$Cr;Z.transformPoints_sdk2(e,r,o,n,s,a,this._$o,this._$A)},Z.transformPoints_sdk2=function(i,e,r,o,n,s,_,a){for(var h,l,$,u=r*n,p=0,f=0,c=0,d=0,g=0,y=0,m=!1,T=o;T=1){var b=s[2*(0+a*M)],F=s[2*(0+a*M)+1],C=p-2*c+1*g,N=f-2*d+1*y,x=p+3*g,O=f+3*y,D=p-2*c+3*g,R=f-2*d+3*y,B=.5*(v- -2),U=.5*(L-1);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else{var G=0|S;G==a&&(G=a-1);var B=.5*(v- -2),U=S-G,Y=G/a,k=(G+1)/a,b=s[2*(0+G*M)],F=s[2*(0+G*M)+1],x=s[2*(0+(G+1)*M)],O=s[2*(0+(G+1)*M)+1],C=p-2*c+Y*g,N=f-2*d+Y*y,D=p-2*c+k*g,R=f-2*d+k*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(1<=v)if(L<=0){var D=s[2*(_+0*M)],R=s[2*(_+0*M)+1],x=p+3*c,O=f+3*d,C=p+1*c-2*g,N=f+1*d-2*y,b=p+3*c-2*g,F=f+3*d-2*y,B=.5*(v-1),U=.5*(L- -2);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L>=1){var C=s[2*(_+a*M)],N=s[2*(_+a*M)+1],b=p+3*c+1*g,F=f+3*d+1*y,D=p+1*c+3*g,R=f+1*d+3*y,x=p+3*c+3*g,O=f+3*d+3*y,B=.5*(v-1),U=.5*(L-1);B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else{var G=0|S;G==a&&(G=a-1);var B=.5*(v-1),U=S-G,Y=G/a,k=(G+1)/a,C=s[2*(_+G*M)],N=s[2*(_+G*M)+1],D=s[2*(_+(G+1)*M)],R=s[2*(_+(G+1)*M)+1],b=p+3*c+Y*g,F=f+3*d+Y*y,x=p+3*c+k*g,O=f+3*d+k*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L<=0){var V=0|P;V==_&&(V=_-1);var B=P-V,U=.5*(L- -2),X=V/_,z=(V+1)/_,D=s[2*(V+0*M)],R=s[2*(V+0*M)+1],x=s[2*(V+1+0*M)],O=s[2*(V+1+0*M)+1],C=p+X*c-2*g,N=f+X*d-2*y,b=p+z*c-2*g,F=f+z*d-2*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else if(L>=1){var V=0|P;V==_&&(V=_-1);var B=P-V,U=.5*(L-1),X=V/_,z=(V+1)/_,C=s[2*(V+a*M)],N=s[2*(V+a*M)+1],b=s[2*(V+1+a*M)],F=s[2*(V+1+a*M)+1],D=p+X*c+3*g,R=f+X*d+3*y,x=p+z*c+3*g,O=f+z*d+3*y;B+U<=1?(e[T]=C+(b-C)*B+(D-C)*U,e[T+1]=N+(F-N)*B+(R-N)*U):(e[T]=x+(D-x)*(1-B)+(b-x)*(1-U),e[T+1]=O+(R-O)*(1-B)+(F-O)*(1-U))}else t.err.printf("_$li calc : %.4f , %.4f\t\t\t\t\t@@BDBoxGrid\n",v,L);else e[T]=p+v*c+L*g,e[T+1]=f+v*d+L*y}else l=P-(0|P),$=S-(0|S),h=2*((0|P)+(0|S)*(_+1)),l+$<1?(e[T]=s[h]*(1-l-$)+s[h+2]*l+s[h+2*(_+1)]*$,e[T+1]=s[h+1]*(1-l-$)+s[h+3]*l+s[h+2*(_+1)+1]*$):(e[T]=s[h+2*(_+1)+2]*(l-1+$)+s[h+2*(_+1)]*(1-l)+s[h+2]*(1-$),e[T+1]=s[h+2*(_+1)+3]*(l-1+$)+s[h+2*(_+1)+1]*(1-l)+s[h+3]*(1-$))}},Z.prototype.transformPoints_sdk1=function(t,i,e,r,o,n,s){for(var _,a,h,l,$,u,p,f=i,c=this._$o,d=this._$A,g=o*s,y=null!=f._$hr?f._$hr:f._$Cr,m=n;m1&&(_=1),a<0?a=0:a>1&&(a=1),_*=c,a*=d,h=0|_,l=0|a,h>c-1&&(h=c-1),l>d-1&&(l=d-1),u=_-h,p=a-l,$=2*(h+l*(c+1))):(_=e[m]*c,a=e[m+1]*d,u=_-(0|_),p=a-(0|a),$=2*((0|_)+(0|a)*(c+1))),u+p<1?(r[m]=y[$]*(1-u-p)+y[$+2]*u+y[$+2*(c+1)]*p,r[m+1]=y[$+1]*(1-u-p)+y[$+3]*u+y[$+2*(c+1)+1]*p):(r[m]=y[$+2*(c+1)+2]*(u-1+p)+y[$+2*(c+1)]*(1-u)+y[$+2]*(1-p),r[m+1]=y[$+2*(c+1)+3]*(u-1+p)+y[$+2*(c+1)+1]*(1-u)+y[$+3]*(1-p))},Z.prototype._$VT=function(){return(this._$o+1)*(this._$A+1)},Z.prototype.getType=function(){return I._$_b},K.prototype=new _t,tt._$42=0,tt.prototype._$zP=function(){this._$3S=new Array,this._$aS=new Array},tt.prototype._$F0=function(t){this._$g0=t._$8L(),this.visible=t._$8L(),this._$NL=t._$nP(),this._$3S=t._$nP(),this._$aS=t._$nP()},tt.prototype.init=function(t){var i=new it(this);return i.setPartsOpacity(this.isVisible()?1:0),i},tt.prototype._$6o=function(t){if(null==this._$3S)throw new Error("_$3S _$6 _$Wo@_$6o");this._$3S.push(t)},tt.prototype._$3o=function(t){if(null==this._$aS)throw new Error("_$aS _$6 _$Wo@_$3o");this._$aS.push(t)},tt.prototype._$Zo=function(t){this._$3S=t},tt.prototype._$xo=function(t){this._$aS=t},tt.prototype.isVisible=function(){return this.visible},tt.prototype._$uL=function(){return this._$g0},tt.prototype._$KP=function(t){this.visible=t},tt.prototype._$ET=function(t){this._$g0=t},tt.prototype.getBaseData=function(){return this._$3S},tt.prototype.getDrawData=function(){return this._$aS},tt.prototype._$p2=function(){return this._$NL},tt.prototype._$ob=function(t){this._$NL=t},tt.prototype.getPartsID=function(){return this._$NL},tt.prototype._$MP=function(t){this._$NL=t},it.prototype=new $,it.prototype.getPartsOpacity=function(){return this._$VS},it.prototype.setPartsOpacity=function(t){this._$VS=t},et._$L7=function(){u._$27(),yt._$27(),b._$27(),l._$27()},et.prototype.toString=function(){return this.id},rt.prototype._$F0=function(t){},ot.prototype._$1s=function(){return this._$4S},ot.prototype._$zP=function(){this._$4S=new Array},ot.prototype._$F0=function(t){this._$4S=t._$nP()},ot.prototype._$Ks=function(t){this._$4S.push(t)},nt.tr=new gt,nt._$50=new gt,nt._$Ti=new Array(0,0),nt._$Pi=new Array(0,0),nt._$B=new Array(0,0),nt.prototype._$lP=function(t,i,e,r){this.viewport=new Array(t,i,e,r)},nt.prototype._$bL=function(){this.context.save();var t=this.viewport;null!=t&&(this.context.beginPath(),this.context._$Li(t[0],t[1],t[2],t[3]),this.context.clip())},nt.prototype._$ei=function(){this.context.restore()},nt.prototype.drawElements=function(t,i,e,r,o,n,s,a){try{o!=this._$Qo&&(this._$Qo=o,this.context.globalAlpha=o);for(var h=i.length,l=t.width,$=t.height,u=this.context,p=this._$xP,f=this._$uP,c=this._$6r,d=this._$3r,g=nt.tr,y=nt._$Ti,m=nt._$Pi,T=nt._$B,P=0;P.02?nt.expandClip(t,i,e,r,l,$,u,p,f,c):nt.clipWithTransform(t,null,o,n,s,_,a,h)},nt.expandClip=function(t,i,e,r,o,n,s,_,a,h){var l=s-o,$=_-n,u=a-o,p=h-n,f=l*p-$*u>0?e:-e,c=-$,d=l,g=a-s,y=h-_,m=-y,T=g,P=Math.sqrt(g*g+y*y),S=-p,v=u,L=Math.sqrt(u*u+p*p),M=o-f*c/r,E=n-f*d/r,A=s-f*c/r,I=_-f*d/r,w=s-f*m/P,x=_-f*T/P,O=a-f*m/P,D=h-f*T/P,R=o+f*S/L,b=n+f*v/L,F=a+f*S/L,C=h+f*v/L,N=nt._$50;return null!=i._$P2(N)&&(nt.clipWithTransform(t,N,M,E,A,I,w,x,O,D,F,C,R,b),!0)},nt.clipWithTransform=function(t,i,e,r,o,n,s,a){if(arguments.length<7)return void _._$li("err : @LDGL.clip()");if(!(arguments[1]instanceof gt))return void _._$li("err : a[0] is _$6 LDTransform @LDGL.clip()");var h=nt._$B,l=i,$=arguments;if(t.beginPath(),l){l._$PS($[2],$[3],h),t.moveTo(h[0],h[1]);for(var u=4;u<$.length;u+=2)l._$PS($[u],$[u+1],h),t.lineTo(h[0],h[1])}else{t.moveTo($[2],$[3]);for(var u=4;u<$.length;u+=2)t.lineTo($[u],$[u+1])}t.clip()},nt.createCanvas=function(t,i){var e=document.createElement("canvas");return e.setAttribute("width",t),e.setAttribute("height",i),e||_._$li("err : "+e),e},nt.dumpValues=function(){for(var t="",i=0;i1?1:.5-.5*Math.cos(t*Lt.PI_F)},lt._$fr=-1,lt.prototype.toString=function(){return this._$ib},$t.prototype=new W,$t._$42=0,$t._$Os=30,$t._$ms=0,$t._$ns=1,$t._$_s=2,$t._$gT=new Array,$t.prototype._$_S=function(t){this._$LP=t},$t.prototype.getTextureNo=function(){return this._$LP},$t.prototype._$ZL=function(){return this._$Qi},$t.prototype._$H2=function(){return this._$JP},$t.prototype.getNumPoints=function(){return this._$d0},$t.prototype.getType=function(){return W._$wb},$t.prototype._$B2=function(t,i,e){var r=i,o=null!=r._$hr?r._$hr:r._$Cr;switch(U._$do){default:case U._$Ms:throw new Error("_$L _$ro ");case U._$Qs:for(var n=this._$d0-1;n>=0;--n)o[n*U._$No+4]=e}},$t.prototype._$zP=function(){this._$GS=new D,this._$GS._$zP()},$t.prototype._$F0=function(t){W.prototype._$F0.call(this,t),this._$LP=t._$6L(),this._$d0=t._$6L(),this._$Yo=t._$6L();var i=t._$nP();this._$BP=new Int16Array(3*this._$Yo);for(var e=3*this._$Yo-1;e>=0;--e)this._$BP[e]=i[e];if(this._$Eo=t._$nP(),this._$Qi=t._$nP(),t.getFormatVersion()>=G._$s7){if(this._$JP=t._$6L(),0!=this._$JP){if(0!=(1&this._$JP)){var r=t._$6L();null==this._$5P&&(this._$5P=new Object),this._$5P._$Hb=parseInt(r)}0!=(this._$JP&$t._$Os)?this._$6s=(this._$JP&$t._$Os)>>1:this._$6s=$t._$ms,0!=(32&this._$JP)&&(this.culling=!1)}}else this._$JP=0},$t.prototype.init=function(t){var i=new ut(this),e=this._$d0*U._$No,r=this._$32();switch(null!=i._$Cr&&(i._$Cr=null),i._$Cr=new Float32Array(e),null!=i._$hr&&(i._$hr=null),i._$hr=r?new Float32Array(e):null,U._$do){default:case U._$Ms:if(U._$Ls)for(var o=this._$d0-1;o>=0;--o){var n=o<<1;this._$Qi[n+1]=1-this._$Qi[n+1]}break;case U._$Qs:for(var o=this._$d0-1;o>=0;--o){var n=o<<1,s=o*U._$No,_=this._$Qi[n],a=this._$Qi[n+1];i._$Cr[s]=_,i._$Cr[s+1]=a,i._$Cr[s+4]=0,r&&(i._$hr[s]=_,i._$hr[s+1]=a,i._$hr[s+4]=0)}}return i},$t.prototype._$Nr=function(t,i){var e=i;if(this!=e._$GT()&&console.log("### assert!! ### "),this._$GS._$Ur(t)&&(W.prototype._$Nr.call(this,t,e),!e._$IS[0])){var r=$t._$gT;r[0]=!1,v._$Vr(t,this._$GS,r,this._$d0,this._$Eo,e._$Cr,U._$i2,U._$No)}},$t.prototype._$2b=function(t,i){try{this!=i._$GT()&&console.log("### assert!! ### ");var e=!1;i._$IS[0]&&(e=!0);var r=i;if(!e&&(W.prototype._$2b.call(this,t),this._$32())){var o=this.getTargetBaseDataID();if(r._$8r==W._$ur&&(r._$8r=t.getBaseDataIndex(o)),r._$8r<0)at._$so&&_._$li("_$L _$0P _$G :: %s",o);else{var n=t.getBaseData(r._$8r),s=t._$q2(r._$8r);null==n||s._$x2()?r._$AT=!1:(n._$nb(t,s,r._$Cr,r._$hr,this._$d0,U._$i2,U._$No),r._$AT=!0),r.baseOpacity=s.getTotalOpacity()}}}catch(t){throw t}},$t.prototype.draw=function(t,i,e){if(this!=e._$GT()&&console.log("### assert!! ### "),!e._$IS[0]){var r=e,o=this._$LP;o<0&&(o=1);var n=this.getOpacity(i,r)*e._$VS*e.baseOpacity,s=null!=r._$hr?r._$hr:r._$Cr;t.setClipBufPre_clipContextForDraw(e.clipBufPre_clipContext),t._$WP(this.culling),t._$Uo(o,3*this._$Yo,this._$BP,s,this._$Qi,n,this._$6s,r)}},$t.prototype.dump=function(){console.log(" _$yi( %d ) , _$d0( %d ) , _$Yo( %d ) \n",this._$LP,this._$d0,this._$Yo),console.log(" _$Oi _$di = { ");for(var t=0;tstartMotion() / start _$K _$3 (m%d)\n",r,e._$sr));if(null==t)return-1;e=new dt,e._$w0=t,this.motions.push(e);var n=e._$sr;return this._$eb&&_._$Ji("MotionQueueManager[size:%2d]->startMotion() / new _$w0 (m%d)\n",r,n),n},ct.prototype.updateParam=function(t){try{for(var i=!1,e=0;eupdateParam() / _$T0 _$w0 (m%d)\n",this.motions.length-1,r._$sr),this.motions.splice(e,1),e--)):(this.motions=this.motions.splice(e,1),e--)}else this.motions.splice(e,1),e--}return i}catch(t){return _._$li(t),!0}},ct.prototype.isFinished=function(t){if(arguments.length>=1){for(var i=0;i.9&&at.EXPAND_W,this.gl);if(null==this.gl)throw new Error("gl is null");var h=1*this._$C0*n,l=1*this._$tT*n,$=1*this._$WL*n,u=this._$lT*n;if(null!=this.clipBufPre_clipContextMask){a.frontFace(a.CCW),a.useProgram(this.shaderProgram),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc),a.vertexAttribPointer(this.a_position_Loc,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc,1),a.enableVertexAttribArray(this.a_texCoord_Loc),a.vertexAttribPointer(this.a_texCoord_Loc,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_matrix_Loc,!1,this.getClipBufPre_clipContextMask().matrixForMask);var p=this.getClipBufPre_clipContextMask().layoutChannelNo,f=this.getChannelFlagAsColor(p);a.uniform4f(this.u_channelFlag,f.r,f.g,f.b,f.a);var c=this.getClipBufPre_clipContextMask().layoutBounds;a.uniform4f(this.u_baseColor_Loc,2*c.x-1,2*c.y-1,2*c._$EL()-1,2*c._$5T()-1),a.uniform1i(this.u_maskFlag_Loc,!0)}else if(null!=this.getClipBufPre_clipContextDraw()){a.useProgram(this.shaderProgramOff),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc_Off),a.vertexAttribPointer(this.a_position_Loc_Off,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc_Off,1),a.enableVertexAttribArray(this.a_texCoord_Loc_Off),a.vertexAttribPointer(this.a_texCoord_Loc_Off,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_clipMatrix_Loc_Off,!1,this.getClipBufPre_clipContextDraw().matrixForDraw),a.uniformMatrix4fv(this.u_matrix_Loc_Off,!1,this.matrix4x4),a.activeTexture(a.TEXTURE2),a.bindTexture(a.TEXTURE_2D,at.fTexture[this.glno]),a.uniform1i(this.s_texture1_Loc_Off,2);var p=this.getClipBufPre_clipContextDraw().layoutChannelNo,f=this.getChannelFlagAsColor(p);a.uniform4f(this.u_channelFlag_Loc_Off,f.r,f.g,f.b,f.a),a.uniform4f(this.u_baseColor_Loc_Off,h,l,$,u)}else a.useProgram(this.shaderProgram),this._$vS=Tt(a,this._$vS,r),this._$no=Pt(a,this._$no,e),a.enableVertexAttribArray(this.a_position_Loc),a.vertexAttribPointer(this.a_position_Loc,2,a.FLOAT,!1,0,0),this._$NT=Tt(a,this._$NT,o),a.activeTexture(a.TEXTURE1),a.bindTexture(a.TEXTURE_2D,this.textures[t]),a.uniform1i(this.s_texture0_Loc,1),a.enableVertexAttribArray(this.a_texCoord_Loc),a.vertexAttribPointer(this.a_texCoord_Loc,2,a.FLOAT,!1,0,0),a.uniformMatrix4fv(this.u_matrix_Loc,!1,this.matrix4x4),a.uniform4f(this.u_baseColor_Loc,h,l,$,u),a.uniform1i(this.u_maskFlag_Loc,!1);this.culling?this.gl.enable(a.CULL_FACE):this.gl.disable(a.CULL_FACE),this.gl.enable(a.BLEND);var d,g,y,m;if(null!=this.clipBufPre_clipContextMask)d=a.ONE,g=a.ONE_MINUS_SRC_ALPHA,y=a.ONE,m=a.ONE_MINUS_SRC_ALPHA;else switch(s){case $t._$ms:d=a.ONE,g=a.ONE_MINUS_SRC_ALPHA,y=a.ONE,m=a.ONE_MINUS_SRC_ALPHA;break;case $t._$ns:d=a.ONE,g=a.ONE,y=a.ZERO,m=a.ONE;break;case $t._$_s:d=a.DST_COLOR,g=a.ONE_MINUS_SRC_ALPHA,y=a.ZERO,m=a.ONE}a.blendEquationSeparate(a.FUNC_ADD,a.FUNC_ADD),a.blendFuncSeparate(d,g,y,m),this.anisotropyExt&&a.texParameteri(a.TEXTURE_2D,this.anisotropyExt.TEXTURE_MAX_ANISOTROPY_EXT,this.maxAnisotropy);var T=e.length;a.drawElements(a.TRIANGLES,T,a.UNSIGNED_SHORT,0),a.bindTexture(a.TEXTURE_2D,null)}},mt.prototype._$Rs=function(){throw new Error("_$Rs")},mt.prototype._$Ds=function(t){throw new Error("_$Ds")},mt.prototype._$K2=function(){for(var t=0;t=48){var r=G._$9o(t);return null!=r?(r._$F0(this),r):null}switch(t){case 1:return this._$bT();case 10:return new n(this._$6L(),!0);case 11:return new S(this._$mP(),this._$mP(),this._$mP(),this._$mP());case 12:return new S(this._$_T(),this._$_T(),this._$_T(),this._$_T());case 13:return new L(this._$mP(),this._$mP());case 14:return new L(this._$_T(),this._$_T());case 15:for(var o=this._$3L(),e=new Array(o),s=0;s>7-this._$hL++&1)},St.prototype._$zT=function(){0!=this._$hL&&(this._$hL=0)},vt.prototype._$wP=function(t,i,e){for(var r=0;rMath.PI;)e-=2*Math.PI;return e},Lt._$9=function(t){return Math.sin(t)},Lt.fcos=function(t){return Math.cos(t)},Mt.prototype._$u2=function(){return this._$IS[0]},Mt.prototype._$yo=function(){return this._$AT&&!this._$IS[0]},Mt.prototype._$GT=function(){return this._$e0},Et._$W2=0,Et.SYSTEM_INFO=null,Et.USER_AGENT=navigator.userAgent,Et.isIPhone=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone},Et.isIOS=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone||Et.SYSTEM_INFO._isIPad},Et.isAndroid=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isAndroid},Et.getOSVersion=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO.version},Et.getOS=function(){return Et.SYSTEM_INFO||Et.setup(),Et.SYSTEM_INFO._isIPhone||Et.SYSTEM_INFO._isIPad?"iOS":Et.SYSTEM_INFO._isAndroid?"Android":"_$Q0 OS"},Et.setup=function(){function t(t,i){for(var e=t.substring(i).split(/[ _,;\.]/),r=0,o=0;o<=2&&!isNaN(e[o]);o++){var n=parseInt(e[o]);if(n<0||n>999){_._$li("err : "+n+" @UtHtml5.setup()"),r=0;break}r+=n*Math.pow(1e3,2-o)}return r}var i,e=Et.USER_AGENT,r=Et.SYSTEM_INFO={userAgent:e};if((i=e.indexOf("iPhone OS "))>=0)r.os="iPhone",r._isIPhone=!0,r.version=t(e,i+"iPhone OS ".length);else if((i=e.indexOf("iPad"))>=0){if((i=e.indexOf("CPU OS"))<0)return void _._$li(" err : "+e+" @UtHtml5.setup()");r.os="iPad",r._isIPad=!0,r.version=t(e,i+"CPU OS ".length)}else(i=e.indexOf("Android"))>=0?(r.os="Android",r._isAndroid=!0,r.version=t(e,i+"Android ".length)):(r.os="-",r.version=-1)},window.UtSystem=w,window.UtDebug=_,window.LDTransform=gt,window.LDGL=nt,window.Live2D=at,window.Live2DModelWebGL=ft,window.Live2DModelJS=q,window.Live2DMotion=J,window.MotionQueueManager=ct,window.PhysicsHair=f,window.AMotion=s,window.PartsDataID=l,window.DrawDataID=b,window.BaseDataID=yt,window.ParamID=u,at.init();var At=!1}()}).call(i,e(7))},function(t,i){t.exports={import:function(){throw new Error("System.import cannot be used indirectly")}}},function(t,i,e){"use strict";function r(t){return t&&t.__esModule?t:{default:t}}function o(){this.models=[],this.count=-1,this.reloadFlg=!1,Live2D.init(),n.Live2DFramework.setPlatformManager(new _.default)}Object.defineProperty(i,"__esModule",{value:!0}),i.default=o;var n=e(0),s=e(9),_=r(s),a=e(10),h=r(a),l=e(1),$=r(l);o.prototype.createModel=function(){var t=new h.default;return this.models.push(t),t},o.prototype.changeModel=function(t,i){if(this.reloadFlg){this.reloadFlg=!1;this.releaseModel(0,t),this.createModel(),this.models[0].load(t,i)}},o.prototype.getModel=function(t){return t>=this.models.length?null:this.models[t]},o.prototype.releaseModel=function(t,i){this.models.length<=t||(this.models[t].release(i),delete this.models[t],this.models.splice(t,1))},o.prototype.numModels=function(){return this.models.length},o.prototype.setDrag=function(t,i){for(var e=0;e0){r.expressions={};for(var t=0;t waifu-tips.js","build-dev":"rollup -c rollup.config.js -f iife -o waifu-tips.js -w"},"repository":{"type":"git","url":"git+https://github.com/stevenjoezhang/live2d-widget.git"},"keywords":["Live2d"],"author":"stevenjoezhang ","license":"GPL-3.0-or-later","bugs":{"url":"https://github.com/stevenjoezhang/live2d-widget/issues"},"homepage":"https://github.com/stevenjoezhang/live2d-widget#readme","devDependencies":{"@fortawesome/fontawesome-free":"^6.2.0","@rollup/plugin-node-resolve":"^15.0.0","@rollup/pluginutils":"^5.0.1","rollup":"^3.2.3","terser":"^5.15.1"}} \ No newline at end of file diff --git a/live2d-widget/rollup.config.js b/live2d-widget/rollup.config.js new file mode 100644 index 00000000..3f46bc8c --- /dev/null +++ b/live2d-widget/rollup.config.js @@ -0,0 +1,38 @@ +import { nodeResolve } from "@rollup/plugin-node-resolve"; +import { createFilter } from "@rollup/pluginutils"; + +function string(opts = {}) { + if (!opts.include) { + throw Error("include option should be specified"); + } + + const filter = createFilter(opts.include, opts.exclude); + + return { + name: "string", + + transform(code, id) { + if (filter(id)) { + return { + code: `export default ${JSON.stringify(code)};`, + map: { mappings: "" } + }; + } + }, + + renderChunk(code, chunk, outputOptions = {}) { + return `/*! + * Live2D Widget + * https://github.com/stevenjoezhang/live2d-widget + */ +` + code; + } + }; +} + +export default { + input: "src/waifu-tips.js", + plugins: [nodeResolve(), string({ + include: "**/*.svg", + })] +}; diff --git a/live2d-widget/src/index.js b/live2d-widget/src/index.js new file mode 100644 index 00000000..cef62d31 --- /dev/null +++ b/live2d-widget/src/index.js @@ -0,0 +1,175 @@ +import Model from "./model.js"; +import showMessage from "./message.js"; +import randomSelection from "./utils.js"; +import tools from "./tools.js"; + +function loadWidget(config) { + const model = new Model(config); + localStorage.removeItem("waifu-display"); + sessionStorage.removeItem("waifu-text"); + document.body.insertAdjacentHTML("beforeend", `
+
+ +
+
`); + // https://stackoverflow.com/questions/24148403/trigger-css-transition-on-appended-element + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + + (function registerTools() { + tools["switch-model"].callback = () => model.loadOtherModel(); + tools["switch-texture"].callback = () => model.loadRandModel(); + if (!Array.isArray(config.tools)) { + config.tools = Object.keys(tools); + } + for (let tool of config.tools) { + if (tools[tool]) { + const { icon, callback } = tools[tool]; + document.getElementById("waifu-tool").insertAdjacentHTML("beforeend", `${icon}`); + document.getElementById(`waifu-tool-${tool}`).addEventListener("click", callback); + } + } + })(); + + function welcomeMessage(time) { + if (location.pathname === "/") { // 如果是主页 + for (let { hour, text } of time) { + const now = new Date(), + after = hour.split("-")[0], + before = hour.split("-")[1] || after; + if (after <= now.getHours() && now.getHours() <= before) { + return text; + } + } + } + const text = `欢迎阅读「${document.title.split(" - ")[0]}」`; + let from; + if (document.referrer !== "") { + const referrer = new URL(document.referrer), + domain = referrer.hostname.split(".")[1]; + const domains = { + "baidu": "百度", + "so": "360搜索", + "google": "谷歌搜索" + }; + if (location.hostname === referrer.hostname) return text; + + if (domain in domains) from = domains[domain]; + else from = referrer.hostname; + return `Hello!来自 ${from} 的朋友
${text}`; + } + return text; + } + + function registerEventListener(result) { + // 检测用户活动状态,并在空闲时显示消息 + let userAction = false, + userActionTimer, + messageArray = result.message.default; + window.addEventListener("mousemove", () => userAction = true); + window.addEventListener("keydown", () => userAction = true); + setInterval(() => { + if (userAction) { + userAction = false; + clearInterval(userActionTimer); + userActionTimer = null; + } else if (!userActionTimer) { + userActionTimer = setInterval(() => { + showMessage(messageArray, 6000, 9); + }, 20000); + } + }, 1000); + showMessage(welcomeMessage(result.time), 7000, 11); + window.addEventListener("mouseover", event => { + for (let { selector, text } of result.mouseover) { + if (!event.target.matches(selector)) continue; + text = randomSelection(text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + return; + } + }); + window.addEventListener("click", event => { + for (let { selector, text } of result.click) { + if (!event.target.matches(selector)) continue; + text = randomSelection(text); + text = text.replace("{text}", event.target.innerText); + showMessage(text, 4000, 8); + return; + } + }); + result.seasons.forEach(({ date, text }) => { + const now = new Date(), + after = date.split("-")[0], + before = date.split("-")[1] || after; + if ((after.split("/")[0] <= now.getMonth() + 1 && now.getMonth() + 1 <= before.split("/")[0]) && (after.split("/")[1] <= now.getDate() && now.getDate() <= before.split("/")[1])) { + text = randomSelection(text); + text = text.replace("{year}", now.getFullYear()); + messageArray.push(text); + } + }); + + const devtools = () => { }; + console.log("%c", devtools); + devtools.toString = () => { + showMessage(result.message.console, 6000, 9); + }; + window.addEventListener("copy", () => { + showMessage(result.message.copy, 6000, 9); + }); + window.addEventListener("visibilitychange", () => { + if (!document.hidden) showMessage(result.message.visibilitychange, 6000, 9); + }); + } + + (function initModel() { + let modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (modelId === null) { + // 首次访问加载 指定模型 的 指定材质 + modelId = 1; // 模型 ID + modelTexturesId = 53; // 材质 ID + } + model.loadModel(modelId, modelTexturesId); + fetch(config.waifuPath) + .then(response => response.json()) + .then(registerEventListener); + })(); +} + +function initWidget(config, apiPath) { + if (typeof config === "string") { + config = { + waifuPath: config, + apiPath + }; + } + document.body.insertAdjacentHTML("beforeend", `
+ 看板娘 +
`); + const toggle = document.getElementById("waifu-toggle"); + toggle.addEventListener("click", () => { + toggle.classList.remove("waifu-toggle-active"); + if (toggle.getAttribute("first-time")) { + loadWidget(config); + toggle.removeAttribute("first-time"); + } else { + localStorage.removeItem("waifu-display"); + document.getElementById("waifu").style.display = ""; + setTimeout(() => { + document.getElementById("waifu").style.bottom = 0; + }, 0); + } + }); + if (localStorage.getItem("waifu-display") && Date.now() - localStorage.getItem("waifu-display") <= 86400000) { + toggle.setAttribute("first-time", true); + setTimeout(() => { + toggle.classList.add("waifu-toggle-active"); + }, 0); + } else { + loadWidget(config); + } +} + +export default initWidget; diff --git a/live2d-widget/src/message.js b/live2d-widget/src/message.js new file mode 100644 index 00000000..4d294b1d --- /dev/null +++ b/live2d-widget/src/message.js @@ -0,0 +1,22 @@ +import randomSelection from "./utils.js"; + +let messageTimer; + +function showMessage(text, timeout, priority) { + if (!text || (sessionStorage.getItem("waifu-text") && sessionStorage.getItem("waifu-text") > priority)) return; + if (messageTimer) { + clearTimeout(messageTimer); + messageTimer = null; + } + text = randomSelection(text); + sessionStorage.setItem("waifu-text", priority); + const tips = document.getElementById("waifu-tips"); + tips.innerHTML = text; + tips.classList.add("waifu-tips-active"); + messageTimer = setTimeout(() => { + sessionStorage.removeItem("waifu-text"); + tips.classList.remove("waifu-tips-active"); + }, timeout); +} + +export default showMessage; diff --git a/live2d-widget/src/model.js b/live2d-widget/src/model.js new file mode 100644 index 00000000..23b036ab --- /dev/null +++ b/live2d-widget/src/model.js @@ -0,0 +1,75 @@ +import showMessage from "./message.js"; +import randomSelection from "./utils.js"; + +class Model { + constructor(config) { + let { apiPath, cdnPath } = config; + let useCDN = false; + if (typeof cdnPath === "string") { + useCDN = true; + if (!cdnPath.endsWith("/")) cdnPath += "/"; + } else if (typeof apiPath === "string") { + if (!apiPath.endsWith("/")) apiPath += "/"; + } else { + throw "Invalid initWidget argument!"; + } + this.useCDN = useCDN; + this.apiPath = apiPath; + this.cdnPath = cdnPath; + } + + async loadModelList() { + const response = await fetch(`${this.cdnPath}model_list.json`); + this.modelList = await response.json(); + } + + async loadModel(modelId, modelTexturesId, message) { + localStorage.setItem("modelId", modelId); + localStorage.setItem("modelTexturesId", modelTexturesId); + showMessage(message, 4000, 10); + if (this.useCDN) { + if (!this.modelList) await this.loadModelList(); + const target = randomSelection(this.modelList.models[modelId]); + loadlive2d("live2d", `${this.cdnPath}model/${target}/index.json`); + } else { + loadlive2d("live2d", `${this.apiPath}get/?id=${modelId}-${modelTexturesId}`); + console.log(`Live2D 模型 ${modelId}-${modelTexturesId} 加载完成`); + } + } + + async loadRandModel() { + const modelId = localStorage.getItem("modelId"), + modelTexturesId = localStorage.getItem("modelTexturesId"); + if (this.useCDN) { + if (!this.modelList) await this.loadModelList(); + const target = randomSelection(this.modelList.models[modelId]); + loadlive2d("live2d", `${this.cdnPath}model/${target}/index.json`); + showMessage("我的新衣服好看嘛?", 4000, 10); + } else { + // 可选 "rand"(随机), "switch"(顺序) + fetch(`${this.apiPath}rand_textures/?id=${modelId}-${modelTexturesId}`) + .then(response => response.json()) + .then(result => { + if (result.textures.id === 1 && (modelTexturesId === 1 || modelTexturesId === 0)) showMessage("我还没有其他衣服呢!", 4000, 10); + else this.loadModel(modelId, result.textures.id, "我的新衣服好看嘛?"); + }); + } + } + + async loadOtherModel() { + let modelId = localStorage.getItem("modelId"); + if (this.useCDN) { + if (!this.modelList) await this.loadModelList(); + const index = (++modelId >= this.modelList.models.length) ? 0 : modelId; + this.loadModel(index, 0, this.modelList.messages[index]); + } else { + fetch(`${this.apiPath}switch/?id=${modelId}`) + .then(response => response.json()) + .then(result => { + this.loadModel(result.model.id, 0, result.model.message); + }); + } + } +} + +export default Model; diff --git a/live2d-widget/src/tools.js b/live2d-widget/src/tools.js new file mode 100644 index 00000000..c8b38525 --- /dev/null +++ b/live2d-widget/src/tools.js @@ -0,0 +1,78 @@ +import fa_comment from "@fortawesome/fontawesome-free/svgs/solid/comment.svg"; +import fa_paper_plane from "@fortawesome/fontawesome-free/svgs/solid/paper-plane.svg"; +import fa_user_circle from "@fortawesome/fontawesome-free/svgs/solid/circle-user.svg"; +import fa_street_view from "@fortawesome/fontawesome-free/svgs/solid/street-view.svg"; +import fa_camera_retro from "@fortawesome/fontawesome-free/svgs/solid/camera-retro.svg"; +import fa_info_circle from "@fortawesome/fontawesome-free/svgs/solid/circle-info.svg"; +import fa_xmark from "@fortawesome/fontawesome-free/svgs/solid/xmark.svg"; + +import showMessage from "./message.js"; + +function showHitokoto() { + // 增加 hitokoto.cn 的 API + fetch("https://v1.hitokoto.cn") + .then(response => response.json()) + .then(result => { + const text = `这句一言来自 「${result.from}」,是 ${result.creator} 在 hitokoto.cn 投稿的。`; + showMessage(result.hitokoto, 6000, 9); + setTimeout(() => { + showMessage(text, 4000, 9); + }, 6000); + }); +} + +const tools = { + "hitokoto": { + icon: fa_comment, + callback: showHitokoto + }, + "asteroids": { + icon: fa_paper_plane, + callback: () => { + if (window.Asteroids) { + if (!window.ASTEROIDSPLAYERS) window.ASTEROIDSPLAYERS = []; + window.ASTEROIDSPLAYERS.push(new Asteroids()); + } else { + const script = document.createElement("script"); + script.src = "https://fastly.jsdelivr.net/gh/stevenjoezhang/asteroids/asteroids.js"; + document.head.appendChild(script); + } + } + }, + "switch-model": { + icon: fa_user_circle, + callback: () => {} + }, + "switch-texture": { + icon: fa_street_view, + callback: () => {} + }, + "photo": { + icon: fa_camera_retro, + callback: () => { + showMessage("照好了嘛,是不是很可爱呢?", 6000, 9); + Live2D.captureName = "photo.png"; + Live2D.captureFrame = true; + } + }, + "info": { + icon: fa_info_circle, + callback: () => { + open("https://github.com/stevenjoezhang/live2d-widget"); + } + }, + "quit": { + icon: fa_xmark, + callback: () => { + localStorage.setItem("waifu-display", Date.now()); + showMessage("愿你有一天能与重要的人重逢。", 2000, 11); + document.getElementById("waifu").style.bottom = "-500px"; + setTimeout(() => { + document.getElementById("waifu").style.display = "none"; + document.getElementById("waifu-toggle").classList.add("waifu-toggle-active"); + }, 3000); + } + } +}; + +export default tools; diff --git a/live2d-widget/src/utils.js b/live2d-widget/src/utils.js new file mode 100644 index 00000000..023b78ad --- /dev/null +++ b/live2d-widget/src/utils.js @@ -0,0 +1,5 @@ +function randomSelection(obj) { + return Array.isArray(obj) ? obj[Math.floor(Math.random() * obj.length)] : obj; +} + +export default randomSelection; diff --git a/live2d-widget/src/waifu-tips.js b/live2d-widget/src/waifu-tips.js new file mode 100644 index 00000000..b4f3291d --- /dev/null +++ b/live2d-widget/src/waifu-tips.js @@ -0,0 +1,3 @@ +import initWidget from "./index.js"; + +window.initWidget = initWidget; diff --git a/live2d-widget/waifu-tips.js b/live2d-widget/waifu-tips.js new file mode 100644 index 00000000..7edc656f --- /dev/null +++ b/live2d-widget/waifu-tips.js @@ -0,0 +1,5 @@ +/*! + * Live2D Widget + * https://github.com/stevenjoezhang/live2d-widget + */ +!function(){"use strict";function e(e){return Array.isArray(e)?e[Math.floor(Math.random()*e.length)]:e}let t;function o(o,s,n){if(!o||sessionStorage.getItem("waifu-text")&&sessionStorage.getItem("waifu-text")>n)return;t&&(clearTimeout(t),t=null),o=e(o),sessionStorage.setItem("waifu-text",n);const i=document.getElementById("waifu-tips");i.innerHTML=o,i.classList.add("waifu-tips-active"),t=setTimeout((()=>{sessionStorage.removeItem("waifu-text"),i.classList.remove("waifu-tips-active")}),s)}class s{constructor(e){let{apiPath:t,cdnPath:o}=e,s=!1;if("string"==typeof o)s=!0,o.endsWith("/")||(o+="/");else{if("string"!=typeof t)throw"Invalid initWidget argument!";t.endsWith("/")||(t+="/")}this.useCDN=s,this.apiPath=t,this.cdnPath=o}async loadModelList(){const e=await fetch(`${this.cdnPath}model_list.json`);this.modelList=await e.json()}async loadModel(t,s,n){if(localStorage.setItem("modelId",t),localStorage.setItem("modelTexturesId",s),o(n,4e3,10),this.useCDN){this.modelList||await this.loadModelList();const o=e(this.modelList.models[t]);loadlive2d("live2d",`${this.cdnPath}model/${o}/index.json`)}else loadlive2d("live2d",`${this.apiPath}get/?id=${t}-${s}`),console.log(`Live2D 模型 ${t}-${s} 加载完成`)}async loadRandModel(){const t=localStorage.getItem("modelId"),s=localStorage.getItem("modelTexturesId");if(this.useCDN){this.modelList||await this.loadModelList();const s=e(this.modelList.models[t]);loadlive2d("live2d",`${this.cdnPath}model/${s}/index.json`),o("我的新衣服好看嘛?",4e3,10)}else fetch(`${this.apiPath}rand_textures/?id=${t}-${s}`).then((e=>e.json())).then((e=>{1!==e.textures.id||1!==s&&0!==s?this.loadModel(t,e.textures.id,"我的新衣服好看嘛?"):o("我还没有其他衣服呢!",4e3,10)}))}async loadOtherModel(){let e=localStorage.getItem("modelId");if(this.useCDN){this.modelList||await this.loadModelList();const t=++e>=this.modelList.models.length?0:e;this.loadModel(t,0,this.modelList.messages[t])}else fetch(`${this.apiPath}switch/?id=${e}`).then((e=>e.json())).then((e=>{this.loadModel(e.model.id,0,e.model.message)}))}}const n={hitokoto:{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:function(){fetch("https://v1.hitokoto.cn").then((e=>e.json())).then((e=>{const t=`这句一言来自 「${e.from}」,是 ${e.creator} 在 hitokoto.cn 投稿的。`;o(e.hitokoto,6e3,9),setTimeout((()=>{o(t,4e3,9)}),6e3)}))}},asteroids:{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{if(window.Asteroids)window.ASTEROIDSPLAYERS||(window.ASTEROIDSPLAYERS=[]),window.ASTEROIDSPLAYERS.push(new Asteroids);else{const e=document.createElement("script");e.src="https://fastly.jsdelivr.net/gh/stevenjoezhang/asteroids/asteroids.js",document.head.appendChild(e)}}},"switch-model":{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{}},"switch-texture":{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{}},photo:{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{o("照好了嘛,是不是很可爱呢?",6e3,9),Live2D.captureName="photo.png",Live2D.captureFrame=!0}},info:{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{open("https://github.com/stevenjoezhang/live2d-widget")}},quit:{icon:'\x3c!--! Font Awesome Free 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc. --\x3e',callback:()=>{localStorage.setItem("waifu-display",Date.now()),o("愿你有一天能与重要的人重逢。",2e3,11),document.getElementById("waifu").style.bottom="-500px",setTimeout((()=>{document.getElementById("waifu").style.display="none",document.getElementById("waifu-toggle").classList.add("waifu-toggle-active")}),3e3)}}};function i(t){const i=new s(t);function c(t){let s,n=!1,i=t.message.default;window.addEventListener("mousemove",(()=>n=!0)),window.addEventListener("keydown",(()=>n=!0)),setInterval((()=>{n?(n=!1,clearInterval(s),s=null):s||(s=setInterval((()=>{o(i,6e3,9)}),2e4))}),1e3),o(function(e){if("/"===location.pathname)for(let{hour:t,text:o}of e){const e=new Date,s=t.split("-")[0],n=t.split("-")[1]||s;if(s<=e.getHours()&&e.getHours()<=n)return o}const t=`欢迎阅读「${document.title.split(" - ")[0]}」`;let o;if(""!==document.referrer){const e=new URL(document.referrer),s=e.hostname.split(".")[1],n={baidu:"百度",so:"360搜索",google:"谷歌搜索"};return location.hostname===e.hostname?t:(o=s in n?n[s]:e.hostname,`Hello!来自 ${o} 的朋友
${t}`)}return t}(t.time),7e3,11),window.addEventListener("mouseover",(s=>{for(let{selector:n,text:i}of t.mouseover)if(s.target.matches(n))return i=e(i),i=i.replace("{text}",s.target.innerText),void o(i,4e3,8)})),window.addEventListener("click",(s=>{for(let{selector:n,text:i}of t.click)if(s.target.matches(n))return i=e(i),i=i.replace("{text}",s.target.innerText),void o(i,4e3,8)})),t.seasons.forEach((({date:t,text:o})=>{const s=new Date,n=t.split("-")[0],c=t.split("-")[1]||n;n.split("/")[0]<=s.getMonth()+1&&s.getMonth()+1<=c.split("/")[0]&&n.split("/")[1]<=s.getDate()&&s.getDate()<=c.split("/")[1]&&(o=(o=e(o)).replace("{year}",s.getFullYear()),i.push(o))}));const c=()=>{};console.log("%c",c),c.toString=()=>{o(t.message.console,6e3,9)},window.addEventListener("copy",(()=>{o(t.message.copy,6e3,9)})),window.addEventListener("visibilitychange",(()=>{document.hidden||o(t.message.visibilitychange,6e3,9)}))}localStorage.removeItem("waifu-display"),sessionStorage.removeItem("waifu-text"),document.body.insertAdjacentHTML("beforeend",'
\n
\n \n
\n
'),setTimeout((()=>{document.getElementById("waifu").style.bottom=0}),0),function(){n["switch-model"].callback=()=>i.loadOtherModel(),n["switch-texture"].callback=()=>i.loadRandModel(),Array.isArray(t.tools)||(t.tools=Object.keys(n));for(let e of t.tools)if(n[e]){const{icon:t,callback:o}=n[e];document.getElementById("waifu-tool").insertAdjacentHTML("beforeend",`${t}`),document.getElementById(`waifu-tool-${e}`).addEventListener("click",o)}}(),function(){let e=localStorage.getItem("modelId"),o=localStorage.getItem("modelTexturesId");null===e&&(e=1,o=53),i.loadModel(e,o),fetch(t.waifuPath).then((e=>e.json())).then(c)}()}window.initWidget=function(e,t){"string"==typeof e&&(e={waifuPath:e,apiPath:t}),document.body.insertAdjacentHTML("beforeend",'
\n 看板娘\n
');const o=document.getElementById("waifu-toggle");o.addEventListener("click",(()=>{o.classList.remove("waifu-toggle-active"),o.getAttribute("first-time")?(i(e),o.removeAttribute("first-time")):(localStorage.removeItem("waifu-display"),document.getElementById("waifu").style.display="",setTimeout((()=>{document.getElementById("waifu").style.bottom=0}),0))})),localStorage.getItem("waifu-display")&&Date.now()-localStorage.getItem("waifu-display")<=864e5?(o.setAttribute("first-time",!0),setTimeout((()=>{o.classList.add("waifu-toggle-active")}),0)):i(e)}}(); diff --git a/live2d-widget/waifu-tips.json b/live2d-widget/waifu-tips.json new file mode 100644 index 00000000..b4c7ff02 --- /dev/null +++ b/live2d-widget/waifu-tips.json @@ -0,0 +1 @@ +{"mouseover":[{"selector":"#live2d","text":["干嘛呢你,快把手拿开~~","鼠…鼠标放错地方了!","你要干嘛呀?","喵喵喵?","怕怕(ノ≧∇≦)ノ","非礼呀!救命!","这样的话,只能使用武力了!","我要生气了哦","不要动手动脚的!","真…真的是不知羞耻!","Hentai!"]},{"selector":"#waifu-tool-hitokoto","text":["猜猜我要说些什么?","我从青蛙王子那里听到了不少人生经验。"]},{"selector":"#waifu-tool-asteroids","text":["要不要来玩飞机大战?","这个按钮上写着「不要点击」。","怎么,你想来和我玩个游戏?","听说这样可以蹦迪!"]},{"selector":"#waifu-tool-switch-model","text":["你是不是不爱人家了呀,呜呜呜~","要见见我的姐姐嘛?","想要看我妹妹嘛?","要切换看板娘吗?"]},{"selector":"#waifu-tool-switch-texture","text":["喜欢换装 PLAY 吗?","这次要扮演什么呢?","变装!","让我们看看接下来会发生什么!"]},{"selector":"#waifu-tool-photo","text":["你要给我拍照呀?一二三~茄子~","要不,我们来合影吧!","保持微笑就好了~"]},{"selector":"#waifu-tool-info","text":["想要知道更多关于我的事么?","这里记录着我搬家的历史呢。","你想深入了解我什么呢?"]},{"selector":"#waifu-tool-quit","text":["到了要说再见的时候了吗?","呜呜 QAQ 后会有期……","不要抛弃我呀……","我们,还能再见面吗……","哼,你会后悔的!"]},{"selector":".menu-item-home a","text":["点击前往首页,想回到上一页可以使用浏览器的后退功能哦。","点它就可以回到首页啦!","回首页看看吧。"]},{"selector":".menu-item-about a","text":["你想知道我家主人是谁吗?","这里有一些关于我家主人的秘密哦,要不要看看呢?","发现主人出没地点!"]},{"selector":".menu-item-tags a","text":["点击就可以看文章的标签啦!","点击来查看所有标签哦。"]},{"selector":".menu-item-categories a","text":["文章都分类好啦~","点击来查看文章分类哦。"]},{"selector":".menu-item-archives a","text":["翻页比较麻烦吗,那就来看看文章归档吧。","文章目录都整理在这里啦!"]},{"selector":".menu-item-friends a","text":["这是我的朋友们哦ヾ(◍°∇°◍)ノ゙","要去大佬们的家看看吗?","要去拜访一下我的朋友们吗?"]},{"selector":".menu-item-search a","text":["找不到想看的内容?搜索看看吧!","在找什么东西呢,需要帮忙吗?"]},{"selector":".menu-item a","text":["快看看这里都有什么呢?"]},{"selector":".site-author","text":["我家主人好看吗?","这是我家主人(*´∇`*)"]},{"selector":".site-state","text":["这是文章的统计信息~","要不要点进去看看?"]},{"selector":".feed-link a","text":["这里可以使用 RSS 订阅呢!","利用 feed 订阅器,就能快速知道博客有没有更新了呢。"]},{"selector":".cc-opacity, .post-copyright-author","text":["要记得规范转载哦。","所有文章均采用 CC BY-NC-SA 4.0 许可协议~","转载前要先注意下文章的版权协议呢。"]},{"selector":".links-of-author","text":["这里是主人的常驻地址哦。","这里有主人的联系方式!"]},{"selector":".followme","text":["手机扫一下就能继续看,很方便呢~","扫一扫,打开新世界的大门!"]},{"selector":".fancybox img, img.medium-zoom-image","text":["点击图片可以放大呢!"]},{"selector":".copy-btn","text":["代码可以直接点击复制哟。"]},{"selector":".highlight .table-container, .gist","text":["GitHub!我是新手!","PHP 是最好的语言!"]},{"selector":"a[href^='mailto']","text":["邮件我会及时回复的!","点击就可以发送邮件啦~"]},{"selector":"a[href^='/tags/']","text":["要去看看 {text} 标签么?","点它可以查看此标签下的所有文章哟!"]},{"selector":"a[href^='/categories/']","text":["要去看看 {text} 分类么?","点它可以查看此分类下的所有文章哟!"]},{"selector":".post-title-link","text":["要看看 {text} 这篇文章吗?"]},{"selector":"a[rel='contents']","text":["点击来阅读全文哦。"]},{"selector":"a[itemprop='discussionUrl']","text":["要去看看评论吗?"]},{"selector":".beian a","text":["我也是有户口的人哦。","我的主人可是遵纪守法的好主人。"]},{"selector":".container a[href^='http'], .nav-link .nav-text","text":["要去看看 {text} 么?","去 {text} 逛逛吧。","到 {text} 看看吧。"]},{"selector":".back-to-top","text":["点它就可以回到顶部啦!","又回到最初的起点~","要回到开始的地方么?"]},{"selector":".reward-container","text":["我是不是棒棒哒~快给我点赞吧!","要打赏我嘛?好期待啊~","主人最近在吃土呢,很辛苦的样子,给他一些钱钱吧~"]},{"selector":"#wechat","text":["这是我的微信二维码~"]},{"selector":"#alipay","text":["这是我的支付宝哦!"]},{"selector":"#bitcoin","text":["这是我的比特币账号!"]},{"selector":"#needsharebutton-postbottom .btn","text":["好东西要让更多人知道才行哦。","觉得文章有帮助的话,可以分享给更多需要的朋友呢。"]},{"selector":".need-share-button_weibo","text":["微博?来分享一波喵!"]},{"selector":".need-share-button_wechat","text":["分享到微信吧!"]},{"selector":".need-share-button_douban","text":["分享到豆瓣好像也不错!"]},{"selector":".need-share-button_qqzone","text":["QQ 空间,一键转发,耶~"]},{"selector":".need-share-button_twitter","text":["Twitter?好像是不存在的东西?"]},{"selector":".need-share-button_facebook","text":["emmm…FB 好像也是不存在的东西?"]},{"selector":".post-nav-item a[rel='next']","text":["来看看下一篇文章吧。","点它可以看下一篇文章哦!","要翻到下一篇文章吗?"]},{"selector":".post-nav-item a[rel='prev']","text":["来看看上一篇文章吧。","点它可以看上一篇文章哦!","要翻到上一篇文章吗?"]},{"selector":".extend.next","text":["去下一页看看吧。","点它可以前进哦!","要翻到下一页吗?"]},{"selector":".extend.prev","text":["去上一页看看吧。","点它可以后退哦!","要翻到上一页吗?"]},{"selector":"input.vnick","text":["该怎么称呼你呢?","留下你的尊姓大名!"]},{"selector":".vmail","text":["留下你的邮箱,不然就是无头像人士了!","记得设置好 Gravatar 头像哦!","为了方便通知你最新消息,一定要留下邮箱!"]},{"selector":".vlink","text":["快快告诉我你的家在哪里,好让我去参观参观!"]},{"selector":".veditor","text":["想要去评论些什么吗?","要说点什么吗?","觉得博客不错?快来留言和主人交流吧!"]},{"selector":".vcontrol a","text":["你会不会熟练使用 Markdown 呀?","使用 Markdown 让评论更美观吧~"]},{"selector":".vemoji-btn","text":["要插入一个萌萌哒的表情吗?","要来一发表情吗?"]},{"selector":".vpreview-btn","text":["要预览一下你的发言吗?","快看看你的评论有多少负熵!"]},{"selector":".vsubmit","text":["评论没有审核,要对自己的发言负责哦~","要提交了吗,请耐心等待回复哦~"]},{"selector":".vcontent","text":["哇,快看看这个精彩评论!","如果有疑问,请尽快留言哦~"]}],"click":[{"selector":"#live2d","text":["是…是不小心碰到了吧…","萝莉控是什么呀?","你看到我的小熊了吗?","再摸的话我可要报警了!⌇●﹏●⌇","110 吗,这里有个变态一直在摸我(ó﹏ò。)","不要摸我了,我会告诉老婆来打你的!","干嘛动我呀!小心我咬你!","别摸我,有什么好摸的!"]},{"selector":".veditor","text":["要吐槽些什么呢?","一定要认真填写喵~","有什么想说的吗?"]},{"selector":".vsubmit","text":["输入验证码就可以提交评论啦~"]}],"seasons":[{"date":"01/01","text":"元旦了呢,新的一年又开始了,今年是{year}年~"},{"date":"02/14","text":"又是一年情人节,{year}年找到对象了嘛~"},{"date":"03/08","text":"今天是国际妇女节!"},{"date":"03/12","text":"今天是植树节,要保护环境呀!"},{"date":"04/01","text":"悄悄告诉你一个秘密~今天是愚人节,不要被骗了哦~"},{"date":"05/01","text":"今天是五一劳动节,计划好假期去哪里了吗~"},{"date":"06/01","text":"儿童节了呢,快活的时光总是短暂,要是永远长不大该多好啊…"},{"date":"09/03","text":"中国人民抗日战争胜利纪念日,铭记历史、缅怀先烈、珍爱和平、开创未来。"},{"date":"09/10","text":"教师节,在学校要给老师问声好呀~"},{"date":"10/01","text":"国庆节到了,为祖国母亲庆生!"},{"date":"11/05-11/12","text":"今年的双十一是和谁一起过的呢~"},{"date":"12/20-12/31","text":"这几天是圣诞节,主人肯定又去剁手买买买了~"}],"time":[{"hour":"6-7","text":"早上好!一日之计在于晨,美好的一天就要开始了~"},{"hour":"8-11","text":"上午好!工作顺利嘛,不要久坐,多起来走动走动哦!"},{"hour":"12-13","text":"中午了,工作了一个上午,现在是午餐时间!"},{"hour":"14-17","text":"午后很容易犯困呢,今天的运动目标完成了吗?"},{"hour":"18-19","text":"傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~"},{"hour":"20-21","text":"晚上好,今天过得怎么样?"},{"hour":"22-23","text":["已经这么晚了呀,早点休息吧,晚安~","深夜时要爱护眼睛呀!"]},{"hour":"0-5","text":"你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?"}],"message":{"default":["好久不见,日子过得好快呢……","大坏蛋!你都多久没理人家了呀,嘤嘤嘤~","嗨~快来逗我玩吧!","拿小拳拳锤你胸口!","记得把小家加入收藏夹哦!"],"console":"哈哈,你打开了控制台,是想要看看我的小秘密吗?","copy":"你都复制了些什么呀,转载要记得加上出处哦!","visibilitychange":"哇,你终于回来了~"}} \ No newline at end of file diff --git a/live2d-widget/waifu.css b/live2d-widget/waifu.css new file mode 100644 index 00000000..48094013 --- /dev/null +++ b/live2d-widget/waifu.css @@ -0,0 +1,332 @@ +#waifu-toggle { + background-color: #fa0; + border-radius: 5px; + bottom: 66px; + color: #fff; + cursor: pointer; + font-size: 12px; + left: 0; + margin-left: -100px; + padding: 5px 2px 5px 5px; + position: fixed; + transition: margin-left 1s; + width: 60px; + writing-mode: vertical-rl; +} + +#waifu-toggle.waifu-toggle-active { + margin-left: -50px; +} + +#waifu-toggle.waifu-toggle-active:hover { + margin-left: -30px; +} + +#waifu { + bottom: -1000px; + right: 160px; + line-height: 0; + margin-bottom: -10px; + position: fixed; + transform: translateY(3px); + transition: transform .3s ease-in-out, bottom 3s ease-in-out; + z-index: 1; +} + +/*定义竖屏 css*/ +@media screen and (orientation:portrait) { + #waifu { + right: 0; + } + + #waifu #live2d { + cursor: grab; + height: 100px; + position: relative; + width: 100px; + } + + #waifu-tips { + display: none; + } + + #waifu-tool { + display: none; + } +} + +#waifu:hover { + transform: translateY(0); +} + +#waifu-tips { + animation: shake 50s ease-in-out 5s infinite; + background-color: rgba(236, 217, 188, .5); + border: 1px solid rgba(224, 186, 140, .62); + border-radius: 12px; + box-shadow: 0 3px 15px 2px rgba(191, 158, 118, .2); + font-size: 14px; + line-height: 24px; + margin: -12px 20px; + min-height: 60px; + opacity: 0; + overflow: hidden; + padding: 5px 10px; + position: absolute; + text-overflow: ellipsis; + transition: opacity 1s; + width: 200px; + word-break: break-all; +} + +#waifu-tips.waifu-tips-active { + opacity: 1; + transition: opacity .2s; +} + +#waifu-tips span { + color: #0099cc; +} + +#live2d { + cursor: grab; + height: 200px; + position: relative; + width: 200px; +} + +#live2d:active { + cursor: grabbing; +} + +#waifu-tool { + color: #aaa; + opacity: 0; + position: absolute; + right: -10px; + top: 10px; + transition: opacity 1s; +} + +#waifu:hover #waifu-tool { + opacity: 1; +} + +#waifu-tool span { + display: block; + height: 30px; + text-align: center; +} + +#waifu-tool svg { + fill: #7b8c9d; + cursor: pointer; + height: 25px; + transition: fill .3s; +} + +#waifu-tool svg:hover { + fill: #0684bd; /* #34495e */ +} + +@keyframes shake { + 2% { + transform: translate(.5px, -1.5px) rotate(-.5deg); + } + + 4% { + transform: translate(.5px, 1.5px) rotate(1.5deg); + } + + 6% { + transform: translate(1.5px, 1.5px) rotate(1.5deg); + } + + 8% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 10% { + transform: translate(.5px, 2.5px) rotate(.5deg); + } + + 12% { + transform: translate(1.5px, 1.5px) rotate(.5deg); + } + + 14% { + transform: translate(.5px, .5px) rotate(.5deg); + } + + 16% { + transform: translate(-1.5px, -.5px) rotate(1.5deg); + } + + 18% { + transform: translate(.5px, .5px) rotate(1.5deg); + } + + 20% { + transform: translate(2.5px, 2.5px) rotate(1.5deg); + } + + 22% { + transform: translate(.5px, -1.5px) rotate(1.5deg); + } + + 24% { + transform: translate(-1.5px, 1.5px) rotate(-.5deg); + } + + 26% { + transform: translate(1.5px, .5px) rotate(1.5deg); + } + + 28% { + transform: translate(-.5px, -.5px) rotate(-.5deg); + } + + 30% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 32% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 34% { + transform: translate(2.5px, 2.5px) rotate(-.5deg); + } + + 36% { + transform: translate(.5px, -1.5px) rotate(.5deg); + } + + 38% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 40% { + transform: translate(-.5px, 2.5px) rotate(.5deg); + } + + 42% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 44% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 46% { + transform: translate(1.5px, -.5px) rotate(-.5deg); + } + + 48% { + transform: translate(2.5px, -.5px) rotate(.5deg); + } + + 50% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 52% { + transform: translate(-.5px, 1.5px) rotate(.5deg); + } + + 54% { + transform: translate(-1.5px, 1.5px) rotate(.5deg); + } + + 56% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 58% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 60% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 62% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 64% { + transform: translate(-1.5px, 1.5px) rotate(1.5deg); + } + + 66% { + transform: translate(.5px, 2.5px) rotate(1.5deg); + } + + 68% { + transform: translate(2.5px, -1.5px) rotate(1.5deg); + } + + 70% { + transform: translate(2.5px, 2.5px) rotate(.5deg); + } + + 72% { + transform: translate(-.5px, -1.5px) rotate(1.5deg); + } + + 74% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 76% { + transform: translate(-1.5px, 2.5px) rotate(1.5deg); + } + + 78% { + transform: translate(-1.5px, 2.5px) rotate(.5deg); + } + + 80% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 82% { + transform: translate(-1.5px, .5px) rotate(-.5deg); + } + + 84% { + transform: translate(-.5px, .5px) rotate(1.5deg); + } + + 86% { + transform: translate(2.5px, 1.5px) rotate(.5deg); + } + + 88% { + transform: translate(-1.5px, .5px) rotate(1.5deg); + } + + 90% { + transform: translate(-1.5px, -.5px) rotate(-.5deg); + } + + 92% { + transform: translate(-1.5px, -1.5px) rotate(1.5deg); + } + + 94% { + transform: translate(.5px, .5px) rotate(-.5deg); + } + + 96% { + transform: translate(2.5px, -.5px) rotate(-.5deg); + } + + 98% { + transform: translate(-1.5px, -1.5px) rotate(-.5deg); + } + + 0%, 100% { + transform: translate(0, 0) rotate(0); + } +} diff --git a/main.0cf68a.css b/main.0cf68a.css new file mode 100644 index 00000000..5072341c --- /dev/null +++ b/main.0cf68a.css @@ -0,0 +1 @@ +.clearfix:after,.clearfix:before{content:"";display:table}.clearfix:after{clear:both}.left-col.show{box-shadow:0 0 6px 0 rgba(0,0,0,.75)}.mid-col,.mid-col.show .article,.tools-col,.tools-col .tools-section .search-tag.tagcloud .article-tag-list,.tools-col .tools-section .search-ul .search-tag span:hover,.tools-col .tools-section .search-ul .search-time span:hover,.tools-col .tools-section .search-ul .search-title:hover,.tools-col .tools-section .search-wrap .icon{transition:all .2s ease-in;-ms-transition:all .2s ease-in}@-webkit-keyframes leftIn{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translateZ(0);transform:translateZ(0)}60%{-webkit-transform:translate3d(358px,0,0);transform:translate3d(358px,0,0)}75%{-webkit-transform:translate3d(323px,0,0);transform:translate3d(323px,0,0)}90%{-webkit-transform:translate3d(338px,0,0);transform:translate3d(338px,0,0)}to{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}}@keyframes leftIn{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translateZ(0);transform:translateZ(0)}60%{-webkit-transform:translate3d(358px,0,0);transform:translate3d(358px,0,0)}75%{-webkit-transform:translate3d(323px,0,0);transform:translate3d(323px,0,0)}90%{-webkit-transform:translate3d(338px,0,0);transform:translate3d(338px,0,0)}to{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}}.mid-col.show{-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:leftIn;animation-name:leftIn}@-webkit-keyframes leftOut{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes leftOut{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.mid-col.hide{-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-name:leftOut;animation-name:leftOut}@-webkit-keyframes smallLeftIn{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translateZ(0);transform:translateZ(0)}60%{-webkit-transform:translate3d(325px,0,0);transform:translate3d(325px,0,0)}75%{-webkit-transform:translate3d(290px,0,0);transform:translate3d(290px,0,0)}90%{-webkit-transform:translate3d(305px,0,0);transform:translate3d(305px,0,0)}to{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0)}}@keyframes smallLeftIn{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translateZ(0);transform:translateZ(0)}60%{-webkit-transform:translate3d(325px,0,0);transform:translate3d(325px,0,0)}75%{-webkit-transform:translate3d(290px,0,0);transform:translate3d(290px,0,0)}90%{-webkit-transform:translate3d(305px,0,0);transform:translate3d(305px,0,0)}to{-webkit-transform:translate3d(300px,0,0);transform:translate3d(300px,0,0)}}.tools-col.show{-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:smallLeftIn;animation-name:smallLeftIn}@-webkit-keyframes smallleftOut{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}@keyframes smallleftOut{0%,60%,75%,90%,to{-webkit-animation-timing-function:cubic-bezier(.215,.61,.355,1);animation-timing-function:cubic-bezier(.215,.61,.355,1)}0%{-webkit-transform:translate3d(333px,0,0);transform:translate3d(333px,0,0)}60%{-webkit-transform:translate3d(-25px,0,0);transform:translate3d(-25px,0,0)}75%{-webkit-transform:translate3d(10px,0,0);transform:translate3d(10px,0,0)}90%{-webkit-transform:translate3d(-5px,0,0);transform:translate3d(-5px,0,0)}to{-webkit-transform:translateZ(0);transform:translateZ(0)}}.tools-col.hide{-webkit-animation-duration:.8s;animation-duration:.8s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:smallleftOut;animation-name:smallleftOut}html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent;height:100%}body{margin:0;font-size:14px;font-family:Helvetica Neue,Helvetica,STHeiTi,Arial,sans-serif;line-height:1.5;color:#333;background-color:#fff;min-height:100%}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block}audio:not([controls]){display:none;height:0}progress{vertical-align:baseline}[hidden],template{display:none}a{background:transparent;text-decoration:none;color:#08c}a:active{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:700}dfn{font-style:italic}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0;vertical-align:middle;max-width:100%}svg:not(:root){overflow:hidden}pre{overflow:auto;white-space:pre;white-space:pre-wrap;word-wrap:break-word}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;vertical-align:middle}button,input,select{overflow:visible}button,select{text-transform:none}button,html input[type=button],input[type=reset],input[type=submit]{-webkit-appearance:button;cursor:pointer}[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;box-sizing:border-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto;resize:vertical;vertical-align:top}optgroup{font-weight:700}button,input,select,textarea{outline:0}input,textarea{-webkit-user-modify:read-write-plaintext-only}input::-ms-clear,input::-ms-reveal{display:none}input::-moz-placeholder,textarea::-moz-placeholder{color:#999}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999}input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999}.placeholder{color:#999}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}blockquote,figure,form,h1,h2,h3,h4,h5,h6,p{margin:0}dd,dl,li,ol,ul{margin:0;padding:0}ol,ul{list-style:none outside none}h1,h2,h3{line-height:2;font-weight:400}h1{font-size:18px}h2{font-size:16px}h3{font-size:14px}i{font-style:normal}*{box-sizing:border-box}@font-face{font-family:iconfont;src:url(./fonts/iconfont.b322fa.eot);src:url(./fonts/iconfont.b322fa.eot#iefix) format("embedded-opentype"),url(./fonts/iconfont.8c627f.woff) format("woff"),url(./fonts/iconfont.16acc2.ttf) format("truetype"),url(./fonts/iconfont.45d7ee.svg#iconfont) format("svg")}[class*=" icon-"],[class^=icon-]{font-family:iconfont!important;speak:none;font-size:16px;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-twitter:before{content:"\E600"}.icon-facebook:before{content:"\E601"}.icon-clock:before{content:"\E602"}.icon-mail:before{content:"\E609"}.icon-link:before{content:"\E6AB"}.icon-search:before{content:"\E65B"}.icon-smile:before{content:"\E64A"}.icon-roundrightfill:before{content:"\E65A"}.icon-list:before{content:"\E682"}.icon-book:before{content:"\E6FE"}.icon-home:before{content:"\E6BB"}.icon-share:before{content:"\E618"}.icon-back:before{content:"\E625"}.icon-qq:before{content:"\E62D"}.icon-weibo:before{content:"\E619"}.icon-segmentfault:before{content:"\E603"}.icon-sort:before{content:"\E700"}.icon-jianshu:before{content:"\E613"}.icon-circle-left:before{content:"\E71F"}.icon-circle-right:before{content:"\E720"}.icon-loading:before{content:"\E614"}.icon-acfun:before{content:"\E604"}.icon-close:before{content:"\E60C"}.icon-tumblr:before{content:"\E6B0"}.icon-calendar:before{content:"\E667"}.icon-rss:before{content:"\E877"}.icon-price-tags:before{content:"\E6F9"}.icon-quo-left:before{content:"\E7F5"}.icon-quo-right:before{content:"\E7F6"}.icon-back1:before{content:"\E64E"}.icon-github:before{content:"\E735"}.icon-film:before{content:"\E7B7"}.icon-weixin:before{content:"\E61F"}.icon-qzone:before{content:"\E680"}.icon-category:before{content:"\E605"}.icon-douban:before{content:"\E64C"}.icon-roundleftfill:before{content:"\E799"}.icon-tuding:before{content:"\E651"}.icon-zhihu:before{content:"\E61B"}.icon-linkedin:before{content:"\E6D4"}.icon-google:before{content:"\E635"}.icon-plane:before{content:"\E62F"}.icon-bilibili:before{content:"\E622"}.icon-psn:before{content:"\E6C7"}body,button,input,select,textarea{color:#1a1a1a;font-family:lucida grande,lucida sans unicode,lucida,helvetica,Hiragino Sans GB,Microsoft YaHei,WenQuanYi Micro Hei,sans-serif;font-size:16px;font-size:1rem;line-height:1.75}body{overflow-y:hidden;background:#eaeaea}#container,body,html{height:100%;overflow-x:hidden;overflow-y:auto}#mobile-nav{display:none}#container{position:relative;min-height:100%}#container .anm-canvas{display:none}#container.show .anm-canvas{display:block;position:fixed}.body-wrap{margin-bottom:80px}.mid-col{position:absolute;right:0;min-height:100%;background:#eaeaea;left:300px;width:auto}.mid-col.show{background:none;opacity:.9}.mid-col.show .article{background:hsla(0,0%,100%,.3)}.left-col{background:#fff;width:300px;position:fixed;opacity:1;transition:all .2s ease-in;height:100%;z-index:999}.left-col .overlay{width:100%;height:180px;position:absolute}.left-col .intrude-less{width:76%;text-align:center;margin:112px auto 0}.left-col #header{width:100%;height:300px;position:relative;border-bottom:1px solid color-border}.left-col #header a{color:#696969}.left-col #header a:hover{color:#b0a0aa}.left-col #header .header-subtitle{text-align:center;color:#999;font-size:14px;line-height:25px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical}.left-col #header .header-menu{font-weight:300;line-height:31px;text-transform:uppercase;float:none;min-height:150px;margin-left:-12px;text-align:center;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-pack:center;-webkit-box-align:center}.left-col #header .header-menu li{cursor:default}.left-col #header .header-menu li a{font-size:14px;min-width:300px}.left-col #header .header-smart-menu{font-size:12px;margin-bottom:20px}.left-col #header .header-smart-menu a:after{content:"/"}.left-col #header .header-smart-menu a:last-child:after{content:""}.left-col #header .profilepic{display:block;border:5px solid #fff;border-radius:300px;width:128px;height:128px;margin:0 auto;position:relative;overflow:hidden;background:#88acdb;-webkit-transition:all .2s ease-in;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-pack:center;-webkit-box-align:center;text-align:center}.left-col #header .profilepic img{border-radius:300px;opacity:1;-webkit-transition:all .2s ease-in}.left-col #header .profilepic img.show{width:100%;height:100%;opacity:1}.left-col #header .header-author{text-align:center;margin:.67em 0;font-family:Roboto,serif;font-size:30px;transition:.3s}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-button{width:0;height:0}::-webkit-scrollbar-button:end:decrement,::-webkit-scrollbar-button:start:increment{display:none}::-webkit-scrollbar-corner{display:block}::-webkit-scrollbar-thumb{border-radius:8px;background-color:rgba(0,0,0,.2)}::-webkit-scrollbar-thumb:hover{border-radius:8px;background-color:rgba(0,0,0,.5)}::-webkit-scrollbar-thumb,::-webkit-scrollbar-track{border-right:1px solid transparent;border-left:1px solid transparent}::-webkit-scrollbar-track:hover{background-color:rgba(0,0,0,.15)}::-webkit-scrollbar-button:start{width:10px;height:10px;background:url(./img/scrollbar_arrow.png) no-repeat 0 0}::-webkit-scrollbar-button:start:hover{background:url(./img/scrollbar_arrow.png) no-repeat -15px 0}::-webkit-scrollbar-button:start:active{background:url(./img/scrollbar_arrow.png) no-repeat -30px 0}::-webkit-scrollbar-button:end{width:10px;height:10px;background:url(./img/scrollbar_arrow.png) no-repeat 0 -18px}::-webkit-scrollbar-button:end:hover{background:url(./img/scrollbar_arrow.png) no-repeat -15px -18px}::-webkit-scrollbar-button:end:active{background:url(./img/scrollbar_arrow.png) no-repeat -30px -18px}.article-entry .highlight,.article-entry pre{background:#272822;margin:10px 0;padding:10px;overflow:auto;color:#fff;font-size:.9em;line-height:22.400000000000002px}.article-entry .gist .gist-file .gist-data .line-numbers,.article-entry .highlight .gutter pre,.article-entry .highlight .gutter pre .line{color:#666}.article-entry code,.article-entry pre{font-family:Source Code Pro,Consolas,Monaco,Menlo,monospace}.article-entry code{background:#eee;padding:0 .3em;border:none}.article-entry pre code{background:none;text-shadow:none;padding:0;}.article-entry .highlight{border-radius:4px}.article-entry .highlight pre{border:none;margin:0;padding:0}.article-entry .highlight table{margin:0;width:auto}.article-entry .highlight td{border:none;padding:0}.article-entry .highlight figcaption{color:highlight-comment;line-height:1em;margin-bottom:1em}.article-entry .highlight figcaption:after,.article-entry .highlight figcaption:before{content:"";display:table}.article-entry .highlight figcaption:after{clear:both}.article-entry .highlight figcaption a{float:right}.article-entry .highlight .gutter pre{text-align:right;padding-right:20px}.article-entry .highlight .gutter pre .line{text-shadow:none}.article-entry .highlight .line{color:rgb(182,182,182);font:Console;min-height:19px}.article-entry .gist{margin:0 -20px;border-style:solid;border-color:#ddd;border-width:1px 0;background:#272822;padding:15px 20px 15px 0}.article-entry .gist .gist-file{border:none;font-family:Source Code Pro,Consolas,Monaco,Menlo,monospace;margin:0}.article-entry .gist .gist-file .gist-data{background:none;border:none}.article-entry .gist .gist-file .gist-data .line-numbers{background:none;border:none;padding:0 20px 0 0}.article-entry .gist .gist-file .gist-data .line-data{padding:0!important}.article-entry .gist .gist-file .highlight{margin:0;padding:0;border:none}.article-entry .gist .gist-file .gist-meta{background:#272822;color:highlight-comment;font:.85em Helvetica Neue,Helvetica,Arial,sans-serif;text-shadow:0 0;padding:0;margin-top:1em;margin-left:20px}.article-entry .gist .gist-file .gist-meta a{color:#258fb8;font-weight:400}.article-entry .gist .gist-file .gist-meta a:hover{text-decoration:underline}pre .comment{color:#75715e}pre .class .params,pre .function .keyword,pre .keyword{color:#66d9ef}pre .css .value,pre .doctype,pre .function,pre .params,pre .tag{color:#fff}pre .at_rule,pre .at_rule .keyword,pre .css~* .tag,pre .preprocessor,pre .preprocessor .keyword,pre .title{color:#f92672}pre .attribute,pre .built_in,pre .class,pre .css~* .class,pre .function .title{color:#a6e22e}pre .string,pre .value{color:#e6db74}pre .number{color:#7163d7}pre .css~* .id,pre .id{color:#fd971f}#header .tagcloud a{color:#fff}.tagcloud a{display:inline-block;text-decoration:none;font-weight:400;font-size:10px;color:#fff;height:18px;line-height:18px;float:left;padding:0 5px 0 10px;position:relative;border-radius:0 5px 5px 0;margin:5px 9px 5px 8px;font-family:Menlo,Monaco,Andale Mono,lucida console,Courier New,monospace}.tagcloud a:hover{opacity:.8}.tagcloud a:before{content:" ";width:0;height:0;position:absolute;top:0;left:-18px;border:9px solid transparent}.tagcloud a:after{content:" ";width:4px;height:4px;background-color:#fff;border-radius:4px;box-shadow:0 0 0 1px rgba(0,0,0,.3);position:absolute;top:7px;left:2px}.tagcloud a.color1{background:#ff945c}.tagcloud a.color1:before{border-right-color:#ff945c}.tagcloud a.color2{background:#cc8167}.tagcloud a.color2:before{border-right-color:#cc8167}.tagcloud a.color3{background:#ba8f6c}.tagcloud a.color3:before{border-right-color:#ba8f6c}.tagcloud a.color4{background:#94635c}.tagcloud a.color4:before{border-right-color:#94635c}.tagcloud a.color5{background:#7b5d5f}.tagcloud a.color5:before{border-right-color:#7b5d5f}.article-tag-list .article-tag-list-item{float:left}.article-pop-out .icon-tuding{color:#999;float:left;margin-right:10px;margin-top:6px}.article-category,.article-category .article-tag-list,.article-tag,.article-tag .article-tag-list{float:left}.article-category .icon,.article-tag .icon{color:#999;float:left;margin-right:10px;margin-top:6px}.article-pop-out{float:left}.archive-article-date{color:#999;margin-right:7.6923%;float:right}.archive-article-date .icon{margin:5px 5px 5px 0}.glass{background-color:rgba(54,70,93,.9);z-index:998;transition:opacity .15s;width:100%;height:100%;display:none}.glass,.tagcloud-ctn{left:0;opacity:1;bottom:0;position:fixed;right:0;top:0}.tagcloud-ctn{z-index:90120;background-size:100% 100%}.tagcloud-ctn .tagcloud-global{position:fixed;top:50%;left:50%;margin-top:-115px;margin-left:-315px;width:630px}.tagcloud-ctn .tagcloud-global a{width:80px;height:80px;border-radius:50%;background:#f2992e;color:#fff;display:block;float:left;line-height:80px;text-align:center}.tagcloud-ctn .tagcloud-global .tab-post-types .tab-post-type:first-child .post-type-icon{background:#f2992e}.tagcloud-ctn .tagcloud-global .tab-post-types .tab-post-type:nth-child(2) .post-type-icon{background:#56bc8a}.tagcloud-ctn .tagcloud-global .tab-post-types .tab-post-type:nth-child(3) .post-type-icon{background:#4aa8d8}.tagcloud-ctn .tagcloud-global .tab-post-types .tab-post-type:nth-child(4) .post-type-icon{background:#a77dc2}.tagcloud-ctn .tagcloud-global .tab-post-types .tab-post-type:nth-child(5) .post-type-icon{background:#dd765d}#header .header-nav{width:100%;position:absolute;transition:-webkit-transform .3s ease-in;transition:transform .3s ease-in;transition:transform .3s ease-in,-webkit-transform .3s ease-in}#header .header-nav .social{margin-top:10px;text-align:center;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}#header .header-nav .social a{border-radius:50%;display:-moz-inline-stack;display:inline-block;vertical-align:middle;*vertical-align:auto;zoom:1;*display:inline;margin:0 8px 15px;transition:.3s;text-align:center;color:#fff;opacity:.7;width:28px;height:28px;line-height:26px}#header .header-nav .social a:hover{opacity:1}#header .header-nav .social a.weibo{background:#aaf;border:1px solid #aaf}#header .header-nav .social a.weibo:hover{border:1px solid #aaf}#header .header-nav .social a.segmentfault{background:#009a61;border:1px solid #009a61}#header .header-nav .social a.segmentfault:hover{border:1px solid #009a61}#header .header-nav .social a.rss{background:#ef7522;border:1px solid #ef7522}#header .header-nav .social a.rss:hover{border:1px solid #cf5d0f}#header .header-nav .social a.github{background:#afb6ca;border:1px solid #afb6ca}#header .header-nav .social a.github:hover{border:1px solid #909ab6}#header .header-nav .social a.facebook{background:#3b5998;border:1px solid #3b5998}#header .header-nav .social a.facebook:hover{border:1px solid #2d4373}#header .header-nav .social a.google{background:#c83d20;border:1px solid #c83d20}#header .header-nav .social a.google:hover{border:1px solid #9c3019}#header .header-nav .social a.twitter{background:#55cff8;border:1px solid #55cff8}#header .header-nav .social a.twitter:hover{border:1px solid #24c1f6}#header .header-nav .social a.linkedin{background:#005a87;border:1px solid #005a87}#header .header-nav .social a.linkedin:hover{border:1px solid #006b98}#header .header-nav .social a.acfun{background:#fd4c5d;border:1px solid #fd4c5d}#header .header-nav .social a.acfun:hover{border:1px solid #fd4c5d}#header .header-nav .social a.bilibili{background:#e15280;border:1px solid #e15280}#header .header-nav .social a.bilibili:hover{border:1px solid #e15280}#header .header-nav .social a.zhihu{background:#0078d8;border:1px solid #0078d8}#header .header-nav .social a.zhihu:hover{border:1px solid #0078d8}#header .header-nav .social a.douban{background:#06c611;border:1px solid #06c611}#header .header-nav .social a.douban:hover{border:1px solid #06c611}#header .header-nav .social a.mail{background:#005a87;border:1px solid #005a87}#header .header-nav .social a.mail:hover{border:1px solid #006b98}#header .header-nav .social a.jianshu{background:#ff5722;border:1px solid #ff5722}#header .header-nav .social a.jianshu:hover{border:1px solid #ff5722}#header .header-nav .social a.weixin{background:#4caf50;border:1px solid #4caf50}#header .header-nav .social a.weixin:hover{border:1px solid #4caf50}#header .header-nav .social a.qq{background:#34baad;border:1px solid #34baad}#header .header-nav .social a.qq:hover{border:1px solid #34baad}#header .header-nav .social a.psn{background:#086ef6;border:1px solid #086ef6}#header .header-nav .social a.psn:hover{border:1px solid #086ef6}#page-nav{text-align:center;margin-top:30px}#page-nav .page-number{width:20px;height:25px;background:#4d4d4d;display:inline-block;color:#fff;line-height:25px;font-size:12px;margin:0 5px 30px;border-radius:2px}#page-nav .page-number:hover{background:#5e5e5e}#page-nav .current{background:#88acdb;cursor:default}#page-nav .current:hover{background:#88acdb}#page-nav .extend{color:#4d4d4d;margin:0 27px;opacity:1}#page-nav .extend:hover{color:#5e5e5e}#page-nav:hover .extend{opacity:1}.archives-wrap{position:relative;margin:0 30px;padding-right:60px;border-bottom:1px solid #eee;background:#fff}.archives-wrap:first-child{margin-top:30px}.archives-wrap:last-child{margin-bottom:80px}.archives-wrap .archive-year-wrap{line-height:35px;width:200px;position:absolute;padding-top:15px;font-size:1.8em;z-index:1}.archives-wrap .archive-year-wrap a{color:#666;font-weight:700;padding-left:48px}.archives{position:relative}.archives .article-info{border:none}.archives .archive-article{margin-left:200px;padding:20px 0;border-bottom:1px solid #eee;border-top:1px solid #fff;position:relative}.archives .archive-article:first-child{border-top:none}.archives .archive-article:last-child{border-bottom:none}.archives .archive-article-title{font-size:16px;color:#333;transition:color .3s}.archives .archive-article-title:hover{color:#657b83}.archives .archive-article-title span{display:block;color:#a8a8a8;font-size:12px;line-height:14px;height:7px;padding-left:2px}.archives .archive-article-title span:before{display:inline-block;content:"\201C";font-family:serif;font-size:30px;float:left;margin:4px 4px 0 -12px;color:#c8c8c8}.archive-article-inner .icon-clock{margin-right:5px}.archive-article-inner .archive-article-header{position:relative;min-height:36px}.archive-article-inner .article-meta{position:relative;float:right;margin-top:-10px;color:#555;background:none;text-align:right;width:auto}.archive-article-inner .article-meta .article-date time{color:#aaa}.archive-article-inner .article-meta .archive-article-date,.archive-article-inner .article-meta .article-tag-list{margin-right:30px;display:-moz-inline-stack;display:inline-block;vertical-align:middle;zoom:1;color:#666;font-size:14px}.archive-article-inner .article-meta .archive-article-date{cursor:default;font-size:12px;margin-bottom:5px;margin-top:-10px;margin-right:0}.archive-article-inner .article-meta .article-category:before{float:left;margin-top:1px;left:15px}.archive-article-inner .article-meta .article-category .article-category-link{width:auto;max-width:83px;padding-left:10px}.archive-article-inner .article-meta .article-tag-list{margin-top:0}.archive-article-inner .article-meta .article-tag-list:before{left:15px}.archive-article-inner .article-meta .article-tag-list .article-tag-list-item{display:inline-block;width:auto;max-width:83px;padding-left:8px;font-size:12px}.tools-col{width:300px;height:100%;position:fixed;left:0;top:0;z-index:0;padding:0;opacity:0;-webkit-overflow-scrolling:touch;overflow-scrolling:touch}.tools-col.show{opacity:1}.tools-col.hide{z-index:0}.tools-col .tools-nav{display:none}.tools-col .tools-section,.tools-col .tools-wrap{height:100%;color:#e5e5e5;width:360px;overflow:hidden;overflow-y:auto}.tools-col .tools-section ::-webkit-scrollbar,.tools-col .tools-wrap ::-webkit-scrollbar{display:none}.tools-col .tools-section .search-wrap{width:310px;margin:20px 20px 10px;position:relative}.tools-col .tools-section .search-wrap .search-ipt{width:310px;color:#fff;background:none;border:none;border-bottom:2px solid #fff;font-family:Roboto,serif}.tools-col .tools-section .search-wrap .icon{position:absolute;right:0;top:7px;color:#fff;cursor:pointer}.tools-col .tools-section .search-wrap .icon:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.tools-col .tools-section .search-wrap ::-webkit-input-placeholder{color:#ededed}.tools-col .tools-section .search-tag.tagcloud{text-align:center;position:relative}.tools-col .tools-section .search-tag.tagcloud .search-tag-wording{font-size:12px;float:right;margin:4px 75px 0 0}.tools-col .tools-section .search-tag.tagcloud .search-switch{width:40px;height:25px;display:block}.tools-col .tools-section .search-tag.tagcloud .search-switch input{width:40px;height:14px;position:absolute;top:0;right:30px;z-index:2;border:0;background:0 0;-webkit-appearance:none;outline:0}.tools-col .tools-section .search-tag.tagcloud .search-switch input:before{content:"";width:40px;height:14px;border:1px solid #bdcabc;background-color:#fdfdfd;border-radius:20px;cursor:pointer;display:inline-block;position:relative;vertical-align:middle;box-sizing:content-box;box-shadow:inset 0 0 0 0 #dfdfdf;transition:border .4s,box-shadow .4s;background-clip:content-box}.tools-col .tools-section .search-tag.tagcloud .search-switch input:checked:before{border-color:#64bd63;box-shadow:inset 0 0 0 .16rem #64bd63;background-color:#64bd63;transition:border .4s,box-shadow .4s,background-color 1.2s}.tools-col .tools-section .search-tag.tagcloud .search-switch input:checked:after{left:27px;background:#fff}.tools-col .tools-section .search-tag.tagcloud .search-switch input:after{content:"";width:14px;height:14px;position:absolute;top:16px;left:2px;-webkit-transform:translateY(-50%);border-radius:100%;background-color:#91c0f1;box-shadow:0 1px 1px rgba(0,0,0,.4);transition:left .2s;cursor:pointer}.tools-col .tools-section .search-tag.tagcloud .article-tag-list{display:none;margin:15px 10px 0;padding:10px;background:hsla(0,0%,100%,.2)}.tools-col .tools-section .search-tag.tagcloud .article-tag-list.show{display:block}.tools-col .tools-section .search-tag.tagcloud .a{float:none}.tools-col .tools-section .search-ul{margin-top:10px;color:rgba(77,77,77,.75);-webkit-overflow-scrolling:touch;overflow-scrolling:touch;overflow-y:auto}.tools-col .tools-section .search-ul .search-li{padding:10px 20px;border-bottom:1px dotted #dcdcdc}.tools-col .tools-section .search-ul .search-li:hover{background:hsla(0,0%,100%,.2)}.tools-col .tools-section .search-ul .search-title{overflow:hidden;white-space:nowrap;text-overflow:ellipsis;display:block;color:#fffff8;text-shadow:1px 1px rgba(77,77,77,.25)}.tools-col .tools-section .search-ul .search-title .icon{margin-right:10px;color:#fffdd8}.tools-col .tools-section .search-ul .search-title:hover{color:#fff}.tools-col .tools-section .search-ul .search-tag,.tools-col .tools-section .search-ul .search-time{font-size:12px;color:#fffdd8;margin-right:10px}.tools-col .tools-section .search-ul .search-tag .icon,.tools-col .tools-section .search-ul .search-time .icon{margin-right:0}.tools-col .tools-section .search-ul .search-tag span,.tools-col .tools-section .search-ul .search-time span{cursor:pointer}.tools-col .tools-section .search-ul .search-tag span:hover,.tools-col .tools-section .search-ul .search-time span:hover{color:#fff}.tools-col .tools-section .search-ul .search-time{float:left}.tools-col .tools-section .search-ul .search-tag span{margin-right:5px}.tools-col .tools-section-friends{padding-top:30px}.tools-col .aboutme-wrap{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:100%;height:100%;color:#fffdd8;text-shadow:1px 1px rgba(77,77,77,.45)}.body-wrap>article{position:relative}@-webkit-keyframes cd-bounce-1{0%{opacity:0;-webkit-transform:scale(1)}60%{opacity:1;-webkit-transform:scale(1.01)}to{-webkit-transform:scale(1)}}@keyframes cd-bounce-1{0%{opacity:0;-webkit-transform:scale(1);transform:scale(1)}60%{opacity:1;-webkit-transform:scale(1.01);transform:scale(1.01)}to{-webkit-transform:scale(1);transform:scale(1)}}.article{margin:30px;position:relative;border:1px solid #ddd;border-top:1px solid #fff;border-bottom:1px solid #fff;background:#fff;transition:all .2s ease-in}.article img{max-width:100%}.article-inner h1.article-title,.article-title{color:#696969;margin-left:0;font-weight:300;line-height:35px;margin-bottom:20px;font-size:26px;transition:color .3s}.article-header{border-left:5px solid #4d4d4d;padding:30px 0 15px 25px;padding-left:7.6923%}.article-meta{width:150px;font-size:14;text-align:right;position:absolute;right:0;top:23px;text-align:center;z-index:1}.article-meta time{color:#aaa}.article-meta time .icon-clock{margin-right:8px;font-size:16px}.article-more-link{margin-top:0;text-align:left;float:right}.article-more-link a{background:#4d4d4d;color:#fff;font-size:12px;padding:5px 8px;line-height:16px;border-radius:2px;transition:background .3s}.article-more-link a:hover{background:#3c3c3c}.article-more-link a.hidden{visibility:hidden}.article-info.info-on-right{margin:10px 0 0;float:right}.article-info-index.article-info{padding-top:20px;margin:30px 7.6923% 0;min-height:72px;border-top:1px solid #ddd}.article-info-post.article-info{padding:0;border:none;margin:-30px 0 20px 7.6923%}.article-inner p{margin:0 0 1.75em}.article-inner{border-color:#d1d1d1}.article-inner h1{font-size:28px;font-size:1.75rem;line-height:1.25;margin-top:2em;margin-bottom:1em}.article-inner h2{font-size:23px;font-size:1.4375rem;line-height:1.2173913043;margin-top:2.4347826087em;margin-bottom:1.2173913043em}.article-inner h3{font-size:19px;font-size:1.1875rem;line-height:1.1052631579;margin-top:2.9473684211em;margin-bottom:1.4736842105em}.article-inner h4,.article-inner h5,.article-inner h6{font-size:16px;font-size:1rem;line-height:1.3125;margin-top:3.5em;margin-bottom:1.75em}.article-inner h4{letter-spacing:.140625em;text-transform:uppercase}.article-inner h6{font-style:italic}.article-inner h1,.article-inner h2,.article-inner h3,.article-inner h4,.article-inner h5,.article-inner h6{font-weight:900}.article-inner h1:first-child,.article-inner h2:first-child,.article-inner h3:first-child,.article-inner h4:first-child,.article-inner h5:first-child,.article-inner h6:first-child{margin-top:0}.article-inner h1:first-child{margin-bottom:10px;display:inline}.article-entry{line-height:1.8em;padding-right:7.6923%;padding-left:7.6923%}.article-entry p{margin-top:10px}.article-entry li code,.article-entry p code{padding:1px 3px;margin:0 3px;background:#ddd;border:1px solid #ccc;font-family:Menlo,Monaco,Andale Mono,lucida console,Courier New,monospace;word-wrap:break-word;font-size:14px}.article-entry blockquote{background:#ddd;border-left:5px solid #ccc;padding:15px 20px;margin-top:10px;border-left:5px solid #657b83;background:#f6f6f6}.article-entry blockquote p{margin-top:0;margin-bottom:0}.article-entry em{font-style:italic}.article-entry ul li:before{content:"";width:6px;height:6px;border:1px solid #999;border-radius:10px;background:#aaa;display:inline-block;margin-right:10px;float:left;margin-top:10px}.article-entry ol{counter-reset:item}.article-entry ol li:before{counter-increment:item;content:counter(item) ".";margin-right:10px}.article-entry ol,.article-entry ul{font-size:14px;margin:10px 0}.article-entry li ol,.article-entry li ul{margin-left:30px}.article-entry li ol li:before,.article-entry li ul li:before{content:"";background:#dedede}.article-entry h1{margin-top:30px}.article-entry h2,.article-entry h3,.article-entry h4,.article-entry h5,.article-entry h6{margin-top:20px;font-weight:700;color:#574c4c;padding-bottom:5px;border-bottom:1px solid #ddd}.article-entry video{max-width:100%}.article-entry strong{font-weight:700}.article-entry .caption{display:block;font-size:.8em;color:#aaa}.article-entry hr{height:0;margin-top:20px;margin-bottom:20px;border-left:0;border-right:0;border-top:1px solid #ddd;border-bottom:1px solid #fff}.article-entry pre{line-height:1.5;margin-top:10px;padding:5px 15px;overflow-x:auto;color:#657b83;border:1px solid #ccc;text-shadow:0 1px #444;font-family:Menlo,Monaco,Andale Mono,lucida console,Courier New,monospace}.article-entry pre code{font-size:14px}.article-entry table{width:100%;border:1px solid #dedede;margin:15px 0;border-collapse:collapse}.article-entry table td,.article-entry table tr{height:35px}.article-entry table thead tr{background:#f8f8f8}.article-entry table tbody tr:hover{background:#efefef}.article-entry table td,.article-entry table th{border:1px solid #dedede;padding:0 10px}.article-entry figure table{border:none;width:auto;margin:0}.article-entry figure table tbody tr:hover{background:none}#article-nav{margin:0 0 20px;padding:0 32px 10px;min-height:30px}#article-nav .article-nav-link-wrap{font-size:14px}#article-nav .article-nav-link-wrap .article-nav-title{display:inline-block;font-size:16px;transition:color .3s}#article-nav .article-nav-link-wrap:hover .article-nav-title,#article-nav .article-nav-link-wrap:hover i{color:#4d4d4d}#article-nav #article-nav-older{float:right}#disqus_thread,#gitment-ctn,#SOHUCS,.cloud-tie-wrapper,.duoshuo{padding:0 30px!important;min-height:20px}#SOHUCS #SOHU_MAIN .module-cmt-list .block-cont-gw{border-bottom:1px dashed #c8c8c8!important}.share-wrap{min-height:20px}.share-btn{float:right;position:relative}.share-icons{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.share-icons a{border:1px solid #fff;border-radius:50%;display:-moz-inline-stack;display:inline-block;vertical-align:middle;zoom:1;margin:10px;transition:.3s;text-align:center;color:#fff;opacity:.7;width:28px;height:28px;line-height:26px;text-shadow:1px 1px 1px #509eb7}.share-icons a:active{color:#fff}.share-icons a:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.share-icons a.share-outer{border:none;color:#fff;background:#4d4d4d;text-shadow:none}.page-modal{position:fixed;top:24%;left:50%;z-index:1001;padding:20px;text-align:center;color:#727272;background:#fff;border-radius:4px;box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);opacity:0;-webkit-transform:translate(-50%,-200%);transform:translate(-50%,-200%)}.page-modal p{margin-bottom:10px}.page-modal.ready{visibility:hidden;display:block;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%);transition:.3s}.page-modal.in{visibility:visible;opacity:1;-webkit-transform:translate(-50%);transform:translate(-50%)}.page-modal .close{position:absolute;right:15px;top:15px;color:rgba(0,0,0,.2);font-size:16px;line-height:20px}.page-modal .close:active,.page-modal .close:hover{color:rgba(0,0,0,.4)}.mask{visibility:hidden;position:fixed;top:0;left:0;bottom:0;z-index:1000;width:100%;height:100%;background:#000;opacity:0;filter:alpha(opacity=0);pointer-events:none;transition:.3s ease-in-out}.mask.in{visibility:visible;pointer-events:auto;opacity:.3}.page-reward{margin:60px 0;text-align:center}.page-reward .page-reward-btn{position:relative;display:inline-block;width:56px;height:56px;line-height:56px;font-size:20px;color:#fff;background:#f44336;border-radius:50%;box-shadow:0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);transition:.4s ease-in-out}.page-reward .page-reward-btn:active,.page-reward .page-reward-btn:hover{box-shadow:0 6px 12px rgba(0,0,0,.2),0 4px 15px rgba(0,0,0,.2)}.page-reward .page-reward-btn .tooltip-item{display:block;width:56px;height:56px}.page-reward .reward-box{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-pack:distribute;justify-content:space-around}.page-reward .reward-p{color:#fff;font-weight:700;text-shadow:1px 1px 1px #45b9e0}.page-reward .reward-p .icon{margin:0 10px;color:#ddd}.page-reward .reward-type{font-size:16px;display:block;color:#4d4d4d;margin:20px 0 0}.page-reward .reward-img{width:130px;height:130px;border:6px solid #fff;border-radius:3px}.wrap-side-operation{position:fixed;right:40px;bottom:50px;z-index:999;font-size:14px}.wrap-side-operation .icon-plane{color:#fff;text-shadow:1px 1px 1px #509eb7;opacity:.7;font-size:52px;line-height:40px;width:40px;text-align:center;display:block}.mod-side-operation{width:40px;text-align:center}.jump-container:hover .icon-back{background:rgba(36,193,246,.9)}.jump-container,.toc-container{position:relative;cursor:pointer;width:40px;height:40px;opacity:.8}.jump-plan-container{position:absolute;top:-11px;left:-4px;width:50px;height:61px;overflow:hidden}.jump-plan-container .jump-plane{display:block;position:absolute;width:42px;height:66px;-webkit-transform:translateY(68px);transform:translateY(68px);left:-2px}.mod-side-operation__jump-to-top .icon-back{transition:.3s;color:#fff;background:#ccc;-webkit-transform:rotate(90deg);transform:rotate(90deg);font-size:32px;line-height:40px;width:40px;text-align:center;display:block}.mod-side-operation__jump-to-top .icon-back:hover{background:#24c1f6;color:#24c1f6}.toc-container.tooltip-left{background:#ccc;margin-top:10px;transition:.3s}.toc-container.tooltip-left:hover{background:rgba(36,193,246,.9)}.toc-container.tooltip-left .icon-font{font-size:22px;line-height:40px;color:#fff}.toc-container.tooltip-left .tooltip{width:40px;height:40px;top:0;left:0}.toc-container.tooltip-left .tooltip-east .tooltip-content{min-height:100px;text-align:left;padding:5px 0 5px 20px;right:4.7em;min-width:200px;width:auto;font-size:14px;text-shadow:1px 1px 1px #398199;bottom:-10px;-webkit-transform-origin:100% 100%;transform-origin:100% 100%;-webkit-transform:translate3d(0,-10px,0) rotate3d(1,1,1,-30deg);transform:translate3d(0,-10px,0) rotate3d(1,1,1,-30deg)}.toc-container.tooltip-left .tooltip-east .tooltip-content a{color:#fff}.toc-container.tooltip-left .tooltip-east .tooltip-content:after{top:auto;bottom:23px}.toc-container.tooltip-left .tooltip-east .tooltip-content .toc-article{max-height:500px;overflow-x:hidden;overflow-y:auto}.toc-container.tooltip-left .tooltip-east .tooltip-content .toc-article li ol,.toc-container.tooltip-left .tooltip-east .tooltip-content .toc-article li ul{margin-left:30px}.toc-container.tooltip-left .tooltip-east .tooltip-content .toc-article li{white-space:nowrap}.toc-container.tooltip-left .tooltip:hover .tooltip-content{bottom:-10px;-webkit-transform:translate(0);transform:translate(0)}.tooltip-left .tooltip{position:absolute;z-index:999;cursor:pointer;width:28px;height:28px;top:-10px;right:10px}.tooltip-left .tooltip:hover a.share-outer{background:#24c1f6}@-webkit-keyframes pulse{0%{-webkit-transform:scale3d(.5,.5,1)}to{-webkit-transform:scaleX(1)}}@keyframes pulse{0%{-webkit-transform:scale3d(.5,.5,1);transform:scale3d(.5,.5,1)}to{-webkit-transform:scaleX(1);transform:scaleX(1)}}.tooltip-left .tooltip-content{position:absolute;background:rgba(36,193,246,.9);z-index:9999;width:200px;bottom:50%;margin-bottom:-10px;border-radius:20px;font-size:1.1em;text-align:center;color:#fff;opacity:0;cursor:default;pointer-events:none;-webkit-font-smoothing:antialiased;transition:opacity .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s;transition:opacity .3s,transform .3s,-webkit-transform .3s}.tooltip-left .tooltip-west .tooltip-content{left:3.5em;-webkit-transform-origin:-2em 50%;transform-origin:-2em 50%;-webkit-transform:translate3d(0,50%,0) rotate3d(1,1,1,30deg);transform:translate3d(0,50%,0) rotate3d(1,1,1,30deg)}.tooltip-left .tooltip-east .tooltip-content{right:3.5em;-webkit-transform-origin:calc(100% + 2em) 50%;transform-origin:calc(100% + 2em) 50%;-webkit-transform:translate3d(0,50%,0) rotate3d(1,1,1,-30deg);transform:translate3d(0,50%,0) rotate3d(1,1,1,-30deg)}.tooltip-left .tooltip:hover .tooltip-content{opacity:1;-webkit-transform:translate3d(0,50%,0) rotate3d(0,0,0,0);transform:translate3d(0,50%,0) rotate3d(0,0,0,0);pointer-events:auto}.tooltip-left .tooltip-content:after,.tooltip-left .tooltip-content:before{content:"";position:absolute}.tooltip-left .tooltip-content:before{height:100%;width:3em}.tooltip-left .tooltip-content:after{width:2em;height:2em;top:50%;margin:-1em 0 0;background:url(./fonts/tooltip.4004ff.svg) no-repeat 50%;background-size:100%}.tooltip-left .tooltip-west .tooltip-content:after,.tooltip-left .tooltip-west .tooltip-content:before{right:99%}.tooltip-left .tooltip-east .tooltip-content:after,.tooltip-left .tooltip-east .tooltip-content:before{left:99%}.tooltip-left .tooltip-east .tooltip-content:after{-webkit-transform:scaleX(-1);transform:scaleX(-1)}.tooltip-top .tooltip{display:inline;position:relative;z-index:999}.tooltip-top .tooltip:after{content:"";position:absolute;width:100%;height:20px;bottom:100%;left:50%;pointer-events:none;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.tooltip-top .tooltip:hover:after{pointer-events:auto}.tooltip-top .tooltip-content{position:absolute;z-index:9999;width:370px;left:50%;bottom:100%;font-size:20px;line-height:1.4;text-align:center;font-weight:400;color:#4d4d4d;background:transparent;opacity:0;margin:0 0 -10px -185px;cursor:default;pointer-events:none;font-family:Satisfy,cursive;-webkit-font-smoothing:antialiased;transition:opacity .3s .3s;padding-bottom:80px}.tooltip-top .tooltip:hover .tooltip-content{opacity:1;pointer-events:auto;transition-delay:0s}.tooltip-top .tooltip-content span{display:block}.tooltip-top .tooltip-text{border-bottom:10px solid #4d4d4d;overflow:hidden;-webkit-transform:scaleX(0);transform:scaleX(0);transition:-webkit-transform .3s .3s;transition:transform .3s .3s;transition:transform .3s .3s,-webkit-transform .3s .3s}.tooltip-top .tooltip:hover .tooltip-text{transition-delay:0s;-webkit-transform:scaleX(1);transform:scaleX(1)}.tooltip-top .tooltip-inner{background:rgba(36,193,246,.9);padding:40px;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s}.tooltip-top .tooltip:hover .tooltip-inner{transition-delay:.3s;-webkit-transform:translateZ(0);transform:translateZ(0)}.tooltip-top .tooltip-content:after{content:"";left:50%;border:solid transparent;height:0;width:0;position:absolute;pointer-events:none;border-color:transparent;border-top-color:#4d4d4d;border-width:10px;margin-left:-10px}#footer{font-size:12px;font-family:Menlo,Monaco,Andale Mono,lucida console,Courier New,monospace;text-shadow:0 1px #fff;position:absolute;bottom:30px;opacity:.6;width:100%;text-align:center}#footer .outer{padding:0 30px}.footer-left{float:left}.footer-right{float:right}@media screen and (max-width:800px){#container,body,html{height:auto;overflow-x:hidden;overflow-y:auto}#mobile-nav{display:block}.body-wrap{margin-bottom:0}.left-col{display:none}.mid-col{left:0}#header .header-nav,.mid-col{position:relative}.wrap-side-operation{display:none}.cloud-tie-wrapper{padding:0;min-height:20px}.tools-col{left:-300px;width:300px}.tools-col .tools-wrap{padding-top:48px}.tools-col .tools-section,.tools-col .tools-wrap{width:300px}.tools-col .tools-section .search-wrap,.tools-col .tools-wrap .search-wrap{width:280px}.tools-col .tools-section .search-tag.tagcloud,.tools-col .tools-wrap .search-tag.tagcloud{margin-right:-30px}.tools-col .tools-section .search-ul .search-li,.tools-col .tools-wrap .search-ul .search-li{padding:5px 20px}.tools-col.show .header-menu.tools-nav{display:block}#container .header-author.fixed{position:fixed;top:-29px;width:100%;color:#ddd}.mobile-mask{width:100%;height:100%;position:fixed;top:0;left:0;background:rgba(0,0,0,.85);z-index:999}.btnctn{position:fixed;width:50px;height:50px;top:-5px;z-index:4}.btnctn .slider-trigger{position:absolute;z-index:101;width:42px;height:42px;text-align:center;line-height:50px}.btnctn .slider-trigger.back{top:0;left:0}.btnctn .slider-trigger.list{bottom:0;left:0}.btnctn .slider-trigger:hover{background:#444}.btnctn .slider-trigger .icon{font-size:24px;color:#fff}.article-header{border-left:none;padding:0;border-bottom:1px dotted #ddd}.article-header h1{margin-bottom:10px}.article-header .archive-article-date{float:none}.header-subtitle .icon{margin:0 10px;color:#d0d0d0}.article-info-index.article-info{min-height:40px;padding-top:10px;margin:0;border-top:1px solid #ddd}.article-info-post.article-info{margin:0;padding-top:10px;border:none}#viewer-box .viewer-box-l{font-size:14px}.article-nav-link-wrap{margin:5px 0;display:block;clear:both}.article-nav-link-wrap .icon-circle-right{float:left;margin:6px 4px 0 0}.article{padding:10px;margin:10px 0;border:0;font-size:16px;color:#555}.article .article-more-link{margin:0}.article .article-entry{padding:10px 0 30px}.article .article-inner h1.article-title,.article .article-title{font-size:18px;font-weight:300;display:block;margin:0}.article .article-meta{width:auto;height:30px;margin-top:-5px;position:ralative}.article .article-meta .article-date{font-size:12px;border-radius:0;color:#666;background:none;height:auto;padding:0;margin:0;width:100%;text-align:left;margin-left:10px}.article .article-meta .article-date time{width:auto;float:right;margin-right:10px}.article .article-meta .article-tag-list{margin-top:7px;position:absolute;right:10px;top:0}.article .article-meta .article-tag-list:before{float:left;margin-top:1px;left:0}.article .article-meta .article-tag-list .article-tag-list-item{float:left;padding-left:0;width:auto;max-width:83px}.article .article-meta .article-category{margin-top:7px;position:absolute;right:10px;top:-30px}.article .article-meta .article-category:before{float:left;margin-top:1px;left:15px}.article .article-meta .article-category .article-category-link{max-width:83px;width:auto;padding-left:10px}.article #article-nav-older{float:none;display:block}.share{padding:3px 10px}#disqus_thread,.duoshuo{padding:0 13px}#article-nav{margin:0;padding:5px 10px 10px}#article-nav #article-nav-older{float:none}#article-nav .article-nav-link-wrap .article-nav-title{font-size:16px}#page-nav .extend{opacity:1}.instagram .open-ins{left:2px;top:-30px;color:#aaa}.info-on-right{float:none}.archives-wrap{margin:10px 10px 0;padding:10px}.archives-wrap .archive-article-title{font-size:16px}.archives-wrap .archive-year-wrap{position:relative;padding:0}.archives-wrap .archive-year-wrap a{padding:0}.archives-wrap .article-meta .archive-article-date{font-size:12px;margin-right:10px;margin-top:-5px}.archives-wrap .article-meta .article-tag-list-link{font-size:12px}.archives .archive-article{padding:10px 0;margin-left:0}#footer{position:relative;bottom:0}#footer .footer-left{float:none;margin-bottom:10px}#footer .footer-right{float:none}#mobile-nav .header-author{margin:0;position:relative;z-index:2;color:#424242}#mobile-nav .overlay{height:110px;position:absolute;width:100%;z-index:2;background:#4d4d4d}#mobile-nav #header{padding:10px 0 0}#mobile-nav #header .profilepic{display:block;position:relative;z-index:100}.header-menu{height:auto;margin:10px 0 20px}.header-menu.tools-nav{display:none;position:fixed;left:0;width:100%;z-index:9999}.header-menu.tools-nav ul{margin-right:28px}.header-menu.tools-nav li,.header-menu.tools-nav ul{border-color:#fff}.header-menu.tools-nav li a,.header-menu.tools-nav ul a{color:#fff}.header-menu.tools-nav li a.active,.header-menu.tools-nav ul a.active{background:#81b5cc}.header-menu ul{text-align:center;cursor:default;display:-webkit-box;display:-ms-flexbox;display:flex;margin:0 auto;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around;position:relative;z-index:1;border:1px solid #a0a0a0;border-radius:3px}.header-menu li{border-left:1px solid #a0a0a0}.header-menu li:first-child{border-left:0}.header-menu li:last-child{border-right:0}.header-menu li a{font-size:14px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;color:#a0a0a0}.header-menu li a.active{color:#eaeaea;background:#a0a0a0}.profilepic{display:block;border:5px solid #fff;border-radius:300px;width:128px;height:128px;margin:0 auto;position:relative;overflow:hidden;background:#88acdb;-webkit-transition:all .2s ease-in;display:-webkit-box;-webkit-box-orient:horizontal;-webkit-box-pack:center;-webkit-box-align:center;text-align:center}.header-author{text-align:center;margin:.67em 0;font-family:Roboto,serif;font-size:30px;transition:.3s}.header-subtitle{text-align:center;color:#999;font-size:14px;line-height:25px;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;padding:0 24px}}/*! PhotoSwipe Default UI CSS by Dmitry Semenov | photoswipe.com | MIT license */.pswp__button{width:44px;height:44px;position:relative;background:none;cursor:pointer;overflow:visible;-webkit-appearance:none;display:block;border:0;padding:0;margin:0;float:right;opacity:.75;transition:opacity .2s;box-shadow:none}.pswp__button:focus,.pswp__button:hover{opacity:1}.pswp__button:active{outline:none;opacity:.9}.pswp__button::-moz-focus-inner{padding:0;border:0}.pswp__ui--over-close .pswp__button--close{opacity:1}.pswp__button,.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{background:url(./img/default-skin.png) 0 0 no-repeat;background-size:264px 88px;width:44px;height:44px}@media (-webkit-min-device-pixel-ratio:1.1),(-webkit-min-device-pixel-ratio:1.09375),(min-resolution:1.1dppx),(min-resolution:105dpi){.pswp--svg .pswp__button,.pswp--svg .pswp__button--arrow--left:before,.pswp--svg .pswp__button--arrow--right:before{background-image:url(./fonts/default-skin.b257fa.svg)}.pswp--svg .pswp__button--arrow--left,.pswp--svg .pswp__button--arrow--right{background:none}}.pswp__button--close{background-position:0 -44px}.pswp__button--share{background-position:-44px -44px}.pswp__button--fs{display:none}.pswp--supports-fs .pswp__button--fs{display:block}.pswp--fs .pswp__button--fs{background-position:-44px 0}.pswp__button--zoom{display:none;background-position:-88px 0}.pswp--zoom-allowed .pswp__button--zoom{display:block}.pswp--zoomed-in .pswp__button--zoom{background-position:-132px 0}.pswp--touch .pswp__button--arrow--left,.pswp--touch .pswp__button--arrow--right{visibility:hidden}.pswp__button--arrow--left,.pswp__button--arrow--right{background:none;top:50%;margin-top:-50px;width:70px;height:100px;position:absolute}.pswp__button--arrow--left{left:0}.pswp__button--arrow--right{right:0}.pswp__button--arrow--left:before,.pswp__button--arrow--right:before{content:"";top:35px;background-color:rgba(0,0,0,.3);height:30px;width:32px;position:absolute}.pswp__button--arrow--left:before{left:6px;background-position:-138px -44px}.pswp__button--arrow--right:before{right:6px;background-position:-94px -44px}.pswp__counter,.pswp__share-modal{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.pswp__share-modal{display:block;background:rgba(0,0,0,.5);width:100%;height:100%;top:0;left:0;padding:10px;position:absolute;z-index:1600;opacity:0;transition:opacity .25s ease-out;-webkit-backface-visibility:hidden;will-change:opacity}.pswp__share-modal--hidden{display:none}.pswp__share-tooltip{z-index:1620;position:absolute;background:#fff;top:56px;border-radius:2px;display:block;width:auto;right:44px;box-shadow:0 2px 5px rgba(0,0,0,.25);-webkit-transform:translateY(6px);transform:translateY(6px);transition:-webkit-transform .25s;transition:transform .25s;transition:transform .25s,-webkit-transform .25s;-webkit-backface-visibility:hidden;will-change:transform}.pswp__share-tooltip a{display:block;padding:8px 12px;font-size:14px;line-height:18px}.pswp__share-tooltip a,.pswp__share-tooltip a:hover{color:#000;text-decoration:none}.pswp__share-tooltip a:first-child{border-radius:2px 2px 0 0}.pswp__share-tooltip a:last-child{border-radius:0 0 2px 2px}.pswp__share-modal--fade-in{opacity:1}.pswp__share-modal--fade-in .pswp__share-tooltip{-webkit-transform:translateY(0);transform:translateY(0)}.pswp--touch .pswp__share-tooltip a{padding:16px 12px}a.pswp__share--facebook:before{content:"";display:block;width:0;height:0;position:absolute;top:-12px;right:15px;border:6px solid transparent;border-bottom-color:#fff;-webkit-pointer-events:none;-moz-pointer-events:none;pointer-events:none}a.pswp__share--facebook:hover{background:#3e5c9a;color:#fff}a.pswp__share--facebook:hover:before{border-bottom-color:#3e5c9a}a.pswp__share--twitter:hover{background:#55acee;color:#fff}a.pswp__share--pinterest:hover{background:#ccc;color:#ce272d}a.pswp__share--download:hover{background:#ddd}.pswp__counter{position:absolute;left:0;top:0;height:44px;font-size:13px;line-height:44px;color:#fff;opacity:.75;padding:0 10px}.pswp__caption{position:absolute;left:0;bottom:0;width:100%;min-height:44px}.pswp__caption small{font-size:11px;color:#bbb}.pswp__caption__center{text-align:left;max-width:420px;margin:0 auto;font-size:13px;padding:10px;line-height:20px;color:#ccc}.pswp__caption--empty{display:none}.pswp__caption--fake{visibility:hidden}.pswp__preloader{width:44px;height:44px;position:absolute;top:0;left:50%;margin-left:-22px;opacity:0;transition:opacity .25s ease-out;will-change:opacity;direction:ltr}.pswp__preloader__icn{width:20px;height:20px;margin:12px}.pswp__preloader--active{opacity:1}.pswp__preloader--active .pswp__preloader__icn{background:url(./img/preloader.gif) 0 0 no-repeat}.pswp--css_animation .pswp__preloader--active{opacity:1}.pswp--css_animation .pswp__preloader--active .pswp__preloader__icn{-webkit-animation:clockwise .5s linear infinite;animation:clockwise .5s linear infinite}.pswp--css_animation .pswp__preloader--active .pswp__preloader__donut{-webkit-animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite;animation:donut-rotate 1s cubic-bezier(.4,0,.22,1) infinite}.pswp--css_animation .pswp__preloader__icn{background:none;opacity:.75;width:14px;height:14px;position:absolute;left:15px;top:15px;margin:0}.pswp--css_animation .pswp__preloader__cut{position:relative;width:7px;height:14px;overflow:hidden}.pswp--css_animation .pswp__preloader__donut{box-sizing:border-box;width:14px;height:14px;border:2px solid #fff;border-radius:50%;border-left-color:transparent;border-bottom-color:transparent;position:absolute;top:0;left:0;background:none;margin:0}@media screen and (max-width:1024px){.pswp__preloader{position:relative;left:auto;top:auto;margin:0;float:right}}@-webkit-keyframes clockwise{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes clockwise{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@-webkit-keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}to{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes donut-rotate{0%{-webkit-transform:rotate(0);transform:rotate(0)}50%{-webkit-transform:rotate(-140deg);transform:rotate(-140deg)}to{-webkit-transform:rotate(0);transform:rotate(0)}}.pswp__ui{-webkit-font-smoothing:auto;visibility:visible;opacity:1;z-index:1550}.pswp__top-bar{position:absolute;left:0;top:0;height:44px;width:100%}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right,.pswp__caption,.pswp__top-bar{-webkit-backface-visibility:hidden;will-change:opacity;transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--has_mouse .pswp__button--arrow--left,.pswp--has_mouse .pswp__button--arrow--right{visibility:visible}.pswp__caption,.pswp__top-bar{background-color:rgba(0,0,0,.5)}.pswp__ui--fit .pswp__caption,.pswp__ui--fit .pswp__top-bar{background-color:rgba(0,0,0,.3)}.pswp__ui--idle .pswp__button--arrow--left,.pswp__ui--idle .pswp__button--arrow--right,.pswp__ui--idle .pswp__top-bar{opacity:0}.pswp__ui--hidden .pswp__button--arrow--left,.pswp__ui--hidden .pswp__button--arrow--right,.pswp__ui--hidden .pswp__caption,.pswp__ui--hidden .pswp__top-bar{opacity:.001}.pswp__ui--one-slide .pswp__button--arrow--left,.pswp__ui--one-slide .pswp__button--arrow--right,.pswp__ui--one-slide .pswp__counter{display:none}.pswp__element--disabled{display:none!important}.pswp--minimal--dark .pswp__top-bar{background:none}/*! PhotoSwipe main CSS by Dmitry Semenov | photoswipe.com | MIT license */.pswp{display:none;position:absolute;width:100%;height:100%;left:0;top:0;overflow:hidden;-ms-touch-action:none;touch-action:none;z-index:1500;-webkit-text-size-adjust:100%;-webkit-backface-visibility:hidden;outline:none}.pswp *{box-sizing:border-box}.pswp img{max-width:none}.pswp--animate_opacity{opacity:.001;will-change:opacity;transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--open{display:block}.pswp--zoom-allowed .pswp__img{cursor:zoom-in}.pswp--zoomed-in .pswp__img{cursor:-webkit-grab;cursor:grab}.pswp--dragging .pswp__img{cursor:-webkit-grabbing;cursor:grabbing}.pswp__bg{background:#000;opacity:0;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-backface-visibility:hidden}.pswp__bg,.pswp__scroll-wrap{position:absolute;left:0;top:0;width:100%;height:100%}.pswp__scroll-wrap{overflow:hidden}.pswp__container,.pswp__zoom-wrap{-ms-touch-action:none;touch-action:none;position:absolute;left:0;right:0;top:0;bottom:0}.pswp__container,.pswp__img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none}.pswp__zoom-wrap{position:absolute;width:100%;-webkit-transform-origin:left top;transform-origin:left top;transition:-webkit-transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1);transition:transform 333ms cubic-bezier(.4,0,.22,1),-webkit-transform 333ms cubic-bezier(.4,0,.22,1)}.pswp__bg{will-change:opacity;transition:opacity 333ms cubic-bezier(.4,0,.22,1)}.pswp--animated-in .pswp__bg,.pswp--animated-in .pswp__zoom-wrap{transition:none}.pswp__container,.pswp__zoom-wrap{-webkit-backface-visibility:hidden}.pswp__item{right:0;bottom:0;overflow:hidden}.pswp__img,.pswp__item{position:absolute;left:0;top:0}.pswp__img{width:auto;height:auto}.pswp__img--placeholder{-webkit-backface-visibility:hidden}.pswp__img--placeholder--blank{background:#222}.pswp--ie .pswp__img{width:100%!important;height:auto!important;left:0;top:0}.pswp__error-msg{position:absolute;left:0;top:50%;width:100%;text-align:center;font-size:14px;line-height:16px;margin-top:-8px;color:#ccc}.pswp__error-msg a{color:#ccc;text-decoration:underline} \ No newline at end of file diff --git a/main.0cf68a.js b/main.0cf68a.js new file mode 100644 index 00000000..aa30ab7b --- /dev/null +++ b/main.0cf68a.js @@ -0,0 +1,14 @@ +!function(e){function t(o){if(n[o])return n[o].exports;var r=n[o]={exports:{},id:o,loaded:!1};return e[o].call(r.exports,r,r.exports,t),r.loaded=!0,r.exports}var n={};return t.m=e,t.c=n,t.p="./",t(0)}({0:function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}n(386),n(192);var r=n(194),i=o(r),a=n(193),u=o(a),l=n(189),c=o(l),s=n(129);(0,s.addLoadEvent)(function(){u.default.init(),i.default.init(),c.default.init()})},5:function(e,t){var n=e.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},8:function(e,t){var n={}.hasOwnProperty;e.exports=function(e,t){return n.call(e,t)}},9:function(e,t,n){var o=n(94),r=n(33);e.exports=function(e){return o(r(e))}},12:function(e,t,n){e.exports=!n(18)(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},13:function(e,t,n){var o=n(14),r=n(22);e.exports=n(12)?function(e,t,n){return o.f(e,t,r(1,n))}:function(e,t,n){return e[t]=n,e}},14:function(e,t,n){var o=n(20),r=n(58),i=n(42),a=Object.defineProperty;t.f=n(12)?Object.defineProperty:function(e,t,n){if(o(e),t=i(t,!0),o(n),r)try{return a(e,t,n)}catch(e){}if("get"in n||"set"in n)throw TypeError("Accessors not supported!");return"value"in n&&(e[t]=n.value),e}},15:function(e,t,n){var o=n(40)("wks"),r=n(23),i=n(5).Symbol,a="function"==typeof i,u=e.exports=function(e){return o[e]||(o[e]=a&&i[e]||(a?i:r)("Symbol."+e))};u.store=o},18:function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},19:function(e,t,n){var o=n(63),r=n(34);e.exports=Object.keys||function(e){return o(e,r)}},20:function(e,t,n){var o=n(21);e.exports=function(e){if(!o(e))throw TypeError(e+" is not an object!");return e}},21:function(e,t){e.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},22:function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},23:function(e,t){var n=0,o=Math.random();e.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+o).toString(36))}},25:function(e,t){var n=e.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n)},33:function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},34:function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},35:function(e,t){e.exports={}},36:function(e,t){e.exports=!0},37:function(e,t){t.f={}.propertyIsEnumerable},38:function(e,t,n){var o=n(14).f,r=n(8),i=n(15)("toStringTag");e.exports=function(e,t,n){e&&!r(e=n?e:e.prototype,i)&&o(e,i,{configurable:!0,value:t})}},39:function(e,t,n){var o=n(40)("keys"),r=n(23);e.exports=function(e){return o[e]||(o[e]=r(e))}},40:function(e,t,n){var o=n(5),r="__core-js_shared__",i=o[r]||(o[r]={});e.exports=function(e){return i[e]||(i[e]={})}},41:function(e,t){var n=Math.ceil,o=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?o:n)(e)}},42:function(e,t,n){var o=n(21);e.exports=function(e,t){if(!o(e))return e;var n,r;if(t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;if("function"==typeof(n=e.valueOf)&&!o(r=n.call(e)))return r;if(!t&&"function"==typeof(n=e.toString)&&!o(r=n.call(e)))return r;throw TypeError("Can't convert object to primitive value")}},43:function(e,t,n){var o=n(5),r=n(25),i=n(36),a=n(44),u=n(14).f;e.exports=function(e){var t=r.Symbol||(r.Symbol=i?{}:o.Symbol||{});"_"==e.charAt(0)||e in t||u(t,e,{value:a.f(e)})}},44:function(e,t,n){t.f=n(15)},51:function(e,t,n){var o=n(5),r=n(25),i=n(91),a=n(13),u="prototype",l=function(e,t,n){var c,s,f,p=e&l.F,d=e&l.G,m=e&l.S,h=e&l.P,v=e&l.B,y=e&l.W,g=d?r:r[t]||(r[t]={}),w=g[u],x=d?o:m?o[t]:(o[t]||{})[u];d&&(n=t);for(c in n)s=!p&&x&&void 0!==x[c],s&&c in g||(f=s?x[c]:n[c],g[c]=d&&"function"!=typeof x[c]?n[c]:v&&s?i(f,o):y&&x[c]==f?function(e){var t=function(t,n,o){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,o)}return e.apply(this,arguments)};return t[u]=e[u],t}(f):h&&"function"==typeof f?i(Function.call,f):f,h&&((g.virtual||(g.virtual={}))[c]=f,e&l.R&&w&&!w[c]&&a(w,c,f)))};l.F=1,l.G=2,l.S=4,l.P=8,l.B=16,l.W=32,l.U=64,l.R=128,e.exports=l},56:function(e,t){var n={}.toString;e.exports=function(e){return n.call(e).slice(8,-1)}},57:function(e,t,n){var o=n(21),r=n(5).document,i=o(r)&&o(r.createElement);e.exports=function(e){return i?r.createElement(e):{}}},58:function(e,t,n){e.exports=!n(12)&&!n(18)(function(){return 7!=Object.defineProperty(n(57)("div"),"a",{get:function(){return 7}}).a})},59:function(e,t,n){"use strict";var o=n(36),r=n(51),i=n(64),a=n(13),u=n(8),l=n(35),c=n(96),s=n(38),f=n(103),p=n(15)("iterator"),d=!([].keys&&"next"in[].keys()),m="@@iterator",h="keys",v="values",y=function(){return this};e.exports=function(e,t,n,g,w,x,b){c(n,t,g);var T,C,I,S=function(e){if(!d&&e in R)return R[e];switch(e){case h:return function(){return new n(this,e)};case v:return function(){return new n(this,e)}}return function(){return new n(this,e)}},E=t+" Iterator",_=w==v,O=!1,R=e.prototype,k=R[p]||R[m]||w&&R[w],D=k||S(w),M=w?_?S("entries"):D:void 0,A="Array"==t?R.entries||k:k;if(A&&(I=f(A.call(new e)),I!==Object.prototype&&(s(I,E,!0),o||u(I,p)||a(I,p,y))),_&&k&&k.name!==v&&(O=!0,D=function(){return k.call(this)}),o&&!b||!d&&!O&&R[p]||a(R,p,D),l[t]=D,l[E]=y,w)if(T={values:_?D:S(v),keys:x?D:S(h),entries:M},b)for(C in T)C in R||i(R,C,T[C]);else r(r.P+r.F*(d||O),t,T);return T}},60:function(e,t,n){var o=n(20),r=n(100),i=n(34),a=n(39)("IE_PROTO"),u=function(){},l="prototype",c=function(){var e,t=n(57)("iframe"),o=i.length,r="<",a=">";for(t.style.display="none",n(93).appendChild(t),t.src="javascript:",e=t.contentWindow.document,e.open(),e.write(r+"script"+a+"document.F=Object"+r+"/script"+a),e.close(),c=e.F;o--;)delete c[l][i[o]];return c()};e.exports=Object.create||function(e,t){var n;return null!==e?(u[l]=o(e),n=new u,u[l]=null,n[a]=e):n=c(),void 0===t?n:r(n,t)}},61:function(e,t,n){var o=n(63),r=n(34).concat("length","prototype");t.f=Object.getOwnPropertyNames||function(e){return o(e,r)}},62:function(e,t){t.f=Object.getOwnPropertySymbols},63:function(e,t,n){var o=n(8),r=n(9),i=n(90)(!1),a=n(39)("IE_PROTO");e.exports=function(e,t){var n,u=r(e),l=0,c=[];for(n in u)n!=a&&o(u,n)&&c.push(n);for(;t.length>l;)o(u,n=t[l++])&&(~i(c,n)||c.push(n));return c}},64:function(e,t,n){e.exports=n(13)},77:function(e,t,n){var o=n(33);e.exports=function(e){return Object(o(e))}},83:function(e,t,n){e.exports={default:n(86),__esModule:!0}},84:function(e,t,n){e.exports={default:n(87),__esModule:!0}},85:function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var r=n(84),i=o(r),a=n(83),u=o(a),l="function"==typeof u.default&&"symbol"==typeof i.default?function(e){return typeof e}:function(e){return e&&"function"==typeof u.default&&e.constructor===u.default&&e!==u.default.prototype?"symbol":typeof e};t.default="function"==typeof u.default&&"symbol"===l(i.default)?function(e){return"undefined"==typeof e?"undefined":l(e)}:function(e){return e&&"function"==typeof u.default&&e.constructor===u.default&&e!==u.default.prototype?"symbol":"undefined"==typeof e?"undefined":l(e)}},86:function(e,t,n){n(110),n(108),n(111),n(112),e.exports=n(25).Symbol},87:function(e,t,n){n(109),n(113),e.exports=n(44).f("iterator")},88:function(e,t){e.exports=function(e){if("function"!=typeof e)throw TypeError(e+" is not a function!");return e}},89:function(e,t){e.exports=function(){}},90:function(e,t,n){var o=n(9),r=n(106),i=n(105);e.exports=function(e){return function(t,n,a){var u,l=o(t),c=r(l.length),s=i(a,c);if(e&&n!=n){for(;c>s;)if(u=l[s++],u!=u)return!0}else for(;c>s;s++)if((e||s in l)&&l[s]===n)return e||s||0;return!e&&-1}}},91:function(e,t,n){var o=n(88);e.exports=function(e,t,n){if(o(e),void 0===t)return e;switch(n){case 1:return function(n){return e.call(t,n)};case 2:return function(n,o){return e.call(t,n,o)};case 3:return function(n,o,r){return e.call(t,n,o,r)}}return function(){return e.apply(t,arguments)}}},92:function(e,t,n){var o=n(19),r=n(62),i=n(37);e.exports=function(e){var t=o(e),n=r.f;if(n)for(var a,u=n(e),l=i.f,c=0;u.length>c;)l.call(e,a=u[c++])&&t.push(a);return t}},93:function(e,t,n){e.exports=n(5).document&&document.documentElement},94:function(e,t,n){var o=n(56);e.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==o(e)?e.split(""):Object(e)}},95:function(e,t,n){var o=n(56);e.exports=Array.isArray||function(e){return"Array"==o(e)}},96:function(e,t,n){"use strict";var o=n(60),r=n(22),i=n(38),a={};n(13)(a,n(15)("iterator"),function(){return this}),e.exports=function(e,t,n){e.prototype=o(a,{next:r(1,n)}),i(e,t+" Iterator")}},97:function(e,t){e.exports=function(e,t){return{value:t,done:!!e}}},98:function(e,t,n){var o=n(19),r=n(9);e.exports=function(e,t){for(var n,i=r(e),a=o(i),u=a.length,l=0;u>l;)if(i[n=a[l++]]===t)return n}},99:function(e,t,n){var o=n(23)("meta"),r=n(21),i=n(8),a=n(14).f,u=0,l=Object.isExtensible||function(){return!0},c=!n(18)(function(){return l(Object.preventExtensions({}))}),s=function(e){a(e,o,{value:{i:"O"+ ++u,w:{}}})},f=function(e,t){if(!r(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!i(e,o)){if(!l(e))return"F";if(!t)return"E";s(e)}return e[o].i},p=function(e,t){if(!i(e,o)){if(!l(e))return!0;if(!t)return!1;s(e)}return e[o].w},d=function(e){return c&&m.NEED&&l(e)&&!i(e,o)&&s(e),e},m=e.exports={KEY:o,NEED:!1,fastKey:f,getWeak:p,onFreeze:d}},100:function(e,t,n){var o=n(14),r=n(20),i=n(19);e.exports=n(12)?Object.defineProperties:function(e,t){r(e);for(var n,a=i(t),u=a.length,l=0;u>l;)o.f(e,n=a[l++],t[n]);return e}},101:function(e,t,n){var o=n(37),r=n(22),i=n(9),a=n(42),u=n(8),l=n(58),c=Object.getOwnPropertyDescriptor;t.f=n(12)?c:function(e,t){if(e=i(e),t=a(t,!0),l)try{return c(e,t)}catch(e){}if(u(e,t))return r(!o.f.call(e,t),e[t])}},102:function(e,t,n){var o=n(9),r=n(61).f,i={}.toString,a="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],u=function(e){try{return r(e)}catch(e){return a.slice()}};e.exports.f=function(e){return a&&"[object Window]"==i.call(e)?u(e):r(o(e))}},103:function(e,t,n){var o=n(8),r=n(77),i=n(39)("IE_PROTO"),a=Object.prototype;e.exports=Object.getPrototypeOf||function(e){return e=r(e),o(e,i)?e[i]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?a:null}},104:function(e,t,n){var o=n(41),r=n(33);e.exports=function(e){return function(t,n){var i,a,u=String(r(t)),l=o(n),c=u.length;return l<0||l>=c?e?"":void 0:(i=u.charCodeAt(l),i<55296||i>56319||l+1===c||(a=u.charCodeAt(l+1))<56320||a>57343?e?u.charAt(l):i:e?u.slice(l,l+2):(i-55296<<10)+(a-56320)+65536)}}},105:function(e,t,n){var o=n(41),r=Math.max,i=Math.min;e.exports=function(e,t){return e=o(e),e<0?r(e+t,0):i(e,t)}},106:function(e,t,n){var o=n(41),r=Math.min;e.exports=function(e){return e>0?r(o(e),9007199254740991):0}},107:function(e,t,n){"use strict";var o=n(89),r=n(97),i=n(35),a=n(9);e.exports=n(59)(Array,"Array",function(e,t){this._t=a(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,n=this._i++;return!e||n>=e.length?(this._t=void 0,r(1)):"keys"==t?r(0,n):"values"==t?r(0,e[n]):r(0,[n,e[n]])},"values"),i.Arguments=i.Array,o("keys"),o("values"),o("entries")},108:function(e,t){},109:function(e,t,n){"use strict";var o=n(104)(!0);n(59)(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,n=this._i;return n>=t.length?{value:void 0,done:!0}:(e=o(t,n),this._i+=e.length,{value:e,done:!1})})},110:function(e,t,n){"use strict";var o=n(5),r=n(8),i=n(12),a=n(51),u=n(64),l=n(99).KEY,c=n(18),s=n(40),f=n(38),p=n(23),d=n(15),m=n(44),h=n(43),v=n(98),y=n(92),g=n(95),w=n(20),x=n(9),b=n(42),T=n(22),C=n(60),I=n(102),S=n(101),E=n(14),_=n(19),O=S.f,R=E.f,k=I.f,D=o.Symbol,M=o.JSON,A=M&&M.stringify,F="prototype",P=d("_hidden"),L=d("toPrimitive"),j={}.propertyIsEnumerable,N=s("symbol-registry"),Z=s("symbols"),U=s("op-symbols"),z=Object[F],B="function"==typeof D,q=o.QObject,W=!q||!q[F]||!q[F].findChild,K=i&&c(function(){return 7!=C(R({},"a",{get:function(){return R(this,"a",{value:7}).a}})).a})?function(e,t,n){var o=O(z,t);o&&delete z[t],R(e,t,n),o&&e!==z&&R(z,t,o)}:R,J=function(e){var t=Z[e]=C(D[F]);return t._k=e,t},H=B&&"symbol"==typeof D.iterator?function(e){return"symbol"==typeof e}:function(e){return e instanceof D},G=function(e,t,n){return e===z&&G(U,t,n),w(e),t=b(t,!0),w(n),r(Z,t)?(n.enumerable?(r(e,P)&&e[P][t]&&(e[P][t]=!1),n=C(n,{enumerable:T(0,!1)})):(r(e,P)||R(e,P,T(1,{})),e[P][t]=!0),K(e,t,n)):R(e,t,n)},Y=function(e,t){w(e);for(var n,o=y(t=x(t)),r=0,i=o.length;i>r;)G(e,n=o[r++],t[n]);return e},V=function(e,t){return void 0===t?C(e):Y(C(e),t)},X=function(e){var t=j.call(this,e=b(e,!0));return!(this===z&&r(Z,e)&&!r(U,e))&&(!(t||!r(this,e)||!r(Z,e)||r(this,P)&&this[P][e])||t)},$=function(e,t){if(e=x(e),t=b(t,!0),e!==z||!r(Z,t)||r(U,t)){var n=O(e,t);return!n||!r(Z,t)||r(e,P)&&e[P][t]||(n.enumerable=!0),n}},Q=function(e){for(var t,n=k(x(e)),o=[],i=0;n.length>i;)r(Z,t=n[i++])||t==P||t==l||o.push(t);return o},ee=function(e){for(var t,n=e===z,o=k(n?U:x(e)),i=[],a=0;o.length>a;)!r(Z,t=o[a++])||n&&!r(z,t)||i.push(Z[t]);return i};B||(D=function(){if(this instanceof D)throw TypeError("Symbol is not a constructor!");var e=p(arguments.length>0?arguments[0]:void 0),t=function(n){this===z&&t.call(U,n),r(this,P)&&r(this[P],e)&&(this[P][e]=!1),K(this,e,T(1,n))};return i&&W&&K(z,e,{configurable:!0,set:t}),J(e)},u(D[F],"toString",function(){return this._k}),S.f=$,E.f=G,n(61).f=I.f=Q,n(37).f=X,n(62).f=ee,i&&!n(36)&&u(z,"propertyIsEnumerable",X,!0),m.f=function(e){return J(d(e))}),a(a.G+a.W+a.F*!B,{Symbol:D});for(var te="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),ne=0;te.length>ne;)d(te[ne++]);for(var te=_(d.store),ne=0;te.length>ne;)h(te[ne++]);a(a.S+a.F*!B,"Symbol",{for:function(e){return r(N,e+="")?N[e]:N[e]=D(e)},keyFor:function(e){if(H(e))return v(N,e);throw TypeError(e+" is not a symbol!")},useSetter:function(){W=!0},useSimple:function(){W=!1}}),a(a.S+a.F*!B,"Object",{create:V,defineProperty:G,defineProperties:Y,getOwnPropertyDescriptor:$,getOwnPropertyNames:Q,getOwnPropertySymbols:ee}),M&&a(a.S+a.F*(!B||c(function(){var e=D();return"[null]"!=A([e])||"{}"!=A({a:e})||"{}"!=A(Object(e))})),"JSON",{stringify:function(e){if(void 0!==e&&!H(e)){for(var t,n,o=[e],r=1;arguments.length>r;)o.push(arguments[r++]);return t=o[1],"function"==typeof t&&(n=t),!n&&g(t)||(t=function(e,t){if(n&&(t=n.call(this,e,t)),!H(t))return t}),o[1]=t,A.apply(M,o)}}}),D[F][L]||n(13)(D[F],L,D[F].valueOf),f(D,"Symbol"),f(Math,"Math",!0),f(o.JSON,"JSON",!0)},111:function(e,t,n){n(43)("asyncIterator")},112:function(e,t,n){n(43)("observable")},113:function(e,t,n){n(107);for(var o=n(5),r=n(13),i=n(35),a=n(15)("toStringTag"),u=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],l=0;l<5;l++){var c=u[l],s=o[c],f=s&&s.prototype;f&&!f[a]&&r(f,a,c),i[c]=i.Array}},129:function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}var r=n(85),i=o(r),a=function(){function e(e,t,n){return t||n?String.fromCharCode(t||n):r[e]||e}function t(e){return f[e]}var n=/"|<|>|&| |'|&#(\d+);|&#(\d+)/g,o=/['<> "&]/g,r={""":'"',"<":"<",">":">","&":"&"," ":" "},u=/\u00a0/g,l=//gi,c=/\r?\n/g,s=/\s/g,f={};for(var p in r)f[r[p]]=p;return r["'"]="'",f["'"]="'",{encode:function(e){return e?(""+e).replace(o,t).replace(c,"
").replace(s," "):""},decode:function(t){return t?(""+t).replace(l,"\n").replace(n,e).replace(u," "):""},encodeBase16:function(e){if(!e)return e;e+="";for(var t=[],n=0,o=e.length;o>n;n++)t.push(e.charCodeAt(n).toString(16).toUpperCase());return t.join("")},encodeBase16forJSON:function(e){if(!e)return e;e=e.replace(/[\u4E00-\u9FBF]/gi,function(e){return escape(e).replace("%u","\\u")});for(var t=[],n=0,o=e.length;o>n;n++)t.push(e.charCodeAt(n).toString(16).toUpperCase());return t.join("")},decodeBase16:function(e){if(!e)return e;e+="";for(var t=[],n=0,o=e.length;o>n;n+=2)t.push(String.fromCharCode("0x"+e.slice(n,n+2)));return t.join("")},encodeObject:function(e){if(e instanceof Array)for(var t=0,n=e.length;n>t;t++)e[t]=a.encodeObject(e[t]);else if("object"==("undefined"==typeof e?"undefined":(0,i.default)(e)))for(var o in e)e[o]=a.encodeObject(e[o]);else if("string"==typeof e)return a.encode(e);return e},loadScript:function(e){var t=document.createElement("script");document.getElementsByTagName("body")[0].appendChild(t),t.setAttribute("src",e)},addLoadEvent:function(e){var t=window.onload;"function"!=typeof window.onload?window.onload=e:window.onload=function(){t(),e()}}}}();e.exports=a},156:function(e,t){function n(e,t){e.classList?e.classList.add(t):e.className+=" "+t}e.exports=n},157:function(e,t){function n(e,t){if(e.classList)e.classList.remove(t);else{var n=new RegExp("(^|\\b)"+t.split(" ").join("|")+"(\\b|$)","gi");e.className=e.className.replace(n," ")}}e.exports=n},189:function(e,t){"use strict";function n(){o(document.getElementById("js-jump-container"),document.getElementById("container"))}var o=function(e,t,n){function o(){e.style.display=(t.scrollTop||document.documentElement.scrollTop||document.body.scrollTop)>(n||500)?"block":"none"}function r(e,t){var n=null;return function(){var o=this,r=arguments;n&&clearTimeout(n),n=setTimeout(function(){return"function"==typeof e&&e.apply(o,r)},t)}}if(e){var i=null,a=window.onscroll,u=e.onclick;(t||window).onscroll=r(function(){"function"==typeof a&&a.apply(this,arguments),o()},100),e.onclick=function(){"function"==typeof u&&u.apply(this,arguments);t.scrollTop||document.documentElement.scrollTop||document.body.scrollTop;i=setInterval(function(){var e=t.scrollTop||document.documentElement.scrollTop||document.body.scrollTop,n=Math.max(10,e/6);e-=n,e>0?(t.scrollTop=t.scrollTop-n,window.scrollTo(0,e)):(t.scrollTop=0,window.scrollTo(0,0),clearInterval(i))},10)}}};e.exports={init:n}},192:function(e,t,n){"use strict";function o(e){var t=new RegExp("(^|&)"+e+"=([^&]*)(&|$)","i"),n=window.location.search.substr(1).match(t);return null!=n?unescape(n[2]):null}var r=n(388);if(n(197),window.BJ_REPORT){BJ_REPORT.init({id:1}),BJ_REPORT.init({id:1,uin:window.location.origin,combo:0,delay:1e3,url:"//litten.me:9005/badjs/",ignore:[/Script error/i],random:1,repeat:5e5,onReport:function(e,t){},ext:{}});var i=window.location.host,a=top===window,u=!(/localhost/i.test(i)||/127.0.0.1/i.test(i)||/0.0.0.0/i.test(i));a&&u&&BJ_REPORT.report("yilia-"+window.location.host);var l=o("f"),c="yilia-from";l?(a&&BJ_REPORT.report("from-"+l),r.set(c,l)):document.referrer.indexOf(window.location.host)>=0?(l=r.get(c),l&&a&&BJ_REPORT.report("from-"+l)):r.remove(c)}e.exports={init:function(){}}},193:function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var e=e.replace(/<%-sUrl%>/g,encodeURIComponent(t.sUrl)).replace(/<%-sTitle%>/g,t.sTitle).replace(/<%-sDesc%>/g,t.sDesc).replace(/<%-sPic%>/g,encodeURIComponent(t.sPic));window.open(e)}function i(){var e=document.querySelector(".js-wx-box"),t=document.querySelector(".mask");(0,c.default)(e,"in"),(0,c.default)(e,"ready"),(0,c.default)(t,"in")}function a(){var e=document.querySelector(".js-wx-box"),t=document.querySelector(".mask");(0,f.default)(e,"in"),(0,f.default)(e,"ready"),(0,f.default)(t,"in")}function u(e,t){"weibo"===e?r("http://service.weibo.com/share/share.php?url=<%-sUrl%>&title=<%-sTitle%>&pic=<%-sPic%>",t):"qq"===e?r("http://connect.qq.com/widget/shareqq/index.html?url=<%-sUrl%>&title=<%-sTitle%>&source=<%-sDesc%>",t):"douban"===e?r("https://www.douban.com/share/service?image=<%-sPic%>&href=<%-sUrl%>&name=<%-sTitle%>&text=<%-sDesc%>",t):"qzone"===e?r("http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=<%-sUrl%>&title=<%-sTitle%>&pics=<%-sPic%>&summary=<%-sDesc%>",t):"facebook"===e?r("https://www.facebook.com/sharer/sharer.php?u=<%-sUrl%>",t):"twitter"===e?r("https://twitter.com/intent/tweet?text=<%-sTitle%>&url=<%-sUrl%>&via=<%-config.url%>",t):"google"===e?r("https://plus.google.com/share?url=<%-sUrl%>",t):"weixin"===e&&i()}var l=n(156),c=o(l),s=n(157),f=o(s),p=function(){var e=document.querySelectorAll(".share-sns");if(e&&0!==e.length){var t=window.location.href,n=document.querySelector("title").innerHTML,o=document.querySelectorAll(".article-entry img"),r=o.length?document.querySelector(".article-entry img").getAttribute("src"):"";""===r||/^(http:|https:)?\/\//.test(r)||(r=window.location.origin+r),e.forEach(function(e){e.onclick=function(o){var i=e.getAttribute("data-type");u(i,{sUrl:t,sPic:r,sTitle:n,sDesc:n})}}),document.querySelector(".mask").onclick=a,document.querySelector(".js-modal-close").onclick=a}};e.exports={init:p}},194:function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function r(){var e=document.querySelectorAll(".pswp")[0],t=document.querySelectorAll(".article-entry img:not(.reward-img)");t.forEach(function(n,o){n.onclick=function(){if(!document.querySelector(".left-col.show")){var n=[];t.forEach(function(e,t){var o=(e.getAttribute("data-idx",t),e.getAttribute("data-target")||e.getAttribute("src")),r=e.getAttribute("alt"),i=new Image;i.src=o,n.push({src:o,w:i.width||e.width,h:i.height||e.height,title:r})});var r=new a.default(e,l.default,n,{index:parseInt(o)});r.init()}}})}var i=n(390),a=o(i),u=n(389),l=o(u);n(384),n(385),window.PhotoSwipe=a.default,window.PhotoSwipeUI_Default=l.default,e.exports={init:r}},197:function(e,t,n){/*! + * @module report + * @author kael, chriscai + * @date @DATE + * Copyright (c) 2014 kael, chriscai + * Licensed under the MIT license. + */ +var o=function(e){if(e.BJ_REPORT)return e.BJ_REPORT;var t=[],n={},o={id:0,uin:0,url:"",combo:1,ext:null,level:4,ignore:[],random:1,delay:1e3,submit:null,repeat:5},r=function(e,t){return Object.prototype.toString.call(e)==="[object "+(t||"Object")+"]"},i=function(e){var t=typeof e;return"object"===t&&!!e},a=function(e){return null===e||!r(e,"Number")&&!e},u=e.onerror;e.onerror=function(t,n,o,i,a){var l=t;a&&a.stack&&(l=c(a)),r(l,"Event")&&(l+=l.type?"--"+l.type+"--"+(l.target?l.target.tagName+"::"+l.target.src:""):""),y.push({msg:l,target:n,rowNum:o,colNum:i}),v(),u&&u.apply(e,arguments)};var l=function(e){try{if(e.stack){var t=e.stack.match("https?://[^\n]+");t=t?t[0]:"";var n=t.match(":(\\d+):(\\d+)");n||(n=[0,0,0]);var o=c(e);return{msg:o,rowNum:n[1],colNum:n[2],target:t.replace(n[0],"")}}return e.name&&e.message&&e.description?{msg:JSON.stringify(e)}:e}catch(t){return e}},c=function(e){var t=e.stack.replace(/\n/gi,"").split(/\bat\b/).slice(0,9).join("@").replace(/\?[^:]+/gi,""),n=e.toString();return t.indexOf(n)<0&&(t=n+"@"+t),t},s=function(e,t){var n=[],r=[],u=[];if(i(e)){e.level=e.level||o.level;for(var l in e){var c=e[l];if(!a(c)){if(i(c))try{c=JSON.stringify(c)}catch(e){c="[BJ_REPORT detect value stringify error] "+e.toString()}u.push(l+":"+c),n.push(l+"="+encodeURIComponent(c)),r.push(l+"["+t+"]="+encodeURIComponent(c))}}}return[r.join("&"),u.join(","),n.join("&")]},f=[],p=function(e){if(o.submit)o.submit(e);else{var t=new Image;f.push(t),t.src=e}},d=function(e){if(!i(e))return!0;var t=e.msg,r=n[t]=(parseInt(n[t],10)||0)+1;return r>o.repeat},m=[],h=0,v=function(e){if(o.report){for(;t.length;){var n=!1,i=t.shift();if(!d(i)){var a=s(i,m.length);if(r(o.ignore,"Array"))for(var u=0,l=o.ignore.length;u=o.random)return y;var n=i(e)?l(e):{msg:e};return o.ext&&!n.ext&&(n.ext=o.ext),n.from||(n.from=location.href),t.push(n),v(),y},report:function(e){return e&&y.push(e),v(!0),y},info:function(e){return e?(i(e)?e.level=2:e={msg:e,level:2},y.push(e),y):y},debug:function(e){return e?(i(e)?e.level=1:e={msg:e,level:1},y.push(e),y):y},init:function(e){if(i(e))for(var n in e)o[n]=e[n];var r=parseInt(o.id,10);return r&&(/qq\.com$/gi.test(location.hostname)&&(o.url||(o.url="//badjs2.qq.com/badjs"),o.uin||(o.uin=parseInt((document.cookie.match(/\buin=\D+(\d+)/)||[])[1],10))),o.report=(o.url||"/badjs")+"?id="+r+"&uin="+o.uin+"&"),t.length&&v(),y},__onerror__:e.onerror};return"undefined"!=typeof console&&console.error&&setTimeout(function(){var e=((location.hash||"").match(/([#&])BJ_ERROR=([^&$]+)/)||[])[2];e&&console.error("BJ_ERROR",decodeURIComponent(e).replace(/(:\d+:\d+)\s*/g,"$1\n"))},0),y}(window);e.exports=o,function(e){if(!e.BJ_REPORT)return void console.error("please load bg-report first");var t=function(t){e.BJ_REPORT.push(t)},n={};e.BJ_REPORT.tryJs=function(e){return e&&(t=e),n};var o,r=function(e,t){for(var n in t)e[n]=t[n]},i=function(e){return"function"==typeof e},a=function(n,r){return function(){try{return n.apply(this,r||arguments)}catch(n){if(t(n),n.stack&&console&&console.error&&console.error("[BJ-REPORT]",n.stack),!o){var i=e.onerror;e.onerror=function(){},o=setTimeout(function(){e.onerror=i,o=null},50)}throw n}}},u=function(e){return function(){for(var t,n=[],o=0,r=arguments.length;o1){if(i=e({path:"/"},o.defaults,i),"number"==typeof i.expires){var u=new Date;u.setMilliseconds(u.getMilliseconds()+864e5*i.expires),i.expires=u}i.expires=i.expires?i.expires.toUTCString():"";try{a=JSON.stringify(r),/^[\{\[]/.test(a)&&(r=a)}catch(e){}r=n.write?n.write(r,t):encodeURIComponent(String(r)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g,decodeURIComponent),t=encodeURIComponent(String(t)),t=t.replace(/%(23|24|26|2B|5E|60|7C)/g,decodeURIComponent),t=t.replace(/[\(\)]/g,escape);var l="";for(var c in i)i[c]&&(l+="; "+c,i[c]!==!0&&(l+="="+i[c]));return document.cookie=t+"="+r+l}t||(a={});for(var s=document.cookie?document.cookie.split("; "):[],f=/(%[0-9A-Z]{2})+/g,p=0;p-1&&(n.onTap(),o=!0);if(o){e.stopPropagation&&e.stopPropagation(),y=!0;var u=t.features.isOldAndroid?600:30;g=setTimeout(function(){y=!1},u)}},_=function(){return!e.likelyTouchDevice||v.mouseUsed||screen.width>v.fitControlsWidth},O=function(e,n,o){t[(o?"add":"remove")+"Class"](e,"pswp__"+n)},R=function(){var e=1===v.getNumItemsFn();e!==h&&(O(o,"ui--one-slide",e),h=e)},k=function(){O(l,"share-modal--hidden",I)},D=function(){return I=!I,I?(t.removeClass(l,"pswp__share-modal--fade-in"),setTimeout(function(){I&&k()},300)):(k(),setTimeout(function(){I||t.addClass(l,"pswp__share-modal--fade-in")},30)),I||A(),!1},M=function(t){t=t||window.event;var n=t.target||t.srcElement;return e.shout("shareLinkClick",t,n),!!n.href&&(!!n.hasAttribute("download")||(window.open(n.href,"pswp_share","scrollbars=yes,resizable=yes,toolbar=no,location=yes,width=550,height=420,top=100,left="+(window.screen?Math.round(screen.width/2-275):100)),I||D(),!1))},A=function(){for(var e,t,n,o,r,i="",a=0;a