[{"content":"说明 EXE文件的ICON图标一般由数个图标组成，在更新ICON图标时需要逐一添加每个图标，再添加ICON_GROUP目录，可以使用ResourceHacker软件进行查看。\nEXE文件中的图标数据结构和ICON图标文件结构很相似，唯一区别在于ICON图标的ICONDIRENTRY最后一个字段标注的是图像数据首地址，EXE文件的GRPICONDIRENTRY最后一个字段标注的是图标的ID。\n代码 #include \u0026lt;windows.h\u0026gt; #include \u0026lt;stdio.h\u0026gt; #pragma pack(push, 2) //结构体需要双字节对齐 typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource Type (1 for icons) WORD idCount; // How many images? // ICONDIRENTRY idEntries[1]; // An entry for each image (idCount of \u0026#39;em) } ICONDIR; typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if \u0026gt;=8bpp) BYTE bReserved; // Reserved ( must be 0) WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // How many bytes in this resource? DWORD dwImageOffset; // Where in the file is this image? } ICONDIRENTRY; typedef struct { BITMAPINFOHEADER icHeader; // DIB header RGBQUAD icColors[1]; // Color table BYTE icXOR[1]; // DIB bits for XOR mask BYTE icAND[1]; // DIB bits for AND mask } ICONIMAGE; typedef struct { WORD idReserved; // Reserved (must be 0) WORD idType; // Resource type (1 for icons) WORD idCount; // How many images? // GRPICONDIRENTRY idEntries[1]; // The entries for each image } GRPICONDIR; typedef struct { BYTE bWidth; // Width, in pixels, of the image BYTE bHeight; // Height, in pixels, of the image BYTE bColorCount; // Number of colors in image (0 if \u0026gt;=8bpp) BYTE bReserved; // Reserved WORD wPlanes; // Color Planes WORD wBitCount; // Bits per pixel DWORD dwBytesInRes; // how many bytes in this resource? WORD nID; // the ID } GRPICONDIRENTRY; #pragma pack(pop) int main(int argc, char *argv[]) { // if (argc != 3) { // printf(\u0026#34;Usage: %s \u0026lt;target_exe\u0026gt; \u0026lt;new_icon.ico\u0026gt;\\n\u0026#34;, argv[0]); // return 1; // } // // const char *exePath = argv[1]; // const char *iconPath = argv[2]; char exePath[] = \u0026#34;pip.exe\u0026#34;; char iconPath[] = \u0026#34;app.ico\u0026#34;; // 打开图标文件 HANDLE hIcon = CreateFile(iconPath, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (hIcon == INVALID_HANDLE_VALUE) { printf(\u0026#34;[%lu]Error opening icon file\\n\u0026#34;, GetLastError()); return 1; } // 获取图标文件大小 DWORD iconSize = GetFileSize(hIcon, NULL); if (iconSize == INVALID_FILE_SIZE) { printf(\u0026#34;[%lu]Error getting icon file size\\n\u0026#34;, GetLastError()); CloseHandle(hIcon); return 1; } // 读取图标文件 BYTE* iconData = malloc(iconSize); DWORD bytesRead; if (!ReadFile(hIcon, iconData, iconSize, \u0026amp;bytesRead, NULL) || bytesRead != iconSize) { printf(\u0026#34;[%lu]Error reading icon file\\n\u0026#34;, GetLastError()); free(iconData); CloseHandle(hIcon); return 1; } CloseHandle(hIcon); // 解析图标文件目录 ICONDIR* iconDir = (ICONDIR*)iconData; if (iconDir-\u0026gt;idReserved != 0 || iconDir-\u0026gt;idType != 1) { printf(\u0026#34;Invalid icon file format\\n\u0026#34;); free(iconData); return 1; } // 计算图标组资源大小 DWORD groupSize = sizeof(GRPICONDIR) + iconDir-\u0026gt;idCount * sizeof(GRPICONDIRENTRY); BYTE* groupData = malloc(groupSize); GRPICONDIR* grpIconDir = (GRPICONDIR*)groupData; grpIconDir-\u0026gt;idReserved = 0; grpIconDir-\u0026gt;idType = 1; // RT_ICON grpIconDir-\u0026gt;idCount = iconDir-\u0026gt;idCount; // 创建图标组资源 ICONDIRENTRY* iconEntries = (ICONDIRENTRY*)(iconData + sizeof(ICONDIR)); GRPICONDIRENTRY* grpEntries = (GRPICONDIRENTRY*)(groupData + sizeof(GRPICONDIR)); for (int i = 0; i \u0026lt; iconDir-\u0026gt;idCount; i++) { grpEntries[i].bWidth = iconEntries[i].bWidth; grpEntries[i].bHeight = iconEntries[i].bHeight; grpEntries[i].bColorCount = iconEntries[i].bColorCount; grpEntries[i].bReserved = iconEntries[i].bReserved; grpEntries[i].wPlanes = iconEntries[i].wPlanes; grpEntries[i].wBitCount = iconEntries[i].wBitCount; grpEntries[i].dwBytesInRes = iconEntries[i].dwBytesInRes; grpEntries[i].nID = i + 1; // 资源ID从1开始 } // 开始更新EXE资源 HANDLE hUpdate = BeginUpdateResource(exePath, FALSE); if (hUpdate == NULL) { printf(\u0026#34;BeginUpdateResource failed: %lu\\n\u0026#34;, GetLastError()); free(iconData); free(groupData); return 1; } // 删除现有的图标组资源 if (!UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(101), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)) { printf(\u0026#34;[%lu]Warning: Failed to remove old icon group ID-101\\n\u0026#34;, GetLastError()); } // 删除现有的图标资源 for (int i = 1; i \u0026lt;= 7; i++) { // 删除ID 1-7的图标资源 if (!UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(i), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)) { printf(\u0026#34;[%lu]Warning: Failed to remove old icon ID-%d\\n\u0026#34;, GetLastError(), i); }; } // 添加新的图标组资源 if (!UpdateResource(hUpdate, RT_GROUP_ICON, MAKEINTRESOURCE(101), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), groupData, groupSize)) { printf(\u0026#34;[%lu]UpdateResource (group icon) failed\\n\u0026#34;, GetLastError()); free(iconData); free(groupData); EndUpdateResource(hUpdate, TRUE); return 1; } // 添加各个图标资源 for (int i = 0; i \u0026lt; iconDir-\u0026gt;idCount; i++) { DWORD offset = iconEntries[i].dwImageOffset; DWORD size = iconEntries[i].dwBytesInRes; if (offset + size \u0026gt; iconSize) { printf(\u0026#34;Icon data out of bounds: entry %d\\n\u0026#34;, i); continue; } if (!UpdateResource(hUpdate, RT_ICON, MAKEINTRESOURCE(i + 1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData + offset, size)) { printf(\u0026#34;[%lu]UpdateResource (icon %d) failed\\n\u0026#34;, i, GetLastError()); } } // 完成资源更新 if (!EndUpdateResource(hUpdate, FALSE)) { printf(\u0026#34;[%lu]EndUpdateResource failed\\n\u0026#34;, GetLastError()); free(iconData); free(groupData); return 1; } printf(\u0026#34;Icon group updated successfully!\\n\u0026#34;); free(iconData); free(groupData); return 0; } ","date":"2025-07-13T00:00:00Z","permalink":"https://kizx.github.io/post/win32_api%E4%BF%AE%E6%94%B9exe%E6%96%87%E4%BB%B6icon%E5%9B%BE%E6%A0%87/","title":"Win32_API修改EXE文件ICON图标"},{"content":"安装Hugo Hugo有标准版、扩展版（extended），还有一个部署版（extended_withdeploy）,扩展板多了图像和Sass处理器，部署版支持直接部署到google、AWS云等。\n直接下载扩展版：https://github.com/gohugoio/hugo/releases/\n解压后将hugo.exe目录添加到全局环境变量中。\n新建站点 hugo new site quickstart\n初始化git git init\nhugo命令见官方指南：https://hugo.opendocs.io/getting-started/\n安装主题 hugo主题网站：https://themes.gohugo.com.cn/\n这里使用stack主题：https://stack.jimmycai.com/\n安装主题 直接使用git命令或者手动下载放到themes目录下\ngit submodule add https://github.com/CaiJimmy/hugo-theme-stack/ themes/hugo-theme-stack\n主题设置 stack主题设置参考：https://stack.jimmycai.com/config/\n以下本站设置：\nbaseURL = \u0026#39;http://kizx.gitee.io/\u0026#39; languageCode = \u0026#39;zh-cn\u0026#39; title = \u0026#39;醉后的星星\u0026#39; theme = \u0026#39;hugo-theme-stack\u0026#39; copyright = \u0026#39;kizx\u0026#39; DefaultContentLanguage = \u0026#39;zh-cn\u0026#39; [params] favicon = \u0026#34;/favicon.ico\u0026#34; [params.sidebar] #compact = true emoji = \u0026#39;🔞\u0026#39; subtitle = \u0026#34;我好菜啊\u0026#34; avatar.enabled = true avatar.local = true avatar.src = \u0026#34;img/avatar.gif\u0026#34; [params.Footer] since = 2019 #customText = \u0026#34;\u0026#34; [params.Article] headingAnchor = true math = true readingTime = false [params.widgets] homepage = [ {type = \u0026#39;search\u0026#39;}, {type = \u0026#39;archives\u0026#39;}, {type = \u0026#39;tag-cloud\u0026#39;}, ] page = [ {type = \u0026#39;toc\u0026#39;}, {type = \u0026#39;categories\u0026#39;}, ] [params.opengraph] twitter.site = \u0026#34;kizx\u0026#34; twitter.card = \u0026#34;summary\u0026#34; enabled = true src = \u0026#34;img/default.jpg\u0026#34; local = true [menu] [[menu.social]] identifier = \u0026#39;github\u0026#39; url = \u0026#39;https://github.com/kizx\u0026#39; params.icon = \u0026#39;brand-github\u0026#39; [[menu.social]] identifier = \u0026#39;bilibili\u0026#39; url = \u0026#39;https://space.bilibili.com/22411920\u0026#39; params.icon = \u0026#39;brand-bilibili\u0026#39; 左侧菜单页设置：\n直接将hugo-theme-stack\\exampleSite\\content\\page拷贝到网页的content\\page中\n需要出现在菜单栏中的页面通过在md文件的Front Matter中添加：\nmenu: main: name: title (optional) weight: -90 params: icon: icon-name 或者直接在配置文件中添加，但在配置文件中添加会缺少当前惨淡选中高亮显示。\n参考 使用hugo stack主题快速搭建博客\n【Hugo】配置 (stack 主题)\n图标下载\n如何用 GitHub Pages + Hugo 搭建个人博客\n","date":"2025-07-06T08:38:00Z","permalink":"https://kizx.github.io/post/hugo%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA/","title":"Hugo博客搭建及stack主题设置"},{"content":"js的sort函数的默认排序方法是将排序对象转成字符串，然后根据字符串中每个字符的ascll码依次进行排序，对于不在ascll表中的中文无法进行排序。\nlocaleCompare localeCompare函数可以比较两个中文的顺序，用该方法配合sort方法可以实现中文排序：\nnames.sort((a, b) =\u0026gt; { return a.username.localeCompare(b.username, \u0026#39;zh\u0026#39;); }); 进一步，如果想获得中文首字母，可以依次和每个字母的第一个中文进行比较，进而得出该中文字符的首字母：\nconst getFirstLetter = function(word) { let letters = \u0026#34;ABCDEFGHJKLMNOPQRSTWXYZ#\u0026#34;; let zh = \u0026#34;阿八嚓哒妸发旮哈讥咔垃呣拏噢妑七呥扨它穵夕丫帀糳\u0026#34;; for (let i = 0; i \u0026lt; letters.length - 1; i++) { if (word.localeCompare(zh[i], \u0026#39;zh\u0026#39;) \u0026gt;= 0 \u0026amp;\u0026amp; word.localeCompare(zh[i + 1], \u0026#39;zh\u0026#39;) \u0026lt; 0) { return letters[i] } } return \u0026#39;#\u0026#39; }; 注意有些字母没有对应的姓氏，因此不在比较之列。 本方法最大的问题是，微信小程序和很多浏览器内核都不支持该函数，用之前先做好测试。\n第三方库 若不能使用上述方法，发现一个第三方库jian-pinyin，体积不大，可以直接给出汉字的拼音，很棒。 地址：https://github.com/xinglie/pinyin 通过该库直接获取汉字的拼音，然后通过sort函数进行排序，注意js中字符串之间是可以直接比较大小的，比较的依据仍然是ascll。\nlet sp = function(word) { return getSpell(word, function(charactor, spell) { return spell[0]; }, \u0026#39;\u0026#39;) } names.sort((a, b) =\u0026gt; { a = sp(a.username); b = sp(b.username); if (a \u0026lt; b) return -1; if (a \u0026gt; b) return 1; return 0 }); ","date":"2023-03-15T15:52:01Z","permalink":"https://kizx.github.io/post/javascript%E4%B8%AD%E6%96%87%E6%8C%89%E6%8B%BC%E9%9F%B3%E9%A1%BA%E5%BA%8F%E6%8E%92%E5%BA%8F/","title":"javascript中文按拼音顺序排序"},{"content":"在VS里用MS编译器不能直接调用pthread库，需要先自行下载该库： http://sourceware.org/pub/pthreads-win32/pthreads-w32-2-9-1-release.zip 解压后用的到的只有Pre-built.2文件夹下的文件。\n配置 如下图分别配置三大项：\n包含目录\u0026ndash;\u0026gt;\u0026hellip;\\pthreads-w32-2-9-1-release\\Pre-built.2\\include 库目录\u0026ndash;\u0026gt;\u0026hellip;\\pthreads-w32-2-9-1-release\\Pre-built.2\\lib\\x86 附加依赖项\u0026ndash;\u0026gt;pthreadVC2.lib 如果代码运行报错：“timespec”;”struct”类型重定义。 解决方法：在pthread.h在第35行加入如下代码： #define HAVE_STRUCT_TIMESPEC 或者在项目属性-\u0026gt;C\\C++-\u0026gt;预处理器-\u0026gt;预处理器定义添加HAVE_STRUCT_TIMESPEC。\n如果代码运行报错：找不到pthreadVC2.dll。 解决方法：将pthreadVC2.dll拷贝到项目的Debug目录下 示例代码 #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;Windows.h\u0026gt; #include \u0026lt;pthread.h\u0026gt; //使用多线程时需要添加\u0026lt;pthread.h\u0026gt;这个头文件 int s = 0; void* transmit(void* args) { char* name = (char*)args; for (int i = 0; i \u0026lt; 1000; i++) { s++; printf(\u0026#34;----------%s : s = %d----------\\n\u0026#34;, name, s); Sleep(1000); } } void* receive(void* args) { char* name = (char*)args; while (1) { printf(\u0026#34;%s : s = %d\\n\u0026#34;, name, s); Sleep(100); } } int main() { pthread_t tx, rx; pthread_create(\u0026amp;tx, NULL, transmit, \u0026#34;TX\u0026#34;); pthread_create(\u0026amp;rx, NULL, receive, \u0026#34;RX\u0026#34;); pthread_join(tx, NULL); pthread_join(rx, NULL); return 0; } 参考 https://www.cnblogs.com/maycpou/p/13895295.html https://zhuanlan.zhihu.com/p/97418361\n","date":"2022-06-28T15:32:00Z","permalink":"https://kizx.github.io/post/vs2019%E9%85%8D%E7%BD%AEpthread%E5%A4%9A%E7%BA%BF%E7%A8%8B/","title":"VS2019配置pthread多线程"},{"content":"时间节点 一般三四月份就会有春招，春招是找暑期实习的时机，就算不去实习，也可以投投简历，面面试积累一些经验，可以提前了解一些岗位要求、面试流程和自身所欠缺的部分。 五月份开始，可能就会有一些研究所开始提前批招聘，有中意单位的，需要特别留意。 暑假七八月份是各个大厂提前批招聘的黄金时期，准备做的差不多了就可以正式应聘了，越早投递，机会越大，很多公司研究所或岗位前面人招满了后面就没有HC了，很多人提前批拿到offer后面压力就会小很多，不过相对来说毕前批的招聘要求都会高一些。 金九银十是正式批的黄金时期，但就个人经验来看关键是九月份，九月份一开学就会有大批研究所和大厂开始招聘，九月份无疑是最忙的一个月份，如果采取海投策略的话，几乎每天都有不止一场面试或笔试，而十月份研究所和大厂招聘就会见少，主要是一些小公司较多，一般人九月份都能拿到offer。 至于后面的时间本人就没有参与了，所以最理想的找工作节奏就是三四月份一边面试试水积攒经验，一边查漏补缺，到了七八月份就应该学习准备的差不多了，提前批争取拿到一个offer，没拿到其实也没关系，经过提前批的磨练，在九月份的正式批里就能更得心应手了，九十月份拿到offer后，后面就能安心写论文了。 求职准备 所需要学习内容应该是视岗位而定的，所以说一开始就定一个目标岗位或方向是十分重要的，尤其是大厂企业招聘，都是看岗位招人的，笔试面试时都会与岗位要求息息相关；而研究所个人感觉更多的是看人招聘，他觉得你可以了，就把你招聘进去然后分配一个合适的岗位，我研究所面试经验不多，个人感觉大概就是这样的。所以企业招聘一定要选好岗位，投对岗位很重要，一旦投出去了后面再改也会比较困难。 一般来说大厂的笔试和面试最难，大厂面试一般分为综合测试-\u0026gt;笔试-\u0026gt;2~3轮面试-\u0026gt;hr面，综合测试是大部分招聘都会有的一个项目，主要是一些性格测试题，一般如实填写即可，只有华为的性格测试需要注意，可能会挂人。研究所一般没有笔试，面试也只有一两轮，面试更偏好问项目，因此此时简历和发挥就很重要了，能力、项目、学历至少要占两项才能脱颖而出。 数据结构与算法是所有程序向的岗位的公共基础，也是花费时间最久最见基本功的一项，这个除了学习外，更重要的是刷题，刷题一般上Leetcode或者牛客网上刷题，Leetcode题目比较多而全，可以按照大神推荐的顺序进行刷题，比如我觉得代码随想录就讲的很不错；牛客网上有很多企业笔试题，可以进行仿真练习，牛客网和Leetcode的代码运行方式有些不同，实际面试时一般就是以牛客网的方式，所以第一次笔试前，一定要在牛客网上做一次仿真练习，否则可能连输入输出都要琢磨半天。一般来说常见数据结构和算法专题都刷个十几道题，加一起刷个两三百题就比较保险了，当然还是得看个人学习方法和习惯，数量有时说明不了问题。然后相应的编程相关问题要具体看岗位所需的语言，这个除了自身掌握，一般就得看面经了，所谓面经，就是其他面试过的同学的经验，在牛客网和一些公众号上会有人总结，这个就看你平时关注了。其他像计算机网络、计算机组成原理等知识也会问，根据岗位侧重进行学习记忆即可。 最难的莫过于项目准备，这个只能看你自己会不会发掘了，只要是你参与过的项目，和岗位相关的项目，哪怕是没有参与过的但是你经过了解后掌握的，也可以写进去，这个就看你自己包装了，别给自己挖坑就行，我也不会包装，我就拿我平时写的小东西放上去了，好充个场面。 简历不用整什么花哨的模板，QQ邮箱自带的建立我看就挺好，怎么写建立这里就不细说了，后面推荐的up里有专门讲的，我想说的是建立一开始也不必写太好，写的差不多就可以投了，因为你会发现真正投递时，各家招聘网站上又得填一遍，填到后面都烦了哈哈。 信息获取 学校就业网和公众号会每天推送一些信息，尤其是九月开学之后，每天都有很多研究所的校招信息，每天关注校招日历以便及时投递。 大厂的校招一般都是线上的，所以学校招聘信息上可能不多，需要自己关注一些内推的公众号，或者牛客网上也有招聘信息，一般大厂都有招聘专用的公众号，一般叫XX招聘或者XX校招，可自行搜索。 可以加一些校招群多和别人了解一些招聘和应聘动态。 研究所的招聘信息一般都不会太公开，都是到学校了来了才发通知，或者有内部消息，可以关注这些所的公众号（如果有的话），也可以关注其他学校的就业网信息作为补充。 大厂薪酬信息一般有迹可循，可以上Offershow小程序搜索或者脉脉App上看看评价，研究所的信息较为封闭，有内部信息自然最好，大部分时候只能从网上的零碎信息去推测。 部分收藏推荐资源 编程资料 https://programmercarl.com/ https://www.iamshuaidi.com/ http://www.cyc2018.xyz/ https://codetop.cc/home https://github.com/jwasham/coding-interview-university/blob/main/translations/README-cn.md https://github.com/MisterBooo/LeetCodeAnimation B站的一些Up主 https://space.bilibili.com/384068749/ https://space.bilibili.com/245645656/ https://space.bilibili.com/327247876/ https://space.bilibili.com/525438321/ https://space.bilibili.com/522846737/ 公众号/小程序 OfferShow 内推指南 低并发编程 labuladong 小K算法 ","date":"2022-04-25T17:27:00Z","permalink":"https://kizx.github.io/post/%E5%85%B3%E4%BA%8E%E6%89%BE%E5%B7%A5%E4%BD%9C%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/","title":"关于找工作的那些事"},{"content":"npm -v 初始化 npm init 默认参数 npm init -y 查看已安装包 当前环境中的包 npm list 系统环境中的包 npm list -g 安装 npm install \u0026lt;Module Name\u0026gt; or npm i \u0026lt;Module Name\u0026gt; 安装到系统坏境中 npm i \u0026lt;Module Name\u0026gt; -g 安装到生产环境 npm i \u0026lt;Module Name\u0026gt; --save or npm i \u0026lt;Module Name\u0026gt; -S 安装到开发坏境 npm i \u0026lt;Module Name\u0026gt; --save-dev or npm i \u0026lt;Module Name\u0026gt; -D 淘宝cnpm npm install -g cnpm 运行 npm run \u0026lt;Script Name\u0026gt; 帮助 npm help npm -l 设置镜像 npm config set registry https://registry.npm.taobao.org 查看镜像 npm config get registry ","date":"2022-02-12T14:26:00Z","permalink":"https://kizx.github.io/post/npm%E5%9F%BA%E6%9C%AC%E5%91%BD%E4%BB%A4/","title":"npm基本命令"},{"content":"校园网是需要通过PPOPE拨号上网的，每次开机都需要在网络里点击连接才能上网，很是令人讨厌，应该让电脑自动联网。\n拨号上网命令 Windows系统里拨号上网的命令是rasdial，用法如下所示\nPS C:\\Users\\kizx\u0026gt; rasdial /h 用法: C:\\Windows\\system32\\rasdial.exe entryname [username [password|*]] [/DOMAIN:domain] [/PHONE:phonenumber] [/CALLBACK:callbacknumber] [/PHONEBOOK:phonebookfile] [/PREFIXSUFFIX] C:\\Windows\\system32\\rasdial.exe [entryname] /DISCONNECT C:\\Windows\\system32\\rasdial.exe 简单来说就是：\nrasdial.exe \u0026#34;连接名称\u0026#34; 账号 密码 任务计划 通过设置任务计划来开机自动运行rasdial命令，这也是网上能查到的最普遍的方法，下面给出一个参考，这里不再赘述。 https://zhuanlan.zhihu.com/p/359897141\n命令脚本 任务计划有时设置了并不起效，这里我给出一种通过开机自动运行脚本的方法，先新建一个开机运行.bat的脚本，然后写入如下内容，注意替换名称、账号和密码：\necho off chcp 65001 echo 正在连接 . . . rasdial \u0026#34;连接名称\u0026#34; 账号 密码 echo 连接成功！ 上面只有第四行是真正有用的，其他行只是我为了美观加上的，让运行起来好看点。\n然后将上述bat文件放到开机自启文件夹下，这个文件夹一般在下面这个目录里\nC:\\Users\\用户名\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup 设置完后，在任务管理器的启动项里就应该会多出一个开机运行.bat启动项。\n免密开机 顺带一提，如果想设置自动免密开机的话，win+R运行netplwiz命令后勾选取消开机密码。 如果没有这个选项，需要修改注册表HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PasswordLess\\Device，双击DevicePasswordLessBuildVersion，把值改成0确定，然后再运行netplwiz。 参考：https://zhidao.baidu.com/question/364115147169595652.html\n","date":"2022-01-14T05:14:00Z","permalink":"https://kizx.github.io/post/win10%E5%BC%80%E6%9C%BA%E8%87%AA%E5%8A%A8%E6%8B%A8%E5%8F%B7%E4%B8%8A%E7%BD%91%E6%96%B9%E6%B3%95/","title":"Win10开机自动拨号上网方法"},{"content":"Pyside6是Qt6对应的官方python库，官方有较全面的使用文档：https://doc.qt.io/qtforpython/contents.html。 本文使用Python3.7版本，从头安装使用Pyside6。\n安装 python版安装只需要一句命令即可：\npip install pyside6 安装包有点大，建议手动下载whl直接安装。 安装后会多两个库：PySide6和shiboken。 在Python环境下的Scripts文件夹下还会多出pyside6-designer.exe、pyside6-uic.exe等几个exe程序。\n界面设计工具设置 打开pyside6-designer.exe，是qt的界面设计程序，可以拖拽设计界面并保存为ui文件。 使用pyside6-uic.exe，通过以下程序命令可以将ui文件转成py文件。\npyside6-uic.exe ui_mainwindow.ui -o ui_mainwindow.py 如果用的是Pycharm，可以添加右键工具直接在文件右键快速打开，添加工具的方法参考以下文章。 [post cid=\u0026ldquo;119\u0026rdquo; /]\n初始代码 参考官方文档：https://doc.qt.io/qtforpython/tutorials/basictutorial/uifiles.html\n直接使用ui文件 import sys from PySide6.QtUiTools import QUiLoader from PySide6.QtWidgets import QApplication from PySide6.QtCore import QFile, QIODevice if __name__ == \u0026#34;__main__\u0026#34;: app = QApplication(sys.argv) ui_file_name = \u0026#34;mainwindow.ui\u0026#34; ui_file = QFile(ui_file_name) if not ui_file.open(QIODevice.ReadOnly): print(f\u0026#34;Cannot open {ui_file_name}: {ui_file.errorString()}\u0026#34;) sys.exit(-1) loader = QUiLoader() window = loader.load(ui_file) ui_file.close() if not window: print(loader.errorString()) sys.exit(-1) window.show() sys.exit(app.exec()) 转成py文件再加载 import sys from PySide6.QtWidgets import QApplication, QMainWindow from PySide6.QtCore import QFile from ui_mainwindow import Ui_MainWindow class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() self.ui = Ui_MainWindow() self.ui.setupUi(self) if __name__ == \u0026#34;__main__\u0026#34;: app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec()) 建议转成py文件再打开，感觉IDE提示更准确，不过直接加载更方便就是了。\n打包 打包建议使用auto-py-to-exe，这是一个基于pyinstaller的带Ui界面的打包程序，对新手极其友好。 使用以下命令安装：\npip install auto-py-to-exe 通过以下命令启动程序：\nauto-py-to-exe ","date":"2021-12-10T02:47:00Z","permalink":"https://kizx.github.io/post/pyside6%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/","title":"Pyside6使用指南"},{"content":"Bezier曲线 定义：对于n+1个控制点V_i(i=0,1,2,\u0026hellip;,n)V_i(i=0,1,2,\u0026hellip;,n)，n次Bezier曲线为： $$ \\begin{align} P_n(t) \u0026amp;= \\sum_{i=0}^{n} B_{n,i}(t)V_i,0\\le t\\le 1v \\ B_{n,i} \u0026amp;=\\frac{n!}{(n-i)!i!}(1-t)^{n-i}t^i \\end{align} $$ 其中B_{n,i}B_{n,i}称为n次Bernstein基函数。 例如，当n=3时，即3次Bezier曲线为：; $$ \\begin{align} P_3(t) \u0026amp;= B_{3,0}(t)V_0+B_{3,1}(t)V_1+B_{3,2}(t)V_2+B_{3,3}(t)V_3,0\\le t\\le 1v \\ B_{3,i} \u0026amp;= \\left{\\begin{matrix} B_{3,0}(t)=(1-t)^3 \\ B_{3,1}(t)=3(1-t)^2t \\ B_{3,2}(t)=3(1-t)t^2 \\ B_{3,3}(t)=t^3 \\end{matrix}\\right. \\end{align} $$\n性质\n两端重合：Bezier曲线和控制多边形起始两端点重合，P(0)=V_0,P(1)=V_nP(0)=V_0,P(1)=V_n 两端相切：Bezier曲线和控制多边形起始两端点相切，且切矢模长为n倍，P\u0026rsquo;(0)=n(V_1-V_0),P\u0026rsquo;(1)=n(V_n-V_{n-1})P\u0026rsquo;(0)=n(V_1-V_0),P\u0026rsquo;(1)=n(V_n-V_{n-1}) 对称性：控制点反序够早的曲线一致，只是参数化相反 凸包性：曲线落在控制多边形形成的凸包内 几何不变形：曲线仅取决于控制点，与坐标系无关 递归分割de Casteljau算法 在控制多边形每条边上按比例t:(1-t)进行分割，初始n+1个点，第一次分割得到n个点，n个点连起来组成新的控制点，第二次分割得到n-1个点，直到最后只剩一个点，该点即Bezier曲线上的点。 de Casteljau建立的递归公式如下： $$ \\begin{array}{c} \\left{\\begin{matrix} \u0026amp;V_i^r(t) = (1-t)V_i^{r-1}+tV_{i+1}^{r-1} ,r = 0,1,2,\u0026hellip;,n\\ \u0026amp;V_i^0(t) = V_i,i = 0,1,2,\u0026hellip;,n \\end{matrix}\\right. \\end{array} $$ 该方法适合于编程几何作图。\n有理Bezier曲线 定义：比Bezier曲线多了个顶点权重系数，至于哪里有理了不清楚。 $$ P_(t)=\\frac{\\sum_{i=0}^{n}B_{n,i}(t)w_iV_i}{B_{n,i}(t)w_i} , 0\\le t\\le 1 $$ 例如，3次有理Bezier曲线表示为： $$ P_3(t)=\\frac{(1-t)^3w_0V_0+3t(1-t)^2w_1V_1+3t^2(1-t)w_2V_2+t^3w_3V_3}{(1-t)^3w_0+3t(1-t)^2w_1+3t^2(1-t)w_2+t^3w_3} $$ 权重$w_i$可以一般取大于零的实数。\n递归分割Farin算法 和上述过程类似： $$ \\begin{array}{c} \\left{\\begin{matrix} \u0026amp;V_i^r(t) = (1-t)\\frac{W_i^{r-1}(t)}{W_i^r(t)} V_i^{r-1}+t\\frac{W_{i-1}^{r-1}(t)}{W_i^r(t)}V_{i+1}^{r-1} ,r = 0,1,2,\u0026hellip;,n\\ \u0026amp;V_i^0(t) = V_i,i = 0,1,2,\u0026hellip;,n \\end{matrix}\\right.\\ \\left{\\begin{matrix} W_i^0=w_i \\ W_i^r(t)=\\sum_{j=0}^{r}W_{i+j}^{r-1}B_{r,j}(t),r=1,2,\u0026hellip;,n \\end{matrix}\\right. \\end{array} $$\nB样条方法 B样条方法是Bezier方法的的一种一般化，给定n+1个控制点和阶次k，以及节点向量${t_0,t_1,\u0026hellip;,t_{n+k+1}}$: $$ \\begin{array}{c} P_n(t) = \\sum_{i = 0}^{n}N_{i,k}(t)V_i=\\sum_{i = j-k}^{j}N_{i,k}(t)V_i,t_j\\le t\\le t_{j+1}\\ N_{j,0}=\\left{\\begin{matrix} 1,t_j\\le t\\le t_{j+1} \\ 0,otherwise \\end{matrix}\\right.\\ N_{i,k}(t)=\\frac{t-t_i}{t_{i+k}-t_i}N_{i,k-1}(t)+\\frac{t_{i+k+1}-t}{t_{i+k+1}-t_{i+1}} N_{i+1,k-1}(t) \\end{array}\\ *约定 frac{0}{0}=0 $$ 其中$N_{i,k}(t)$为k阶( k-1次 )B样条基函数，${t_0,t_1,\u0026hellip;,t_{n+k+1}}$为节点矢量，B样条按其节点矢量分布可分为以下三类：\n均匀B样条：均匀分布或等距分布。 准均匀分布：与均匀B样条区别在于两端端点为重节点。 非均匀B样条：任意分布。 例如三次均匀B样条基函数为： $$ \\left{\\begin{matrix} N_{0,3}(t)=\\frac{1}{6}(1-t)^3 \\ N_{1,3}(t)=\\frac{1}{6}(3t^3-6t^2+4) \\ N_{2,3}(t)=\\frac{1}{6}(-3t^3+3t^2+3t+1) \\ N_{3,3}(t)=\\frac{1}{6}t^3 \\end{matrix}\\right. $$ B样条具有局部性：改变一个控制点时，只会对附近曲线段的形状产生影响。 对于一个k次的n+1个控制点的B样条，当k=n时，退化为Bezier曲线。 NURBS方法 NURBS曲线全称非均匀有理B样条，是B样条的一般化，非均匀指节点的选取可以是不均匀的，有理主要体现在每个控制点有个权因子。 $$ R_n(t)=\\frac{\\sum_{i=0}^{n}N_{i,k}(t)w_iV_i}{N_{i,k}(t)w_i} $$\n参考 https://blog.csdn.net/johnhany/article/details/8830928 《形状可调的参数曲线曲面造型方法研究》 《Bezier曲线曲面的造型设计理论研究》\n","date":"2021-10-25T12:37:00Z","permalink":"https://kizx.github.io/post/bezier%E6%9B%B2%E7%BA%BFb%E6%A0%B7%E6%9D%A1%E6%9B%B2%E7%BA%BFnurbs%E6%9B%B2%E7%BA%BF/","title":"Bezier曲线、B样条曲线、NURBS曲线"},{"content":"已知未知系数的方程$ f(x)=p(x)^{T}*\\alpha $，以及一系列数据点$(x_{i},y_{i})$，其中$p(x)$是基函数，$\\alpha$是系数向量，求解该方程的系数向量，使得损失函数$J=\\sum_{i=0}^{n} (f(x_{i})-y_{i})^2$值最小。联立所有方程，一般是一个超定方程组（等式个数大于未知数），一般可以表示为$Ax=b$形式，这里的$x$是指待求系数。 以方程$f(x)=a+bx+cx^{2}$为例，可以表示成如下形式： $$ \\begin{bmatrix} 1 \u0026amp; x_{1} \u0026amp; x_{1}^{2}\\ 1 \u0026amp; x_{2} \u0026amp; x_{2}^{2}\\ \u0026hellip; \u0026amp; \u0026hellip; \u0026amp; \u0026hellip;\\ 1 \u0026amp; x_{n} \u0026amp; x_{n}^{2} \\end{bmatrix} * \\begin{bmatrix} a\\ b\\ c \\end{bmatrix} \\begin{bmatrix} y_{1}\\ y_{2}\\ \u0026hellip;\\ y_{n} \\end{bmatrix} $$\n求解上述问题，可以有两种思路，一种是从投影的角度，另一种是对损失函数求偏导数令其等于0。结果都是$x=(A^{T}A)^{-1}A^{T}b$，用法线方程法公式计算有个前提就是式中有个逆矩阵，必须保证可逆，否则得用别的方法求解。 上述方法解出来的解误差分布不一定理想，可以通过计算$Cond(A^TA)$条件数判断方程是否是病态的，必要时可以考虑QR分解等解法。 如果方程自变量个数不止一个，或者方程形式较复杂，一般都是通过化简和变量组合向上面的线性形式凑齐然后求解。 至于为什么损失函数是平方和，需要从概率论角度解释，大概意思是残差满足正态分布的最大似然估计就是最小二乘形式。 移动最小二乘法MLS (Moving Least Square) MLS的拟合方程：$f(x)=p(x)^{T}\\alpha(x)$，其中$p(x)$是基函数列向量，$\\alpha(x)$不再是常数，而是基于$x$的函数。常见的基函数有线性基：$[1,x]^T$，二次基：$[1,x,x^2]^T$，三次基：$[1,x,x^2，x^3]^T$，而$\\alpha(x)$是我们欲求的未知函数。 另外MLS引入了紧支概念：即某点处的函数值只受附近点的影响，或者说每个数据点只对自己影响区域内的拟合结果有影响，由此引入权函数$w(x)$，此时损失函数为$J=\\sum_{i=0}^{n} w(x-x_i)(f(x_{i})-y_{i})^2=\\sum_{i=0}^{n} w(x-x_i)(p(x)^{T}\\alpha(x)-y_{i})^2$。 比如三次样条函数权函数如下： $$ \\begin{array}{c} s=\\frac{|x-x_i|}{r}\\ w(s)=\\left{\\begin{matrix} \\frac{2}{3}-4s^2+4s^3, \u0026amp;s\\le 0.5 \\ \\frac{4}{3}-4s+4s^2-\\frac{4s^2}{3}, \u0026amp;0.5\u0026lt;s\\le1\\ 0,\u0026amp; s\u0026gt;1 \\end{matrix}\\right. \\end{array} $$ 其中$r$表示影响范围半径。 对损失函数求偏导等于0可得$\\alpha(x)$： $$ \\begin{align} \\frac{\\partial J}{\\partial \\alpha(x)} \u0026amp;= A(x)\\alpha(x)-B(x)y = 0 \\ \\alpha(x) \u0026amp;= A^{-1}(x)B(x)y \\ \u0026amp; 其中: \\ w_i(x) \u0026amp;= w(\\frac{|x-x_i|}{r})\\ P \u0026amp;= \\begin{bmatrix} p_1(x_1)\u0026amp; p_2(x_1)\u0026amp; \u0026hellip;\u0026amp; p_m(x_1)\\ p_1(x_2)\u0026amp; p_2(x_2)\u0026amp; \u0026hellip;\u0026amp; p_m(x_2)\\ \u0026hellip;\u0026amp; \u0026hellip;\u0026amp; \u0026hellip;\u0026amp; \u0026hellip;\\ p_1(x_n)\u0026amp; p_2(x_n)\u0026amp; \u0026hellip;\u0026amp; p_m(x_n) \\end{bmatrix}\\ w(x) \u0026amp;= \\begin{bmatrix} w_1(x) \u0026amp; 0\u0026amp; \u0026hellip;\u0026amp; 0\\ 0\u0026amp; w_2(x)\u0026amp; \u0026hellip;\u0026amp; 0\\ \u0026hellip;\u0026amp; \u0026hellip;\u0026amp; \u0026hellip;\u0026amp; \u0026hellip;\\ 0\u0026amp; 0\u0026amp; \u0026hellip;\u0026amp; w_n(x) \\end{bmatrix}\\ A(x) \u0026amp;= P^TW(x)P \\ B(x) \u0026amp;= P^TW(x) \\ \\end{align} $$\n权函数$w(s)$应该是非负的，并伴随着$||x-x_i||_2$增大而减小。 实际应用过程中，取不同基函数可以获得不同的拟合精度，取不同的权函数可以获得不同的平滑度。 一般基函数次数越高，曲线越平滑；影响半径越大，曲线越平滑。 影响半径不能太小，太小的话局部点数不够会造成奇异矩阵不可解。 参考 最小二乘： https://zhuanlan.zhihu.com/p/38128785 https://www.zhihu.com/question/37031188/answer/2041682439 https://ww2.mathworks.cn/help/matlab/ref/lsqr.html 移动最小二乘： https://wenku.baidu.com/view/fe7a74976f1aff00bed51eb1.html https://www.doc88.com/p-8778611828185.html https://www.freesion.com/article/7962225749/ https://www.freesion.com/article/991733680/ https://www.doc88.com/p-8778611828185.html https://d.wanfangdata.com.cn/periodical/szjsyyy201510082\n","date":"2021-10-14T10:59:00Z","permalink":"https://kizx.github.io/post/%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95%E5%92%8C%E7%A7%BB%E5%8A%A8%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%B3%95/","title":"最小二乘法和移动最小二乘法"},{"content":"首先会判断两者类型，相同直接比较是否全等，类型不相同的话，就会进行类型转换，按以下规则：\n布尔-\u0026gt;数值 字符+数值-\u0026gt;数值 对象-\u0026gt;valueof null==undefined 遇到NaN直接不等 全等===不全等!== 类型不相同时不会转换类型，直接返回false\nnull===undefined //true Object.is() 除了特殊情况一般和===相同\nObject.is(NaN,NaN) //true Object.is(0,-0) //false 转为数值 null-\u0026gt;0 undefined-\u0026gt;NaN true-\u0026gt;1 false-\u0026gt;0 数字字符串-\u0026gt;数字 字符串包含非数字-\u0026gt;NaN \u0026ldquo;\u0026rdquo;-\u0026gt;0 Symbol-\u0026gt;报错 对象-\u0026gt;valueOf()??toString() []-\u0026gt;0 [1]-\u0026gt;1 [1,1]-\u0026gt;NaN {}-\u0026gt;NaN 转为布尔 记住以下false假值：\nundefined null +0、-0 NaN 转为字符串 null-\u0026gt;\u0026ldquo;null\u0026rdquo; undefined-\u0026gt;\u0026ldquo;undefined\u0026rdquo; true-\u0026gt;\u0026ldquo;true\u0026rdquo;、false-\u0026gt;\u0026ldquo;false\u0026rdquo; 数值-\u0026gt;\u0026ldquo;数值\u0026rdquo; 对象-\u0026gt;toString()方法，该方法会被重写，未重写Object.prototype.toString-\u0026gt;\u0026quot;[object 具体类型]\u0026quot; Symbol-\u0026gt;只能强制转换，隐式转换报错 加法 数值+数值：\nNaN+*=NaN Infinity+-Infinity=NaN -Infinity+-Infinity=-Infinity -0+-0=-0 0+-0=0 只要有一个操作数是字符串，则转换为字符串进行拼接 []+{}=\u0026quot;[object Object]\u0026quot; {}+[]=0 减法 NaN-*=NaN Infinity-Infinity=NaN -Infinity\u0026ndash;Infinity=NaN 操作数是字符串、布尔、null、undefined-\u0026gt;数值 对象-\u0026gt;valueOf()??toString() \u0026gt;和\u0026lt; 字符串比较-\u0026gt;逐个比较字母编码 有一个是数值-\u0026gt;将另一个转为数值 对象-》valueof().toString() 布尔-\u0026gt;数值 NaN-\u0026gt;返回false valueOf()、toString() [1,\u0026lsquo;a\u0026rsquo;].valueOf() -\u0026gt; [1,\u0026lsquo;a\u0026rsquo;] [1,\u0026lsquo;a\u0026rsquo;].toString() -\u0026gt; \u0026lsquo;1,a\u0026rsquo; {}.valueOf() -\u0026gt; {} {}.toString() -\u0026gt; \u0026lsquo;[Object Object]\u0026rsquo; arguments 在严格模式或使用...args的的情况下arguments不再追踪参数的变化。\n","date":"2021-08-27T15:04:00Z","permalink":"https://kizx.github.io/post/js%E7%B1%BB%E5%9E%8B%E8%BD%AC%E6%8D%A2/","title":"JS类型转换"},{"content":"将创建对象的具体逻辑封装在?个函数中，创建后返回这个对象，那么这个函数就可以被视为?个??。\n// 简单??模式：只需要?个正确的参数，就可以获取到你所需要的对象，?于?成实例 // 比如对象工厂，函数工厂 function Animal(opts) { var obj = new Object(); obj.color = opts.color; obj.name = opts.name; obj.getInfo = function () { return \u0026#34;名称：\u0026#34; + obj.name + \u0026#34;， 颜?：\u0026#34; + obj.color; }; return obj; } var cat = Animal({ name: \u0026#34;波斯猫\u0026#34;, color: \u0026#34;??\u0026#34; }); // ???法模式：本意是将实际创建对象的?作推迟到?类中，这样核?类就变成了抽象类， // ???法只是?个实例化对象的??，只做实例化对象这?件事情，?于?成实例 class User { constructor(name = \u0026#34;\u0026#34;, viewPage = []) { if (new.target === User) { throw new Error(\u0026#34;抽象类不能实例化!\u0026#34;); } this.name = name; this.viewPage = viewPage; } } class UserFactory extends User { constructor(name, viewPage) { super(name, viewPage); // 调??类的constructor(name, viewPage)，继承?类的this对象 } } // let user = new User(); // 不允许直接实例化 let userFactory = new UserFactory(); //抽象??模式：并不直接?成实例，?是?于对产品类簇的创建 function getAbstractUserFactory(type) { switch (type) { case \u0026#34;wechat\u0026#34;: return UserOfWechat; break; case \u0026#34;qq\u0026#34;: return UserOfQq; break; case \u0026#34;weibo\u0026#34;: return UserOfWeibo; break; default: throw new Error(\u0026#34;参数错误, 可选参数:wechat、qq、weibo\u0026#34;); } } let WechatUserClass = getAbstractUserFactory(\u0026#34;wechat\u0026#34;); let QqUserClass = getAbstractUserFactory(\u0026#34;qq\u0026#34;); let WeiboUserClass = getAbstractUserFactory(\u0026#34;weibo\u0026#34;); let wechatUser = new WechatUserClass(\u0026#34;微信?李\u0026#34;); let qqUser = new QqUserClass(\u0026#34;QQ?李\u0026#34;); let weiboUser = new WeiboUserClass(\u0026#34;微博?李\u0026#34;); 单例模式 保证?个类仅有?个实例，并提供?个访问它的全局访问点。\nclass Singleton { static getInstance = (function () { let instance; return function () { if (!instance) { instance = new Singleton(...arguments); } return instance; }; })(); constructor(name) { this.name = name; } } let s1 = Singleton.getInstance(\u0026#34;lisi\u0026#34;); console.log(s1.name); //lisi let s2 = Singleton.getInstance(\u0026#34;san\u0026#34;); console.log(s1.name); //lisi console.log(s1 === s2); // true 观察者模式 定义了对象间?对多的依赖关系，当?标对象的状态发?改变时，所有依赖它的对象都会得到通知。\n// ?标者类 class Subject { constructor() { this.observers = []; // 观察者列表 } // 添加 add(observer) { this.observers.push(observer); } // 删除 remove(observer) { let idx = this.observers.findIndex((item) =\u0026gt; item === observer); idx \u0026gt; -1 \u0026amp;\u0026amp; this.observers.splice(idx, 1); } // 通知 notify() { for (let observer of this.observers) { observer.update(); } } } // 观察者类 class Observer { constructor(name) { this.name = name; } // ?标对象更新时触发的回调 update() { console.log(`?标者通知我更新了，我是：${this.name}`); } } // 实例化?标者 let subject = new Subject(); // 实例化两个观察者 let obs1 = new Observer(\u0026#34;前端开发者\u0026#34;); let obs2 = new Observer(\u0026#34;后端开发者\u0026#34;); // 向?标者添加观察者 subject.add(obs1); subject.add(obs2); // ?标者通知更新 subject.notify(); // 输出： // ?标者通知我更新了，我是前端开发者 // ?标者通知我更新了，我是后端开发者 发布订阅模式 实现了对象间多对多的依赖关系，通过事件中?管理多个事件。?标对象并不直接通知观察者，?是通过事件中?来派发通知。\n// 事件中? let pubSub = { list: {}, // {onwork:[fn1,fn2],offwork:[fn1,fn2],launch:[fn1,fn2]} subscribe: function (key, fn) { // 订阅 if (!this.list[key]) { this.list[key] = []; } this.list[key].push(fn); }, publish: function (key, ...arg) { // 发布 for (let fn of this.list[key]) { fn.call(this, ...arg); } }, unSubscribe: function (key, fn) { // 取消订阅 let fnList = this.list[key]; if (!fnList) return false; if (!fn) { // 不传?指定取消的订阅?法，则清空所有key下的订阅 fnList \u0026amp;\u0026amp; (fnList.length = 0); } else { fnList.forEach((item, index) =\u0026gt; { if (item === fn) { fnList.splice(index, 1); } }); } }, }; // 订阅 pubSub.subscribe(\u0026#34;onwork\u0026#34;, (time) =\u0026gt; { console.log(`上班了：${time}`); }); pubSub.subscribe(\u0026#34;offwork\u0026#34;, (time) =\u0026gt; { console.log(`下班了：${time}`); }); pubSub.subscribe(\u0026#34;launch\u0026#34;, (time) =\u0026gt; { console.log(`吃饭了：${time}`); }); // 发布 pubSub.publish(\u0026#34;onwork\u0026#34;, \u0026#34;9:00:00\u0026#34;); pubSub.publish(\u0026#34;offwork\u0026#34;, \u0026#34;18:00:00\u0026#34;); pubSub.publish(\u0026#34;launch\u0026#34;, \u0026#34;12:00:00\u0026#34;); // 取消订阅 pubSub.unSubscribe(\u0026#34;onwork\u0026#34;); pubSub.publish(\u0026#34;onwork\u0026#34;, \u0026#34;9:00:00\u0026#34;); 适配器模式 适配器?来解决两个接?不兼容的情况，不需要改变已有的接?，通过包装?层的?式实现两个接?的正常协作。\n// 已有的地图接? var googleMap = { show: function () { console.log(\u0026#34;开始渲染?歌地图\u0026#34;); }, }; var baiduMap = { display: function () { console.log(\u0026#34;开始渲染百度地图\u0026#34;); }, }; // 已有的渲染接? var renderMap = function (map) { if (map.show instanceof Function) { map.show(); } }; // 适配器 var baiduMapAdapter = { show: function () { return baiduMap.display(); }, }; renderMap(googleMap); // 开始渲染?歌地图 renderMap(baiduMapAdapter); // 开始渲染百度地图 代理模式 不直接引?另?个对象，通过代理对象间接引用，起到中介的作?。\nvar obj = {}; var proxy = new Proxy(obj, { get: function (target, key, receiver) { console.log(`getting ${key}!`); return Reflect.get(target, key, receiver); }, set: function (target, key, value, receiver) { console.log(`setting ${key}=${value}!`); return Reflect.set(target, key, value, receiver); }, }); proxy.count = 1; proxy.count; 装饰模式 不改变已有的函数，给函数添加额外的功能，?如ES7中的装饰器。\n参考 https://refactoringguru.cn/design-patterns/catalog\n","date":"2021-08-23T13:44:00Z","permalink":"https://kizx.github.io/post/js%E5%B8%B8%E8%A7%81%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/","title":"JS常见设计模式"},{"content":"后盾人 CS-Note\n算法 代码随想录\n知识点 Cookies,Session和Token TCP 三次握手源码 TCP握手挥手 Service Worker HTTPS 加密、证书、签名与握手 4种常见的内存泄露 JS模块化 简单了解二叉树diff算法 如何实现一个 Virtual DOM 算法 js 异步历史与 co.js 解读\n面试相关 vue2,vue3面试汇总 前端面试资源 计算机网络面试真题 前端面试宝典 前端面试小本本\n博客 https://78.al/ https://jerryzou.com/posts/rxjs-practice-01/ 前端面试题 阮一峰的网络日志\n","date":"2021-07-13T07:55:00Z","permalink":"https://kizx.github.io/post/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99/","title":"学习资料"},{"content":"# -*- coding: utf8 -*- from urllib import parse def get_url(type=\u0026#39;pivix\u0026#39;): pass def main_handler(event, context): if event[\u0026#39;httpMethod\u0026#39;] == \u0026#39;GET\u0026#39;: if \u0026#39;type\u0026#39; in event[\u0026#39;queryString\u0026#39;]: imgtype = event[\u0026#39;queryString\u0026#39;][\u0026#39;type\u0026#39;] url = get_url(imgtype) else: url = get_url() if url: return {\u0026#39;code\u0026#39;: 0, \u0026#39;url\u0026#39;: url, \u0026#39;msg\u0026#39;: \u0026#34;成功\u0026#34;} else: return {\u0026#39;code\u0026#39;: 1, \u0026#39;msg\u0026#39;: \u0026#34;失败\u0026#34;} if event[\u0026#39;httpMethod\u0026#39;] == \u0026#39;POST\u0026#39;: body = parse.parse_qs(event[\u0026#39;body\u0026#39;]) print(body) if \u0026#39;type\u0026#39; in body: imgtype = body[\u0026#39;type\u0026#39;][0] url = get_url(imgtype) else: url = get_url() if url: return {\u0026#39;code\u0026#39;: 0, \u0026#39;url\u0026#39;: url, \u0026#39;msg\u0026#39;: \u0026#34;成功\u0026#34;} else: return {\u0026#39;code\u0026#39;: 1, \u0026#39;msg\u0026#39;: \u0026#34;失败\u0026#34;} 阿里云 # -*- coding: utf-8 -*- import logging import json from urllib import parse # To enable the initializer feature (https://help.aliyun.com/document_detail/158208.html) # please implement the initializer function as below： # def initializer(context): # logger = logging.getLogger() # logger.info(\u0026#39;initializing\u0026#39;) def handler(environ, start_response): context = environ[\u0026#39;fc.context\u0026#39;] request_uri = environ[\u0026#39;fc.request_uri\u0026#39;] for k, v in environ.items(): if k.startswith(\u0026#39;HTTP_\u0026#39;): # process custom request headers pass # do something here try: request_body_size = int(environ.get(\u0026#39;CONTENT_LENGTH\u0026#39;, 0)) except (ValueError): request_body_size = 0 request_body = environ[\u0026#39;wsgi.input\u0026#39;].read(request_body_size).decode(encoding=\u0026#34;utf-8\u0026#34;) body = parse.parse_qs(request_body) for i in body: body[i] = body[i][0] status = \u0026#39;200 OK\u0026#39; response_headers = [(\u0026#39;Content-type\u0026#39;, \u0026#39;application/json\u0026#39;)] start_response(status, response_headers) return [json.dumps(body).encode(encoding=\u0026#34;utf-8\u0026#34;)] ","date":"2021-06-13T14:03:32Z","permalink":"https://kizx.github.io/post/%E8%85%BE%E8%AE%AF%E4%BA%91%E5%87%BD%E6%95%B0%E9%98%BF%E9%87%8C%E4%BA%91%E5%87%BD%E6%95%B0python%E5%88%9B%E5%BB%BAhttp%E5%87%BD%E6%95%B0%E7%A4%BA%E4%BE%8B/","title":"腾讯云函数、阿里云函数Python创建HTTP函数示例"},{"content":"https://www.tslang.cn/docs/home.html\n变量 // 布尔 let isDone: boolean = false; // 数字 let decLiteral: number = 6; let hexLiteral: number = 0xf00d; let binaryLiteral: number = 0b1010; let octalLiteral: number = 0o744; // 字符串 let fname: string = \u0026#34;bob\u0026#34;; let sentence: string = `Hello, my name is ${fname}.`; // 数组 let list1: number[] = [1, 2, 3]; let list2: Array\u0026lt;number\u0026gt; = [1, 2, 3]; // 元组 let x: [string, number]; x = [\u0026#34;hello\u0026#34;, 10]; // OK // x = [10, \u0026#34;hello\u0026#34;]; // Error // 枚举 enum Color { Red, Green, Blue, } let c: Color = Color.Green; console.log(c); //1 let colorName: string = Color[2]; console.log(colorName); //Blue // Any let notSure: any = 4; notSure = \u0026#34;maybe a string instead\u0026#34;; notSure = false; // ok let list: any[] = [1, true, \u0026#34;free\u0026#34;]; list[1] = 100; let some; //声明时未指定类型时默认any some = 1; some = \u0026#34;a\u0026#34;; // void function warnUser(): void { console.log(\u0026#34;This is my warning message\u0026#34;); } // undefined null 可以赋给其他类型变量 let u: undefined = undefined; let n: null = null; // never function error(message: string): never { throw new Error(message); } function infiniteLoop(): never { while (true) {} } // Object let o: object = {}; // 类型断言 规避类型检查 let someValue: any = \u0026#34;this is a string\u0026#34;; let strLength1: number = (\u0026lt;string\u0026gt;someValue).length; let strLength: number = (someValue as string).length; // 类型推断 let somea = 1; //类型自动推断为number // somea = \u0026#34;1\u0026#34;; //报错 //联合类型 let star: string | number = \u0026#34;1\u0026#34;; star = 1; // 别名 type mytype = string | number; type Eventname = \u0026#34;Click\u0026#34; | \u0026#34;scroll\u0026#34;; 接口 // 对象接口 interface person { name: string; age: number; readonly gender: string; //只读属性 like?: string; //可选属性 [propName: string]: any; //任意属性 } // 索引 interface numberArr { [index: number]: number; } // 函数接口 interface SearchFunc { (source: string, subString: string): boolean; } let mySearch: SearchFunc; mySearch = function (src, sub) { let result = src.search(sub); return result \u0026gt; -1; }; // 类接口 interface ClockInterface { currentTime: Date; setTime(d: Date): void; } class Clock implements ClockInterface { currentTime: Date; setTime(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { this.currentTime = new Date(); } } // 接口继承 interface Shape { color: string; } interface PenStroke { penWidth: number; } interface Square extends Shape, PenStroke { sideLength: number; } let square = \u0026lt;Square\u0026gt;{}; square.color = \u0026#34;blue\u0026#34;; square.sideLength = 10; square.penWidth = 5.0; 面向对象 class Animal { // 继承类可以访问 protected name: string; // 构造函数里可以使用 public name 来简写 constructor(name: string) { this.name = name; } move(distanceInMeters: number = 0) { console.log(`Animal moved ${distanceInMeters}m.`); } static isAnimal(animal: object): boolean { return animal instanceof Animal; } } //继承 class Dog extends Animal { // 私有属性，只读 private readonly color: string = \u0026#34;blackack\u0026#34;; constructor(name: string) { super(name); } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } bark() { console.log(`${this.color} ${this.name}: Woof! Woof!`); } } const dog = new Dog(\u0026#34;dog\u0026#34;); dog.move(10); dog.bark(); console.log(Animal.isAnimal(dog)); //抽象类 abstract class absAnimal { abstract makeSound(): void; // 必须在派生类中实现 move(): void { console.log(\u0026#34;roaming the earch...\u0026#34;); } } 函数 //可选参数 function buildName1(firstName: string, lastName?: string) { if (lastName) return firstName + \u0026#34; \u0026#34; + lastName; else return firstName; } //默认参数 function buildName2(firstName: string, lastName = \u0026#34;Smith\u0026#34;) { if (lastName) return firstName + \u0026#34; \u0026#34; + lastName; else return firstName; } //收集参数 function buildName3(firstName: string, ...restOfName: string[]) { return firstName + \u0026#34; \u0026#34; + restOfName.join(\u0026#34; \u0026#34;); } //函数重载 function getInfo(name: string): void; function getInfo(age: number): void; function getInfo(str: any): void { if (typeof str == \u0026#34;string\u0026#34;) { console.log(\u0026#34;名字:\u0026#34;, str); } if (typeof str == \u0026#34;number\u0026#34;) { console.log(\u0026#34;年龄\u0026#34;, str); } } 泛型 function createArray\u0026lt;T\u0026gt;(value: T, length: number): Array\u0026lt;T\u0026gt; { let result: T[] = []; for (let i = 0; i \u0026lt; length; i++) { result[i] = value; } return result; } let a = createArray([1, 2, 3], 3); class GenericNumber\u0026lt;T\u0026gt; { zeroValue: T; add: (x: T, y: T) =\u0026gt; T; } let myGenericNumber = new GenericNumber\u0026lt;number\u0026gt;(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function (x, y) { return x + y; }; ","date":"2021-06-05T14:09:00Z","permalink":"https://kizx.github.io/post/typescript%E5%9F%BA%E7%A1%80/","title":"TypeScript基础"},{"content":"准备 现要利用阿里云OSS部署一个静态网页，通过本地编译生成静态网页后实现自动上传更新部署。\n首先开通阿里OSS服务，然后新建一个存储桶，权限设为公共可读，地域选择香港，因为国内域名需备案。 去存储桶基础设置-\u0026gt;静态页面设置首页为index.html；然后去传输管理-\u0026gt;绑定域名，最后去DNS设置cname，也可以自行配置CDN加速。 然后去阿里云控制台新建一个RAM访问控制用户，记住accessKeyId和accessKeySecret，然后为该用户添加OSS权限。 本地上传代码 本地安装npm i ali-oss -D，我们要实现将本地dist目录下所有的文件原封不动的上传至OSS上，为了保持OSS文件清洁，上传前最好先清空OSS，最终代码如下。\nconst OSS = require(\u0026#34;ali-oss\u0026#34;); const path = require(\u0026#34;path\u0026#34;); var fs = require(\u0026#34;fs\u0026#34;); const client = new OSS({ region: \u0026#34;oss-cn-hongkong\u0026#34;, accessKeyId: \u0026#34;xxxxxxxxxxxx\u0026#34;, accessKeySecret: \u0026#34;xxxxxxxxxxxx\u0026#34;, bucket: \u0026#34;xxxxxx\u0026#34;, }); async function list() { try { let result = await client.list(); result = result.objects || []; let file_list = result.map(i =\u0026gt; i.name); return file_list; } catch (err) { console.log(err); } } async function deleteMulti(filelist) { try { let result = await client.deleteMulti(filelist, { verbose: true, }); console.log(\u0026#34;deleted:\\n\u0026#34;, result.deleted); } catch (e) { console.log(e); } } async function put(filename) { try { let result = await client.put( filename.slice(5).replace(/\\\\/g, \u0026#34;/\u0026#34;), path.normalize(filename) ); console.log(\u0026#34;upload: \u0026#34;, result.name); } catch (e) { console.log(e); } } function getAllfiles(dir, filelist) { let files = fs.readdirSync(dir); files.forEach(file =\u0026gt; { let filepath = path.join(dir, file); let stat = fs.statSync(filepath); if (stat.isFile()) filelist.push(filepath); if (stat.isDirectory()) { filelist = filelist.concat(getAllfiles(filepath, [])); } }); return filelist; } async function main() { const file_list = await list(); console.log(\u0026#34;quire result:\\n\u0026#34;, file_list); if (file_list.length \u0026gt; 0) { await deleteMulti(file_list); } let files = getAllfiles(\u0026#34;./dist\u0026#34;, []); files.forEach(file =\u0026gt; { put(file); }); } main(); 运行结果 参考 https://help.aliyun.com/document_detail/32068.html?spm=a2c4g.11186623.6.1058.42b92a220SHC2F https://help.aliyun.com/document_detail/39630.html?spm=a2c4g.11186623.6.666.1b263331Q5jiQY\n","date":"2021-05-29T13:44:00Z","permalink":"https://kizx.github.io/post/%E9%98%BF%E9%87%8C%E4%BA%91oss%E8%87%AA%E5%8A%A8%E4%B8%8A%E4%BC%A0%E9%83%A8%E7%BD%B2%E9%9D%99%E6%80%81%E7%BD%91%E7%AB%99/","title":"阿里云OSS自动上传部署静态网站"},{"content":"// 全局安装以便可以命令行调用gulp命令 npm install -g gulp-cli npm init -y npm i gulp -D gulpfile.js 旧task写法 const gulp = require(\u0026#34;gulp\u0026#34;); const imagemin = require(\u0026#34;gulp-imagemin\u0026#34;); const uglify = require(\u0026#34;gulp-uglify\u0026#34;); const sass = require(\u0026#34;gulp-sass\u0026#34;); const concat = require(\u0026#34;gulp-concat\u0026#34;); const { series } = require(\u0026#34;gulp\u0026#34;); // 复制文件 gulp.task(\u0026#34;html\u0026#34;, async function () { gulp.src(\u0026#34;src/*.html\u0026#34;).pipe(gulp.dest(\u0026#34;dist\u0026#34;)); }); // 压缩图片 得用cnpm安装 gulp.task(\u0026#34;img\u0026#34;, async function () { gulp.src(\u0026#34;src/*.{jpg,png,gif}\u0026#34;) .pipe(imagemin()) .pipe(gulp.dest(\u0026#34;dist/imgs\u0026#34;)); }); // 压缩合并js gulp.task(\u0026#34;js\u0026#34;, async function () { gulp.src(\u0026#34;src/*.js\u0026#34;) .pipe(concat(\u0026#34;index.js\u0026#34;)) .pipe(uglify()) .pipe(gulp.dest(\u0026#34;dist/js\u0026#34;)); }); // sass处理 gulp.task(\u0026#34;css\u0026#34;, async function () { gulp.src(\u0026#34;src/*.scss\u0026#34;) .pipe(sass().on(\u0026#34;error\u0026#34;, sass.logError)) .pipe(gulp.dest(\u0026#34;dist/css\u0026#34;)); }); // 监听文件变化 gulp.task(\u0026#34;watch\u0026#34;, function () { gulp.watch(\u0026#34;src/*.js\u0026#34;, series(\u0026#34;js\u0026#34;)); gulp.watch(\u0026#34;src/*.html\u0026#34;, series(\u0026#34;html\u0026#34;)); }); // 组合任务 gulp.task(\u0026#34;default\u0026#34;, series(\u0026#34;html\u0026#34;, \u0026#34;css\u0026#34;, \u0026#34;img\u0026#34;, \u0026#34;js\u0026#34;)); 推荐写法 const imagemin = require(\u0026#34;gulp-imagemin\u0026#34;); const uglify = require(\u0026#34;gulp-uglify\u0026#34;); const sass = require(\u0026#34;gulp-sass\u0026#34;); const concat = require(\u0026#34;gulp-concat\u0026#34;); const babel = require(\u0026#34;gulp-babel\u0026#34;); const gulp = require(\u0026#34;gulp\u0026#34;); const del = require(\u0026#34;del\u0026#34;); // 复制文件 function html() { return gulp.src(\u0026#34;src/*.html\u0026#34;).pipe(gulp.dest(\u0026#34;dist\u0026#34;)); } // 压缩图片 得用cnpm安装 function img() { return gulp .src(\u0026#34;src/*.{jpg,png,gif}\u0026#34;) .pipe(imagemin()) .pipe(gulp.dest(\u0026#34;dist/imgs\u0026#34;)); } // 压缩合并js function js() { return gulp .src(\u0026#34;src/*.js\u0026#34;) .pipe(concat(\u0026#34;index.js\u0026#34;)) .pipe(babel()) .pipe(uglify()) .pipe(gulp.dest(\u0026#34;dist/js\u0026#34;)); } // sass处理 function css() { return gulp .src(\u0026#34;src/*.scss\u0026#34;) .pipe(sass().on(\u0026#34;error\u0026#34;, sass.logError)) .pipe(gulp.dest(\u0026#34;dist/css\u0026#34;)); } // 清空输出 function clean() { return del(\u0026#34;dist/**/*\u0026#34;); } // 监听文件变化 function watch() { gulp.watch(\u0026#34;src/*.js\u0026#34;, gulp.series(js)); gulp.watch(\u0026#34;src/*.html\u0026#34;, gulp.series(html)); } // 组合任务 exports.default = gulp.series(clean, html, css, js); exports.watch = watch; exports.clean = clean; exports.img = img; //测试时这个插件有问题 启动 //编译 gulp //监听 gulp watch 其他 新版sass需要安装npm i -D sass gulp-sass并如下引用 const sass = require(\u0026#39;gulp-sass\u0026#39;)(require(\u0026#39;sass\u0026#39;)); 参考 https://www.gulpjs.com.cn/docs/getting-started/quick-start/\n","date":"2021-05-28T12:30:00Z","permalink":"https://kizx.github.io/post/gulp%E5%85%A5%E9%97%A8/","title":"gulp入门"},{"content":"下面均已 webpack5 为例\nnpm init -y npm install webpack webpack-cli --save-dev 运行命令 可以使用 webpack 初始化命令快速生成一个项目\nnpx webpack-cli init 以下是自动生成的webpack.config.js\n// Generated using webpack-cli https://github.com/webpack/webpack-cli const path = require(\u0026#34;path\u0026#34;); const HtmlWebpackPlugin = require(\u0026#34;html-webpack-plugin\u0026#34;); const MiniCssExtractPlugin = require(\u0026#34;mini-css-extract-plugin\u0026#34;); const isProduction = process.env.NODE_ENV == \u0026#34;production\u0026#34;; const stylesHandler = isProduction ? MiniCssExtractPlugin.loader : \u0026#34;style-loader\u0026#34;; const config = { entry: \u0026#34;./src/index.js\u0026#34;, output: { path: path.resolve(__dirname, \u0026#34;dist\u0026#34;), }, devServer: { open: true, host: \u0026#34;localhost\u0026#34;, }, plugins: [ new HtmlWebpackPlugin({ template: \u0026#34;index.html\u0026#34;, }), // Add your plugins here // Learn more about plugins from https://webpack.js.org/configuration/plugins/ ], module: { rules: [ { test: /\\.(js|jsx)$/i, loader: \u0026#34;babel-loader\u0026#34;, }, { test: /\\.css$/i, use: [stylesHandler, \u0026#34;css-loader\u0026#34;], }, { test: /\\.s[ac]ss$/i, use: [stylesHandler, \u0026#34;css-loader\u0026#34;, \u0026#34;sass-loader\u0026#34;], }, { test: /\\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i, type: \u0026#34;asset\u0026#34;, }, // Add your rules for custom modules here // Learn more about loaders from https://webpack.js.org/loaders/ ], }, }; module.exports = () =\u0026gt; { if (isProduction) { config.mode = \u0026#34;production\u0026#34;; config.plugins.push(new MiniCssExtractPlugin()); } else { config.mode = \u0026#34;development\u0026#34;; } return config; }; 也可以手动新建一个 webpack.config.js 文件手动配置 可以配置 npm run script 命令运行 webpack，也可以手动 npx webpack xxx 运行\n\u0026#34;scripts\u0026#34;: { \u0026#34;test\u0026#34;: \u0026#34;echo \\\u0026#34;Error: no test specified\\\u0026#34; \u0026amp;\u0026amp; exit 1\u0026#34;, \u0026#34;build\u0026#34;: \u0026#34;webpack --mode=production --node-env=production\u0026#34;, \u0026#34;build:dev\u0026#34;: \u0026#34;webpack --mode=development\u0026#34;, \u0026#34;build:prod\u0026#34;: \u0026#34;webpack --mode=production --node-env=production\u0026#34;, \u0026#34;watch\u0026#34;: \u0026#34;webpack --watch\u0026#34;, \u0026#34;serve\u0026#34;: \u0026#34;webpack serve\u0026#34; }, 入口 入口可以是一个文件或多个 js 文件\nmodule.exports = { //... entry: { home: \u0026#34;./home.js\u0026#34;, about: \u0026#34;./about.js\u0026#34;, contact: \u0026#34;./contact.js\u0026#34;, }, }; https://webpack.docschina.org/configuration/entry-context/#entry\n输出 设置输出的文件，设置clean: true输出前先清空输出目录\noutput: { filename: \u0026#34;[name].[contenthash].js\u0026#34;, path: path.resolve(__dirname, \u0026#34;dist\u0026#34;), clean: true, }, 可以用多种方式设置输出文件的名称 https://webpack.docschina.org/configuration/output/#outputfilename\n加载 html 模板 使用html-webpack-plugin插件\nconst HtmlWebpackPlugin = require(\u0026#34;html-webpack-plugin\u0026#34;); plugins: [ new HtmlWebpackPlugin({ template: \u0026#34;./src/index.html\u0026#34;, filename: \u0026#34;index.html\u0026#34;, }), ]; 加载 CSS 需要先 npm 安装相应包，sass-loader将 sass 文件转换为 css 文件，css-loader加载 css 文件，style-loader将 css 文件通过 js 的方式将 css 加载到页面中。\nmodule: { rules: [ { test: /\\.s[ac]ss$/i, use: [\u0026#34;style-loader\u0026#34;, \u0026#34;css-loader\u0026#34;, \u0026#34;sass-loader\u0026#34;], }, ], }, 如果要分离 css 文件，可以使用MiniCssExtractPlugin，会自动 link 到 HtmlWebpackPlugin 中\nconst HtmlWebpackPlugin = require(\u0026#34;html-webpack-plugin\u0026#34;); const MiniCssExtractPlugin = require(\u0026#34;mini-css-extract-plugin\u0026#34;); //... { test: /\\.s[ac]ss$/i, use: [MiniCssExtractPlugin.loader, \u0026#34;css-loader\u0026#34;, \u0026#34;sass-loader\u0026#34;], }, //... plugins: [ new HtmlWebpackPlugin({ template: \u0026#34;./src/index.html\u0026#34;, filename: \u0026#34;index.html\u0026#34;, }), new MiniCssExtractPlugin({ filename: \u0026#34;style.min.css\u0026#34;, }), ], 加载静态文件 webpack5 使用asset-modules模块来管理静态文件 https://webpack.docschina.org/guides/asset-modules/\n环境分离 使用webpack-merge模块实现生产开发环境分开设置 https://webpack.docschina.org/guides/production/\n开发环境设置 设置 devtool 使用 source map https://webpack.docschina.org/configuration/devtool/ 设置热更新\ndevServer: { contentBase: \u0026#34;./dist\u0026#34;, hot: true, }, 参考 https://webpack.docschina.org/guides/getting-started/ https://www.lookroot.cn/course/webpack/ https://szxio.gitee.io/hexoblog/Tool/webpack/\n","date":"2021-05-27T10:25:00Z","permalink":"https://kizx.github.io/post/webpack5%E5%9F%BA%E7%A1%80/","title":"webpack5基础"},{"content":"复现了大佬的操作，这里总结一下。 大佬源文章：https://nocilol.me/archives/lab/add-dynamic-poster-girl-with-live2d-to-your-blog-02/\n步骤 下载live2d.js：https://github.com/journey-ad/live2d_src/releases 新建waifu-tips.js function render(template, context) { var tokenReg = /(\\\\)?\\{([^\\{\\}\\\\]+)(\\\\)?\\}/g; return template.replace(tokenReg, function (word, slash1, token, slash2) { if (slash1 || slash2) { return word.replace(\u0026#34;\\\\\u0026#34;, \u0026#34;\u0026#34;); } var variables = token.replace(/\\s/g, \u0026#34;\u0026#34;).split(\u0026#34;.\u0026#34;); var currentObject = context; var i, length, variable; for (i = 0, length = variables.length; i \u0026lt; length; ++i) { variable = variables[i]; currentObject = currentObject[variable]; if (currentObject === undefined || currentObject === null) return \u0026#34;\u0026#34;; } return currentObject; }); } String.prototype.render = function (context) { return render(this, context); }; var re = /x/; console.log(re); re.toString = function () { showMessage(\u0026#34;哈哈，你打开了控制台，是想要看看我的秘密吗？\u0026#34;, 5000); return \u0026#34;\u0026#34;; }; $(document).on(\u0026#34;copy\u0026#34;, function () { showMessage(\u0026#34;你都复制了些什么呀，转载要记得加上出处哦\u0026#34;, 5000); }); $.ajax({ cache: true, url: \u0026#34;path/to/waifu-tips.json\u0026#34;, dataType: \u0026#34;json\u0026#34;, success: function (result) { $.each(result.mouseover, function (index, tips) { $(document).on(\u0026#34;mouseover\u0026#34;, tips.selector, function () { var text = tips.text; if (Array.isArray(tips.text)) text = tips.text[ Math.floor(Math.random() * tips.text.length + 1) - 1 ]; text = text.render({ text: $(this).text() }); showMessage(text, 3000); }); }); $.each(result.click, function (index, tips) { $(document).on(\u0026#34;click\u0026#34;, tips.selector, function () { var text = tips.text; if (Array.isArray(tips.text)) text = tips.text[ Math.floor(Math.random() * tips.text.length + 1) - 1 ]; text = text.render({ text: $(this).text() }); showMessage(text, 3000); }); }); }, }); (function () { var text; if (document.referrer !== \u0026#34;\u0026#34;) { var referrer = document.createElement(\u0026#34;a\u0026#34;); referrer.href = document.referrer; text = \u0026#39;Hello! 来自 \u0026lt;span style=\u0026#34;color:#0099cc;\u0026#34;\u0026gt;\u0026#39; + referrer.hostname + \u0026#34;\u0026lt;/span\u0026gt; 的朋友\u0026#34;; var domain = referrer.hostname.split(\u0026#34;.\u0026#34;)[1]; if (domain == \u0026#34;baidu\u0026#34;) { text = \u0026#39;Hello! 来自 百度搜索 的朋友\u0026lt;br\u0026gt;你是搜索 \u0026lt;span style=\u0026#34;color:#0099cc;\u0026#34;\u0026gt;\u0026#39; + referrer.search.split(\u0026#34;\u0026amp;wd=\u0026#34;)[1].split(\u0026#34;\u0026amp;\u0026#34;)[0] + \u0026#34;\u0026lt;/span\u0026gt; 找到的我吗？\u0026#34;; } else if (domain == \u0026#34;so\u0026#34;) { text = \u0026#39;Hello! 来自 360搜索 的朋友\u0026lt;br\u0026gt;你是搜索 \u0026lt;span style=\u0026#34;color:#0099cc;\u0026#34;\u0026gt;\u0026#39; + referrer.search.split(\u0026#34;\u0026amp;q=\u0026#34;)[1].split(\u0026#34;\u0026amp;\u0026#34;)[0] + \u0026#34;\u0026lt;/span\u0026gt; 找到的我吗？\u0026#34;; } else if (domain == \u0026#34;google\u0026#34;) { text = \u0026#39;Hello! 来自 谷歌搜索 的朋友\u0026lt;br\u0026gt;欢迎阅读\u0026lt;span style=\u0026#34;color:#0099cc;\u0026#34;\u0026gt;『\u0026#39; + document.title.split(\u0026#34; - \u0026#34;)[0] + \u0026#34;』\u0026lt;/span\u0026gt;\u0026#34;; } } else { if (window.location.href == \u0026#34;https://imjad.cn/\u0026#34;) { //如果是主页 var now = new Date().getHours(); if (now \u0026gt; 23 || now \u0026lt;= 5) { text = \u0026#34;你是夜猫子呀？这么晚还不睡觉，明天起的来嘛\u0026#34;; } else if (now \u0026gt; 5 \u0026amp;\u0026amp; now \u0026lt;= 7) { text = \u0026#34;早上好！一日之计在于晨，美好的一天就要开始了\u0026#34;; } else if (now \u0026gt; 7 \u0026amp;\u0026amp; now \u0026lt;= 11) { text = \u0026#34;上午好！工作顺利嘛，不要久坐，多起来走动走动哦！\u0026#34;; } else if (now \u0026gt; 11 \u0026amp;\u0026amp; now \u0026lt;= 14) { text = \u0026#34;中午了，工作了一个上午，现在是午餐时间！\u0026#34;; } else if (now \u0026gt; 14 \u0026amp;\u0026amp; now \u0026lt;= 17) { text = \u0026#34;午后很容易犯困呢，今天的运动目标完成了吗？\u0026#34;; } else if (now \u0026gt; 17 \u0026amp;\u0026amp; now \u0026lt;= 19) { text = \u0026#34;傍晚了！窗外夕阳的景色很美丽呢，最美不过夕阳红~\u0026#34;; } else if (now \u0026gt; 19 \u0026amp;\u0026amp; now \u0026lt;= 21) { text = \u0026#34;晚上好，今天过得怎么样？\u0026#34;; } else if (now \u0026gt; 21 \u0026amp;\u0026amp; now \u0026lt;= 23) { text = \u0026#34;已经这么晚了呀，早点休息吧，晚安~\u0026#34;; } else { text = \u0026#34;嗨~ 快来逗我玩吧！\u0026#34;; } } else { text = \u0026#39;欢迎阅读\u0026lt;span style=\u0026#34;color:#0099cc;\u0026#34;\u0026gt;『\u0026#39; + document.title.split(\u0026#34; - \u0026#34;)[0] + \u0026#34;』\u0026lt;/span\u0026gt;\u0026#34;; } } showMessage(text, 6000); })(); window.setInterval(showHitokoto, 30000); function showHitokoto() { $.getJSON( \u0026#34;https://api.imjad.cn/hitokoto/?cat=\u0026amp;charset=utf-8\u0026amp;length=28\u0026amp;encode=json\u0026#34;, function (result) { showMessage(result.hitokoto, 5000); } ); } function showMessage(text, timeout) { if (Array.isArray(text)) text = text[Math.floor(Math.random() * text.length + 1) - 1]; console.log(text); $(\u0026#34;.waifu-tips\u0026#34;).stop(); $(\u0026#34;.waifu-tips\u0026#34;).html(text).fadeTo(200, 1); if (timeout === null) timeout = 5000; hideMessage(timeout); } function hideMessage(timeout) { $(\u0026#34;.waifu-tips\u0026#34;).stop().css(\u0026#34;opacity\u0026#34;, 1); if (timeout === null) timeout = 5000; $(\u0026#34;.waifu-tips\u0026#34;).delay(timeout).fadeTo(200, 0); } 新建waifu-tips.json，可以设置看板娘交互文字 { \u0026#34;mouseover\u0026#34;: [ { \u0026#34;selector\u0026#34;: \u0026#34;.container a[href^=\u0026#39;http\u0026#39;]\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;要看看 \u0026lt;span style=\\\u0026#34;color:#0099cc;\\\u0026#34;\u0026gt;{text}\u0026lt;/span\u0026gt; 么？\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.fui-home\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;点击前往首页，想回到上一页可以使用浏览器的后退功能哦\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#tor_show\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;翻页比较麻烦吗，点击可以显示这篇文章的目录呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#comment_go,.fui-chat\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;想要去评论些什么吗？\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#night_mode\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;深夜时要爱护眼睛呀\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#qrcode\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;手机扫一下就能继续看，很方便呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.comment_reply\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;要吐槽些什么呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#back-to-top\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;回到开始的地方吧\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#author\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;该怎么称呼你呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#mail\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;留下你的邮箱，不然就是无头像人士了\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#url\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;你的家在哪里呢，好让我去参观参观\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#textarea\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;认真填写哦，垃圾评论是禁止事项\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.OwO-logo\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;要插入一个表情吗\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;#csubmit\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;要提交了吗，首次评论需要审核，请耐心等待~\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.ImageBox\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;点击图片可以放大呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;input[name=s]\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;找不到想看的内容？搜索看看吧\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.previous\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;去上一页看看吧\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.next\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;去下一页看看吧\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.dropdown-toggle\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;这里是菜单\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;c-player a.play-icon\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;想要听点音乐吗\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;c-player div.time\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;在这里可以调整\u0026lt;span style=\\\u0026#34;color:#0099cc;\\\u0026#34;\u0026gt;播放进度\u0026lt;/span\u0026gt;呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;c-player div.volume\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;在这里可以调整\u0026lt;span style=\\\u0026#34;color:#0099cc;\\\u0026#34;\u0026gt;音量\u0026lt;/span\u0026gt;呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;c-player div.list-button\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;\u0026lt;span style=\\\u0026#34;color:#0099cc;\\\u0026#34;\u0026gt;播放列表\u0026lt;/span\u0026gt;里都有什么呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;c-player div.lyric-button\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;有\u0026lt;span style=\\\u0026#34;color:#0099cc;\\\u0026#34;\u0026gt;歌词\u0026lt;/span\u0026gt;的话就能跟着一起唱呢\u0026#34;] }, { \u0026#34;selector\u0026#34;: \u0026#34;.waifu #live2d\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;干嘛呢你，快把手拿开\u0026#34;, \u0026#34;鼠…鼠标放错地方了！\u0026#34;] } ], \u0026#34;click\u0026#34;: [ { \u0026#34;selector\u0026#34;: \u0026#34;.waifu #live2d\u0026#34;, \u0026#34;text\u0026#34;: [\u0026#34;是…是不小心碰到了吧\u0026#34;, \u0026#34;萝莉控是什么呀\u0026#34;, \u0026#34;你看到我的小熊了吗\u0026#34;, \u0026#34;再摸的话我可要报警了！?●﹏●?\u0026#34;, \u0026#34;110吗，这里有个变态一直在摸我(ó﹏ò?)\u0026#34;] } ] } 新建style.css .waifu { position: fixed; bottom: 0; left: 0; z-index: 1; font-size: 0; transition: all 0.3s ease-in-out; -webkit-transform: translateY(3px); transform: translateY(3px); } .waifu:hover { -webkit-transform: translateY(0); transform: translateY(0); } @media (max-width: 768px) { .waifu { display: none; } } .waifu-tips { opacity: 0; width: 250px; height: 70px; margin: -20px 20px; padding: 5px 10px; border: 1px solid rgba(224, 186, 140, 0.62); border-radius: 12px; background-color: rgba(236, 217, 188, 0.5); box-shadow: 0 3px 15px 2px rgba(191, 158, 118, 0.2); font-size: 12px; text-overflow: ellipsis; overflow: hidden; position: absolute; animation-delay: 5s; animation-duration: 50s; animation-iteration-count: infinite; animation-name: shake; animation-timing-function: ease-in-out; } .waifu #live2d { position: relative; } @keyframes shake { 2% { transform: translate(0.5px, -1.5px) rotate(-0.5deg); } 4% { transform: translate(0.5px, 1.5px) rotate(1.5deg); } 6% { transform: translate(1.5px, 1.5px) rotate(1.5deg); } 8% { transform: translate(2.5px, 1.5px) rotate(0.5deg); } 10% { transform: translate(0.5px, 2.5px) rotate(0.5deg); } 12% { transform: translate(1.5px, 1.5px) rotate(0.5deg); } 14% { transform: translate(0.5px, 0.5px) rotate(0.5deg); } 16% { transform: translate(-1.5px, -0.5px) rotate(1.5deg); } 18% { transform: translate(0.5px, 0.5px) rotate(1.5deg); } 20% { transform: translate(2.5px, 2.5px) rotate(1.5deg); } 22% { transform: translate(0.5px, -1.5px) rotate(1.5deg); } 24% { transform: translate(-1.5px, 1.5px) rotate(-0.5deg); } 26% { transform: translate(1.5px, 0.5px) rotate(1.5deg); } 28% { transform: translate(-0.5px, -0.5px) rotate(-0.5deg); } 30% { transform: translate(1.5px, -0.5px) rotate(-0.5deg); } 32% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 34% { transform: translate(2.5px, 2.5px) rotate(-0.5deg); } 36% { transform: translate(0.5px, -1.5px) rotate(0.5deg); } 38% { transform: translate(2.5px, -0.5px) rotate(-0.5deg); } 40% { transform: translate(-0.5px, 2.5px) rotate(0.5deg); } 42% { transform: translate(-1.5px, 2.5px) rotate(0.5deg); } 44% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 46% { transform: translate(1.5px, -0.5px) rotate(-0.5deg); } 48% { transform: translate(2.5px, -0.5px) rotate(0.5deg); } 50% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 52% { transform: translate(-0.5px, 1.5px) rotate(0.5deg); } 54% { transform: translate(-1.5px, 1.5px) rotate(0.5deg); } 56% { transform: translate(0.5px, 2.5px) rotate(1.5deg); } 58% { transform: translate(2.5px, 2.5px) rotate(0.5deg); } 60% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 62% { transform: translate(-1.5px, 0.5px) rotate(1.5deg); } 64% { transform: translate(-1.5px, 1.5px) rotate(1.5deg); } 66% { transform: translate(0.5px, 2.5px) rotate(1.5deg); } 68% { transform: translate(2.5px, -1.5px) rotate(1.5deg); } 70% { transform: translate(2.5px, 2.5px) rotate(0.5deg); } 72% { transform: translate(-0.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(0.5deg); } 80% { transform: translate(-1.5px, 0.5px) rotate(-0.5deg); } 82% { transform: translate(-1.5px, 0.5px) rotate(-0.5deg); } 84% { transform: translate(-0.5px, 0.5px) rotate(1.5deg); } 86% { transform: translate(2.5px, 1.5px) rotate(0.5deg); } 88% { transform: translate(-1.5px, 0.5px) rotate(1.5deg); } 90% { transform: translate(-1.5px, -0.5px) rotate(-0.5deg); } 92% { transform: translate(-1.5px, -1.5px) rotate(1.5deg); } 94% { transform: translate(0.5px, 0.5px) rotate(-0.5deg); } 96% { transform: translate(2.5px, -0.5px) rotate(-0.5deg); } 98% { transform: translate(-1.5px, -1.5px) rotate(-0.5deg); } 0%, 100% { transform: translate(0, 0) rotate(0); } } 网页中插入以下内容 \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;style.css\u0026#34; /\u0026gt; \u0026lt;div class=\u0026#34;waifu\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;waifu-tips\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;canvas id=\u0026#34;live2d\u0026#34; width=\u0026#34;280\u0026#34; height=\u0026#34;250\u0026#34; class=\u0026#34;live2d\u0026#34;\u0026gt;\u0026lt;/canvas\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;script src=\u0026#34;//cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;script async src=\u0026#34;waifu-tips.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;script src=\u0026#34;live2d.js\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; // 这里填写模型的model.json的地址 loadlive2d(\u0026#34;live2d\u0026#34;, \u0026#34;models/snow_miku/model.json\u0026#34;); \u0026lt;/script\u0026gt; 其中model需要自己制造或者下载大佬分享的 这个网站有一些分享的模型：https://mx.paul.ren/\n案例 https://pan.2bboy.com/home/test/live2d/\n","date":"2021-05-19T10:48:00Z","permalink":"https://kizx.github.io/post/%E7%BD%91%E9%A1%B5%E4%B8%AD%E6%B7%BB%E5%8A%A0live2d%E7%9C%8B%E6%9D%BF%E5%A8%98/","title":"网页中添加live2d看板娘"},{"content":"当我们有如下的布局时，其中 img 是我们内容，用一个 overflow:auto 来设置一个滚动区域，当图片较长时，会发现即使滚动到顶部，图片顶部仍有部分看不到。\n\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;zh\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Document\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;style\u0026gt; .container { width: 500px; height: 500px; overflow: auto; display: flex; justify-content: center; align-items: center; } img { width: 100%; } \u0026lt;/style\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div class=\u0026#34;container\u0026#34;\u0026gt; \u0026lt;img src=\u0026#34;./static/1.jpg\u0026#34; alt=\u0026#34;\u0026#34; /\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 解决方法 设置内容的 margin:auto 就可以滚动显示完全了。\nimg { width: 100%; margin: auto; } 我们换一张宽度较宽的图，并设置 height:100%，这时新的问题出现了，图片滚动到最左边，图片左边仍有部分被遮挡显示不全。\nimg { height: 100%; margin: auto; } 继续解决 我们换一种居中布局的方式，就可是使图片左右滚动能显示全。\n.container { width: 500px; height: 500px; overflow: auto; position: relative; } img { height: 100%; margin: auto; position: absolute; top: 0; right: 0; bottom: 0; left: 0; } 但是当我们换回高度较高的图片，并设置 width:100%时，发现问题又回来了，图片顶部显示不全。 难道说说没有一种同时能满足上下滚动和左右滚动显示全的布局方式吗？\n解决方案 一般来说图片要么 width:100%，要么 height:100%，所以上面选一种布局方式即可，但是我写的一个页面刚好要在两种状态中进行切换，因为切换是通过 js 操作的，可以在 css 里写两个布局，然后通过 js 控制元素 class 来进行切换。 我在 flex 布局的基础上，当图片左右滚动不能显示完全时，只需要改变 flex-direction 的方向即可。\n.container { width: 500px; height: 500px; overflow: auto; display: flex; justify-content: center; align-items: center; flex-direction: column; } img { height: 100%; margin: auto; } ","date":"2021-05-14T02:42:27Z","permalink":"https://kizx.github.io/post/css%E5%B1%85%E4%B8%AD%E6%97%B6%E5%86%85%E5%AE%B9%E6%BA%A2%E5%87%BA%E6%BB%9A%E5%8A%A8%E6%98%BE%E7%A4%BA%E4%B8%8D%E5%85%A8%E7%9A%84%E9%97%AE%E9%A2%98/","title":"CSS居中时内容溢出滚动显示不全的问题"},{"content":"subprocess库用于在控制台中调用子进程，可以模拟控制台命令输入输出。\nsubprocess.run 如果只是简单调用运行第三方程序的话，使用subprocess.run最为简单。 下面以调用ping命令为例\n# 直接在控制台输出 但由于编码问题中文为乱码 subprocess.run([\u0026#39;ping\u0026#39;, \u0026#39;baidu.com\u0026#39;]) subprocess.run(\u0026#39;ping baidu.com\u0026#39;, shell=True) # 通过stdout来获取输出 p = subprocess.run([\u0026#39;ping\u0026#39;, \u0026#39;baidu.com\u0026#39;], stdout=subprocess.PIPE) print(p.stdout.decode(\u0026#39;gbk\u0026#39;)) subprocess.Popen 下面以下面这个相加函数为例，利用subprocess.Popen来调用它\n#!/usr/bin/env python # -*- coding: utf-8 -*- n = int(input()) nums = [] while n \u0026gt; 0: a, b = list(map(int, input().strip().split())) nums.append([a, b]) n -= 1 for a, b in nums: print(f\u0026#39;{a}+{b}={a + b}\u0026#39;) 仿照牛客网上测试程序的流程来进行输入输出，注意stdin的用法\ndef test(pyfile, datafile): p = subprocess.Popen([\u0026#39;python.exe\u0026#39;, pyfile], stdin=subprocess.PIPE) with open(datafile) as f: line = f.readline() print(\u0026#39;..........输入..........\u0026#39;) while line: print(line.strip()) p.stdin.write(line.encode()) line = f.readline() p.stdin.close() print(\u0026#39;..........输出..........\u0026#39;) p.wait(2000) test(\u0026#39;add.py\u0026#39;, \u0026#39;data.txt\u0026#39;) # ..........输入.......... # 3 # 1 2 # 5 6 # 7 8 # ..........输出.......... # 1+2=3 # 5+6=11 # 7+8=15 如果有多个测试用例，可以在输入数据时用一个标志符#进行分割\ndef tests(pyfile, datafile): with open(datafile) as f: line = f.readline() n = 0 while line.strip().startswith(\u0026#39;#\u0026#39;): n += 1 p = subprocess.Popen([\u0026#39;python.exe\u0026#39;, pyfile], stdin=subprocess.PIPE) line = f.readline() print(f\u0026#39;..........案例[{n}]输入..........\u0026#39;) while line: print(line.strip()) p.stdin.write(line.encode()) line = f.readline() if line.strip().startswith(\u0026#39;#\u0026#39;): break p.stdin.close() print(f\u0026#39;..........案例[{n}]输出..........\u0026#39;) p.wait() tests(\u0026#39;add.py\u0026#39;, \u0026#39;data.txt\u0026#39;) # ..........案例[1]输入.......... # 3 # 1 2 # 5 6 # 7 8 # ..........案例[1]输出.......... # 1+2=3 # 5+6=11 # 7+8=15 # ..........案例[2]输入.......... # 2 # 1 2 # 5 6 # 7 8 # ..........案例[2]输出.......... # 1+2=3 # 5+6=11 参考 https://www.runoob.com/w3cnote/python3-subprocess.html https://docs.python.org/zh-cn/3/library/subprocess.html\n","date":"2021-05-13T03:06:00Z","permalink":"https://kizx.github.io/post/python%E8%B0%83%E7%94%A8%E5%AD%90%E8%BF%9B%E7%A8%8Bsubprocess/","title":"Python调用子进程subprocess"},{"content":"\u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html lang=\u0026#34;en\u0026#34;\u0026gt; \u0026lt;head\u0026gt; \u0026lt;meta charset=\u0026#34;UTF-8\u0026#34; /\u0026gt; \u0026lt;meta http-equiv=\u0026#34;X-UA-Compatible\u0026#34; content=\u0026#34;IE=edge\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;viewport\u0026#34; content=\u0026#34;width=device-width, initial-scale=1.0\u0026#34; /\u0026gt; \u0026lt;title\u0026gt;Document\u0026lt;/title\u0026gt; \u0026lt;style\u0026gt; .container { background-color: darkorange; width: 500px; height: 500px; } .content { background-color: cyan; width: 200px; height: 200px; } \u0026lt;/style\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div class=\u0026#34;container\u0026#34;\u0026gt; \u0026lt;div class=\u0026#34;content\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; 定位布局 .container { position: relative; } .content { position: absolute; top: 0; right: 0; bottom: 0; left: 0; margin: auto; } 定位+移动布局 .container { position: relative; } .content { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } flex 布局 .container { display: flex; justify-content: center; align-items: center; } grid 布局 .container { display: grid; align-items: center; justify-items: center; } inline-block 布局 .container { text-align: center; line-height: 500px; } .content { display: inline-block; vertical-align: middle; } table-cell 布局 .container { display: table-cell; vertical-align: middle; } .content { margin: auto; } ","date":"2021-05-13T02:32:35Z","permalink":"https://kizx.github.io/post/css%E7%9B%92%E5%AD%90%E5%B1%85%E4%B8%AD%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E6%B3%95/","title":"CSS盒子居中的几种方法"},{"content":"一般将TCP/IP分为四层，OSI参考模型分为7层 7 应用层 针对每个应用程序的协议 如电子邮件协议、远程登录协议、文件传输协议ftp、http、DNS、URI、SSH 6 表示层 设备固有数据格式和网络标准数据格式间的转换 5 会话层 通信管理，负责建立和断开通信连接，以及数据分割等处理 4 传输层 负责管理两个节点之间的数据可靠传输（确保数据可靠地传送到目标地址） TCP、UDP协议 3 网络层 主要负责寻址和路由选择 IP协议(IPv4\\IPv6)、ARP、ICMP 2 数据链路层 互联设备之间的传送和数据帧的生成与接收 通过MAC来唯一标识(MAC,物理地址，一个主机会有一个MAC地址) 1 物理层 数字信号和点子信号间的转换 数据发送和接收 每个分层中，都会对所发送的数据附加一个首部，每个包首部中至少会包含两个信息：发送端地址和接收端地址。以太网用MAC地址，网络层用IP地址，TCP/UDP会用端口号。 另外每个分层包首部还包含一个标志位，用来标志上一层协议种类信息 IP协议 IPv4地址由32位数表示，ip地址由网络地址（网络标识）和主机地址（主机标识）两部分组成。网络地址和主机地址的分段以子网掩码区分，子网掩码的主要作用有两个，一是用于屏蔽IP地址的一部分以区别网络标识和主机标识，并说明该IP地址是在局域网上，还是在远程网上。二是用于将一个大的IP网络划分为若干小的子网络。子网掩码可在ip地址后加上/表示，比如172.20.0.0/16或172.20/16 IP地址分类 A类\n0开头 区间：0.0.0.0~127.0.0.0 子网掩码：255.0.0.0 私有地址：10.0.0.0~10.255.255.255(10/8) B类\n10开头 区间：128.0.0.0~191.255.0.0 子网掩码：255.255.0.0 私有地址：172.16.0.0~172.31.255.255(172.16/12) C类\n110开头 区间：192.0.0.0~223.255.255.0 子网掩码：255.255.255.0 私有地址：192.168.0.0~192.168.255.255(192.168/16) 每个网段只有254个地址，因为全0表示对应网段或地址不可知，全1表示广播地址 D类\n1110开头 区间：224.0.0.0~239.255.255.255 子网掩码：255.255.255.255 多拨地址 E类\n区间：240.0.0.0~255.255.255.254 保留地址 广播地址\n将主机地址全部设为1，就是广播地址 ARP/RARP协议 ARP 是根据IP地址获取MAC地址的一种协议。 在以太网上发送ip包时，因为链路层需要知道MAC地址，先根据ip地址查一下ARP缓存，如果没有查到，则发送一个ARP协议广播包，这个广播包里面就有待查询的IP地址，而直接收到这份广播的包的所有主机都会查询自己的IP地址，如果收到广播包的某一个主机发现自己符合条件，那么就准备好一个包含自己的MAC地址的ARP包传送给发送ARP广播的主机。广播主机拿到ARP包后会更新自己的ARP缓存。 只适用于ipv4，ipv6中用ICMPv6代替。 RARP 是从MAC地址定位ip地址的一种协议。 arp 命令 ICMP协议 ICMP的主要功能包括，确认IP包是否成功到达目标地址，通知发送过程中ip包被弃用的原因，改善网络设置等。当传送IP数据包发生错误，比如主机不可达，路由不可达等等，ICMP协议将会把错误信息封包，然后传送回给主机。 常用命令\nping traceroute NAT NAT用于在局域网中使用私有地址，在链接互联网时使用全局ip地址，除ip地址转换外，还有可以转换TCP、UDP端口号的NAPT技术。 缺点：不能从NAT外部向内部服务器建立连接\nTCP/UDP TCP连接的建立与终止 三次握手 第一次握手：建立连接。客户端发送连接请求报文段，将SYN位置为1，Sequence Number为x；然后，客户端进入SYN_SEND状态，等待服务器的确认； 第二次握手：服务器收到SYN报文段。服务器收到客户端的SYN报文段，需要对这个SYN报文段进行确认，设置Acknowledgment Number为x+1(Sequence Number+1)；同时，自己自己还要发送SYN请求信息，将SYN位置为1，Sequence Number为Y；服务器端将上述所有信息放到一个报文段（即SYN+ACK报文段）中，一并发送给客户端，此时服务器进入SYN_RECV状态； 第三次握手：客户端收到服务器的SYN+ACK报文段。然后将Acknowledgment Number设置为y+1，向服务器发送ACK报文段，这个报文段发送完毕以后，客户端和服务器端都进入ESTABLISHED状态，完成TCP三次握手。 为什么要三次握手？两报文握手可以吗？ 为了防止已失效的连接请求报文段突然又传送到了服务端，因而产生错误。\n具体例子：“已失效的连接请求报文段”的产生在这样一种情况下：client发出的第一个连接请求报文段并没有丢失，而是在某个网络结点长时间的滞留了，以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后，就误认为是client再次发出的一个新的连接请求。\n于是就向client发出确认报文段，同意建立连接。假设不采用“三次握手”，那么只要server发出确认，新的连接就建立了。由于现在client并没有发出建立连接的请求，因此不会理睬server的确认，也不会向server发送数据。但server却以为新的运输连接已经建立，并一直等待client发来数据。这样，server的很多资源就白白浪费掉了。采用“三次握手”的办法可以防止上述现象发生。例如刚才那种情况，client不会向server的确认发出确认。server由于收不到确认，就知道client并没有要求建立连接。”\n四次分手 第一次分手：主机1（可以使客户端，也可以是服务器端），设置Sequence Number，向主机2发送一个FIN报文段；此时，主机1进入FIN_WAIT_1状态；这表示主机1没有数据要发送给主机2了； 第二次分手：主机2收到了主机1发送的FIN报文段，向主机1回一个ACK报文段，Acknowledgment Number为Sequence Number加1；主机1进入FIN_WAIT_2状态；主机2告诉主机1，我“同意”你的关闭请求； 第三次分手：主机2向主机1发送FIN报文段，请求关闭连接，同时主机2进入LAST_ACK状态； 第四次分手：主机1收到主机2发送的FIN报文段，向主机2发送ACK报文段，然后主机1进入TIME_WAIT状态；主机2收到主机1的ACK报文段以后，就关闭连接；此时，主机1等待2MSL后依然没有收到回复，则证明Server端已正常关闭，那好，主机1也可以关闭连接了。 为什么要四次分手？ TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式，这就意味着，当主机1发出FIN报文段时，只是表示主机1已经没有数据要发送了，主机1告诉主机2，它的数据已经全部发送完毕了；但是，这个时候主机1还是可以接受来自主机2的数据；当主机2返回ACK报文段时，表示它已经知道主机1没有数据发送了，但是主机2还是可以发送数据到主机1的；当主机2也发送了FIN报文段时，这个时候就表示主机2也没有数据要发送了，就会告诉主机1，我也没有数据要发送了，之后彼此就会愉快的中断这次TCP连接。 为什么要等待2MSL MSL：报文段最大生存时间，它是任何报文段被丢弃前在网络内的最长时间。\n保证TCP协议的全双工连接能够可靠关闭 保证这次连接的重复数据段从网络中消失 第一点：如果主机1直接CLOSED了，那么由于IP协议的不可靠性或者是其它网络原因，导致主机2没有收到主机1最后回复的ACK。那么主机2就会在超时之后继续发送FIN，此时由于主机1已经CLOSED了，就找不到与重发的FIN对应的连接。所以，主机1不是直接进入CLOSED，而是要保持TIME_WAIT，当再次收到FIN的时候，能够保证对方收到ACK，最后正确的关闭连接。 第二点：如果主机1直接CLOSED，然后又再向主机2发起一个新连接，我们不能保证这个新连接与刚关闭的连接的端口号是不同的。也就是说有可能新连接和老连接的端口号是相同的。一般来说不会发生什么问题，但是还是有特殊情况出现：假设新连接和已经关闭的老连接端口号是一样的，如果前一次连接的某些数据仍然滞留在网络中，这些延迟数据在建立新连接之后才到达主机2，由于新连接和老连接的端口号是一样的，TCP协议就认为那个延迟的数据是属于新连接的，这样就和真正的新连接的数据包发生混淆了。所以TCP连接还要在TIME_WAIT状态等待2倍MSL，这样可以保证本次连接的所有数据都从网络中消失。 窗口控制 如果每发一个段都进行一次确认应答会很慢，于是引入窗口概念，发松端无需等待确认应答而是继续发送，窗口大小就是指无需等待确认应答的可以继续发送数据的最大值。 确认应答丢失不会重发；报文段丢失，发松端连续3次收到收到同一个确认应答就会进行重发。\n流量控制 如果发送方把数据发送得过快，接收方可能会来不及接收，这就会造成数据的丢失。所谓流量控制就是让发送方的发送速率不要太快，要让接收方来得及接收。 TCP首部中，有一个字段用来通知窗口大小。利用滑动窗口机制可以很方便地在TCP连接上实现对发送方的流量控制。 接收端的缓冲区一旦面临数据溢出时，窗口大的值就会设置为一个更小的值通知给发松端，发松端就会根据接收端的指示，进行流量控制。\n拥塞控制 发送方维持一个拥塞窗口 cwnd ( congestion window )的状态变量。拥塞窗口的大小取决于网络的拥塞程度，并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口。 发送方控制拥塞窗口的原则是：只要网络没有出现拥塞，拥塞窗口就再增大一些，以便把更多的分组发送出去。但只要网络出现拥塞，拥塞窗口就减小一些，以减少注入到网络中的分组数。\n当 cwnd \u0026lt; ssthresh 时，使用上述的慢开始算法。 当 cwnd \u0026gt; ssthresh 时，停止使用慢开始算法而改用拥塞避免算法。 当 cwnd = ssthresh 时，既可使用慢开始算法，也可使用拥塞避免算法。 慢开始 通常在刚刚开始发送报文段时，先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后，把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ，可以使分组注入到网络的速率更加合理。 拥塞避免 拥塞窗口cwnd缓慢地增大，即每经过一个往返时间RTT就把发送方的拥塞窗口cwnd加1，而不是加倍。 快重传 快重传算法首先要求接收方每收到一个失序的报文段后就立即发出重复确认（为的是使发送方及早知道有报文段没有到达对方）而不要等到自己发送数据时才进行捎带确认。 快重传算法还规定，发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段，而不必继续等待未收到的报文段设置的重传计时器到期。 快恢复 与快重传配合使用的还有快恢复算法 当发送方连续收到三个重复确认，就执行“乘法减小”算法，把慢开始门限ssthresh减半。 参考 https://juejin.cn/post/6844903490595061767 https://www.ihewro.com/archives/913/ https://mp.weixin.qq.com/s/VMz2bDV5JZo0YH5fRQ9mSw\n","date":"2021-04-25T13:58:00Z","permalink":"https://kizx.github.io/post/tcpip%E5%8D%8F%E8%AE%AE%E6%80%BB%E7%BB%93/","title":"TCP/IP协议总结"},{"content":"注：排序算法的稳定性指相等的元素在排序前后相对位置是否变化，稳定排序主要用于不同键值比较，比如ACM成绩排序，先按分数排序，相同分数再按用时最短排序。\n冒泡排序 不断比较相邻元素，每次遍历将最大值移至队尾。\ndef bubble(arr): swapped = True end = len(arr) while swapped: swapped = False for i in range(1, end): if arr[i-1] \u0026gt; arr[i]: arr[i-1], arr[i] = arr[i], arr[i-1] swapped = True end -= 1 return arr 选择排序 每次遍历找到一个最小值，将其移至队首。\ndef selection(arr): for start in range(len(arr)-1): mini = start for i in range(start+1, len(arr)): if arr[i] \u0026lt; arr[mini]: mini = i arr[start], arr[mini] = arr[mini], arr[start] return arr 插入排序 很像打麻将，每摸到一张牌，就依次比较将其插入正确的位置。\ndef insertion(arr): for cur in range(len(arr)): for i in range(cur-1, -1, -1): if arr[cur] \u0026lt; arr[i]: arr[cur], arr[i] = arr[i], arr[cur] cur = i else: break return arr 归并排序 分分合合\ndef merge(arr): l = len(arr) if l \u0026lt;= 1: return arr arrleft = merge(arr[:l//2]) arright = merge(arr[l//2:]) res = [] while arrleft or arright: if arrleft and arright: res.append(arrleft.pop( 0) if arrleft[0] \u0026lt; arright[0] else arright.pop(0)) elif arrleft: res.append(arrleft.pop(0)) elif arright: res.append(arright.pop(0)) return res 快速排序 选一个基准，然后将基准放在正确的位置上，并保证左边比基准小，右边比基准大，再一直递推下去。\ndef quick(arr): def _quick(i, j): if i \u0026gt;= j: return # 这里选取左端点为参考点 pivot = arr[i] low = i high = j while i != j: # 从右往左 找小于pivot的 while i \u0026lt; j and arr[j] \u0026gt;= pivot: j -= 1 arr[i] = arr[j] # 从左往右 找大于pivot的 while i \u0026lt; j and arr[i] \u0026lt;= pivot: i += 1 arr[j] = arr[i] arr[i] = pivot _quick(low, i-1) _quick(i+1, high) return arr return _quick(0, len(arr)-1) 堆排序 每次将堆顶元素和最后一个元素交换，交换后上浮\nclass HeapSort: def __init__(self, arr): self.arr = arr self.len = len(arr) for i in range(len(arr)//2, -1, -1): self.heapify(i) def heapify(self, i): left = 2*i+1 right = 2*i+2 largest = i if left \u0026lt; self.len and self.arr[left] \u0026gt; self.arr[largest]: largest = left if right \u0026lt; self.len and self.arr[right] \u0026gt; self.arr[largest]: largest = right if largest != i: self.swap(i, largest) self.heapify(largest) def swap(self, a, b): self.arr[a], self.arr[b] = self.arr[b], self.arr[a] def heapSort(arr): heapq = HeapSort(arr) for i in range(len(arr)-1, 0, -1): heapq.swap(0, i) heapq.len -= 1 heapq.heapify(0) return heapq.arr 计数排序 统计每个数字出现的次数，然后依次取出，适合都是整数且数字集中的场景。\ndef count(arr): if not arr: return arr minn = min(arr) maxn = max(arr) dic = {n: 0 for n in range(minn, maxn+1)} for n in arr: dic[n] += 1 res = [] for n in range(minn, maxn+1): res += [n]*dic[n] return res 基数排序 先创建10个队列（0~9桶），先按个位放入桶中，然后依次清空桶，然后是十位\u0026hellip; 适合整数，数据跨度较大的场景。\ndef radix(arr): buckets = [[] for _ in range(10)] flag = True rad = 1 while flag: flag = False for n in arr: buckets[n // rad % 10].append(n) if not flag and n % rad \u0026lt; n: flag = True i = 0 for bucket in buckets: while bucket: arr[i] = bucket.pop(0) i += 1 rad *= 10 return arr 桶排序 每个桶有不同的范围，桶内有自己的排序算法 参考 https://visualgo.net/zh/sorting\n","date":"2021-04-15T07:26:00Z","permalink":"https://kizx.github.io/post/%E5%90%84%E7%A7%8D%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95%E7%9A%84python%E5%AE%9E%E7%8E%B0/","title":"各种排序算法的Python实现"},{"content":"一般认为js数据类型为7种：number,string,boolean,undefined,null,symbol,object，（有的把bigint也算一种，）其中object为引用类型，其余为基本类型。\nconsole.log(typeof 2); // number console.log(typeof true); // boolean console.log(typeof \u0026#34;str\u0026#34;); // string console.log(typeof []); // object console.log(typeof {}); // object console.log(typeof function () {}); // function console.log(typeof undefined); // undefined console.log(typeof null); // object console.log((2).constructor === Number); // true console.log(true.constructor === Boolean); // true console.log(\u0026#34;str\u0026#34;.constructor === String); // true console.log([].constructor === Array); // true console.log({}.constructor === Object); // true console.log(function () {}.constructor === Function); // true let str = Object.prototype.toString; console.log(str.call(2)); //[object Number] console.log(str.call(true)); //[object Boolean] console.log(str.call(\u0026#34;str\u0026#34;)); //[object String] console.log(str.call([])); //[object Array] console.log(str.call(function () {})); //[object Function] console.log(str.call({})); //[object Object] console.log(str.call(undefined)); //[object Undefined] console.log(str.call(null)); //[object Null] instanceof instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置，不能用来判断包装对象。\nconsole.log(2 instanceof Number); // false console.log(true instanceof Boolean); // false console.log(\u0026#39;str\u0026#39; instanceof String); // false console.log([] instanceof Array); // true console.log(function () {} instanceof Function); // true console.log({} instanceof Object); // true console.log(Object instanceof Object); //true console.log(Function instanceof Object); //true // 原理实现 function myInstanceof(obj, tar) { // 获取对象的原型 let proto = Object.getPrototypeOf(obj); // 获取构造函数的 prototype 对象 let prototype = tar.prototype; // 对象原型走到头了 if (!proto) return false; //判断原型是否相等 return proto === prototype ? true : myInstanceof(proto, tar); } 深拷贝 数组、对象的typeof结果都为\u0026rsquo;object\u0026rsquo;，需要注意的是null的typeof结果也为\u0026rsquo;object\u0026rsquo;，函数的typeof结果为\u0026rsquo;function\u0026rsquo;，symbol无法直接遍历到。\nfunction deepcopy(data) { if (data === null) return null; let obj = data instanceof Array ? [] : {}; for (const [k, v] of Object.entries(data)) { obj[k] = typeof v === \u0026#34;object\u0026#34; ? deepcopy(v) : v; } for (const k of Object.getOwnPropertySymbols(data)) { obj[k] = typeof data[k] === \u0026#34;object\u0026#34; ? deepcopy(data[k]) : data[k]; } return obj; } Object.create Object.create()方法创建一个新对象，使用现有的对象来提供新创建的对象的__proto__，和new有点像。\nfunction create(proto) { obj = {}; obj.__proto__ = proto; return obj; } //直译 function create(proto) { function F() {} F.prototype = proto; return new F(); } //推荐 new new操作主要执行了以下操作：\n新建一个空对象obj 将空对象的__proto__原型链指向构造函数的原型prototype 将构造函数的this指向obj，执行构造函数 返回构造函数的返回，如果返回为空则返回obj function newObj(p, ...args) { const obj = Object.create(p.prototype); const result = p.apply(obj, args); return result || obj; } function Person(name) { this.name = name; } Person.prototype.getname = function () { console.log(this.name); }; let person1 = new Person(\u0026#34;san\u0026#34;); console.log(person1); let person2 = newObj(Person, \u0026#34;si\u0026#34;); console.log(person2); 防抖 快速连续触发事件时，只有最后一次触发能成功执行。\nfunction debounce(fn) { let timeout = null; // 创建一个标记用来存放定时器的返回值 return function () { clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉 timeout = setTimeout(() =\u0026gt; { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话，就不会执行 fn 函数 fn.apply(this, arguments); }, 500); }; } function sayHi() { console.log(\u0026#34;防抖成功\u0026#34;); } let inp = document.createElement(\u0026#34;input\u0026#34;); inp.addEventListener(\u0026#34;input\u0026#34;, debounce(sayHi)); document.body.append(inp); 节流 一定时间内只会执行1次，上一次未处理完则不会执行。\nfunction throttle(fn) { let canRun = true; // 通过闭包保存一个标记 return function () { if (!canRun) return; // 在函数开头判断标记是否为true，不为true则return canRun = false; // 立即设置为false setTimeout(() =\u0026gt; { // 将外部传入的函数的执行放在setTimeout中 fn.apply(this, arguments); // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false，在开头被return掉 canRun = true; }, 500); }; } function sayHi() { console.log(\u0026#34;节流成功\u0026#34;); } btn = document.createElement(\u0026#34;button\u0026#34;); btn.innerHTML = \u0026#34;节流\u0026#34;; btn.addEventListener(\u0026#34;click\u0026#34;, throttle(sayHi)); document.body.append(btn); call 将this挂载到目标上后执行，最后再删除\nFunction.prototype.myCall = function (context) { context = context || window; context.fn = this; let arg = [...arguments].slice(1); let result = context.fn(...arg); delete context.fn; return result; }; apply Function.prototype.myApply = function (context) { context = context || window; context.fn = this; let result; // 需要判断是否存储第二个参数 // 如果存在，就将第二个参数展开 if (arguments[1]) { result = context.fn(...arguments[1]); } else { result = context.fn(); } delete context.fn; return result; }; bind Function.prototype.myBind = function (context) { let fn = this; var args = [...arguments].slice(1); // 返回一个函数 return function () { return fn.apply(context, args.concat(...arguments)); }; }; 柯里化 将能够接收多个参数的函数转化为接收单一参数的函数，并且返回能接收余下参数且返回结果的新函数的技术\nfunction add() { return Array.from(arguments).reduce((cur, item) =\u0026gt; cur + item, 0); } function currying(fn) { let args = []; return function () { args.push(...arguments); return fn.apply(this, args); }; } add = currying(add); console.log(add(1)); //1 console.log(add(2)); //3 console.log(add(3, 4)); //10 console.log(add()); //10 反柯里化 方法借用，扩展方法使用范围，和call,apply,bind类似\nfunction unCurrying(fn) { return function (obj, ...args) { return fn.apply(obj, args); }; } push = unCurrying(Array.prototype.push); obj = {}; push(obj, \u0026#34;lisi\u0026#34;, \u0026#34;san\u0026#34;); console.log(obj); // 等同于bind方法 obj = {}; push = Array.prototype.push.bind(obj); push(\u0026#34;lisi\u0026#34;, \u0026#34;san\u0026#34;); console.log(obj); 双向绑定 通过Proxy实现对数据监听。\n\u0026lt;input type=\u0026#34;text\u0026#34; v-model=\u0026#34;input\u0026#34; /\u0026gt; \u0026lt;input type=\u0026#34;text\u0026#34; v-model=\u0026#34;input\u0026#34; /\u0026gt; \u0026lt;div v-bind=\u0026#34;input\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; data = {}; proxy = new Proxy(data, { get(obj, property) {}, set(obj, property, value) { // model赋值 // obj[property] = value; Reflect.set(...arguments); //视图响应 let els = document.querySelectorAll( `[v-model=\u0026#34;${property}\u0026#34;],[v-bind=\u0026#34;${property}\u0026#34;]` ); for (let el of els) { el.innerHTML = value; el.value = value; } return true; }, }); (function () { const els = document.querySelectorAll(\u0026#34;[v-model]\u0026#34;); for (const el of els) { el.addEventListener(\u0026#34;keyup\u0026#34;, function () { proxy[this.getAttribute(\u0026#34;v-model\u0026#34;)] = this.value; }); } })(); \u0026lt;/script\u0026gt; 数组扁平化 function flat(arr) { let res = []; for (let item of arr) { res = Array.isArray(item) ? res.concat(flat(item)) : res.concat(item); } return res; } ","date":"2021-04-13T10:01:00Z","permalink":"https://kizx.github.io/post/javascript%E4%B8%80%E4%BA%9B%E6%96%B9%E6%B3%95%E5%8E%9F%E7%90%86%E5%AE%9E%E7%8E%B0/","title":"javascript一些方法原理实现"},{"content":"隐式原型__proto__ 除了元对象Object，每个js对象都有隐式原型，但也可以通过Object.create(null)强制创建一个没有__proto__的对象，__proto__指向该对象的构造函数的原型对象。 原型链指的就是__proto__串起来的链。\n原型prototype 函数对象拥有prototype属性，函数的原型对象包含所有实例共享的方法，包含__proto__和constructor两个属性，constructor指回函数本身，函数原型对象也有__proto__属性，指向构造函数的原型即Function.prototype。 实例的__proto__指向函数原型对象，即f1.__proto__ === Foo.prototype。 Object.prototype.__proto__指向null。\n总结 定义函数时自动创建prototype原型对象，原型对象包含constructor构造函数，构造函数指回函数本身，new出来的实例拥有__proto__指向prototype原型对象。 类式继承（原型链继承） 将父类的实例赋给子类的prototype，缺点是父类共有属性为引用对象时，所有子类实例会公用同一个对象；无法向父类传参；子类不是父类的实例，而子类的原型是父类的实例，缺少constructor属性。\nfunction Animal() { this.name = \u0026#39;动物\u0026#39; this.animal = \u0026#39;父类属性\u0026#39; } Animal.prototype.getname = function () { console.log(this.name) } Animal.prototype.getsupername = function () { console.log(this.animal) } function Dog() { this.name = \u0026#39;狗\u0026#39; } Dog.prototype = new Animal() dog = new Dog() dog.getname() dog.getsupername() console.log(dog) 构造函数继承 将子类的变量在父类中执行一遍，即在子类的构造函数中执行一次父类的构造函数，缺点只执行了父类的构造函数，没有继承父类原型，父类的所有方法必须在构造函数中声明才能继承。\nfunction Animal(name) { this.name = name this.animal = \u0026#39;父类属性\u0026#39; } Animal.prototype.getname = function () { console.log(this.name) } Animal.prototype.getsupername = function () { console.log(this.animal) } function Dog(name) { Animal.call(this, name) //执行父类构造函数 } dog = new Dog(\u0026#39;狗\u0026#39;) // dog.getname() //无法继承原型方法 // dog.getsupername() console.log(dog) 组合继承 结合前面两种方法，在子类构造函数中执行父类构造函数，子类原型指向父类的实例，缺点是父类构造函数执行了两遍，子类不是父类的实例。\nfunction Animal(name) { this.name = name this.animal = \u0026#39;父类属性\u0026#39; console.log(\u0026#39;执行了父类构造函数\u0026#39;) } Animal.prototype.getname = function () { console.log(this.name) } Animal.prototype.getsupername = function () { console.log(this.animal) } function Dog(name) { Animal.call(this, name) //继承属性 } Dog.prototype = new Animal() //继承方法 dog = new Dog(\u0026#39;狗\u0026#39;) dog.getname() dog.getsupername() console.log(dog) 原型式继承 和类式继承相似，创建一个新对象并使用父类对象做为新对象的原型对象，和类式继承存在一样的问题，引用值会在实例间共享。和Object.create()方法作用一致。适合不需要单独创建构造函数，但仍需要在实例间共享属性的场合。\nfunction inherit(o) { function F() { } F.prototype = o return new F() } let Animal = { name: \u0026#39;动物\u0026#39; } animal = inherit(Animal) console.log(animal) 寄生式继承 对原型继承的二次封装，对继承的对象进行了拓展。\nfunction inherit(o) { function F() { } F.prototype = o return new F() } let Animal = { name: \u0026#39;动物\u0026#39; } function createDog(obj) { let o = new inherit(obj) o.getname = function () { console.log(this.name) } // 增加属性和方法 return o } dog = new createDog(Animal) dog.getname() console.log(dog) 寄生组合式继承 寄生继承和构造函数继承的组合，修复子类的原型，子类的原型指向父类原型的一份实例，construction指向子类本身。\nfunction inherit(o) { function F() { } F.prototype = o return new F() } function inheritPtototype(subClass, superClass) { let p = inherit(superClass.prototype) p.construction = subClass subClass.prototype = p } function Animal(name) { this.name = name this.animal = \u0026#39;父类属性\u0026#39; console.log(\u0026#39;执行了父类构造函数\u0026#39;) } Animal.prototype.getname = function () { console.log(this.name) } Animal.prototype.getsupername = function () { console.log(this.animal) } function Dog(name) { Animal.call(this, name) //构造函数式继承 } inheritPtototype(Dog, Animal) //寄生式继承 dog = new Dog(\u0026#39;狗\u0026#39;) dog.getname() dog.getsupername() console.log(dog) 但是上面左还有一个小问题，就是遍历子类实例属性时，会把construction也遍历出来，可以通过Object.defineProperty方法禁止遍历。\nfor (const key in dog) { console.log(key); } 所以再升级一下\nfunction extend(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype) Object.defineProperty(subClass.prototype, \u0026#34;constructor\u0026#34;, { value: subClass, enumerable: false //禁止遍历 }); } function Animal(name) { this.name = name this.animal = \u0026#39;父类属性\u0026#39; console.log(\u0026#39;执行了父类构造函数\u0026#39;) } Animal.prototype.getname = function () { console.log(this.name) } Animal.prototype.getsupername = function () { console.log(this.animal) } function Dog(name) { Animal.call(this, name) //构造函数式继承 } extend(Dog, Animal) //寄生式继承 dog = new Dog(\u0026#39;狗\u0026#39;) dog.getname() dog.getsupername() mixin多继承 const Mammal = { skill() { console.log(this.name + \u0026#39;是哺乳动物\u0026#39;) } } // mixin类 function Dog(name) { Animal.call(this, name) //构造函数式继承 } extend(Dog, Animal) //寄生式继承 Object.assign(Dog.prototype, Mammal) //往子类原型拓展其他类方法 dog = new Dog(\u0026#39;狗\u0026#39;) dog.getname() dog.getsupername() dog.skill() 参考 帮你彻底搞懂JS中的prototype、__proto__与constructor（图解） JavaScript中的new操作符的原理解析 js中__proto__和prototype的区别和关系？ 原型基础\n","date":"2021-04-11T12:33:00Z","permalink":"https://kizx.github.io/post/js%E5%8E%9F%E5%9E%8B%E4%B8%8E%E7%BB%A7%E6%89%BF/","title":"JS原型与继承"},{"content":"查询：O(1) 插入：O(n) 删除：O(n)\n链表 查询：O(n) 插入：O(1) 删除：O(1)\n迭代 递归 环判断 set判重 快慢指针 栈Stack 先进后出(FILO)\n单调栈 下一个更大的数\n队列Queue 先进先出(FIFO)\nfrom collections import deque q = deque() q.append(1) q.append(2) q.append(3) q.popleft() q.pop() 堆 log(n) import heapq # 小顶堆 heap0 = [] heapq.heappush(heap0, 5) heapq.heappush(heap0, 4) heap1 = [5, 2, 3, 4] heapq.heapify(heap1) # 优先队列 heap2 = [] heapq.heappush(heap2, (5, \u0026#39;5\u0026#39;)) heapq.heappush(heap2, (4, \u0026#39;4\u0026#39;)) print(heapq.heappop(heap0)) # 出堆 print(heapq.heappushpop(heap0, 0)) # 先压后弹 print(heapq.heapreplace(heap0, 0)) # 先弹后压 # 大顶堆，没法push，一般用小顶堆相反数 data = [1, 5, 3, 2, 8, 5] heapq._heapify_max(data) # 优先队列，可以用heapq实现，也可以用下面的同步方法 from queue import PriorityQueue 二叉堆 父节点的权值不大于儿子的权值（小顶堆），可以用数组存储数据\n单调队列 固定大小滑动窗口，获取最值。 单独看 push 操作的复杂度确实不是 O(1)，但是算法整体的复杂度依然是 O(N) 线性时间。要这样想，nums 中的每个元素最多被 push_back 和 pop_back 一次，没有任何多余操作，所以整体的复杂度还是 O(N)。 单调队列\n映射Map HashMap/TreeMap 无序/有序\nfrom collections # 有序字典 ordmap = collections.OrderedDict() ordmap.move_to_end(key) ordmap.popitem(last=False) # 计数字典 countmap = collections.Counter() # 访问不存在的key时自动添加key值为默认值 defaultdict([int,list,set,str,dict]) 散列冲突：分离链接、线性探查\n集合Set HashSet/TreeSet\nset_a = set(\u0026#39;12345\u0026#39;) set_b = set([\u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;, \u0026#39;3\u0026#39;, \u0026#39;4\u0026#39;, \u0026#39;5\u0026#39;, \u0026#39;5\u0026#39;]) set_c = {1, 2, 3, 4, 5, 5} set_d = set(set_a) set_a.add(\u0026#39;6\u0026#39;) set_a.update([\u0026#39;1\u0026#39;, \u0026#39;2\u0026#39;]) # 可以添加列表、集合等 set_a.remove(\u0026#39;1\u0026#39;) # 元素不存在会报错 set_a.discard(\u0026#39;1\u0026#39;) # 元素不存在不会报错 print(set_a-set_b) print(set_a | set_b) print(set_a \u0026amp; set_b) print(set_a ^ set_b) 树Tree 二叉树-完全二叉树-满二叉树\n二叉搜索树BST 左子树小于根节点 右子树大于根节点 左右子书满足二叉搜索树\n遍历 前序pre：根-左-右 中序in：左-根-右 升序返回 后续post：左-右-根 中序遍历的两种写法\n# 递归 def inorder(root): if root: inorder(root.left) print(root.val) inorder(root.right) # 迭代 stack = [] while root or stack: while root: stack.append(root) root = root.left root = stack.pop() print(root.val) root = root.right 字典树/前缀树Trie 图Graph 广度优先搜索BFS 最短路径问题\n狄克斯特拉算法 有向无环加权图最小开销问题\n深度优先搜索DFS 递归 重复计算-\u0026gt;效率低\n分治 贪心 剪枝-回溯 位运算 x^0=X x^x=0 x\u0026amp;1==0or1 #判断奇偶 x=x\u0026amp;(x-1) #清零最低位1 x\u0026amp;(-x) #取最低位的1 补码=反码+1 动态规划 NP完全问题 旅行商问题 集合覆盖问题\n并查集 数组实现\nLRU/LFU Cache 缓存替换算法 双链表实现\n布隆过滤器 判断在不在，肯定不在/应该在\n","date":"2021-03-02T08:36:00Z","permalink":"https://kizx.github.io/post/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95/","title":"数据结构与算法"},{"content":"本软件集成百度云、阿里云和讯飞云的在线语音合成的功能，可以实现将SRT格式的字幕文件或TXT格式的台词文本转换为时间轴对应的语音。\n下载地址 当前版本：V3.0.0 [button color=\u0026ldquo;info\u0026rdquo; icon=\u0026quot;\u0026quot; url=\u0026ldquo;https://github.com/kizx/subtitle2audio\u0026rdquo; type=\u0026quot;\u0026quot;]开源地址[/button] [button color=\u0026ldquo;success\u0026rdquo; icon=\u0026quot;\u0026quot; url=\u0026ldquo;https://kizx.lanzoui.com/b01hhub9g\u0026rdquo; type=\u0026quot;\u0026quot;]密码:gyb3[/button]\n使用方法 获取相关KEY 使用前需先去相关云平台注册并开通语音合成服务，各个平台语音种类和收费策略不一样，个人轻量使用白嫖完全够用。 百度云：https://ai.baidu.com/tech/speech/tts 阿里云：https://ai.aliyun.com/nls/tts 讯飞云：https://www.xfyun.cn/services/online_tts\n各个平台具体注册和开通语音合成服务的过程这里就不赘述了，如果遇到问题可以向平台客服求助，以下是各个平台开通后密钥的位置。 [tabs] [tab name=\u0026ldquo;百度云\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;][/tab] [tab name=\u0026ldquo;阿里云\u0026rdquo;] 阿里云的密钥需要在两个页面分别获取 [/tab] [tab name=\u0026ldquo;讯飞云\u0026rdquo;] [/tab] [/tabs]\n字幕生成语音 本软件只支持utf8编码的srt格式的字幕文件，其他格式的需要先自行转换下，生成成功后会自动打开输出目录，输出目录里包含输出.mp3和audio文件夹，文件夹内为一句句单独的语音供备用。 文本生成语音 和字幕生成语音操作没有区别，文本的格式为每行一句台词，唯一不同的是可以设置两句话之间的停顿时间。 ","date":"2021-01-28T07:30:00Z","permalink":"https://kizx.github.io/post/%E5%AD%97%E5%B9%95%E6%9C%97%E8%AF%BB%E5%99%A8%E5%88%A9%E7%94%A8%E4%BA%91%E8%AF%AD%E9%9F%B3%E5%B9%B3%E5%8F%B0%E4%B8%BA%E8%A7%86%E9%A2%91%E9%85%8D%E9%9F%B3/","title":"字幕朗读器——利用云语音平台为视频配音"},{"content":"如标题所示，在重写了QPlainTextEdit的拖放方法后，发现拖放文件后光标就不动了，但编辑功能正常，就很奇怪，虽然不会报bug，但很影响使用，文档里翻了半天没有找到问题，换了个搜索姿势后找到了和我遇到相同问题的人，并且解决方法也很奇特。\n解决方法 方法来自：PyQt5 QTextEdit重写dropEvent方法后拖入文件光标不动的问题 问题出在重写的dropEvent方法上，只需要加一句super().dropEvent(event)重新继承方法即可。\nclass MyQPlainTextEdit(QPlainTextEdit): \u0026#34;\u0026#34;\u0026#34;实现文件拖放功能\u0026#34;\u0026#34;\u0026#34; def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) def dragEnterEvent(self, e): if e.mimeData().text().endswith(\u0026#39;.srt\u0026#39;): e.accept() else: e.ignore() def dropEvent(self, e): path = e.mimeData().text().replace(\u0026#39;file:///\u0026#39;, \u0026#39;\u0026#39;) super().dropEvent(e) # 加这一句即可 self.setPlainText(path) ","date":"2021-01-26T14:32:00Z","permalink":"https://kizx.github.io/post/pyqt%E5%A4%9A%E8%A1%8C%E6%96%87%E6%9C%ACqplaintextedit%E6%8B%96%E6%94%BE%E6%96%87%E4%BB%B6%E5%90%8E%E5%85%89%E6%A0%87%E4%B8%8D%E5%8A%A8%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95/","title":"PyQt多行文本QPlainTextEdit拖放文件后光标不动解决方法"},{"content":"微软商店搜索Windows Terminal下载即可，或者去github下载：https://github.com/microsoft/terminal\n默认打开CMD 打开Windows Terminal，找到设置，打开设置文件，将defaultProfile设置为CMD的那一串值，这串值可以在设置文件下面找到。\n\u0026#34;defaultProfile\u0026#34;: \u0026#34;{0caa0dad-35be-5f56-a8ff-afceeeaa6101}\u0026#34;, 添加到右键菜单 对一个文件夹右键默认是集成了右键打开的，但在空白处右键是没有的，需要手动配置注册表。 以下是注册表注册文件，其中注意替换两个地址，一个是ico图标的地址，图标可以从GitHub上下载，另一个是程序wt.exe的地址。\nWindows Registry Editor Version 5.00 [HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\WT] @=\u0026#34;Terminal Here\u0026#34; \u0026#34;Icon\u0026#34;=\u0026#34;D:\\\\admin\\\\Documents\\\\ICO\\\\terminal.ico\u0026#34; \u0026#34;Position\u0026#34;=\u0026#34;Top\u0026#34; [HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\WT\\command] @=\u0026#34;C:\\\\Users\\\\onepiece\\\\AppData\\\\Local\\\\Microsoft\\\\WindowsApps\\\\wt.exe\u0026#34; 地址替换后将上面保存为wt.reg文件运行即可，以下注册表中注册后的状态。 后记 我发现现在好像软件自己添加了右键，不需要手动配置了，而且用上面方法配置的只是打开了wt.exe，但没有自动切换到当前目录下，并没有什么卵用。 要删除注册表在上面命令的头部加上-即可\n[-HKEY_CLASSES_ROOT\\Directory\\Background\\shell\\WT] ","date":"2021-01-26T06:29:00Z","permalink":"https://kizx.github.io/post/windows-terminal%E4%BD%BF%E7%94%A8%E9%85%8D%E7%BD%AE/","title":"Windows Terminal使用配置"},{"content":"在uniapp中小程序登录这一块上，关于如何登录授权，获取openid，存储用户信息，网上虽然有很多范例，但都讲的很乱，很容易就把人看晕了，这里简单总结下，真正使用时应该是按需使用。\nopenid openid是微信小程序中由官方生成的每个账户对每个小程序唯一的一串字符，不管用户有没有授权，只要用户访问了小程序就可以获取openid，openid可以作为用户的身份识别id。获取方法是通过uni.login获取一个code，这个code每次刷新后都是不唯一的，需要利用这个code向微信官方接口换取openid。 uni.login：https://uniapp.dcloud.net.cn/api/plugins/login?id=login openid换取接口：https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html 要注意的是，用code换取openid时需要传递小程序appid和secret，所以这个请求过程建议在后台而非前端进行，比如在云函数中请求：\n\u0026#39;use strict\u0026#39;; exports.main = async (event, context) =\u0026gt; { const appid = \u0026#39;小程序后台查看\u0026#39; const secret = \u0026#39;小程序后台查看\u0026#39; const js_code = event.code const grant_type = \u0026#39;authorization_code\u0026#39; const url = \u0026#39;https://api.weixin.qq.com/sns/jscode2session\u0026#39; const res = await uniCloud.httpclient.request(url, { data: { appid, secret, js_code, grant_type }, dataType: \u0026#39;json\u0026#39; }) return res }; 授权登陆 我这里授权登录指的是弹出那个获取昵称和头像的授权框，准确的说只是授权，登录是上面的login，但很多小程序都把这个按钮叫做登陆按钮，也就混为一谈了。由于微信小程序政策的变化，好像现在只能通过用户点击按钮进行主动登录，通过设置button按钮的open-type属性即可弹出授权框，触发@getuserinfo事件可以获取用户信息，网上这里案例很多。 详见：https://uniapp.dcloud.net.cn/component/button\n获取用户信息 除了在用户授权时获取用户信息，如果用户没有登出或清除授权信息，用户是已知保持登陆状态的，可以主动通过uni.getUserInfo来获取用户信息用于判断用户是否登录或者其他用途。 详见：https://uniapp.dcloud.net.cn/api/plugins/login?id=getuserinfo\n获取平台信息 uniapp还有一个uni.getProvider方法用来获取服务供应商信息，其实就是检测当前是小程序还是app什么的，只有在程序跨端时才会用到，因为我们前面的方法在使用时需要传入一个provider信息，该信息就可以通过本方法来获取。 详见：https://uniapp.dcloud.net.cn/api/plugins/provider?id=getprovider\n存储用户信息 货去了用户的openid或者其他信息后就需要在数据存到缓存中，这样下次用户就不用重复登录，程序也不用重复获取信息了，不论你是把信息存到全局变量还是vuex中，用户刷新后这些信息都会重置，真正应该存到的应该是本地，用到的方法是uni.setStorageSync,与之对应的读取缓存信息的方法是uni.getStorage。 详见：https://uniapp.dcloud.net.cn/api/storage/storage?id=setstoragesync\n","date":"2021-01-10T08:53:00Z","permalink":"https://kizx.github.io/post/uni-app%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%99%BB%E5%BD%95%E7%9B%B8%E5%85%B3%E6%96%B9%E6%B3%95%E8%AF%B4%E6%98%8E/","title":"uni-app微信小程序登录相关方法说明"},{"content":"用于求解形如AX=b的方程组。\n不同点 numpy.linalg.solve需要A矩阵为方阵，求解的结果为方程准确解。 numpy.linalg.lstsq允许A矩阵为超定的，当方程数大于未知数时求解结果为最小二乘近似解。 另外在使用时注意返回值不同，lstsq返回更多信息。\nX = numpy.linalg.solve(A, b) X = np.linalg.lstsq(A, B, rcond=None)[0] 当A矩阵为方阵时，计算结果没有差别，可以认为lstsq是solve的超集。\n参考 https://numpy.org/doc/stable/reference/generated/numpy.linalg.solve.html https://numpy.org/doc/stable/reference/generated/numpy.linalg.lstsq.html\n","date":"2020-12-27T11:53:16Z","permalink":"https://kizx.github.io/post/numpy.linalg%E4%B8%ADsolve%E5%92%8Clstsq%E7%9A%84%E5%8C%BA%E5%88%AB/","title":"numpy.linalg中solve和lstsq的区别"},{"content":"一直空间散点坐标值，计算三点组成三角形的面积。\n方法1 利用矩阵来计算 这里是否需要加绝对值？\nimport numpy as np def area(p): p1, p2, p3 = p a = [[1, 1, 1], [p2[0] - p1[0], p2[1] - p1[1], p2[2] - p1[2]], [p3[0] - p1[0], p3[1] - p1[1], p3[2] - p1[2]]] s = 0.5 * np.linalg.det(a) return s 方法2 利用海伦公式\ndef heron(p): p1, p2, p3 = p a = ((p1[0]-p2[0])**2+((p1[1]-p2[1]))**2+((p1[2]-p2[2]))**2)**0.5 b = ((p1[0]-p3[0])**2+((p1[1]-p3[1]))**2+((p1[2]-p3[2]))**2)**0.5 c = ((p2[0]-p3[0])**2+((p2[1]-p3[1]))**2+((p2[2]-p3[2]))**2)**0.5 l = (a+b+c)/2 s = (l*(l-a)*(l-b)*(l-c))**0.5 return s ","date":"2020-12-26T13:14:00Z","permalink":"https://kizx.github.io/post/%E8%AE%A1%E7%AE%97%E7%A9%BA%E9%97%B4%E4%B8%89%E8%A7%92%E5%BD%A2%E9%9D%A2%E7%A7%AF/","title":"计算空间三角形面积"},{"content":"blender插件脚本里新建物体的两种方法，其实本质上是一样的，这里做个记录以防日后忘记。\n方法一 来自之前在网络上搜到的方法，是直接在data里新建物体并link到场景集合里。\nclass PointsImport(bpy.types.Operator): bl_idname = \u0026#39;obj.import_points\u0026#39; bl_label = \u0026#39;导入点云\u0026#39; bl_options = {\u0026#39;REGISTER\u0026#39;, \u0026#39;UNDO\u0026#39;} name: bpy.props.StringProperty(default=\u0026#39;points\u0026#39;) path: bpy.props.StringProperty(subtype=\u0026#39;FILE_PATH\u0026#39;) def execute(self, context): points = np.load(self.path) verts = [] for i in points: verts.append(tuple(i)) # 新建mesh mymesh = bpy.data.meshes.new(self.name) mymesh.from_pydata(verts, [], []) mymesh.update() # 新建object并添加到场景 myobject = bpy.data.objects.new(self.name, mymesh) bpy.context.scene.collection.objects.link(myobject) self.report({\u0026#39;INFO\u0026#39;}, f\u0026#39;import {len(points)} points\u0026#39;) return {\u0026#39;FINISHED\u0026#39;} 方法二 来自blender自带的demo，直接调用了object_data_add方法，是更正规的方法，需要注意的是需要继承AddObjectHelper\nimport bpy from bpy.types import Operator from bpy.props import FloatVectorProperty from bpy_extras.object_utils import AddObjectHelper, object_data_add from mathutils import Vector def add_object(self, context): scale_x = self.scale.x scale_y = self.scale.y verts = [ Vector((-1 * scale_x, 1 * scale_y, 0)), Vector((1 * scale_x, 1 * scale_y, 0)), Vector((1 * scale_x, -1 * scale_y, 0)), Vector((-1 * scale_x, -1 * scale_y, 0)), ] edges = [] faces = [[0, 1, 2, 3]] mesh = bpy.data.meshes.new(name=\u0026#34;New Object Mesh\u0026#34;) mesh.from_pydata(verts, edges, faces) # useful for development when the mesh may be invalid. # mesh.validate(verbose=True) object_data_add(context, mesh, operator=self) class OBJECT_OT_add_object(Operator, AddObjectHelper): \u0026#34;\u0026#34;\u0026#34;Create a new Mesh Object\u0026#34;\u0026#34;\u0026#34; bl_idname = \u0026#34;mesh.add_object\u0026#34; bl_label = \u0026#34;Add Mesh Object\u0026#34; bl_options = {\u0026#39;REGISTER\u0026#39;, \u0026#39;UNDO\u0026#39;} scale: FloatVectorProperty( name=\u0026#34;scale\u0026#34;, default=(1.0, 1.0, 1.0), subtype=\u0026#39;TRANSLATION\u0026#39;, description=\u0026#34;scaling\u0026#34;, ) def execute(self, context): add_object(self, context) return {\u0026#39;FINISHED\u0026#39;} ","date":"2020-12-08T07:55:51Z","permalink":"https://kizx.github.io/post/blender%E8%84%9A%E6%9C%AC%E6%96%B0%E5%BB%BA%E7%89%A9%E4%BD%93%E7%9A%84%E6%96%B9%E6%B3%95/","title":"blender脚本新建物体的方法"},{"content":"都说blender的python脚本编写起来很简单，虽然已经能够在脚本里调用一些api实现自动化，但实际写成插件还是有很多东西需要摸索的，这里记录一些关键知识点。\n参考 先将一些重要的和有益的参考或学习资料列一下：\n一篇相当棒的入门教程 Blender Python小白向入门\n主要是第2期和第3期杂志关于插件一节写的很棒 blendercn电子杂志\n其中Quickstart部分不错，不过需要一定经验后回头看才能看的更明白，其他时候主要是当作字典查询，其中有许多example值得参考 blenderAPI\nblender软件中自带的Templates\n概览 blender插件大部分内容都是写在class中的，无论是新建一个api接口，还是绘制一个新的界面，都是新建一个class，然后继承相应的类，所以找到相应的类，是编写插件的第一步。 然后新写的类都要通过下面的注册函数register才能成为blender的一部分，有注册就有注销，注册函数在启用插件时激活，注销函数在取消启用插件时激活。\nbpy.utils.register_class(CLASS_NAME) bpy.utils.unregister_class(CLASS_NAME) 下面是一个在顶部添加语言切换功能的面板示例代码，关键的部分有继承bpy.types.Header，定义bl_space_type等内容，这些参数可以通过查阅api获取，或者从别人的代码参考过来，绘制界面就是重写draw()函数。\nclass LanguageChange(bpy.types.Header): bl_space_type = \u0026#34;TOPBAR\u0026#34; bl_idname = \u0026#34;MY_HT_LanguageChange\u0026#34; def draw(self, context): if context.region.alignment != \u0026#34;RIGHT\u0026#34;: self.layout.prop(context.preferences.view, \u0026#34;use_translate_interface\u0026#34;, text=\u0026#34;Language\u0026#34;) 传入的context就表示当前上下文，通过打印dir(context)可知其包涵以下属性和方法：\n[\u0026rsquo;doc\u0026rsquo;, \u0026lsquo;module\u0026rsquo;, \u0026lsquo;slots\u0026rsquo;, \u0026lsquo;active_annotation_layer\u0026rsquo;, \u0026lsquo;active_base\u0026rsquo;, \u0026lsquo;active_bone\u0026rsquo;, \u0026lsquo;active_editable_fcurve\u0026rsquo;, \u0026lsquo;active_gpencil_frame\u0026rsquo;, \u0026lsquo;active_gpencil_layer\u0026rsquo;, \u0026lsquo;active_object\u0026rsquo;, \u0026lsquo;active_operator\u0026rsquo;, \u0026lsquo;active_pose_bone\u0026rsquo;, \u0026lsquo;annotation_data\u0026rsquo;, \u0026lsquo;annotation_data_owner\u0026rsquo;, \u0026lsquo;area\u0026rsquo;, \u0026lsquo;bl_rna\u0026rsquo;, \u0026lsquo;blend_data\u0026rsquo;, \u0026lsquo;collection\u0026rsquo;, \u0026lsquo;copy\u0026rsquo;, \u0026rsquo;edit_object\u0026rsquo;, \u0026rsquo;editable_bones\u0026rsquo;, \u0026rsquo;editable_fcurves\u0026rsquo;, \u0026rsquo;editable_gpencil_layers\u0026rsquo;, \u0026rsquo;editable_gpencil_strokes\u0026rsquo;, \u0026rsquo;editable_objects\u0026rsquo;, \u0026rsquo;engine\u0026rsquo;, \u0026rsquo;evaluated_depsgraph_get\u0026rsquo;, \u0026lsquo;gizmo_group\u0026rsquo;, \u0026lsquo;gpencil_data\u0026rsquo;, \u0026lsquo;gpencil_data_owner\u0026rsquo;, \u0026lsquo;image_paint_object\u0026rsquo;, \u0026rsquo;layer_collection\u0026rsquo;, \u0026lsquo;mode\u0026rsquo;, \u0026lsquo;object\u0026rsquo;, \u0026lsquo;objects_in_mode\u0026rsquo;, \u0026lsquo;objects_in_mode_unique_data\u0026rsquo;, \u0026lsquo;particle_edit_object\u0026rsquo;, \u0026lsquo;pose_object\u0026rsquo;, \u0026lsquo;preferences\u0026rsquo;, \u0026lsquo;region\u0026rsquo;, \u0026lsquo;region_data\u0026rsquo;, \u0026lsquo;rna_type\u0026rsquo;, \u0026lsquo;scene\u0026rsquo;, \u0026lsquo;screen\u0026rsquo;, \u0026lsquo;sculpt_object\u0026rsquo;, \u0026lsquo;selectable_objects\u0026rsquo;, \u0026lsquo;selected_bones\u0026rsquo;, \u0026lsquo;selected_editable_bones\u0026rsquo;, \u0026lsquo;selected_editable_fcurves\u0026rsquo;, \u0026lsquo;selected_editable_objects\u0026rsquo;, \u0026lsquo;selected_editable_sequences\u0026rsquo;, \u0026lsquo;selected_nla_strips\u0026rsquo;, \u0026lsquo;selected_objects\u0026rsquo;, \u0026lsquo;selected_pose_bones\u0026rsquo;, \u0026lsquo;selected_pose_bones_from_active_object\u0026rsquo;, \u0026lsquo;selected_sequences\u0026rsquo;, \u0026lsquo;selected_visible_fcurves\u0026rsquo;, \u0026lsquo;sequences\u0026rsquo;, \u0026lsquo;space_data\u0026rsquo;, \u0026rsquo;tool_settings\u0026rsquo;, \u0026lsquo;vertex_paint_object\u0026rsquo;, \u0026lsquo;view_layer\u0026rsquo;, \u0026lsquo;visible_bones\u0026rsquo;, \u0026lsquo;visible_fcurves\u0026rsquo;, \u0026lsquo;visible_gpencil_layers\u0026rsquo;, \u0026lsquo;visible_objects\u0026rsquo;, \u0026lsquo;visible_pose_bones\u0026rsquo;, \u0026lsquo;weight_paint_object\u0026rsquo;, \u0026lsquo;window\u0026rsquo;, \u0026lsquo;window_manager\u0026rsquo;, \u0026lsquo;workspace\u0026rsquo;]\n界面布局layout就不细说了，prop和operator两个控件用的比较多，前者用于显示各种属性值，后者就是一个按钮，按下可以执行关联的的api，这两个控件也不细说了，可以查阅api文档。\n自定义方法 到目前位置我们还只能调用blender已有的属性和方法的api，我们实现自己的功能必然需要新建一个自己的api，同样新建api也是新写一个类，如下所示，继承bpy.types.Operator，然后定义bl_idname等内容，执行的具体代码在execute()函数中编写，同样这个类写完后记得注册后才能调用。\nclass PointsImport(bpy.types.Operator): bl_idname = \u0026#39;obj.import_points\u0026#39; bl_label = \u0026#39;导入点云\u0026#39; bl_options = {\u0026#39;REGISTER\u0026#39;, \u0026#39;UNDO\u0026#39;} def execute(self, context): print(\u0026#39;我的代码\u0026#39;) return {\u0026#39;FINISHED\u0026#39;} 调用的方法是在界面类里调用layout.operator(\u0026quot;obj.import_points\u0026quot;)，可以看到，bl_idname 就是注册后api的名字。\n自定义变量 除了自定义方法，有时候我们还需要自定义变量，可以参考文档 https://docs.blender.org/api/current/bpy.props.html 这一节，就是在方法的类中通过bpy.props.FloatProperty等函数定义变量，调用的时候需要将实例赋值给一个变量，然后通过变量去调用和修改，可以参考文档的示例代码。\n有时候我们希望从界面视图中输入一个值，然后将这个值作为自定义api的一个输入参数，如果在界面中直接调用我们创建的方法的属性变量，你就会发现在界面中这个值只能显示出来而不能修改。\n要想获得一个可以在界面中修改的属性，需要在blender的data中创建一个数据，方法如下，在Scene中加入了一个变量，或者在WindowManager中添加一个变量，当然在其他数据块中添加变量也可以，添加的变量可以在blender api data面板中进行查看。\nbpy.types.Scene.points_name = bpy.props.StringProperty() bpy.types.WindowManager.points_name = bpy.props.StringProperty() 然后将这个值再赋值给方法的属性就可以了，参考我的下面代码。\nclass MyPanel(bpy.types.Panel): bl_label = \u0026#34;面板\u0026#34; # 面板显示的名称 bl_idname = \u0026#34;MY_PT_Import\u0026#34; # 面板的id，每个面版类的id应保持唯一，建议格式大写NAME_PT_id bl_space_type = \u0026#34;VIEW_3D\u0026#34; # 面板所处的模式，\u0026#34;VIEW_3D\u0026#34;=3D视窗 bl_region_type = \u0026#34;UI\u0026#34; # 面板所在的位置，\u0026#34;UI\u0026#34;=N面板 bl_category = \u0026#34;点云\u0026#34; # 面板所在的标签页 bpy.types.Scene.points_name = bpy.props.StringProperty(default=\u0026#39;yp\u0026#39;) bpy.types.Scene.points_file_path = bpy.props.StringProperty( default=r\u0026#39;C:\\Users\\kizx\\Desktop\\Projects\\cv\\ypa.npy\u0026#39;, subtype=\u0026#39;FILE_PATH\u0026#39;) def draw(self, context): layout = self.layout row = layout.row() row.prop(context.scene, \u0026#34;points_name\u0026#34;, text=\u0026#34;名称\u0026#34;) row = layout.row() row.prop(context.scene, \u0026#34;points_file_path\u0026#34;, text=\u0026#34;点云文件\u0026#34;) row = layout.row() pc = row.operator(\u0026#34;obj.import_points\u0026#34;) pc.path = context.scene.points_file_path pc.name = context.scene.points_name ","date":"2020-12-05T14:12:00Z","permalink":"https://kizx.github.io/post/blender%E6%8F%92%E4%BB%B6%E7%BC%96%E5%86%99%E5%85%A5%E9%97%A8/","title":"blender插件编写入门"},{"content":"只要安装fake-bpy-module这个模块就可以实现代码自动补全了，正如其名，这个库只用于代码提示补全作用，并不具备任何实质可运行代码。\npip安装 如果你编程时使用的是自己的python坏境，那么使用以下的pip命令安装即可。\npip install fake-bpy-module- \u0026lt;version\u0026gt; # version: 2.78|2.79|2.80|2.81|2.82|2.83 # e.g. pip install fake-bpy-module-2.80 手动安装 如果你用的是blender自带的python坏境，不好用pip进行安装，此时只能手动安装了。\nvscode 从 https://github.com/nutti/fake-bpy-module/releases 页面下载对应版本的包并解压，打开vscode，Ctrl+Shift+P搜索Settings打开工作区设置（打开设置文件setting.json），设置以下内容，其中填写刚才解压的路径。\n{ \u0026#34;python.autoComplete.extraPaths\u0026#34;: [ \u0026#34;\u0026lt;path-to-generated-modules\u0026gt;\u0026#34; ] } 保存后重启vscode就行了。\npycharm 日后补充\n参考 https://github.com/nutti/fake-bpy-module\n","date":"2020-08-19T12:13:16Z","permalink":"https://kizx.github.io/post/blender%E8%84%9A%E6%9C%ACpython%E4%BB%A3%E7%A0%81%E8%87%AA%E5%8A%A8%E8%A1%A5%E5%85%A8%E6%96%B9%E6%B3%95/","title":"blender脚本python代码自动补全方法"},{"content":"用blender内置的文本编辑器来编写代码体验实在是太糟糕了，利用JacquesLucke大神编写的vscode插件Blender Development就可以开心的在vscode里编写代码了。 打开vscode在插件市场里搜索Blender Development安装即可，该插件依赖于python和C/C++插件，安装时会自动安装依赖，如果没有安装请手动安装。\n使用 插件 ctrl+shift+P打开控制台，输入blender就能看到本插件的所有命令，点击Blender: New Addon，弹出模板选项，可以选择Simple简单模板或者WithAutoLoad模板。然后输入插件名和作者名，最后给插件选择一个目录，一个插件模板就新建成功了。\n如果你选的是Simple模板，那么就只会生成一个__init__.py，如果你选择的是WithAutoLoad模板，会生成__init__.py、auto_load.py、operators.py三个文件，两个模板的主要区别在于后者会自动注册register()和注销unregister()operators.py中的类，当然我们我们自己写一下注册方法也不是多麻烦。\n代码有了，下面就是如何联合blender了，我们都知道blender里自带一个python解释器，首先我们应该在vscode中点击左下角的python解释器选择blender安装文件夹里的python.exe作为解释器，这个路径一般形如 \\blender-2.83.0-windows64\\2.83\\python\\bin\\python.exe。当然你不用blender自带的解释器也行，但是需要在vscode设置里打开blender.allowModifyExternalPython，允许后面自动下载依赖库。\n然后ctrl+shift+P打开控制台，搜索执行Blender: Start命令，这时选择你的blender.exe，一切正常的话，程序会自动下载ptvsd、flask、requests几个库，所以第一次启动会慢点，如果你卡在这里的话，一般是网络原因，请尝试更新pip、更换pip镜像源，再不济手动安装这些库。\n[post cid=\u0026ldquo;156\u0026rdquo; cover=\u0026ldquo;http://\u0026rdquo;/]\n启动blender后，打开N面板有一个Dev的面板就说明成功了。\n保存自动刷新 当我们更改代码后，我们总是希望已保存代码blender那边就立马更新，只需要在vscode设置里打开blender.addon.reloadOnSave即可。\n脚本 插件还提供了快速脚本功能，脚本就是类似于直接在blender交互式命令行直接输入命令，不用像写插件一样那么麻烦了，ctrl+shift+P打开控制台选择Blender: New Script就可以新建一个脚本，然后通过Blender: Start打开blender，运行脚本用Blender: Run Script命令，不过我测试了下这个脚本命令写的一不留神一运行就闪退了，感觉不如在blender的文本编辑器里好用。\n更改上下文 有时脚本需要特定的模式下，通过Blender: Set Script Context命令可以设置形如#context.area: VIEW_3D的注释来达到控制上下文的作用。\nDebug 用vscode的一大好处在于可以打断点进行debug，这些都是vscode的基本操作就不说了。\n后记 vscode插件更新到0.0.15版本后，只能适配blender2.92及以上版本，如果还用小于2.92的版本，就需要安装0.0.14版本的插件，并禁用vscode插件自动更新功能。\n参考 https://github.com/JacquesLucke/blender_vscode\nhttps://www.bilibili.com/video/BV1EJ41187hT\n","date":"2020-08-18T14:50:00Z","permalink":"https://kizx.github.io/post/%E5%9C%A8vscode%E4%B8%AD%E5%BC%80%E5%8F%91blender%E6%8F%92%E4%BB%B6%E5%92%8C%E8%84%9A%E6%9C%AC/","title":"在vscode中开发blender插件和脚本"},{"content":"a:5:{s:4:\u0026ldquo;name\u0026rdquo;;s:9:\u0026ldquo;image.png\u0026rdquo;;s:4:\u0026ldquo;path\u0026rdquo;;s:35:\u0026quot;/usr/uploads/2020/08/2078653010.png\u0026quot;;s:4:\u0026ldquo;size\u0026rdquo;;i:17900;s:4:\u0026ldquo;type\u0026rdquo;;s:3:\u0026ldquo;png\u0026rdquo;;s:4:\u0026ldquo;mime\u0026rdquo;;s:9:\u0026ldquo;image/png\u0026rdquo;;}\n","date":"2020-08-18T14:24:52Z","permalink":"https://kizx.github.io/post/image.png/","title":"image.png"},{"content":"numpy中可用于拼接的函数有：\nappend(arr, values, axis=None) concatenate((a1, a2, \u0026hellip;), axis=0, out=None) stack(arrays, axis=0, out=None) hstack(tup) vstack(tup) dstack(tup) 使用时需要注意的是除了append都需要以tup形式传入，axis=0表示按行拼接，axis=1表示按列拼接，拼接时需要注意数组形状要匹配。\n测试代码 a = np.array([[1, 2, 3], [1, 2, 3]]) b = np.array([[4, 5, 6]]) np.append(a, b) # 其实底层调用concatenate() # array([1, 2, 3, 1, 2, 3, 4, 5, 6]) np.append(a, b, axis=0) # 必须保证列数一样 # array([[1, 2, 3], # [1, 2, 3], # [4, 5, 6]]) np.append(a, a, axis=1) # 必须保证行数一样 # array([[1, 2, 3, 1, 2, 3], # [1, 2, 3, 1, 2, 3]]) np.concatenate((a, b)) # 默认axis=0 np.concatenate((a, b), axis=0) # array([[1, 2, 3], # [1, 2, 3], # [4, 5, 6]]) np.concatenate((a, a), axis=1) # array([[1, 2, 3, 1, 2, 3], # [1, 2, 3, 1, 2, 3]]) np.stack((a, a)) # 会增加一个维度 # array([[[1, 2, 3], # [1, 2, 3]], # [[1, 2, 3], # [1, 2, 3]]]) np.stack((b, b), axis=1) # array([[[4, 5, 6], # [4, 5, 6]]]) np.hstack((a, a)) # 水平拼接 # array([[1, 2, 3, 1, 2, 3], # [1, 2, 3, 1, 2, 3]]) np.vstack((a, a)) # 垂直拼接 # array([[1, 2, 3], # [1, 2, 3], # [1, 2, 3], # [1, 2, 3]]) np.dstack((a, a)) # 会增加维度 # array([[[1, 1], # [2, 2], # [3, 3]], # [[1, 1], # [2, 2], # [3, 3]]]) np.dstack((b, b)) # array([[[4, 4], # [5, 5], # [6, 6]]]) 参考 https://blog.csdn.net/guofei_fly/article/details/85485173\n","date":"2020-08-11T10:36:00Z","permalink":"https://kizx.github.io/post/numpy%E6%95%B0%E7%BB%84%E6%8B%BC%E6%8E%A5/","title":"numpy数组拼接"},{"content":"台式机没有摄像头，有时候有些代码会调用摄像头，比如下面的项目有用到面部捕捉，这时候拿手机充当摄像头是个不错的选择。\n[post cid=\u0026ldquo;147\u0026rdquo; cover=\u0026quot;\u0026quot;/]\n软件 百度搜索 iVCam 下载安装即可，手机上也要扫码安装相应的客户端。连接前必须保证手机和电脑处在同一个局域网中，如果手机搜索不到电脑，可以手动输入电脑的局域网ipv4地址（通过cmd窗口 ipconfig命令可以查看）。\n捕获 之前的那个项目是使用OpenCV的api捕获摄像头的，默认摄像头的设备id为0，但用这个软件进行捕获时可能也为1或者更大的数字。\nvideo_capture = cv2.VideoCapture(1) # 摄像头id可能不为0 ","date":"2020-07-29T07:01:19Z","permalink":"https://kizx.github.io/post/%E7%94%B5%E8%84%91%E8%BF%9E%E6%8E%A5%E6%89%8B%E6%9C%BA%E6%91%84%E5%83%8F%E5%A4%B4/","title":"电脑连接手机摄像头"},{"content":"DHNN网络由n个神经元组成，每个神经元取值为1或-1。 每个神经元既是输入，也是输出，如果采用异步更新的策略，每次只更新一个神经元，更新顺序可以任意。激活函数为符号函数，大于等于零激活为1，反之为-1，每个神经元没有自反馈，即权重矩阵对角线为零。 DHNN输入一个值后，神经元状态不断更新后最终会收敛于某个“吸引子”。“吸引子”就是网络存储的记忆，是通过网络权重存储的。网络权重的计算方法一般有下面两种：联立方程求解法和外积和法。一般后面的方法用得较多。 DHNN网络是批学习网络，一次性输入样本一次性学习。输入的样本即“吸引子”，若样本值两两正交，则网络最稳定，理论上样本数上限为n。但一般很难做到两两正交，减少样本数（p\u0026lt;0.14n）可以提高抗畸变性，否则会出现“伪吸引子”。 DHNN网络可以靠下面的能量函数判断收敛状态，随着网络更新，能量函数处于递减趋势。 程序实现 下面是一个简单的python实现程序，可以输入简单样本和预测目标后进行不断更新。 [button color=\u0026ldquo;primary\u0026rdquo; icon=\u0026ldquo;fa fa-github\u0026rdquo; url=\u0026ldquo;https://github.com/kizx/DHNN\u0026rdquo; type=\u0026quot;\u0026quot;]Github地址[/button]\n# -*- coding: utf-8 -*- import numpy as np import time def sgn(x): \u0026#34;\u0026#34;\u0026#34;激活函数\u0026#34;\u0026#34;\u0026#34; y = 1 if x \u0026gt;= 0 else -1 return y class DHNN: def __init__(self, v0, tra): \u0026#34;\u0026#34;\u0026#34;初始化\u0026#34;\u0026#34;\u0026#34; self.n = np.size(v0) # 神经元个数 self.W = np.diag(np.zeros(self.n)) # 权矩阵 对角线元素为零的对称矩阵 self.V = v0 # 神经元状态 取值:{-1,1} self.Ip = np.zeros(self.n) # 偏置矢量 self.T = np.zeros(self.n) # 阈值矢量 self.train(tra) def update(self, i): \u0026#34;\u0026#34;\u0026#34;网络更新\u0026#34;\u0026#34;\u0026#34; net = np.dot(self.V, self.W[:, i]) + self.Ip[i] - self.T[i] self.V[i] = sgn(net) E = -1 / 2 * np.dot(np.dot(self.V.T, self.W), self.V) - np.dot(self.Ip.T, self.V) + np.dot(self.T.T, self.V) # print(\u0026#39;能量\u0026#39;, E) # print(\u0026#39;状态\u0026#39;, self.V) return E, sgn(net) def train(self, sample): \u0026#34;\u0026#34;\u0026#34;网络权重计算（记忆存储）\u0026#34;\u0026#34;\u0026#34; S = sample for i in range(self.n): for j in range(self.n): delta = 1 if i == j else 0 a = [] for m in S: a_ = m[i] * m[j] a.append(a_) self.W[i, j] = (1 - delta) * np.sum(a) print(\u0026#39;权重\\n\u0026#39;, self.W) if __name__ == \u0026#39;__main__\u0026#39;: St = np.array([[-1, -1, 1, 1], [-1, 1, 1, -1]]) test = DHNN(np.array([1, 1, -1, 1]), St) while True: time.sleep(1) test.update(3) 上面这个程序我还做了一个gui界面用于上课演示。 当我将上面的程序用于手写数字识别时，图片采用16*16共256个神经元，当样本数量小于4个时，还有点效果，当样本数多了之后，某些“伪吸引子”和样本的吸引力实在太强导致网络效果极差。想必用于实际用途需要更多的改进算法。\n参考 https://zhuanlan.zhihu.com/p/144624580 https://blog.csdn.net/qq_41185868/article/details/80789989 https://blog.csdn.net/weixin_42398658/article/details/84027012 https://space.bilibili.com/529985682/video\n","date":"2020-07-03T08:09:00Z","permalink":"https://kizx.github.io/post/%E5%8D%95%E5%B1%82%E7%A6%BB%E6%95%A3hopfield%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9Cdhnn%E7%A8%8B%E5%BA%8F%E5%AE%9E%E7%8E%B0/","title":"单层离散Hopfield神经网络(DHNN)程序实现"},{"content":"[post cid=\u0026ldquo;184\u0026rdquo; /] 前面借助vtk库实现读取stl模型，不过这有点杀鸡牛刀了，因为stl模型本身并不复杂，参考这篇文章。自己手写一个读取stl的程序也很简单，但我就是懒得写怎么办 ::aru:cryingface::\nstl库 其实前面已经尝试过用这个库了，但是当时总是报错。这个库还有个官方文档，之所以报错是因为这个库太老了，也没人维护。但知道了读取stl的原理后就好办了，把源码修改几处就可以在py3环境下使用了，以下是测试代码 。\nimport stl with open(\u0026#39;kiki.stl\u0026#39;, \u0026#39;rb\u0026#39;) as f: kiki = stl.read_binary_file(f) print(kiki.facets[0].normal, kiki.facets[0].vertices) print(kiki.name) 其实修改也很简单，把下面后面的strip去掉后，再将两处xrange改成range就行了。\n# return struct.unpack(\u0026#39;80s\u0026#39;, bytes)[0].strip(\u0026#39;\\0\u0026#39;) return struct.unpack(\u0026#39;80s\u0026#39;, bytes)[0] numpy-stl库 最好用的东西当然得放最后面，这个库依赖于numpy，功能丰富，可读取、修改、保存stl模型，不过要注意的是这里import的包名也是stl，和上面的包名是一样的，要先卸载上面的stl包再安装numpy-stl。 官方文档：https://pythonhosted.org/numpy-stl/usage.html\nimport numpy from stl import mesh your_mesh = mesh.Mesh.from_file(\u0026#39;cube.stl\u0026#39;) print(\u0026#39;法线\u0026#39;, your_mesh.normals) print(\u0026#39;点\u0026#39;, your_mesh.points) print(\u0026#39;v0表示三角面第一个点\u0026#39;, your_mesh.v0) print(\u0026#39;x表示所有点的x坐标\u0026#39;, your_mesh.x) ","date":"2020-06-14T14:28:00Z","permalink":"https://kizx.github.io/post/%E5%86%8D%E8%B0%88python%E8%AF%BB%E5%8F%96stl%E6%A8%A1%E5%9E%8B/","title":"再谈Python读取stl模型"},{"content":"本来以为python应该有个专门的库用来读取stl模型，实际上也的确有个叫 stl的库，不过经测试这个库完全没法用(或许是我不会用？)。 后来发现vtk库可以读取并显示stl模型，查了一下vtk无法直接pip安装，需要手动下载whl https://www.lfd.uci.edu/~gohlke/pythonlibs/#vtk，下载时根据自己python版本下载就行了，下载完进入工程venv环境进行pip安装。\npip install VTK?8.2.0?cp37?cp37m?win32.whl 读取代码 关于vtk库，我只是听说过但从来没用过，反正照着下面的代码可以正常读取stl模型，然后输出所有顶点坐标并显示出来。\nimport vtk # Read from file stlreader = vtk.vtkSTLReader() stlreader.SetFileName(\u0026#34;cube.stl\u0026#34;) # 输出所有点坐标 stlreader.Update() stlMapper = vtk.vtkPolyDataMapper() stlMapper.SetInputConnection(stlreader.GetOutputPort()) p = [0, 0, 0] polydata = stlreader.GetOutput() for i in range(polydata.GetNumberOfPoints()): polydata.GetPoint(i, p) print(p) cylinderMapper = vtk.vtkPolyDataMapper() # 渲染多边形几何数据 cylinderMapper.SetInputConnection(stlreader.GetOutputPort()) # VTK可视化管线的输入数据接口 ，对应的可视化管线输出数据的接口为GetOutputPort()； cylinderActor = vtk.vtkActor() cylinderActor.SetMapper(cylinderMapper) # 设置生成几何图元的Mapper。即连接一个Actor到可视化管线的末端(可视化管线的末端就是Mapper)。 renderer = vtk.vtkRenderer() # 负责管理场景的渲染过程 renderer.AddActor(cylinderActor) renderer.SetBackground(0.1, 0.2, 0.4) renWin = vtk.vtkRenderWindow() # 将操作系统与VTK渲染引擎连接到一起。 renWin.AddRenderer(renderer) renWin.SetSize(300, 300) iren = vtk.vtkRenderWindowInteractor() # 提供平台独立的响应鼠标、键盘和时钟事件的交互机制 iren.SetRenderWindow(renWin) # 交互器样式的一种，该样式下，用户是通过控制相机对物体作旋转、放大、缩小等操作 style = vtk.vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style) iren.Initialize() iren.Start() # Clean up # del cylinder del stlreader del cylinderMapper del cylinderActor del renderer del renWin del iren 后记 其实stl文件有两种编码，一种是Ascall模式，可以直接用记事本打开，其中按规定记录了模型信息，如果能掌握这种规定的话，直接通过文本读取就可以获取坐标信息了，另外一种格式是二进制格式，这个就没法用记事本打开了，不过肯定也是按某种规定编码的。 [post cid=\u0026ldquo;185\u0026rdquo; /]\n参考 VTK中获取STL模型点的坐标以及对其进行变换 从文件读取STL数据 Python配置VTK库\n","date":"2020-06-13T16:03:00Z","permalink":"https://kizx.github.io/post/python%E8%AF%BB%E5%8F%96stl%E6%A8%A1%E5%9E%8B%E5%B9%B6%E8%8E%B7%E5%8F%96%E7%82%B9%E5%9D%90%E6%A0%87%E5%80%BC/","title":"Python读取stl模型并获取点坐标值"},{"content":"前面已经用Visual Studio成功运行了OpenGL了，但是VS的界面比较丑，而且代码提示和补全等各方面不够人性化（主要是我不习惯），相比之下，JB家的CLion虽然运行上慢一点，bug多一点，配置麻烦一点（喂！这缺点太多了吧），但是为了颜值和流畅的编程体验，用一下也不是不可以。\n配置 安装什么的就不说了，新建一个项目，Clion会自动生成一个CMakeLists.txt和main.cpp，点击运行没毛病，那就进入opengl的环境配置。 我这里用的是glut库，别的库参照着配置问题应该不大。在vs里我们是通过右键项目属性设置“三大件”的，但CLion是通过cmake来管理编译和链接的，只能通过手写CMakelists来进行配置。其实配置思路都差不多，手写配置还可以更清晰。 以下是CMakeLists.txt内容：\ncmake_minimum_required(VERSION 3.16) project(gl_demo) set(CMAKE_CXX_STANDARD 14) include_directories(C:/dev/glut/include) # 添加include头文件目录 link_directories(C:/dev//glut/lib) # 添加lib库目录 add_executable(gl_demo main.cpp) target_link_libraries(gl_demo glut32.lib opengl32.lib) # 添加链接的具体lib项 以下是demo\n// Lines.c // OpenGL SuperBible, Chapter 4 // Demonstrates primitive GL_LINES // Program by Richard S. Wright Jr. #include \u0026lt;gl/glut.h\u0026gt; #include \u0026lt;math.h\u0026gt; // Define a constant for the value of PI #define GL_PI 3.1415f // Rotation amounts static GLfloat xRot = 0.0f; static GLfloat yRot = 0.0f; // Called to draw scene void RenderScene(void) { GLfloat x, y, z, angle; // Storage for coordinates and angles // Clear the window with current clearing color glClear(GL_COLOR_BUFFER_BIT); // Save matrix state and do the rotation glPushMatrix(); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); // Call only once for all remaining points glBegin(GL_LINES); z = 0.0f; for (angle = 0.0f; angle \u0026lt;= GL_PI * 3.0f; angle += 0.5f) { // Top half of the circle x = 50.0f * cos(angle); y = 50.0f * sin(angle); glVertex3f(x, y, z); // Bottom half of the circle x = 50.0f * cos(angle + 3.1415f); y = 50.0f * sin(angle + 3.1415f); glVertex3f(x, y, z); } // Done drawing points glEnd(); // Restore transformations glPopMatrix(); // Flush drawing commands glutSwapBuffers(); } // This function does any needed initialization on the rendering void SetupRC() { // Black background glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set drawing color to green glColor3f(0.0f, 1.0f, 0.0f); } void SpecialKeys(int key, int x, int y) { if (key == GLUT_KEY_UP) xRot -= 5.0f; if (key == GLUT_KEY_DOWN) xRot += 5.0f; if (key == GLUT_KEY_LEFT) yRot -= 5.0f; if (key == GLUT_KEY_RIGHT) yRot += 5.0f; if (key \u0026gt; 356.0f) xRot = 0.0f; if (key \u0026lt; -1.0f) xRot = 355.0f; if (key \u0026gt; 356.0f) yRot = 0.0f; if (key \u0026lt; -1.0f) yRot = 355.0f; // Refresh the Window glutPostRedisplay(); } void KeyPressFunc(unsigned char key, int x, int y) { if (key == 32) xRot -= 5.0f; if (key == 97) xRot += 5.0f; if (key == 98) yRot -= 5.0f; if (key == 99) yRot += 5.0f; if (key \u0026gt; 356.0f) xRot = 0.0f; if (key \u0026lt; -1.0f) xRot = 355.0f; if (key \u0026gt; 356.0f) yRot = 0.0f; if (key \u0026lt; -1.0f) yRot = 355.0f; // Refresh the Window glutPostRedisplay(); } void ChangeSize(int w, int h) { GLfloat nRange = 100.0f; // Prevent a divide by zero if (h == 0) h = 1; // Set Viewport to window dimensions glViewport(0, 0, w, h); // Reset coordinate system glMatrixMode(GL_PROJECTION); glLoadIdentity(); // Establish clipping volume (left, right, bottom, top, near, far) if (w \u0026lt;= h) glOrtho(-nRange, nRange, -nRange * h / w, nRange * h / w, -nRange, nRange); else glOrtho(-nRange * w / h, nRange * w / h, -nRange, nRange, -nRange, nRange); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } int main(int argc, char *argv[]) { GLsizei h = 500; GLsizei w = 500; GLsizei x = 200, y = 100; glutInit(\u0026amp;argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(h, w); glutInitWindowPosition(x, y); glutCreateWindow(\u0026#34;Lines Example\u0026#34;); glutDisplayFunc(RenderScene); glutReshapeFunc(ChangeSize); glutSpecialFunc(SpecialKeys); glutKeyboardFunc(KeyPressFunc); SetupRC(); glutMainLoop(); return 0; } ","date":"2020-06-04T13:31:51Z","permalink":"https://kizx.github.io/post/clion%E7%BC%96%E8%AF%91%E8%BF%90%E8%A1%8Copengl%E9%A1%B9%E7%9B%AE/","title":"CLion编译运行OpenGL项目"},{"content":"python的opengl库叫PyOpenGL，安装这个库的时候要注意位数版本要正确，比如我的python37是32位的，安装PyOpenGL-3.1.5-cp37-cp37m-win32.whl才行，默认pip安装的运行时可能会有问题，所以需要手动下载安装对应版本的whl。\ndemo 这是一个直接运行的demo\n# !/usr/bin/python # -*- coding: utf-8 -*- # ------------------------------------------- # quidam_01.py 三维空间的世界坐标系和三角形 # ------------------------------------------- from OpenGL.GL import * from OpenGL.GLUT import * def draw(): # --------------------------------------------------------------- glBegin(GL_LINES) # 开始绘制线段（世界坐标系） # 以红色绘制x轴 glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明 glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点（x轴负方向） glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点（x轴正方向） # 以绿色绘制y轴 glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明 glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点（y轴负方向） glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点（y轴正方向） # 以蓝色绘制z轴 glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明 glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点（z轴负方向） glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点（z轴正方向） glEnd() # 结束绘制线段 # --------------------------------------------------------------- glBegin(GL_TRIANGLES) # 开始绘制三角形（z轴负半区） glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明 glVertex3f(-0.5, -0.366, -0.5) # 设置三角形顶点 glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明 glVertex3f(0.5, -0.366, -0.5) # 设置三角形顶点 glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明 glVertex3f(0.0, 0.5, -0.5) # 设置三角形顶点 glEnd() # 结束绘制三角形 # --------------------------------------------------------------- glFlush() # 清空缓冲区，将指令送往硬件立即执行 if __name__ == \u0026#34;__main__\u0026#34;: glutInit() # 1. 初始化glut库 glutCreateWindow(\u0026#39;Quidam Of OpenGL\u0026#39;) # 2. 创建glut窗口 glutDisplayFunc(draw) # 3. 注册回调函数draw() glutMainLoop() # 4. 进入glut主循环 pyqtopengl 这是pyqt中QOpenGLWidget的demo\n# !/usr/bin/python # -*- coding: utf-8 -*- from PySide2.QtWidgets import * from OpenGL.GL import * from OpenGL.GLUT import * class MyOpenglWidget(QOpenGLWidget): def __init__(self, parent=None): super().__init__(parent) def initializeGL(self): pass def paintGL(self): glBegin(GL_LINES) # 开始绘制线段（世界坐标系） # 以红色绘制x轴 glColor4f(1.0, 0.0, 0.0, 1.0) # 设置当前颜色为红色不透明 glVertex3f(-0.8, 0.0, 0.0) # 设置x轴顶点（x轴负方向） glVertex3f(0.8, 0.0, 0.0) # 设置x轴顶点（x轴正方向） # 以绿色绘制y轴 glColor4f(0.0, 1.0, 0.0, 1.0) # 设置当前颜色为绿色不透明 glVertex3f(0.0, -0.8, 0.0) # 设置y轴顶点（y轴负方向） glVertex3f(0.0, 0.8, 0.0) # 设置y轴顶点（y轴正方向） # 以蓝色绘制z轴 glColor4f(0.0, 0.0, 1.0, 1.0) # 设置当前颜色为蓝色不透明 glVertex3f(0.0, 0.0, -0.8) # 设置z轴顶点（z轴负方向） glVertex3f(0.0, 0.0, 0.8) # 设置z轴顶点（z轴正方向） glEnd() # 结束绘制线段 pass def resizeGL(self, w, h): pass 参考 https://blog.csdn.net/xufive/article/details/86565130 https://doc.qt.io/qtforpython/PySide2/QtWidgets/QOpenGLWidget.html?highlight=qopenglwidget\n","date":"2020-06-02T15:10:00Z","permalink":"https://kizx.github.io/post/python%E8%BF%90%E8%A1%8Copengl%E7%A4%BA%E4%BE%8B/","title":"Python运行OpenGL示例"},{"content":"glut/freeglut是opengl的一个封装库，虽然现在一般都是用glfw了，但一些教材和课堂上仍旧采用glut库，没办法，那就来配置一下吧。其中glut比较古老，而且好像闭源且早已不再维护了，其官网首页也直接推荐到freeglut库。freeglut是glut的开源版，且一直有人维护。 glut官网：https://www.opengl.org/resources/libraries/glut/ freeglut官网下载：https://www.transmissionzero.co.uk/software/freeglut-devel/\nps:其实网上也有不少教程，但那些教程都是直接把下载好的库复制到系统文件夹和VS文件夹下，这种做法实在不优雅，更正常的做法应该是在VS的工程里进行属性配置才对。\nfreeglut配置 从上面的官网点击Download freeglut 3.0.0 for MSVC下载二进制库下载解压到一个你喜欢的目录。 然后配置三大件： 添加include头文件 添加lib目录 添加lib项，其中opengl32.lib不添加好像也行，我是配置glfw时看要加上，所以这里顺手也加上了。 ps：如果是vs2019，include和lib位置放到这里也可以 如果此时运行会报无法找到dll的错误，将C:\\dev\\freeglut\\bin的目录添加到系统Path变量下就行了(添加后工程得重启才能生效) 测试代码：\n#include \u0026lt;GL/glut.h\u0026gt; void Show() { glClear(GL_COLOR_BUFFER_BIT); glRectf(-0.5f, -0.5f, 0.5f, 0.5f); glFlush(); } int main(int argc, char* argv[]) { glutInit(\u0026amp;argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE); glutInitWindowPosition(100, 100); glutInitWindowSize(500, 500); glutCreateWindow(\u0026#34;OpenGL-窗口\u0026#34;); glutDisplayFunc(Show); glutMainLoop(); return 0; } 官方的Hello-GLUT测试代码：https://github.com/TransmissionZero/Hello-GLUT 建议自己复制粘贴这些代码运行\nglut配置 如果非要用glut也不是不行，官方下载地址：https://www.opengl.org/resources/libraries/glut/glut_downloads.php#windows 选择Download the GLUT 3.6 headers and pre-compiled libraries: glutdlls36.zip下载应该就可以。 下载解压后就5个文件和一个readme，这怎么用？网上的教程都是分别塞到系统目录和VS安装目录下的，这里我觉得可以像上面freeglut一样进行配置，手动将这5个文件安排成和freeglut相似的目录结构：新建三个bin,include/GL,lib目录然后将5个文件一一放进去，将bin的目录添加到系统path环境变量。 然后后面在VS里的设置就和上面freeglut一样了，只需要将相应名称改一下就行了，测试代码也是一样的。\n","date":"2020-06-01T08:17:00Z","permalink":"https://kizx.github.io/post/visual-studio%E9%85%8D%E7%BD%AEglutfreeglut%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/","title":"Visual Studio配置glut/freeglut开发环境"},{"content":"要说到VS(C/C++)最麻烦的地方就是各种环境，各种库配置来配置去，因此将配置好的工程设置保存下来，以备下次新建工程时直接引用很有必要。\n方法 切到属性管理器窗口，右键选择添加一个新的属性表。 比如我们新建一个名为opengl的属性表，然后打开任一个文件，右键点击opengl选择属性。 然后就是对项目属性进行配置。 另外在配置时选择所有配置和所有平台可以避免各种模式都要配一遍的烦恼。 当新建一个工程时只需要在同样的地方添加现有属性表即可。\n","date":"2020-05-31T15:44:00Z","permalink":"https://kizx.github.io/post/visual-studio%E4%BF%9D%E5%AD%98%E5%B7%A5%E7%A8%8B%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/","title":"Visual Studio保存工程环境配置"},{"content":"基于glfw和glew进行开发配置。\n下载安装库 下载32位glfw二进制包：https://www.glfw.org/download.html 下载glew二进制包：http://glew.sourceforge.net/ 上面的两个包下载解压到一个固定目录。\nVS2019配置 添加include目录 添加lib目录 添加附加依赖项 运行测试 生成一个窗口\n#define GLEW_STATIC #include \u0026lt;GL/glew.h\u0026gt; #include \u0026lt;GLFW/glfw3.h\u0026gt; #include \u0026lt;iostream\u0026gt; void processInput(GLFWwindow* window) { if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) { glfwSetWindowShouldClose(window, true); } } int main() { glfwInit(); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(800,600,\u0026#34;First Window\u0026#34;,NULL,NULL); if (window == NULL) { std::cout \u0026lt;\u0026lt; \u0026#34;Failed to create GLFW window\u0026#34; \u0026lt;\u0026lt; std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glewExperimental = true; if (glewInit() != GLEW_OK) { std::cout \u0026lt;\u0026lt; \u0026#34;Failed\u0026#34; \u0026lt;\u0026lt; std::endl; glfwTerminate(); return -1; } glViewport(0, 0, 800, 600); while (!glfwWindowShouldClose(window)) { processInput(window); glClearColor(0, 0.5f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glfwSwapBuffers(window); glfwPollEvents(); } glfwTerminate(); return 0; } 参考 https://www.bilibili.com/video/BV11W411N7b9\n","date":"2020-05-31T04:57:00Z","permalink":"https://kizx.github.io/post/opengl%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/","title":"OPENGL环境配置"},{"content":"CGAL是一个C++计算几何算法库，官方安装说明：https://doc.cgal.org/latest/Manual/windows.html 我的配置是win10+vs2019，已安装有CMake。 [button color=\u0026ldquo;success\u0026rdquo; icon=\u0026ldquo;fa fa-download\u0026rdquo; url=\u0026ldquo;https://pan.2bboy.com/Public/Software/CGAL/\u0026rdquo; type=\u0026quot;\u0026quot;]我用到的所有安装文件[/button]\n下载安装boost CGAL依赖于boost库，因此需要先安装boost，二进制boost下载地址：https://sourceforge.net/projects/boost/files/boost-binaries/ 根据官网说明选择1.17.0版本即可，然后下载具体版本根据vs版本和位数来选择，14.0对应VC2015，14.1对应VC2017，14.2对应VC2019，因此我选择boost_1_71_0-msvc-14.2-64.exe下载即可。 下载解压到硬盘，比如解压到C:\\dev\\目录下，然后设置环境变量。\nBOOST_LIBRARYDIR = C:\\dev\\libboost_1_71_0\\lib64-msvc-XX.Y BOOST_INCLUDEDIR = C:\\dev\\libboost_1_71_0 最后将C:\\dev\\libboost_1_71_0\\lib64-msvc-XX.Y添加到系统环境变量PATH中。\n自己编译 如果不直接下载二进制文件，自己来编译也是可以的（我刚开始就这么干的(ー_ー)!!） 下载解压boost源文件：https://sourceforge.net/projects/boost/files/boost-binaries/ 解压过程比较慢，解压后得到一堆文件，运行解压目录下的bootstrap.bat文件进行编译。 第一次运行会报下面的错误：\n\u0026#39;cl\u0026#39; 不是内部或外部命令，也不是可运行的程序或批处理文件。 解决方法是将C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.26.28801\\bin\\Hostx64\\x64添加到系统变量，然后运行vs的命令行工具x64 Native Tools Command Prompt for VS 2019(用系统的命令行会报错)，这个命令行不能直接cd切到另一个盘符下，需要先输入d:切换盘符才行。 然后cd d:\\boost\\boost_1_66_0切换到文件目录，输入bootstrap.bat运行，然后目录下就会生成几个文件，其中有个b2.exe，直接运行会报错。 解决方法是打开project-config.jam，修改为\nimport option ; using msvc : 16.0 : \u0026#34;C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.26.28801\\bin\\Hostx64\\x64\\c1.exe\u0026#34;; option.set keep-going : false ; 然后输入b2.exe --with-system --with-thread进行编译，不带后面参数会编译所有库，相当费时间，只编译需要的库就好。 编译好的lib库在\u0026quot;/stage/lib\u0026quot;下，将根目录和lib目录添加到系统变量。\n下载安装CGAL 从github上下载CGAL-5.0.2-Setup.exe：https://github.com/CGAL/cgal/releases 点击安装，安装到最后应该会有一个弹窗提醒手动设置环境变量，那就将C:\\dev\\CGAL-5.0.2\\auxiliary\\gmp\\lib添加到环境变量PATH中。\n其他可选依赖 Qt 下载地址：https://www.qt.io/offline-installers 或 http://download.qt.io/official_releases/ 安装时勾选MSVC2017的编译器和Qt Script(有些demo可能会用到)，如果硬盘够大的话，把下面几个Qt都勾了也没什么不好。如果现在不勾选，后面再想安装就会很麻烦，具体方法可以自行百度。 完成后添加QTDIR的系统变量，路径为根目录C:\\Qt\\Qt5.12.8，然后添加之前勾选的编译器系统坏境路径C:\\Qt\\Qt5.12.8\\5.12.8\\msvc2017_64\\bin到PATH中。\nEigen 下载地址：http://eigen.tuxfamily.org/index.php?title=Main_Page\nCmake编译运行 然后我们按照官网上的说明进入examples\\Triangulation_2目录，新建一个build文件夹，然后启动Cmake，设置源文件夹和输出文件夹，如果用下面的命令行启动的话会自动设置好。\nC:\\dev\\CGAL-5.0.2\u0026gt; cd examples\\Triangulation_2 C:\\dev\\CGAL-5.0.2\\examples\\Triangulation_2\u0026gt; mkdir build C:\\dev\\CGAL-5.0.2\\examples\\Triangulation_2\u0026gt; cd build C:\\dev\\CGAL-5.0.2\\examples\\Triangulation_2\\build\u0026gt; cmake-gui .. 点击左下角Configure进行配置，一般要点两次。 继续点击Generate。 生成成功的话在build目录下会生成Triangulation_2_Examples.sln文件，点击打开或者点击Open Project也可以直接打开，在vs里生成不报错应该就没问题。 但是直接点击(ctrl)F5会报错无法启动程序，那是因为当前项目是CMake自动生成的ALL_BUILD，需要将别的项目切换为当前项目（不会用vs的我被这个给坑了好久。。。） 官网上面是一个编译了一个三角剖分Triangulation的example，运行起来没有什么意思。 其实我们可以对CGAL里的任何一个demo或者example进行编译，当然也可以对整个CGAL文件夹或demo/examples文件夹进行编译，只要文件夹下有CMakeLists.txt文件就能被CMake编译，不过整个编译文件夹容易出错，因为包含了更多的库，可能这些库我们并没有装全，而且全部编译后的工程文件太大对电脑性能要求也更高。 下面是编译demo文件夹后，运行P4HDT2的界面。 参考 https://blog.csdn.net/u013094443/article/details/51106015 https://blog.csdn.net/s_lisheng/article/details/72871218 https://zhuanlan.zhihu.com/p/99814130\n","date":"2020-05-25T18:11:00Z","permalink":"https://kizx.github.io/post/windows%E7%BC%96%E8%AF%91%E5%AE%89%E8%A3%85cgal/","title":"Windows编译安装CGAL"},{"content":"OneManager是什么 这是一个利用微软onedrive api将onedrive目录映射成一个云盘的程序，类似的程序有很多，比如OneIndex、Pyone、OnePoint等等。这个程序的特点是支持多种onedrive类型，可以部署在vps，heroku，以及腾讯云scf上。 [button color=\u0026ldquo;info\u0026rdquo; icon=\u0026quot;\u0026quot; url=\u0026ldquo;https://github.com/qkqpttgf/OneManager-php\u0026rdquo; type=\u0026quot;\u0026quot;]项目地址[/button] [button color=\u0026ldquo;info\u0026rdquo; icon=\u0026quot;\u0026quot; url=\u0026ldquo;https://pan.2bboy.com/\u0026rdquo; type=\u0026quot;\u0026quot;]我的Demo[/button]\n部署教程 参考项目readme说明，网上一些博客也有不少教程，这不是本文的重点，本文主要讲的是部署好后的设置问题。 部署成功后在设置-\u0026gt;首页里添加相应的盘，可以添加多个盘，同一个盘也可以添加多次。\n平台变量 登录后，在管理\u0026gt;设置里有一些自定义设置，有些人不清楚这些设置是干嘛的，这可以理解，毕竟项目的说明写的太简单了。 注意本文的操作都是针对程序默认主题来说的，其他主题由于是第三方人员开发，不保证所有功能都能正常使用。\nadminloginpage 自定义登录地址，设置后就会隐藏登录按钮(有些主题本来就没有登录按钮)，登录时需要手动在网盘地址后加上?你设置的值进行登录。 比如设置为abc，那么你只能通过http://xxx.com/xxx?abc地址来登录 。所以一旦设置就要记住你设置的值，不然连你自己也没法知道登录地址那就麻烦了。 这个设置是为了防止别人通过默认的登录界面尝试登录你的网盘，设置本项后只要猜不到登录界面，即使别人知道登录密码也没用，多一道防护墙，让网盘更安全。\nautoJumpFirstDisk 设置点击网盘标题时跳转到绑定的第一个盘还是当前绑定的网盘根目录。\nbackground 自定义背景图片，填入一个图片的url地址，因为图片加载通常需要更多时间，为了速度考虑不建议放入大体积图片。\nbackgroundm 手机端显示的背景图片地址。\ncustomCss 设置自定义css的地方，这里设置的css会作用于网盘所有页面。 比如我想隐藏语言选项框：\n\u0026lt;style\u0026gt;.changelanguage{display:none}\u0026lt;/style\u0026gt; 同时隐藏复制下载链接按钮\n\u0026lt;style\u0026gt;.file button{display:none}.changelanguage{display:none}\u0026lt;/style\u0026gt; customScript 设置自定义js，会作用于所有页面。 比如设置http重定向到https：\n\u0026lt;script type=\u0026#34;text/javascript\u0026#34;\u0026gt; var targetProtocol = \u0026#34;https:\u0026#34;; if (window.location.protocol != targetProtocol) window.location.href = targetProtocol + window.location.href.substring(window.location.protocol.length); \u0026lt;/script\u0026gt; customTheme 通过url的方式引用html主题，比如你可以通过设置下面的地址来使用我的主题。\nhttps://cdn.jsdelivr.net/gh/kizx/onemoe-theme/onemoe.html disableChangeTheme 设置为1后游客浏览时将不显示右下角的主题切换功能。\ndisableShowThumb 设置为1后将不显示缩略图的按钮和功能，对于云函数用户来说，建议设为1来关闭该功能，因为该功能可能点一下就是一分钱。\nhideFunctionalityFile 设置为1后，游客浏览网盘时就会看不到read.md，head.md，head.ofm，foo.omf这些文件，这些文件是干嘛的后面会说。\npassfile 设置密码文件名，比如这里设置为password.txt，那么在某一个目录下新建一个password.txt文件，其中写入密码，这样任何人在浏览这个网盘目录时都需要输入相应密码后才能访问。\nsitename 设置网站名称。\ntheme 切换主题。\ntimezone 设置时区，国内可设置为8。\n每个盘独立变量 diskname 多盘在网盘界面显示的名称。\ndomain_path 当绑定多个域名时，可以使不同域名打开时访问不同目录。当然如果你只有一个域名也可以用，通过这种方式可以使当前域名访问一个指定子目录，和后面的public_path起到一样的作用。 下面是两个域名的设置方法，中间用|隔开，如果有多个域名只设置一个域名时，未设置的域名好像也会只访问该目录，要访问根目录dirname设置为/。\ndomain1.com:/dir1name|domain2.com:/dir2name downloadencrypt 设置为1时启用该功能，这样在设置了密码的目录下的文件虽然无法在网页端浏览，但可以通过具体的文件链接进行下载。\nguestup_path 设置图床路径或者叫游客上传路径，设置后游客只能看到上传按钮看不到目录下的文件。\npublic_path 设置该盘的显示的根目录，默认为/，换个说法就是可以显示指定的文件夹，默认显示全部。 比如我们只想将网盘下的public文件夹内容作为网盘，可以设置为/public/。 有了这个功能，即使只有一个onedrive账号，我们也可以通过重复绑定同一个账号来生成多盘，然后每个盘的public_path设置为不同的路径，这样可以将一个盘的功能分开。\n还有一种特殊情况是我既想让游客上传文件，又想让游客看见上传后的文件目录，目前就只能通过这种方法将该目录设置到两个盘，一个盘作上传，一个盘作目录展示。\n进阶设置 设置网站ico图标 将favicon.ico图片放在网盘根目录下，如果你设置了多盘的的话，则需要在每个盘的根目录下都放置一个favicon.ico文件，新版的html主题只需要在绑定的第一个盘下面设置就行了。 当然你也可以在customCss或customScript中进行全局设置：\n\u0026lt;link rel=\u0026#34;icon\u0026#34; href=\u0026#34;https://cloud.tencent.com/favicon.ico\u0026#34; type=\u0026#34;image/x-icon\u0026#34;\u0026gt; 这里我使用了腾讯云的网站图标，你应该改为自己的favicon.ico图片地址。 刷新自动切换背景图片 这个是通过设置特殊的图片api来实现的，这些api每次刷新都会返回一张不同的图片，将后台background设置为这些api的url即可。 网上类似的api有很多，以下是群友收集的免费图片api：\nhttps://api.ixiaowai.cn/api/api.php (二次元动漫) http://www.dmoe.cc/random.php（二次元随机图） https://api.ixiaowai.cn/mcapi/mcapi.php （menhera酱） https://api.ixiaowai.cn/gqapi/gqapi.php （风景） https://acg.yanwz.cn/wallpaper/api.php（二次元随机图） 利用index.html设置自定义页面 如果一个目录下有名为index.html的文件，则直接显示该文件，可以利用这个功能设置一个自定义页面或者用于隐藏一个特定页面，相当于部署了一个静态页面。\n设置顶部和底部说明文字 在需要展示顶部说明的目录下新建一个head.md文件，在文件里写入说明内容即可，这是一个markdown文件，可以使用markdown语言进行书写。 底部说明说明文字对应的是readme.md文件，规则与顶部文字一样。\n利用head.omf设置一言 head.omf作用和head.md一样，区别是他不支持markdonw语言，但是支持html语言，可以写入html、css、js内容。 在想展示一言的目录新建head.omf文件，然后写入以下内容：\n\u0026lt;p id=\u0026#34;hitokoto\u0026#34;\u0026gt;:D 获取中...\u0026lt;/p\u0026gt; \u0026lt;script\u0026gt; fetch(\u0026#39;https://v1.hitokoto.cn\u0026#39;) .then(response =\u0026gt; response.json()) .then(data =\u0026gt; { const hitokoto = document.getElementById(\u0026#39;hitokoto\u0026#39;) hitokoto.innerText = data.hitokoto }) .catch(console.error) \u0026lt;/script\u0026gt; 以上是使用了https://developer.hitokoto.cn/ 的一言接口，你也可以尝试更换其他接口或者自建接口。\n利用foot.omf设置Valine评论 使用Valine需要先注册LeanCloud并实名认证，然后新建应用获取AppID和AppKey。 具体过程参考：https://valine.js.org/quickstart.html 然后新建foot.omf，写入以下内容（注意填入替换自己的AppID和AppKey）：\n\u0026lt;script src=\u0026#39;//unpkg.com/valine/dist/Valine.min.js\u0026#39;\u0026gt;\u0026lt;/script\u0026gt; \u0026lt;div id=\u0026#34;vcomments\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; new Valine({ el: \u0026#39;#vcomments\u0026#39;, appId: \u0026#39;你获取的AppID\u0026#39;, appKey: \u0026#39;你获取的AppKey\u0026#39; }) \u0026lt;/script\u0026gt; ps: 上面的js用的是unpkg的cdn，国内速度完全不行，建议改用jsdelivr的cdn\n\u0026lt;script src=\u0026#39;//cdn.jsdelivr.net/npm/valine/dist/Valine.min.js\u0026#39;\u0026gt;\u0026lt;/script\u0026gt; 展示Demo见：https://pan.2bboy.com/home/\n如果对样式不满意，建议直接在omf文件写css美化。 设置动态背景 这里的动态背景指我们经常在一些网页见到的那种下雪、粒子线条、彩条等动态背景，一般是通过js实现的，可以自己在网上找找现成的教程，js我不会，这里只展示一种我找到的动态彩条背景。 我将下面的代码写在了foot.omf中，可以访问 https://pan.2bboy.com/home/test/colored-ribbon/ 查看其效果。\n\u0026lt;script size=\u0026#34;90\u0026#34; alpha=\u0026#34;0.5\u0026#34; zIndex=\u0026#34;0\u0026#34; src=\u0026#34;https://pan.2bboy.com/ppx/test/ribbon.js\u0026#34; type=\u0026#34;text/javascript\u0026#34; charset=\u0026#34;utf-8\u0026#34;\u0026gt;\u0026lt;/script\u0026gt; 其中最重要的是 ribbon.js 这个js文件，我将他放在网盘目录下，你应该下载该文件放在自己的云空间里，然后替换引用的地址。 如果将代码放在omf文件里则只能在当前目录有效果，设置在后台的customScript中就可以全局生效了。\n当然只要你懂点js，利用omf文件可以玩出很多东西，比我这里有一些示例：https://pan.2bboy.com/home/test/\n美化自定义登录页面 修改common.php相应地方，添加style和br\n$html .= \u0026#39; \u0026lt;style\u0026gt;body{background-image:linear-gradient(60deg,#343b44 0%,#485563 100%);background-attachment:fixed;color:#343b44}body\u0026gt;div{position:absolute;text-align:center;background-color:rgba(221,221,221,.5);border-radius:20px;width:75vw;max-width:500px;height:350px;margin:auto;top:25%;bottom:50%;left:0;right:0}body\u0026gt;div:hover{box-shadow:3px 3px 6px 3px rgba(0,0,0,.3)}h4{font-size:40px}input{font-size:20px;margin:2%auto;border:#343b44 2px solid;border-radius:10px;padding:10px;height:50px;text-align:center}input:last-of-type{color:#343b44;height:50px;width:80px;font-weight:800}input:hover:last-of-type{cursor:pointer;color:#ddd;background-color:#485563}\u0026lt;/style\u0026gt; \u0026lt;body\u0026gt; \u0026lt;div\u0026gt; \u0026lt;center\u0026gt;\u0026lt;h4\u0026gt;\u0026#39;.getconstStr(\u0026#39;InputPassword\u0026#39;).\u0026#39;\u0026lt;/h4\u0026gt; \u0026lt;form action=\u0026#34;\u0026#34; method=\u0026#34;post\u0026#34;\u0026gt; \u0026lt;div\u0026gt; \u0026lt;input name=\u0026#34;password1\u0026#34; type=\u0026#34;password\u0026#34;/\u0026gt; \u0026lt;/br\u0026gt; \u0026lt;input type=\u0026#34;submit\u0026#34; value=\u0026#34;\u0026#39;.getconstStr(\u0026#39;Login\u0026#39;).\u0026#39;\u0026#34;\u0026gt; \u0026lt;/div\u0026gt; \u0026lt;/form\u0026gt; \u0026lt;/center\u0026gt; \u0026lt;/div\u0026gt; \u0026#39;; 提示 游客上传文件时只能单个上传，不能批量上传。 由于scf的缓存系统，在scf上进行某项改动后有时候不会立马生效，或者刷新后时而生效时而不生效，只要多等一会儿，等旧缓存自己失效就好了。 php格式的主题为旧版主题，许多功能不支持，html格式的主题为新版主题，不同主题的作者更新频率和支持功能都可能不同，功能测试请以最新版本的默认主题为准。 ","date":"2020-05-24T08:06:00Z","permalink":"https://kizx.github.io/post/onedrive%E4%BA%91%E7%9B%98%E7%A8%8B%E5%BA%8Fonemanager%E5%B0%8F%E7%99%BD%E8%AE%BE%E7%BD%AE%E6%8C%87%E5%8D%97/","title":"Onedrive云盘程序——OneManager小白设置指南"},{"content":"百度统计平台：https://tongji.baidu.com/web/28991244/welcome/login\n其实对于个人网站来说，统计功能也就是看个乐，不过说实话百度的统计功能至少看起来还不错。\n使用方法：在管理页面找到代码获取，handsome主题在后台将获取到的代码粘贴到自定义head里就行了，反正就是放在网站所有页面的head标签前，获取代码的地方有安装方式和检测是否安装成功的按钮。\n而且百度统计还有高级统计代码，针对一些特别站点的特别功能，我是用不上也不会用啦。 小应用功能 在应用功能里可以看到一些应用功能，这才是百度统计有趣的地方。 置顶工具 开通后会在网站右下角出现一个返回顶部的按钮，当然大部分主题基本都有这个功能了，不过不失为一种添加返回顶部按钮的方法 地图名片 开通后会在网站右下角出现，但我试了由于包含非https请求地图没显示出来，不过这功能感觉一般人也用不到。 反馈工具 添加后在网站右下角添加一个建议反馈的功能，这个功能经常能在一些文档页面能看到，感觉还是很不错的，但是我试了收不到邮件(╯°A°)╯︵○○○。 专题推送 类似公告功能，可以推送一个指定页面或一张二维码，如果有微信公众号的话挂个二维码在这里不错。\n百度推荐 应该是一个类似随机文章推荐的功能，可以像弹窗广告一样弹出来，看起来很有意思不过我没开通成功。φ(￣?￣o)\n百度搜索 这是一个由百度提供的网站页面搜索工具：https://ziyuan.baidu.com/cse/wiki/index?category_id=17 可以在网站页面提供一个搜索框，搜索框可以是浮动的，也可以是嵌入页面的，点击搜索后会跳转到一个类似百度搜索的页面，这些页面都是可以进行一定自定义的，使用起来很方便，如果你的网站还没有搜索功能的话，用这个也不是不可以，很多论坛的搜索功能就和这个有点像。 不过默认生成的链接包含http链接，https站点需要想办法将中间的链接替换下。 ","date":"2020-05-21T06:13:00Z","permalink":"https://kizx.github.io/post/%E4%BD%BF%E7%94%A8%E7%99%BE%E5%BA%A6%E7%BB%9F%E8%AE%A1%E5%92%8C%E7%99%BE%E5%BA%A6%E6%90%9C%E7%B4%A2%E4%B8%BA%E7%BD%91%E7%AB%99%E5%A2%9E%E5%8A%A0%E5%B0%8F%E5%8A%9F%E8%83%BD/","title":"使用百度统计和百度搜索为网站增加小功能"},{"content":"[post cid=\u0026ldquo;159\u0026rdquo; /] 我之前需要对一个QLineEdit控件实现文件拖拽的功能，在折腾一番后发现只有继承QLineEdit类重写方法才能实现我的功能，但我是用动态加载ui文件的方法，所以没办法直接加载我写的自定义控件，当时是用把原控件删除了再把自己的控件加进去的野蛮方法，但后来我看了黑羽的新教程才知道Qt设计师里右键有个提升控件功能就是专门解决这个问题的。\nclass MainWindow(QObject): def __init__(self): super().__init__() self.ui = QUiLoader().load(\u0026#39;static/mainwindow.ui\u0026#39;) self.ui.file_path.deleteLater() # 删除原有的路径框 self.ui.file_path = MyQLine() # 新建自己的替换原有的 self.ui.file_path.setPlaceholderText(\u0026#39;浏览或拖拽SRT字幕文件到这里\u0026#39;) self.ui.horizontalLayout_2.addWidget(self.ui.file_path) self.ui.horizontalLayout_2.addWidget(self.ui.file) ... 方法 先新建一个MyWidget.py文件用于写自定义控件。\nfrom PySide2.QtWidgets import QLineEdit class MyQLine(QLineEdit): \u0026#34;\u0026#34;\u0026#34;实现文件拖放功能\u0026#34;\u0026#34;\u0026#34; def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) def dragEnterEvent(self, e): if e.mimeData().text().endswith(\u0026#39;.srt\u0026#39;): # 这里只接受拖入srt文件，别的文件拖入无效 e.accept() else: e.ignore() def dropEvent(self, e): path = e.mimeData().text().replace(\u0026#39;file:///\u0026#39;, \u0026#39;\u0026#39;) self.setText(path) 先在Qt设计师里右键提升控件，提升控件的基类一般就是控件自身本来的类，提升的类名称就是自定义的类名称，头文件是指自定义的类所在的库的名称。如果搞不清这里，可以将ui文件转为py文件，然后查看import部分就明白了。 这里就要注意了，这个提升的类名的路径是基于我们ui文件而言的，所以我这里ui文件必须和MyWidget.py在同一目录下，而且必须保证这里不能有报错，比如我之前在自定义MyQLine时没有传入parent参数就会报错。\n然后就是在主程序里加载界面就行了，如果用的是Pyside2还需要加一步注册\nclass MainWindow(QObject): def __init__(self): super().__init__() loader = QUiLoader() loader.registerCustomWidget(MyQLine) # 注册 self.ui = loader.load(\u0026#39;mainwindow.ui\u0026#39;) ··· 参考 http://www.python3.vip/tut/py/gui/pyqtgraph-2/ https://blog.csdn.net/qq937772489/article/details/81332037\n","date":"2020-05-12T16:43:00Z","permalink":"https://kizx.github.io/post/pyqt%E6%8F%90%E5%8D%87%E6%8E%A7%E4%BB%B6%E4%B8%BA%E8%87%AA%E5%AE%9A%E4%B9%89%E6%8E%A7%E4%BB%B6%E7%9A%84%E6%96%B9%E6%B3%95%E5%8A%A8%E6%80%81%E5%8A%A0%E8%BD%BDui%E6%96%87%E4%BB%B6/","title":"Pyqt提升控件为自定义控件的方法(动态加载ui文件)"},{"content":"现有近似分布在球面上的点云，试进行球面拟合，求出球心坐标和半径。\n解 球面方程为： $$ (x-x_0)^{2}+(y-y_0)^{2}+(z-z_0)^{2}=r^{2} $$ 其中 $ x_0, y_0, z_0, r $是我们要求的参数。\n利用求偏导的方式求最小值 构造方程： $$ E(x_0,y_0,z_0,r)=\\sum_{i=0}^n((x-x_0)^2+(y-y_0)^2+(z-z_0)^2-r^2)^2 $$ 使方程 $E$ 值最小的参数 $x_0, y_0, z_0, r$ 就是我们的所求。 求偏导并使其等于0： $$ \\frac{\\partial E}{\\partial x_0}=-4\\sum_{i=0}^n(x_i-x_0)((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\frac{\\partial E}{\\partial y_0}=-4\\sum_{i=0}^n(x_i-y_0)((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\frac{\\partial E}{\\partial z_0}=-4\\sum_{i=0}^n(z_i-z_0)((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\frac{\\partial E}{\\partial r}=-4\\sum_{i=0}^nr((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$\n化简得： $$ \\sum_{i=0}^nx_i((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\sum_{i=0}^ny_i((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\sum_{i=0}^nz_i((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$ $$ \\sum_{i=0}^n((x_i-x_0)^2+(y_i-y_0)^2+(z_i-z_0)^2-r^2)=0 $$\n整理得： $$ \\frac{\\overline{x^3}}{\\overline{x}}-2x_0\\frac{\\overline{x^2}}{\\overline{x}}+x_0^2+\\frac{\\overline{xy^2}}{\\overline{x}}-2y_0\\frac{\\overline{xy}}{\\overline{x}}+y_0^2+\\frac{\\overline{xz^2}}{\\overline{x}}-2z_0\\frac{\\overline{xz}}{\\overline{x}}+z_0^2=r^2 \\tag{1} $$ $$ \\frac{\\overline{xy^2}}{\\overline{y}}-2x_0\\frac{\\overline{xy}}{\\overline{y}}+x_0^2+\\frac{\\overline{y^3}}{\\overline{y}}-2y_0\\frac{\\overline{y^2}}{\\overline{y}}+y_0^2+\\frac{\\overline{yz^2}}{\\overline{y}}-2z_0\\frac{\\overline{yz}}{\\overline{y}}+z_0^2=r^2\\tag{2} $$ $$ \\frac{\\overline{x^2z}}{\\overline{z}}-2x_0\\frac{\\overline{xz}}{\\overline{z}}+x_0^2+\\frac{\\overline{y^2z}}{\\overline{z}}-2y_0\\frac{\\overline{yz}}{\\overline{z}}+y_0^2+\\frac{\\overline{z^3}}{\\overline{x}}-2z_0\\frac{\\overline{yz}}{\\overline{z}}+z_0^2=r^2\\tag{3} $$ $$ \\overline{x^2}-2x_0\\overline{x}+x_0^2+\\overline{y^2}-2y_0\\overline{y}+y_0^2+\\overline{z^2}-2z_0\\overline{z}+z_0^2=r^2\\tag{4} $$\n分别减去 (4) 式最终可以得到如下线性方程组：\n$$ \\begin{bmatrix} \\overline{x^2}-\\bar{x}^2 \u0026amp; \\overline{xy}-\\bar{x}\\cdot \\bar{y} \u0026amp; \\overline{xz}-\\bar{x}\\bar{z} \\ \\overline{xy}-\\bar{x}\\bar{y} \u0026amp; \\overline{y^2}-\\bar{y}^2 \u0026amp; \\overline{yz}-\\bar{y}\\bar{z} \\ \\overline{xz}-\\bar{x}\\bar{z} \u0026amp; \\overline{yz}-\\bar{y}\\bar{z} \u0026amp; \\overline{z^2}-\\bar{z}^2 \\ \\end{bmatrix} \\begin{bmatrix} x_0\\ y_0\\ z_0\\ \\end{bmatrix}=\\frac{1}{2} \\begin{bmatrix} (\\overline{x^3}-\\bar{x}\\overline{x^2})+(\\overline{x y^2}-\\bar{x}\\overline{y^2})+(\\overline{xz^2}-\\bar{x}\\overline{z^2}) \\ (\\overline{x^2y}-\\overline{x^2}\\bar{y})+(\\overline{y^3}-\\bar{y}\\overline{y^2})+(\\overline{yz^2}-\\bar{y}\\overline{z^2}) \\ (\\overline{x^2z}-\\overline{x^2}\\bar{z})+(\\overline{zy^2}-\\bar{z}*\\overline{y^2})+(\\overline{z^3}-\\bar{z} * \\overline{z^2})\\ \\end{bmatrix} $$\n解此线性方程组即可得到坐标 $(x_0, y_0, z_0)$，再代回 (4) 式求出 $r$ 即可。\n利用法方程求解矩阵 也可以直接对球面的方程进行拟合，每一个点云坐标对应一个方程，方程数显然大于未知数，可以利用最小二乘法进行求解出一个最小值。\n将方程稍微化简可得： $$ 2ax+2by+2cz+r^2-(a^2+b^2+c^2)=x^2+y^2+z^2 $$\n将每一个点坐标代入得到一个 $n\\times4$ 的矩阵 A： $$ \\begin{bmatrix} x_1\u0026amp;y_1\u0026amp;z_1\u0026amp;1\\ x_2\u0026amp;y_2\u0026amp;z_2\u0026amp;1\\ \\vdots\u0026amp;\\vdots\u0026amp;\\vdots\u0026amp;\\vdots\\ x_n\u0026amp;y_n\u0026amp;z_n\u0026amp;1\\ \\end{bmatrix}\\begin{bmatrix}2a\\2b\\2c\\r^2-(a^2+b^2+c^2)\\end{bmatrix}= \\begin{bmatrix}x_1^2+y_1^2+z_1^2\\\\vdots\\x_n^2+y_n^2+z_n^2\\end{bmatrix} $$ 方程两边同时左乘以 $A^T$ 可以得到和第一种方法一样的方程，或者直接用公式 $x=(A^TA)^{-1}A^Tb$ 进行求解，这两种方法在本质上是完全一样的。\npython实现 针对第一种方法的具体代码\nimport numpy as np points = np.array(coor) # coor为点云坐标的列表 points = points.astype(np.float64) # 防止溢出 num_points = points.shape[0] print(num_points) x = points[:, 0] y = points[:, 1] z = points[:, 2] x_avr = sum(x) / num_points y_avr = sum(y) / num_points z_avr = sum(z) / num_points xx_avr = sum(x * x) / num_points yy_avr = sum(y * y) / num_points zz_avr = sum(z * z) / num_points xy_avr = sum(x * y) / num_points xz_avr = sum(x * z) / num_points yz_avr = sum(y * z) / num_points xxx_avr = sum(x * x * x) / num_points xxy_avr = sum(x * x * y) / num_points xxz_avr = sum(x * x * z) / num_points xyy_avr = sum(x * y * y) / num_points xzz_avr = sum(x * z * z) / num_points yyy_avr = sum(y * y * y) / num_points yyz_avr = sum(y * y * z) / num_points yzz_avr = sum(y * z * z) / num_points zzz_avr = sum(z * z * z) / num_points A = np.array([[xx_avr - x_avr * x_avr, xy_avr - x_avr * y_avr, xz_avr - x_avr * z_avr], [xy_avr - x_avr * y_avr, yy_avr - y_avr * y_avr, yz_avr - y_avr * z_avr], [xz_avr - x_avr * z_avr, yz_avr - y_avr * z_avr, zz_avr - z_avr * z_avr]]) b = np.array([xxx_avr - x_avr * xx_avr + xyy_avr - x_avr * yy_avr + xzz_avr - x_avr * zz_avr, xxy_avr - y_avr * xx_avr + yyy_avr - y_avr * yy_avr + yzz_avr - y_avr * zz_avr, xxz_avr - z_avr * xx_avr + yyz_avr - z_avr * yy_avr + zzz_avr - z_avr * zz_avr]) # print(A, b) b = b / 2 center = np.linalg.solve(A, b) x0 = center[0] y0 = center[1] z0 = center[2] r2 = xx_avr - 2 * x0 * x_avr + x0 * x0 + yy_avr - 2 * y0 * y_avr + y0 * y0 + zz_avr - 2 * z0 * z_avr + z0 * z0 r = r2 ** 0.5 print(center, r) 参考 https://blog.csdn.net/sunshine_zoe/article/details/78852978 https://blog.csdn.net/liyuanbhu/article/details/80201371 https://blog.csdn.net/woniu199166/article/details/79459807?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1\u0026depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1\n","date":"2020-04-29T04:44:00Z","permalink":"https://kizx.github.io/post/%E7%82%B9%E4%BA%91%E7%90%83%E9%9D%A2%E6%9C%80%E5%B0%8F%E4%BA%8C%E4%B9%98%E6%8B%9F%E5%90%88%E7%9A%84python%E5%AE%9E%E7%8E%B0/","title":"点云球面最小二乘拟合的python实现"},{"content":"前几天我接触了一个由2D图片生成3D视频的开源项目：https://github.com/vt-vl-lab/3d-photo-inpainting [post cid=\u0026ldquo;168\u0026rdquo; /] 当时是在谷歌的Colab平台上运行的，在线平台虽方便，但是连接性不好，时断时续的体验差。最蛋疼的是运行环境不能被保存，第二天想用就得从头安装环境，相当耽误时间。于是我就试了本地部署该项目，虽然官方给出的Linux上的部署教程，但我又不是程序员，懒得整一套Linux系统了，就仿照着在Windows上部署了一下，结果是完全可行的。\n前提 电脑已安装Anaconda 电脑GPU支持cuda加速并安装相应版本cuda驱动 [post cid=\u0026ldquo;146\u0026rdquo; /]\n步骤 打开Anaconda控制台新建一个环境 conda create -n 3DP python=3.7 anaconda conda activate 3DP 下载项目和模型 git clone git@github.com:vt-vl-lab/3d-photo-inpainting.git 手动下载这里面的4个模型并放置在相应文件夹：https://github.com/vt-vl-lab/3d-photo-inpainting/blob/master/download.sh [scode type=\u0026ldquo;blue\u0026rdquo;]这一步我下好并打包放在一起了：https://pan.2bboy.com/Public/Software/www/3d-photo-inpainting.zip[/scode]\n下载依赖库 cd 3d-photo-inpainting pip install -r requirements.txt conda install pytorch==1.4.0 torchvision==0.5.0 cudatoolkit==10.1.243 -c pytorch 下载速度感人请试着换源或代理 [post cid=\u0026ldquo;163\u0026rdquo; /]\n将jpg格式的图片放在image目录下，运行命令 python main.py --config argument.yml 更多设置 项目默认运行的参数都写在了argument.yml文件中，这里面的参数意义参考：https://github.com/vt-vl-lab/3d-photo-inpainting/blob/master/DOCUMENTATION.md 这里面参数可以控制输出视频大小和镜头运动等，具体设置就自己探索吧。\n","date":"2020-04-27T12:12:00Z","permalink":"https://kizx.github.io/post/windows%E6%9C%AC%E5%9C%B0%E9%83%A8%E7%BD%B23d-photo-inpainting%E9%A1%B9%E7%9B%AE/","title":"Windows本地部署3d-photo-inpainting项目"},{"content":"偶然在 果壳的推送 中看到这个项目：https://shihmengli.github.io/3D-Photo-Inpainting/ 感觉很有意思，可以将一张普通的2D照片经过处理得到一张具有深度空间的3D照片，准确点来说这应该叫2.5D比较像。应该是基于Pytorch训练出来的模型，官网展示的效果都相当惊艳。 官网展示的都是现实中照片，下面我试着对动漫图片进行处理，看看能不能得到一个“3D老婆”。\n实践 官网拉到下面的Links，开发者提供了github链接和Golab链接，github链接的文档有详细的本地部署说明，用的是Anaconda部署的。 这里我笔记本不便于运行这种大项目，好在它直接提供了Golab的demo，只要你有一个谷歌账号或者说是gmail邮箱，然后能上得了人家的Colab网站，直接点击官网的Demo或者下面的链接就可以在线部署运行了。 https://colab.research.google.com/drive/1706ToQrkIZshRSJSHvZ1RuCiM__YX3Bz 先点击切换到playgrand模式，当然你也可以继续点击复制到云端硬盘来创建属于你的副本。 然后按顺序一路点击运行即可，中间需要的只有漫长的等待。运行前可以先看下它遗留的那一长串运行结果，我们命令执行完成后会得到与之相同的输出结果，如果哪一句运行失败继续点击重新运行直至成功。 运行下面这一句上传一张原始jpg图片，上传的图片会放在左边image目录下，上传前最好清空image目录下的图片防止后面一步读取到错误的图片。 有时候由于连接性问题会上传不上去，这时候可以试试手动上传然后将图片拖动到image目录下。 最后一步生成3D深度图片，这里也需要等待。。。 生成的可视化视频在video目录下，每次程序会生成四个不同角度的的视频，双击可下载到本地。 视频演示 B站上面部分图片打了码，下面是原视频。 [vplayer url=\u0026ldquo;https://pan.2bboy.com/img/video/3dpic_p2.mp4\u0026rdquo; /]\n后记 [post cid=\u0026ldquo;170\u0026rdquo; /]\n","date":"2020-04-22T11:16:00Z","permalink":"https://kizx.github.io/post/%E5%88%A9%E7%94%A8%E5%88%86%E5%B1%82%E6%B7%B1%E5%BA%A6%E4%BF%AE%E8%A1%A5%E6%8A%80%E6%9C%AF%E5%B0%862d%E5%9B%BE%E7%89%873d%E5%8C%96/","title":"利用分层深度修补技术将2D图片3D化"},{"content":"通常我们如果想要搭建一个API服务，最起码都需要一个服务器，但是即使是最便宜的虚拟主机价格也不一定便宜，而且就算你会用自己的语言写API接口，服务器的响应环境配置也是相当麻烦。而利用云函数则完美避开了这些坑，腾讯云函数的免费额度个人用的话基本等于免费。关于云函数的使用我之前也略微了解过，下面就用Python搭建一个简单的一言API接口来实际操作下。 [post cid=\u0026ldquo;143\u0026rdquo; /]\n搭建过程 首先新建函数，这里我选择python3.6环境 函数创建完成后，去触发方式里添加一个触发方式，这里要保持默认不勾选集成响应，因为我们返回的不是网页 触发方式创建后会生成一个链接，这个链接就是我们的API接口，现在点击这个链接应该会返回\u0026quot;Hello World\u0026quot; 下面我们开始写我们自己的函数，如果你看了官方文档会本地部署的话，比如用vscode云函数插件，可以用插件把当前项目下载到本地，不会本地的话直接在网页上操作也是可以的。 新建一个yiyan.py和yiyan.txt\nimport random def yiyan(): with open(\u0026#34;yiyan.txt\u0026#34;, \u0026#39;r\u0026#39;, encoding=\u0026#39;utf-8\u0026#39;) as f: lines = f.readlines() line = random.sample(lines, 1)[0] line = line.strip() return line if __name__ == \u0026#34;__main__\u0026#34;: print(yiyan()) yiyan.txt里写入所有一言语句，比如我写的燕双鹰语录\n你太情绪化，也不大冷静，不习惯用大脑思考问题。 在行动面前，语言永远是苍白无力的。 老子是你祖宗！ 我说过，你们会付出十倍的代价！ 为什么总有人觉得自己能够杀得了我？ 恐吓是最低级的手段，是外强中干的表现。 你通常都会把自己爱的人，引进伏击圈吗？说实话，这种表达爱情的方式太与众不同，也太令人毛骨悚然了你的心！ 不要再大喊大叫了，心疼心疼自己可怜的肺吧！ 你喜欢死吗？ 不要做个破坏气场的人，这样会受到自然的惩罚。 我会让你看到自己的脑浆。 回答我！ 我总是很快。 谁要低估女人的能力，一定吃大亏！ 要站在敌人的背后，让敌人变成睁眼瞎。 能够让你轻易背叛的，绝不是你真正的信仰。 即使你拿枪对准了我的后背，我也可以在一秒钟之内让你看到自己的脑浆。 你没听到我说的话吗？ 我赌你的枪里没有子弹。 谁要是低估女人的能力，一定会吃大亏！ 手段并不能说明什么，只有目的才能分得出正义和邪恶。 小心背后啊。 一个善良的人，不管他的信仰是什么，也不管他是不是有信仰，至少会做出善良的事情。 不要制造自己解决不了的麻烦，也不要许下无法兑现的诺言。 自信总不是坏事，只要不是盲目的。 意志并不是空穴来风，想有就有，那里面闪烁着正义和人性的光芒。 不要用枪指着我的头，否则你会看到自己的脑浆！ 这一点已经不重要了。 别让我再说第二遍。 你的眼睛会欺骗你，你的直觉会误导你，只有心才是最可靠的！ 你信不信，我可以在一秒钟内让你看到自己的脑浆！ 你只需要知道，我所知道的比你们知道的要多得多！ 你已经死了，死人能杀人吗？ 你真的不会讲故事！ 这种死法，真的是很惨。 我有个习惯，会杀死向自己开枪的人，哪怕他的枪里没有子弹。 速度不是靠双臂和力量达到的，而是靠心。 我的枪口再低半寸，你们就会看到自己老大的脑浆！ 这种试探才可怕是在拿自己弟兄的生命开玩笑，这种不信任更加可怕很难想象今后你我双方能够精诚合作。 你相信自己的眼睛吗？有时眼睛会欺骗你。 像你这样的人要怎么改变，嗯？你不会改变，只有死！ 休息是养精蓄锐，睡觉则是懒惰松散！ 然后重写index.py\n# -*- coding: utf8 -*- import logging from yiyan import yiyan logger = logging.getLogger() def main_handler(event, context): result = yiyan() logger.info(result) return result 上传部署或者点击完成后，点击测试或者打开前面生成的API链接，应该就可以返回一言了 自定义域名 这个默认链接太长了，我们可以自定义域名。回到上面的触发方式那里，点击这个服务名 点击自定义域名，然后点击新建 根据页面提示自行添加域名解析，如果选择https的话，还需要自行添加证书，建议在腾讯云申请证书，这样就不用再添加一遍证书密钥什么的了，最后别忘了自定义路径映射，否则访问链接都得带/release/样的后缀 现在我们访问[域名]/[云函数的名称]（比如http://api.2bboy.com/api）就能访问到你的一言啦！ 如果你不想要后面这个云函数的名称或者想换一个，还是那个服务界面，选择管理API，点击编辑就能自定义后缀了，修改后按照提示下一步然后重新发布就行了，现在就能通过http://api.2bboy.com/访问了 ","date":"2020-04-16T14:11:00Z","permalink":"https://kizx.github.io/post/%E5%88%A9%E7%94%A8%E8%85%BE%E8%AE%AF%E4%BA%91scf%E5%85%8D%E8%B4%B9%E6%90%AD%E5%BB%BA%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%80%E8%A8%80api%E6%8E%A5%E5%8F%A3/","title":"利用腾讯云SCF免费搭建自己的一言API接口"},{"content":"这个参数有以下三个值。 对于一个单独的布局的label来说，两者参数的表现并无不同，但是当我的图片放置在一个网格布局中时，Pyside2的参数设置为KeepAspectRatio和Pyqt5参数设置为KeepAspectRatioByExpanding表现是一样的，很是奇怪。 以下是Pyqt5的显示结果。 准确点来说是Pyqt5的参数在这里显示有点不对劲，具体原因有待研究。\n参考 https://doc.qt.io/qtforpython/PySide2/QtGui/QPixmap.html?highlight=qpixmap#PySide2.QtGui.PySide2.QtGui.QPixmap.scaled https://doc.qt.io/archives/qtjambi-4.5.2_01/com/trolltech/qt/core/Qt.AspectRatioMode.html\n","date":"2020-04-13T16:23:00Z","permalink":"https://kizx.github.io/post/qpixmap.scaled%E5%9C%A8pyside2%E5%92%8Cpyqt5%E4%B8%AD%E7%9A%84%E4%B8%8D%E5%90%8C/","title":"QPixmap.scaled在Pyside2和Pyqt5中的不同"},{"content":"注意我这里主界面ui文件是一个QWidget，不是一个QMainWindow，QMainWindow的稍有不同。\n动态加载 动态加载不用将ui文件转换为py文件，边改界面就能边用，很是方便，适合绝大多数情况，这种方法唯一的缺点大概就是编程时控件不能进行自动补全，因为IDE没法知道控件继承自哪里。 [tabs] [tab name=\u0026ldquo;Pyside2的加载方法\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;]\nfrom PySide2.QtWidgets import QApplication from PySide2.QtUiTools import QUiLoader class Window: def __init__(self): self.ui = QUiLoader().load(\u0026#39;view.ui\u0026#39;) # 假设我们的ui文件为view.ui app = QApplication([]) window = Window() window.ui.show() app.exec_() 官网教程:https://doc.qt.io/qtforpython/tutorials/basictutorial/uifiles.html [/tab] [tab name=\u0026ldquo;Pyqt5的加载方法\u0026rdquo;]\nfrom PyQt5.QtWidgets import QApplication from PyQt5 import uic class Window: def __init__(self): self.ui = uic.loadUi(\u0026#34;view.ui\u0026#34;) app = QApplication([]) window = Window() window.ui.show() app.exec_() [/tab] [/tabs]\n静态加载 就是先用uic工具将ui文件转换成py文件，然后再导入ui文件，每次ui文件更新都需要重新转换一次。适合需要对控件功能进行重写的场合，一句话就是辅助手写ui而已，另一个在用pyinstaller打包时这样应该能减小打包后的体积，因为转换出来的py文件默认from PySide2.QtWidgets import *，直接导入了所有包，如果按需导入的话应该可以减小一点体积，不过经我测试只减小了1M不到的体积，意义不大。 [tabs] [tab name=\u0026ldquo;Pyside2的加载方法\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;]\nfrom PySide2.QtWidgets import QApplication, QWidget from view import Ui_Form import sys class Window(QWidget): # 这里继承QWidget,因为我的ui主界面是Widget,官网上这点不一样 def __init__(self): super().__init__() self.ui = Ui_Form() self.ui.setupUi(self) if __name__ == \u0026#34;__main__\u0026#34;: app = QApplication([]) window = Window() window.show() # 这里不是self.ui app.exec_() [/tab] [tab name=\u0026ldquo;Pyqt5的加载方法\u0026rdquo;] 和前面类似，注意要用Pyqt5的uic工具进行转换才行，因为生成的py文件自动导入的包名不一样。 [/tab] [/tabs]\n总结 动态加载不能进行代码自动补全，打包时ui文件也必须一同打包；静态加载每次手动转换麻烦了点，但转换后因为有了明确的代码可以自动补全代码，进行一些高级编程时有问题也可以更好的debug。 所以我觉得最好先用动态加载的方法把界面先搞定，然后写代码时再切到静态加载方法。\n","date":"2020-04-13T15:55:00Z","permalink":"https://kizx.github.io/post/pyqt%E5%8A%A0%E8%BD%BDui%E6%96%87%E4%BB%B6%E7%95%8C%E9%9D%A2%E7%9A%84%E6%96%B9%E6%B3%95/","title":"Pyqt加载ui文件界面的方法"},{"content":"与 pip设置pypi源 不同，conda需要设置的源是anaconda的源，annaconda的国内镜像目前好像只有清华。科大那个现在直接重定向转到清华，已经不能用了。\n设置 与pip设置pypi源类似，conda可以在windows用户目录下创建一个.condarc文件，然后写入以下内容即可。\nssl_verify: true channels: - defaults show_channel_urls: true channel_alias: https://mirrors.tuna.tsinghua.edu.cn/anaconda default_channels: - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/pro - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2 custom_channels: conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud msys2: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud bioconda: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud menpo: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud simpleitk: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud 如果无法创建这个文件，可以使用以下命令创建。\nconda config --set show_channel_urls yes 如果命令行一个个添加源也是可以的。\nconda config --add channels 源地址 参考 https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ http://mirrors.ustc.edu.cn/help/anaconda.html\n","date":"2020-04-07T08:59:00Z","permalink":"https://kizx.github.io/post/conda%E8%AE%BE%E7%BD%AE%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F%E6%BA%90/","title":"conda设置国内镜像源"},{"content":"Python处理json文件很简单，只需要import json即可，所需要掌握的函数也只有以下四个。 json.dumps(obj)：将python数据类型转化为str类型 json.dump(obj,fp)：将python数据写入文件fp中\nimport json dic = {\u0026#39;a\u0026#39;: \u0026#39;aa\u0026#39;, \u0026#39;b\u0026#39;: \u0026#39;bb\u0026#39;, \u0026#39;c\u0026#39;: {\u0026#39;c1\u0026#39;: \u0026#39;cc\u0026#39;, \u0026#39;c2\u0026#39;: \u0026#39;cc\u0026#39;}} with open(\u0026#39;config.json\u0026#39;, \u0026#39;w\u0026#39;) as f: # 先转换成字符串再写入 config = json.dumps(dic) f.write(config) # 直接写入 json.dump(dic, f) 为了美观，我们一般加上参数config = json.dumps(dic, indent=4)，首行缩进4个字符。\njson.load(fp)：从json文件中读取数据 json.loas(str)：将str类型转换为python数据类型\n# 一般是下面这种用法 with open(\u0026#39;config.json\u0026#39;, \u0026#39;r\u0026#39;) as f: config = json.load(f) # 这种很少用 config = json.loads(json.dumps(dic)) 注意事项 有时候我们需要读取一个json文件，文件必须确保先被创建\nif not os.path.exists(\u0026#39;config.json\u0026#39;): with open(\u0026#39;config.json\u0026#39;, \u0026#39;w\u0026#39;) as f: f.write(\u0026#39;{}\u0026#39;) # 写入一个空字典，确保后面读取后不会出错 对配置进行改动后再保存，需要先清空配置文件\nwith open(\u0026#39;config.json\u0026#39;, \u0026#39;r+\u0026#39;) as f: # 这里只能用\u0026#39;r+\u0026#39;模式打开 config = json.load(f) # 读取json文件 config.pop(\u0026#39;c\u0026#39;) # 剔除参数 # 不加下面两句就会在文件末尾继续续写 f.seek(0) # 指针移到文件头 f.truncate() # 清空文件 json.dump(config, f, indent=2) # 写入新配置 或者采用下面的分开读取和写入的方法\nwith open(\u0026#39;config.json\u0026#39;, \u0026#39;r\u0026#39;) as f: config = json.load(f) # 读取json文件 config.pop(\u0026#39;c\u0026#39;) # 剔除参数 with open(\u0026#39;config.json\u0026#39;, \u0026#39;w\u0026#39;) as f: # \u0026#39;w\u0026#39;模式打开文件默认先清空 json.dump(config, f, indent=2) # 写入新配置 ","date":"2020-03-27T11:00:00Z","permalink":"https://kizx.github.io/post/python%E5%A4%84%E7%90%86%E5%92%8C%E4%BF%9D%E5%AD%98json%E6%96%87%E4%BB%B6%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9/","title":"Python处理和保存json文件注意事项"},{"content":"文件拖放自动填充路径操作本应该是个很简单的操作，结果搜到的教程都在讲控件的拖拽，几经折磨后终于算是实现了这个功能吧。\n操作 首先，要知道pyqt的控件有个setAcceptDrops(bool)方法可以设置控件是否接受拖放这个动作，如果是用qt设计师设计的界面可以看到该属性是默认打开的，既然默认打开，那么理论就应该可以实现文件拖放功能。 但实际操作时我却发现在IDE里可以拖放，但是到了实际的桌面却无法拖放，这一点我真是无法理解啊。。 因此我只好去看了一些拖拽的教程，发现在重写一个新的QLineEdit类的情况下是可以使用的，重写的类如下：\nclass MyQLine(QLineEdit): \u0026#34;\u0026#34;\u0026#34;实现文件拖放功能\u0026#34;\u0026#34;\u0026#34; def __init__(self): super().__init__() self.setAcceptDrops(True) # 设置接受拖放动作 def dragEnterEvent(self, e): if e.mimeData().text().endswith(\u0026#39;.srt\u0026#39;): # 如果是.srt结尾的路径接受 e.accept() else: e.ignore() def dropEvent(self, e): # 放下文件后的动作 path = e.mimeData().text().replace(\u0026#39;file:///\u0026#39;, \u0026#39;\u0026#39;) # 删除多余开头 self.setText(path) 最关键的是e.mimeData().text()获取路径，这里的mimeData()可以参考官方说明 https://doc.qt.io/qtforpython/PySide2/QtCore/QMimeData.html。 在上面的动图里能看到拖放文件后获得的文件路径是以\u0026rsquo;file:///\u0026lsquo;开头的，所以需要去掉这玩意，剩下的应该很简单了。\n还有一个问题就是我是用qt设计师设计界面然后动态导入的，我自己新建了一个单行文本控件后，哪怕控件名字和之前的名字一样，最后生成的界面里还是会出现两个文本框，但我又不想在qt设计师里删除原来的文本框。所以我只好来个移花接木，把原来的文本框删掉并替换成我自己的。\nself.ui.file_path.deleteLater() # 删除原有的路径框 self.ui.file_path = MyQLine() # 新建自己的替换原有的 self.ui.file_path.setPlaceholderText(\u0026#39;浏览或拖拽SRT字幕文件到这里\u0026#39;) self.ui.horizontalLayout_2.addWidget(self.ui.file_path) self.ui.horizontalLayout_2.addWidget(self.ui.file) 针对上面的问题我后来找到了解决方案。 [post cid=\u0026ldquo;173\u0026rdquo; /]\n","date":"2020-03-21T14:11:00Z","permalink":"https://kizx.github.io/post/pyqt%E5%AE%9E%E7%8E%B0%E6%96%87%E4%BB%B6%E6%8B%96%E6%94%BE%E8%8E%B7%E5%8F%96%E8%B7%AF%E5%BE%84/","title":"pyqt实现文件拖放获取路径"},{"content":"因为平时看图较多（不是那种图），所以一款好的看图软件显得很重要，我以连续查看4K大图作为测试手段，主要从速度、颜值、功能、便捷几个角度来评判。\nHoneyView 我一直在用的看图软件，速度超级快，毫无卡顿，颜值在线，鼠标键位可以自由设置，右键有几个简单画面增强效果很好用，可以幻灯片播放，可以查看预览这点很棒。 唯一缺点是放大锁定后无法锁定住当前位置。\n万能看图王 看这名字和2345那个流氓有点像，实际页面也很像，但既然下载了就测试下。底部有预览窗，颜值也还好。 缺点首先疑似会有广告，因为设置里有关闭广告的选项，至于流不流氓就不知道了。速度超级慢，光凭这一点就可以卸载了，放大锁定后不能锁定区域。\n看图啦 同样是国产的一个软件，感觉也和上面那个有点像，但速度稍快一点，不过也仍然很慢，可以左右同时查看两张图这点是唯一亮点。 操作不是很方便，感觉是bug，图片缩放锁定功能虽然有但也是坏的，总之不推荐。\nXnView 很多人推荐的软件，刚打开是一个文件浏览器的亚子，一看就知道功能很丰富，速度较快，但没有HoneyView快，有局部裁剪功能，也有划定一个区域然后放大的功能，放大后能固定放大比和区域，同时拥有许多调节画面的功能，完全可以当作一个简易PS用。 缺点大概就是没有HoneyView快，然后那个浏览器界面复杂了点，把颜值一下拉低了，总体来说还是很推荐的。\nIranfanView 一个英文界面的软件，和上面的软件风格有点像，像是上面软件的精简版，有划定区域放大的功能，速度很快，和HoneyView差不多。 缺点是无法锁定放大区域，颜值也不是很高，英文界面让我懒得看设置了(虽然好像有中文语言包)，不设置的话可以说体验不太好。\nJPEGView 一款小巧的软件，速度很快，毫无卡顿，有许多增强图片的功能，并且能保持参数，当然也能保持锁定放大比和放大区域。 缺点是找不到设置快捷键的地方，只有一个配置文件，仔细找找应该有设置快捷键的地方。界面过于简陋，颜值差点。 不在意颜值的话，这些增强功能真的很棒，而且可以保持参数这点太棒了。\nACDSee 官方免费版有广告，使用前还需要注册，打开一看就知道更偏向于图片管理软件，只是兼带图片查看功能而已，速度一般，功能似乎很多但懒得看了。 免费版带广告这点就劝退了，偏向于管理图片而非单纯的图片查看。\nFastStone Image Viewer 和上面的XnView有点类似，颜值稍高一点，可以批量处理图片，没有缩放锁定。\nImageGlass 颜值不错，但速度太慢，不考虑。\nPictus 非常小巧的一款软件，只有5M大小，所以功能没有很多，速度一般，适合追求极简的用户。\nFastPictureViewer 左键按住显示原始大小，右键按住显示三倍大小，这个设定倒是很有趣，速度较慢，不支持tif格式。\n","date":"2020-03-17T07:11:00Z","permalink":"https://kizx.github.io/post/%E5%87%A0%E6%AC%BE%E7%9C%8B%E5%9B%BE%E8%BD%AF%E4%BB%B6%E6%B5%8B%E8%AF%84/","title":"几款看图软件测评"},{"content":"Kite是一款基于深度学习的代码自动补全的应用，其特点就是智能化，人性化，不仅代码补全更智能，还贴心的自动为你搜索方法文档和使用案例，甚至可以使面向谷歌编程变成面向Kite编程。 介绍视频： https://www.youtube.com/watch?v=bF50YPyUKTQ\n使用 官网下载：https://kite.com/ 下载安装登录后会自动下载相关插件，然后打开你的IDE就可以用了。 更多详细说明可以参考帮助文档。\n参考 官方帮助文档： https://help.kite.com/\n后记 用了有一段时间了，说实话没感觉带来多大方便，不过当个函数手册查查参数也还行。\n","date":"2020-03-16T11:48:17Z","permalink":"https://kizx.github.io/post/kite%E8%AE%A9%E4%BB%A3%E7%A0%81%E8%A1%A5%E5%85%A8%E6%9B%B4%E6%99%BA%E8%83%BD/","title":"Kite——让代码补全更智能"},{"content":"开源镜像站 [scode type=\u0026ldquo;blue\u0026rdquo;]阿里镜像https://mirrors.aliyun.com/pypi/simple/[/scode]\n[scode type=\u0026ldquo;blue\u0026rdquo;]网易镜像https://mirrors.163.com/pypi/simple/[/scode]\n[scode type=\u0026ldquo;blue\u0026rdquo;]清华镜像https://pypi.tuna.tsinghua.edu.cn/simple[/scode]\n[scode type=\u0026ldquo;blue\u0026rdquo;]豆瓣镜像https://pypi.doubanio.com/simple/[/scode]\n临时使用 使用pip的时候在后面加上-i参数，指定pip源： pip install xxx -i 镜像地址\n一劳永逸 Linux/Unix中使用 ~/.pip/pip.conf 修改pip.conf\n[global] index-url = 镜像地址 Windows中使用 一句命令 pip config set global.index-url 镜像地址\n这句命令命令干了什么事呢，其实就是创建了一个pip.ini文件，我们也可以手动创建，在哪创建呢，我们输入 pip config list -v 得到如下输出\nD:\\admin\\Desktop\u0026gt;pip config list -v For variant \u0026#39;global\u0026#39;, will try loading \u0026#39;C:\\ProgramData\\pip\\pip.ini\u0026#39; For variant \u0026#39;user\u0026#39;, will try loading \u0026#39;C:\\Users\\admin\\pip\\pip.ini\u0026#39; For variant \u0026#39;user\u0026#39;, will try loading \u0026#39;C:\\Users\\admin\\AppData\\Roaming\\pip\\pip.ini\u0026#39; For variant \u0026#39;site\u0026#39;, will try loading \u0026#39;c:\\users\\admin\\appdata\\local\\programs\\python\\python37-32\\pip.ini\u0026#39; global.index-url=\u0026#39;https://mirrors.aliyun.com/pypi/simple/\u0026#39; install.trusted-host=\u0026#39;mirrors.aliyun.com\u0026#39; 可以看出pip安装时搜索pip.ini来源的路径以及搜索到的镜像源，所以我们只需向其中任一个路径创建一个pip文件夹，然后创建pip.ini文件就行了，可以看到前面的路径都是类似系统路径，最后一个路径是pip环境的路径，所以靠后的路径优先级是更高的，但一般我们只需在系统环境里设置一下就可以一劳永逸了，上面的一句命令行是向Roaming路径（也就是%APPDATA%路径）写入pip/pip.ini。 pip.ini里可以这样写\n[global] index-url = https://mirrors.aliyun.com/pypi/simple/ [install] trusted-host=mirrors.aliyun.com 下面的一句trusted-host是添加信任防止报错\n参考 http://mirrors.163.com/.help/pypi.html https://mirror.tuna.tsinghua.edu.cn/help/pypi/ https://developer.aliyun.com/mirror/pypi?spm=a2c6h.13651102.0.0.3e221b11kAuK9K https://pip.pypa.io/en/stable/user_guide/#config-file\n","date":"2020-03-11T12:14:00Z","permalink":"https://kizx.github.io/post/pip%E8%AE%BE%E7%BD%AEpypi%E5%9B%BD%E5%86%85%E9%95%9C%E5%83%8F/","title":"pip设置pypi国内镜像"},{"content":"python打包成exe程序的方法有不少，但最常用的还是pyinstaller，打包python程序主要是为了给那些不懂python的人用的，而且如果是像pyqt一类的图形界面程序，打包一下也会变得更易用。\n安装 建议被打包的程序都放在一个虚拟环境中，不论是用venv，pipenv还是conda都是可以的，然后在虚拟环境中安装pyinstaller。\npip install pyinstaller 使用 命令行进入虚拟环境，使用pyinstaller就是一条命令行的事，命令的格式如下： pyinstaller [选项] xxx.py 其中选项可以用命令 pyinstaller -h 查看，常用命令如下:\n选项 功能 -h, \u0026ndash;help 帮助 \u0026ndash;distpath DIR 生成exe程序的位置，默认在当前目录的dist文件下 \u0026ndash;workpath WORKPATH 生成临时文件的位置，默认在当前目录的build文件下 \u0026ndash;clean 清除生成的文件（重新生成前先清除） -D, \u0026ndash;onedir 打包成一个包含exe程序的文件夹 -F, \u0026ndash;onefile 打包成一个独立的exe程序（运行起来会慢很多） \u0026ndash;hidden-import MODULENAME 有些依赖包是动态导入的需手动导入告诉pyinstaller -d {all,imports,bootloader,noarchive} 生成debug版本 -w, \u0026ndash;windowed, \u0026ndash;noconsole 隐藏命令行窗口 -i \u0026lt;FILE.ico or FILE.exe,ID or FILE.icns\u0026gt; 为程序添加ico图标 -n NAME, \u0026ndash;name NAME 为exe程序指定名称，默认和py程序名一样 打包完成后会生成三个文件(夹)：build，dist，以及一个.spec文件，这个文件记录你的打包参数，可以直接在里面修改参数，然后执行以下命令直接打包，对于依赖复杂的程序这么做更方便，毕竟谁也不想每次打包都输那么长的命令行。 pyinstaller xxx.spec 至于spec文件具体怎么用参考官方文档。\n一些坑 打包pyqt程序 [scode type=\u0026ldquo;blue\u0026rdquo;] 虽然理论上程序打包很简单，但实际上可能会遇到各种问题，在打包pyqt程序时如果用的是动态导入ui文件，那么就得加上 --hidden-import PySide2.QtXml 并且把ui文件也一同放入exe文件夹内，因为程序并不会打包ui文件；如果程序用到了什么像图标，图片之类的静态文件，也需要都放到exe文件夹下。 [/scode]\n单个程序还是文件夹 [scode type=\u0026ldquo;blue\u0026rdquo;] 程序打包默认打包成一个文件夹，使用-F参数可以打包成一个单独的exe程序，但经测试，单独一个程序启动速度起码慢了10倍不止，所以建议还是默认文件夹方式，但文件夹太乱了怎么办，可以采取后面的方法整理一下。 另外我发现我的程序在打包成一个独立的exe的情况下，隐藏命令行窗口的话，程序中间有个命令无法正常运行，但是打包成文件夹就可以正常运行，由此可见打包成文件夹的容错率更大。 [/scode] [tabs] [tab name=\u0026ldquo;方法1. 利用runtime-hook参数\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;] 新建一个runtimehook.py文件：\nimport sys import os currentdir = os.path.dirname(sys.argv[0]) libdir = os.path.join(currentdir, \u0026#34;lib\u0026#34;) print(currentdir) sys.path.append(libdir) os.environ[\u0026#39;path\u0026#39;] += \u0026#39;;./lib\u0026#39; 然后打包时加上参数 --runtime-hook=\u0026quot;runtimehook.py\u0026quot; ，这样就可以把除了下面的几个文件外的库文件放到一个lib文件夹中了。\nbase_library.zip xxxx.exe xxxx.exe.manifest python37.dll 这个方法摘自白月黑羽，注意文件夹不能放到lib里。[/tab] [tab name=\u0026ldquo;方法2. 利用快捷方式\u0026rdquo;] 新建一个快捷方式或者符号链接，可以参照我另一篇文章。不过在自己电脑新建的快捷方式不能打包发给别人，因为绝对路径不一样，如果用符号链接的话在打成压缩包时会被打回原型。 所以我们可以仿照某些软件安装包的样子做一个自解压的压缩包，在解压软件安装时加上生成桌面快捷方式的选项。打包可以用一些打包工具（比如某些压缩工具就带这个功能），直接打包生成自解压的exe文件然后还带桌面快捷方式，这样显得更高大上。[/tab] [/tabs]\n隐藏命令行窗口 [scode type=\u0026ldquo;blue\u0026rdquo;]\n如果你是gui程序自然不希望出现命令行，那么加上-w参数就行了。 另外隐藏命令行的话，就无法查看报错信息，那么只能在程序里捕捉异常然后通过gui的方法把错误显示出来。但这种错误显示通常不能获取多少有用信息，只是给用户看的。 有时候程序隐藏了窗口，但运行时总有黑黑的命令行窗口不时的闪现出来，网上查找到的弹窗多半是因为程序中引用了os.system引起的，但其实任何可能调用命令行窗口的程序命令都有可能导致弹窗。 比如我的程序因为黑窗口闪现太快肉眼无法捕捉，为了看清这个窗口究竟是什么，我利用录屏一帧帧查看发现是ffmpeg.exe的窗口，好吧，我的程序的pydub库的确用到了它，但怎么让它消失呢，我找到了一篇参考文章。因为pydub库的源码是直接使用subprocess调用ffmpeg.exe和ffprobe.exe的，只需要在audio_segment.py和utils.py文件中调用subprocess.Popen()时指定参数 shell=True, stdin=subprocess.PIPE 即可。 [/scode] 参考 Pyinstaller文档：https://pyinstaller.readthedocs.io/en/stable/ 白月黑羽教Python：http://www.python3.vip/doc/tutorial/python/level2/gui/qt_04/\n","date":"2020-03-04T06:03:00Z","permalink":"https://kizx.github.io/post/pyinstaller%E6%89%93%E5%8C%85%E7%9A%84%E6%AD%A3%E7%A1%AE%E5%A7%BF%E5%8A%BF/","title":"Pyinstaller打包的正确姿势"},{"content":"假期刚看了一点css教程，就花了两个晚上给onedrive-OneManager重新写了个样式当作练手了，本来是想在原有的基础上做一点美化，但程序原样式都是内部样式，而且还有许多内联样式，改起来超级麻烦，所以干脆就从头开始重写了。\n下载地址 [scode type=\u0026ldquo;green\u0026rdquo;]下载地址[/scode]\n预览 [scode type=\u0026ldquo;green\u0026rdquo;]在线预览[/scode] 虽然本人的审美不咋地，但是原主题那个超大的圆角我已经忍了很久了┻━┻ ヘ╰( ??ε?? ╰)，主题的配色我不是很懂，你要是不喜欢反正在我css的基础上改起来也简单。\n使用说明 [tabs] [tab name=\u0026quot;旧版本\u0026quot;]\n简单点就是直接把下载的onemoe.php复制到theme文件夹下然后网站后台切换主题即可。 我的onemoe.php其实是在classic.php基础上改的，本着尽量不改动内部的原则（其实是我不会php,另一个是改动的越少主程序更新时就修改的越少），改动的地方是把head里所有内部样式删除，然后替换成下面这句。 \u0026lt;link rel=\u0026quot;stylesheet\u0026quot; href=\u0026quot;[onemoe.css的地址]\u0026quot; type=\u0026quot;text/css\u0026quot; /\u0026gt; 更新多盘后发现多了个div不好定位，无奈只好在内部加了两个onemoe的class，一个位于底部readme，一个位于多盘位置，另外删除了文件大小和时间两个标题的内联样式。所以如果你用这个主题出现什么问题，除了显示样式上的问题，其余的bug肯定与我无瓜。 现在我把onemoe.css文件放在我的网站上并提供了百度cdn加速，如果你想修改主题配色什么的，可以直接在我的css上进行修改，然后把你修改的css文件放在自己的onedrive目录或者别的cdn处，然后把上面的链接替换下就可以了，主题更新时同理也只需把新的css文件链接替换下就行。 [/tab] [tab name=\u0026ldquo;新版本\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;] 程序已内置本主题，后台切换主题即可使用。 或者可以手动下载onemoe.html放在程序theme文件夹下后台启用主题，以此来获取最新主题。 本主题只是基于classic主题的css重写，并未改动原主题任何主体内容。 css文件默认从 https://cdn.jsdelivr.net/gh/kizx/onemoe-theme/onemoe.min.css 加载，你也可以自行修改上述地址，改成自己的cdn地址。 \u0026lt;link rel=\u0026#34;stylesheet\u0026#34; href=\u0026#34;https://cdn.jsdelivr.net/gh/kizx/onemoe-theme/onemoe.min.css\u0026#34; type=\u0026#34;text/css\u0026#34; /\u0026gt; [/tab] [/tabs]\n更多关于OneManager的设置 [post cid=\u0026ldquo;176\u0026rdquo; /]\n","date":"2020-02-19T13:28:00Z","permalink":"https://kizx.github.io/post/onedrive-onemanager%E4%BA%91%E7%9B%98%E7%A8%8B%E5%BA%8Fonemoe%E4%B8%BB%E9%A2%98/","title":"OneDrive-OneManager云盘程序onemoe主题"},{"content":"Setting -\u0026gt; Plugins里搜索相应插件名即可，或者去网页 https://plugins.jetbrains.com/pycharm 搜索插件下载后本地安装亦可，唯一的问题可能就是网络连接性可能不太好。\n主题推荐 先说说主题设置，下好主题后在设置Appearance里切换主题。 设完主题后还可以设置代码样式，这两个是可以分开设置的，比如我主题是One Dark，代码样式是Atom One Dark。如果你不喜欢现有的代码配色风格，可以在Color Theme网站 下载喜欢的配色，然后在代码样式里导入即可。 另外字体也可以自定义，软件界面字体在settings-\u0026gt;appearance里修改。代码字体在settings-\u0026gt;editor-\u0026gt;font里（如果直接改这里没用，点上面有个感叹号那里，其实就是color scheme font里改）。 1. One Dark 主题地址 我最常用的主题，还有一个Atom One Dark的主题也不错。 2. Material Theme UI 主题地址 这大概是使用最广泛的主题了吧，毕竟人家样式全，美化全面，但是个人不是很喜欢。 3. The Doki-Doki Theme 主题地址 看这名字就知道是一款二次元主题，不仅有心跳人物的主题，还包含Re0等二次元人物，下面只列举部分，作者更新相当勤快，可以说是老二次元了。 [album] [/album]\n4. gruvbox-theme 主题地址 深色配色很舒服 5. Visual Studio Code Dark Plus Theme 主题地址 vscode风格主题，适合vscode爱好者 插件推荐 1. CodeGlance 可以像VScode一样在右侧显示预览条，插件地址 2. Save Actions Pycharm的代码格式化每次都要按快捷键太麻烦了，有了这个插件就可以在保存的时候自动格式化了，插件地址 插件需要在Setting -\u0026gt; Other Settings里启动才行 唯一不足的是这个插件的设置是针对每个项目单独设置的，默认下图是都没有勾选的，每次新开一个工程都需要重新设置一遍 要想新建工程时默认勾选，需要你打开软件时在configure里进行设置（前提设置打开软件弹出这个界面而非上次的工程） 该插件还有另一个分支版本功能相同Save Actions Reborn\n3. Background Image Plus + 可以设置背景图的插件，插件地址，下载后在下图所示的位置设置背景图片文件夹。 如果只是一张图的话，软件默认就带这个功能，不需要插件。 4. Key Promoter X 如果你使用鼠标点击了某个按钮，右下角就会弹窗提醒你相应的快捷键，想不记住快捷键都难。 5. Translation 翻译插件，可以随时随地一键翻译，再也不用担心读不懂源码注释了，插件地址，使用方法可以参照插件地址。 6.Atom Material Icons 插件地址，更改文件图标的插件。 7.Rainbow Brackets 彩虹括号，插件地址 8.Indent Rainbow 彩虹缩进，插件地址 9.Rainbow Fart 彩虹屁插件，一个在你编程时持续用语音夸你写的牛逼的插件，插件地址，支持自定义语音包：https://github.com/izhangzhihao/intellij-rainbow-fart\n10.Nyan Progress Bar 彩虹猫进度条，插件地址\n11.中文语言包 官方出的中文语言包，比什么汉化都要好使 插件地址\n附 官方帮助：https://www.jetbrains.com/help/pycharm/2020.1/quick-start-guide.html 一个很全的设置说明：https://blog.csdn.net/u013088062/article/details/50388329 对部分设置选项功能进行说明：https://segmentfault.com/a/1190000022799670 一些有用的设置：https://cloud.tencent.com/developer/news/393471 一个炒鸡棒的PyCharm 中文指南：http://pycharm.iswbm.com/zh_CN/latest/index.html\n","date":"2020-02-16T10:50:00Z","permalink":"https://kizx.github.io/post/pycharm%E4%B8%BB%E9%A2%98%E6%8F%92%E4%BB%B6%E6%8E%A8%E8%8D%90/","title":"PyCharm主题，插件推荐"},{"content":" 后盾人|选择器[/scode] /*标签选择器*/ h1 { color: red; } /*子代选择 h1\u0026gt;h2*/ /*同代选择 h1~h2*/ /*相邻选择 h1+h2*/ /*class类选择器*/ .h1-class { color: orange; } /*id选择器*/ #h1-id { color: yellow; } /*属性选择，可以指定多个，如h1[title][class]， 也可以指定属性的值 如h1[title=\u0026#34;h1\u0026#34;] 属性值可以使用正则匹配 如：^=表示开头匹配 $=表示结尾匹配 *=表示包含匹配 ~=表示单词匹配 |=表示结尾或-结尾匹配*/ h1[title] { color: green; } /*伪类选择器*/ a:link { color: blue; font-size: xx-large; } a:visited { color: blue; } a:hover { color: yellow; } a:active { color: green; } input:focus { color: red; } input:target{ } input:empty{ /*display: none;*/ } /*标签限定位置的伪类*/ h1 h2:first-child{ /*第一个标签是h2 last同理*/ } h1 h2:first-of-type{ /*出现的第一个h2 last同理*/ } h1 h2:only-of-type{ /*唯一的*/ } h1 h2:nth-child(2){ /*限定为第二个* last同理/ } h1 h2:nth-of-type(2){ /*第二个出现的* last同理/ } /*一个样式可以对应多个标签 如：h1,h2,.class*/ /*一个标签也可以对应多个样式 如：\u0026lt;h1 class=\u0026#34;class1 class2\u0026#34;\u0026gt;\u0026lt;/h1\u0026gt;*/ ","date":"2020-02-01T05:43:08Z","permalink":"https://kizx.github.io/post/css%E9%80%89%E6%8B%A9%E5%99%A8/","title":"CSS选择器"},{"content":"最新版本请转下面这篇 [post cid=\u0026ldquo;210\u0026rdquo; /]\n这是什么 起因是我做视频懒得说话，最多在视频做好后加上字幕，但光有字幕没语音感觉还是差了点意思。市面上有很多文本朗读器，可是我并没有找到一款能朗读字幕的应用，我这里的朗读字幕指语音能自动和字幕时间轴匹配。虽然有几款播放器（potplayer、kmplayer、VLC）自带字幕朗读功能，通过一边朗读一遍录音的话就可以得到我想要的音频，但这种做法过于笨拙。本着学习的目的，我试着用py写了一个小程序实现了字幕朗读的功能。\n实现原理 充分利用已有的轮子\n通过百度AI平台和阿里云语音服务实现语音合成 利用srt库处理srt字幕文件 利用pydub库对声音进行合成和拼接 代码 写完了发现比想象中要简单，几行代码就搞定了。目前只支持SRT格式的字幕文件，反正字幕文件间可以互相转，对于复杂的字幕可能引发的bug现在一概忽略（比如字幕重叠、一句话语音过长，多轨字幕等）。 另外目前都是单线程，速度可能有点慢，程序可能出现假死无响应状态，只要后台文件一直在增加，大可不用管。（因为语音平台都是限制并发数的，感觉多线程有必要？） 现已添加多线程。 [scode type=\u0026ldquo;green\u0026rdquo;]代码地址：https://github.com/kizx/subtitle2audio[/scode]\n下载 [button color=\u0026ldquo;success\u0026rdquo; icon=\u0026ldquo;fa fa-download\u0026rdquo; url=\u0026ldquo;https://pan.2bboy.com/Public/Software/%E5%AD%97%E5%B9%95%E6%9C%97%E8%AF%BB/\u0026rdquo; type=\u0026quot;\u0026quot;]onedrive下载地址[/button]\n[button color=\u0026ldquo;success\u0026rdquo; icon=\u0026ldquo;fa fa-download\u0026rdquo; url=\u0026ldquo;https://wws.lanzous.com/b01hhub9g\u0026rdquo; type=\u0026quot;\u0026quot;]蓝奏云下载 密码:gyb3[/button]\n使用 [tabs] [tab name=\u0026quot;v1.0 控制台版\u0026quot;]\n安装依赖 pip install -r requirements.txt 安装 ffmpeg 下载解压ffmpeg 将解压的 ffmpeg/bin 路径添加到系统环境变量 填写百度 KEY在百度 AI 平台获取相关 KEY ，打开 main.py 填写相应 KEY 启动 python main.py [.srt文件] [/tab] [tab name=\u0026quot;v1.1 web-gui版\u0026quot;] 安装 ffmpeg 下载解压ffmpeg 将解压的 ffmpeg/bin 路径添加到系统环境变量 安装依赖\npython -m venv venv venv\\Scripts\\activate pip install -r requirements.txt 启动 flask run浏览器打开 http://127.0.0.1:5000/ 获取并填写相关 key 后点击生成，所有生成的文件在 output 文件夹内。 [/tab] [tab name=\u0026ldquo;v2.x pyqt-gui版\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;]\n安装 ffmpeg\n下载解压ffmpeg 将解压的 ffmpeg/bin 路径添加到系统环境变量（可能需要重启电脑） 下载运行 下载地址 使用前需自行获取相关key 由于申请不了谷歌api，目前做不了谷歌接口 报毒请添加白名单或者信任，我自己电脑都报毒→_→，不放心自己下载源码运行\n[/tab] [/tabs]\n视频案例演示 后记 后来发现一个有同样功能的软件：http://www.cross-plus-a.com/cn/balabolka.htm 打开工具-\u0026gt;字幕转换器功能就是，这功能藏的太隐秘当初都没找到。\n后后来发现一个叫字幕说的网站也有类似的服务，不过介绍来看，这个是输入文本，然后生成同步的语音和字幕。虽然节省了做字幕的功夫，但这种只适合那种一刻不停的说的视频，适用性还有待提高（有空我也可以整合实现这种功能）。\n","date":"2020-01-27T12:46:00Z","permalink":"https://kizx.github.io/post/%E5%AD%97%E5%B9%95%E6%9C%97%E8%AF%BB%E5%99%A8%E7%94%B1%E5%AD%97%E5%B9%95%E6%96%87%E4%BB%B6%E7%94%9F%E6%88%90%E9%9F%B3%E9%A2%91/","title":"字幕朗读器——由字幕文件生成音频"},{"content":"官方安装说明\n下载解压ffmpeg或libav 将解压的ffmpeg/bin路径添加到系统环境变量 pip install pydub 使用教程 官方文档 python音频处理 pydub的中文文档 ","date":"2020-01-25T15:41:00Z","permalink":"https://kizx.github.io/post/python%E9%9F%B3%E9%A2%91%E5%A4%84%E7%90%86pydub%E5%BA%93/","title":"Python音频处理——pydub库"},{"content":" 在线试用 官方文档 官方案例 自主调用 api_key = \u0026#39;FpGBW******Mvz2SDG\u0026#39; secret_key = \u0026#39;Poxd******XR27G7y\u0026#39; token_url = f\u0026#39;https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials\u0026amp;client_id={api_key}\u0026amp;client_secret={secret_key}\u0026#39; print(token_url) # 从这个链接获取token token = \u0026#39;24.6430b0df******-18339246\u0026#39; # 获取到的token test_url = f\u0026#39;http://tsn.baidu.com/text2audio?lan=zh\u0026amp;ctp=1\u0026amp;cuid=abcdxxx\u0026amp;tok={token}\u0026amp;tex=%e7%99%be%e5%ba%a6%e4%bd%a0%e5%a5%bd\u0026amp;vol=9\u0026amp;per=0\u0026amp;spd=5\u0026amp;pit=5\u0026amp;aue=3\u0026#39; print(test_url) # 从这个链接获取音频 请求方式及参数基本说明 利用官方SDK 官方使用说明 参数说明 from aip import AipSpeech \u0026#34;\u0026#34;\u0026#34; 你的 APPID AK SK \u0026#34;\u0026#34;\u0026#34; APP_ID = \u0026#39;18***46\u0026#39; API_KEY = \u0026#39;FpGBW******vz2SDG\u0026#39; SECRET_KEY = \u0026#39;Poxd******XR27G7y\u0026#39; client = AipSpeech(APP_ID, API_KEY, SECRET_KEY) result = client.synthesis(\u0026#39;你好百度\u0026#39;, \u0026#39;zh\u0026#39;, 1, { \u0026#39;vol\u0026#39;: 5, }) if not isinstance(result, dict): with open(\u0026#39;auido.mp3\u0026#39;, \u0026#39;wb\u0026#39;) as f: f.write(result) ","date":"2020-01-25T10:22:00Z","permalink":"https://kizx.github.io/post/%E7%99%BE%E5%BA%A6%E8%AF%AD%E9%9F%B3%E5%90%88%E6%88%90%E5%B9%B3%E5%8F%B0%E4%BD%BF%E7%94%A8/","title":"百度语音合成平台使用"},{"content":"官方教程 Google Colab——用谷歌免费GPU跑你的深度学习代码 如何正确地使用Google Colab 在COLAB中使用GOOGLE云端硬盘中的教程数据\n经验 在菜单的修改-\u0026gt;笔记本设置中开启GPU 使用命令行命令只需在命令前加! 挂载google硬盘使用以下命令 from google.colab import drive drive.mount(\u0026#39;/content/drive\u0026#39;) 但实际上硬盘根目录在/content/drive/My Drive，这个目录是固定的，直接输入这个目录会提示目录包含空格，太沙雕了，需要使用python命令切换工作目录\nimport os os.chdir(\u0026#34;/content/drive/My Drive\u0026#34;) ！ls #查看当前目录 print(os.getcwd()) #或者 print(os.listdir(os.getcwd())) 不过有一说一，google硬盘速度还是很快的\n安装PyTorch 虽然google的cuda版本是10.0的，我懒得找相应的包了，直接!pip3 install torch torchvision即可 ","date":"2020-01-13T03:41:00Z","permalink":"https://kizx.github.io/post/google-golab%E5%85%8D%E8%B4%B9%E7%9A%84gpu%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%B9%B3%E5%8F%B0/","title":"Google Golab——免费的GPU深度学习平台"},{"content":"什么是Vtuber我就不多说了，目前的Vtuber大概要么是传统的基于Live2D，然后配合视频捕捉；要么就是3D模型结合动补设备来实现。本篇介绍的这个生成器主要是类似前者，因为即使是平面的Live2D，制作起来也是非常耗时费力的。 那么有没有这么一种方法可以直接从一张人设图直接生成可动的模型呢，然后配合视频捕捉出道Vtuber呢，这就是今天所介绍的生成器的功能。\n原理 这是原作者的说明界面：https://pkhungurn.github.io/talking-head-anime/ 里面较为详细介绍了他的生成器的原理和训练过程。 这里介绍一个图片生成网站：https://waifulabs.com/ 一个可以生成老婆半身像的网站，作者用这个网站生成的图片来对软件进行测试，当然你也可以拿自己喜欢的图来测试。\n试玩 这是原作者的源码：https://github.com/pkhungurn/talking-head-anime-demo 以下是我根据源码说明做的简单总结。 步骤： [scode type=\u0026ldquo;lblue\u0026rdquo;]1. 安装PyTorch，电脑要求必须是能支持CUDA的N卡才行，PyTorch安装[/scode]\n[scode type=\u0026ldquo;yellow\u0026rdquo;]后面作者的源码和readme都进行了一定更新，建议自己根据源码里的readme进行部署，本文的文件和方法可能过时，仅供参考。[/scode]\n[scode type=\u0026ldquo;lblue\u0026rdquo;] 2. 下载上面的源码，然后下载这里的模型数据 和 这个文件。下载好后把文件按源码说明解压放到data目录下。[/scode]\n[scode type=\u0026ldquo;lblue\u0026rdquo;]3. 接下来要安装相应的库，简单点就按作者文档里的运行要先安装cv2和dlib库，否则会报错，安装cv2用 pip install opencv-python ,安装dlib还有个坑，踩坑。[/scode]\n[scode type=\u0026ldquo;lblue\u0026rdquo;] 4. 进入PyTorch环境，cd到项目文件夹，输入 python app/manual_poser.py，弹出界面，导入图片即可，这里的图片还必须是256x256的背景为空的png图片，人物的脸也要保持在中间位置，然后拖动滑块图片就能动了。 强调一下这里仅仅是让图片动起来了，并不能生成其他的什么模型用于第三方软件，而且图片也挑的，不是随便张图片都能有很好的效果。[/scode]\n[scode type=\u0026ldquo;lblue\u0026rdquo;]5. 作者原文里还有一个 python app/puppeteer.py应该是直接动补摄像头数据的，由于我电脑没有摄像头，后面有空再研究。[/scode]\n视频演示 后记 后来用手机摄像头连接电脑，测试了面捕功能，见视频的P2。\n","date":"2020-01-11T12:52:00Z","permalink":"https://kizx.github.io/post/%E5%9F%BA%E4%BA%8E%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%9A%84vtuber%E7%94%9F%E6%88%90%E5%99%A8/","title":"基于深度学习的Vtuber生成器"},{"content":"先确保你的电脑的独显支持CUDA，否则只能用CPU运算。 这里可以查看自己显卡型号是否支持CUDA以及CUDA计算能力：https://developer.nvidia.com/ 安装工具：Anaconda 常用命令 这是官方安装指南：https://pytorch.org/get-started/locally/#anaconda\n安装CUDA 官方安装指南：https://docs.nvidia.com/cuda/cuda-installation-guide-microsoft-windows/index.html 查看自己的显卡驱动型号支持的CUDA版本：\n方式一 在命令行里依次输入下面两条命令\ncd C:\\Program Files\\NVIDIA Corporation\\NVSMI nvidia-smi.exe 然后根据显示的 Driver Version 和下面的图确定自己驱动支持的cude版本 上面这张表来自：https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html#cuda-major-component-versions\n方式二 通过NVIDIA的控制面板查看自己显卡驱动版本：https://jingyan.baidu.com/article/363872ecf07d652f4ba16fda.html\n确定CUDA版本后去官网下载：https://developer.nvidia.com/cuda-toolkit-archive 根据自己系统选择相应版本下载后安装。 下载完成后点击安装即可，安装完在cmd控制台输入nvcc -V返回版本信息即安装成功。 注：有些安装教程会要求安装cudnn，我这里暂时不用\n安装PyTorch 因为是用Anaconda安装，先进入Anaconda控制台新建一个环境并激活，然后进入https://pytorch.org/get-started/locally/#anaconda 选择你要安装的版本和方式，会自动生成一条安装命令，复制命令粘贴运行。 安装过程可能会很艰辛，主要就是那个pytorch的包太大了，足足有480M，建议试试换镜像源看看速度是否会提升，反正我最后是开了全局代理才下下来的。其他安装方式也可以试试。 安装完成后输入python然后运行以下代码，返回Ture就说明CUDA是可以使用的\nimport torch torch.torch.cuda.is_available() ","date":"2020-01-11T10:48:00Z","permalink":"https://kizx.github.io/post/win10%E5%AE%89%E8%A3%85pytorchgpu/","title":"Win10安装PyTorch（GPU）"},{"content":"Anaconda简单入门\n命令 # 查看conda版本 conda --version conda -V # 获取帮助 conda --help conda -h # 查看当前环境 conda env list # 新建环境 conda create -n env_name conda create -n your_env_name python=3.7 conda create -n your_env_name python=3.7 numpy pandas # 保存环境 conda env export \u0026gt; environment.yml # 从保存环境新建 conda env create -f environment.yml # 删除环境 conda remove -n env_name --all # 一键更新 conda update --all # 环境切换 activate env_name conda deactivate env_name # 包管理 conda install/updata/remove # 换源 参考:https://blog.csdn.net/observador/article/details/83618540 保存在用户目录.condarc文件中 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --set show_channel_urls yes # 换回默认的源 conda config --remove-key channels ","date":"2020-01-11T08:03:00Z","permalink":"https://kizx.github.io/post/anaconda%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/","title":"Anaconda常用命令"},{"content":" PMXEditer 2.1 PE多功能插件 [Blender_mmd_tools]9https://github.com/powroupi/blender_mmd_tools) ","date":"2020-01-10T08:15:00Z","permalink":"https://kizx.github.io/post/mmd%E5%BB%BA%E6%A8%A1%E7%9B%B8%E5%85%B3%E8%BD%AF%E4%BB%B6%E5%8F%8A%E6%8F%92%E4%BB%B6/","title":"MMD建模相关软件及插件"},{"content":"使用腾讯云控制台城建函数 之前安装onedrive云盘用的就是这种方式，装多了感觉就简单了，官方文档：https://cloud.tencent.com/document/product/583/37509\n使用控制台创建函数 官方文档：https://cloud.tencent.com/document/product/583/37510 其实就是使用cmd控制台来创建，和hexo或者git操作有点类似。 这里简单说下步骤：\n安装scf：pip install scf 可通过scf --version查看是否安装成功 配置账号：scf configure set 账号信息可以查看链接 初始化项目：scf init cd进入项目后本地调试运行函数scf native invoke --no-event，调试参数见链接，说一下调试环境python或nodejs均可，如果是用scf local invoke则需要docker。 编写函数和配置文件 部署scf deploy,成功后在腾讯云控制台可以查看 将 serviceId 复制到 template.yaml VSCode插件 官方教程：https://cloud.tencent.com/document/product/583/37511 在插件市场搜索Tencent Serverless安装结果第一个即可，将之前的命令都按钮化了，更简单直观，还能在vscode里debug。\n为云函数打包依赖 函数用到了第三方依赖需自行打包随函数一起上传：https://cloud.tencent.com/developer/article/1443081\n","date":"2020-01-09T13:43:00Z","permalink":"https://kizx.github.io/post/%E8%85%BE%E8%AE%AF%E4%BA%91%E5%87%BD%E6%95%B0%E5%85%A5%E9%97%A8/","title":"腾讯云函数入门"},{"content":"VirtualBox下载地址：https://www.virtualbox.org/wiki/Downloads 系统镜像下载，这是网易的镜像下载地址，速度很快：http://mirrors.163.com/ubuntu-releases/\n安装 安装教程： https://www.bilibili.com/video/av82489244\n可能遇到的问题 VirtualBox中默认启用了硬件虚拟化，可以在任务管理器cpu里进行查看,未启用的话需在bios里启用 网络无法连接可以换回默认的连接方式 ","date":"2020-01-08T09:47:00Z","permalink":"https://kizx.github.io/post/virtualbox%E5%AE%89%E8%A3%85linux%E8%99%9A%E6%8B%9F%E6%9C%BA/","title":"VirtualBox安装linux虚拟机"},{"content":"教程官方教程就够了： https://docs.aiohttp.org/en/latest/client.html\n案例：\nimport aiohttp import aiofiles import asyncio async def yiyan(): \u0026#39;\u0026#39;\u0026#39;简单的get请求\u0026#39;\u0026#39;\u0026#39; async with aiohttp.ClientSession() as session: async with session.get(\u0026#39;https://api.n-1.cn/yiyan\u0026#39;) as response: print(await response.text()) async def acgpic1(name): \u0026#39;\u0026#39;\u0026#39;下载是异步的\u0026#39;\u0026#39;\u0026#39; async with aiohttp.ClientSession() as session: async with session.get(\u0026#39;https://api.n-1.cn/ACG\u0026#39;) as response: print(f\u0026#39;下载{name}中...\u0026#39;) pic = await response.read() print(f\u0026#39;{name}下载完成\u0026#39;) with open(f\u0026#39;{name}.jpg\u0026#39;, \u0026#39;wb+\u0026#39;) as f: f.write(pic) print(f\u0026#39;{name}保存完毕\u0026#39;) async def acgpic2(name): \u0026#39;\u0026#39;\u0026#39;下载是异步的 保存也是异步的(虽然这里没体现出来)\u0026#39;\u0026#39;\u0026#39; async with aiohttp.ClientSession() as session: async with session.get(\u0026#39;https://api.n-1.cn/ACG\u0026#39;) as response: print(f\u0026#39;下载{name}中...\u0026#39;) pic = await response.read() print(f\u0026#39;{name}下载完成\u0026#39;) async with aiofiles.open(f\u0026#39;{name}.jpg\u0026#39;, \u0026#39;wb\u0026#39;) as f: print(f\u0026#39;{name}保存中...\u0026#39;) await f.write(pic) print(f\u0026#39;{name}保存完毕\u0026#39;) loop = asyncio.get_event_loop() task = [acgpic1(i) for i in range(10)] loop.run_until_complete(asyncio.wait(task)) ","date":"2019-12-30T03:56:00Z","permalink":"https://kizx.github.io/post/aiohttp%E5%BC%82%E6%AD%A5%E7%BC%96%E7%A8%8B%E5%85%A5%E9%97%A8/","title":"aiohttp异步编程入门"},{"content":"i\u0026gt; We always have to remember a lot of accounts and passwords in our daily life. Some people like to use their particular passwords, while others like to keep them in a notebook. If you\u0026rsquo;re frustrated to manage your passwords, here are some password management tools you can have a try. Good tools can improve our efficiency, but even the best tools can be a burden if they don\u0026rsquo;t fit us; therefore, don\u0026rsquo;t use a tool just to use the tool.\nkeepass 一款本地的密码管理软件，不能云端，就是个高级的带密码的记事本或者数据库，好像有浏览器插件但必须本地开着keepass的客户端才能用。如果只是喜欢记一些数据到本地，配合坚果云同步用用还可以。\n1password 之前刚好有活动就领了一年的试用，软件界面很漂亮，浏览器插件用着也很舒服，云端同步，平台齐全，唯一的缺点就是太贵了，虽然有一年试用，但我觉得还是没有必要在密码管理上花一笔钱就没继续用了\nlastpass 一款免费的密码管理软件，浏览器插件界面略丑，不支持中文，用了一个多月，老是弹升级信息。总之一句话不够简洁，越用越讨厌。\nBitwarden 也是免费的一款软件，特点是可以自建云端，同时也自带的云端同步。浏览器插件界面简洁，支持中文，各方面都还优秀，唯一的缺点就是无法自动感知你网页密码的添加和改变，也不能自动填入密码，得在插件上点一下才行。如果不怕麻烦的话这款软件用着很舒服。\n","date":"2019-12-29T08:26:00Z","permalink":"https://kizx.github.io/post/%E5%87%A0%E6%AC%BE%E5%AF%86%E7%A0%81%E7%AE%A1%E7%90%86%E8%BD%AF%E4%BB%B6/","title":"几款密码管理软件"},{"content":"美化教程 handsome使用文档\nhandsome社区分享\n史上最全的handsome美化，没有之一！\nsunpma.com主题美化记录\nwww.onlaly.com的魔改\nblog.qqiyu.cn美化魔改\nitudo.cn魔改合集\ngordsky.cn美化分享\nwww.cooyf.com的一些美化\ntypecho评论后台图片超出范围\ntypecho文章挂载Bilibili视频\n弹窗提醒以及个性化提示\n插件 代码高亮插件Code Prettify\nTypecho炫彩鼠标插件:HoerMouse\n评论通知推送多服务\n百度提交插件BaiduSubmit魔改\nLive2D 插件Pio\n后台编辑文章时增加标签选择列表\n文章内容替换工具\nBangumi 追番列表\nPandaBangumi 追番列表\nEditorMD + handsome 编辑器插件整合\nWowScroll动感元素插件\nWenYu特效管理插件\n博主的介绍 \u0026lt;!--博主介绍的闪字特效--\u0026gt; \u0026lt;span class=\u0026#34;text-muted text-xs block\u0026#34;\u0026gt; \u0026lt;div id=\u0026#34;chakhsu\u0026#34;\u0026gt;\u0026lt;/div\u0026gt; \u0026lt;script\u0026gt; var chakhsu = function (r) { function t() { return b[Math.floor(Math.random() * b.length)] } function e() { return String.fromCharCode(94 * Math.random() + 33) } function n(r) { for (var n = document.createDocumentFragment(), i = 0; r \u0026gt; i; i++) { var l = document.createElement(\u0026#34;span\u0026#34;); l.textContent = e(), l.style.color = t(), n.appendChild(l) } return n } function i() { var t = o[c.skillI]; c.step ? c.step-- : (c.step = g, c.prefixP \u0026lt; l.length ? (c.prefixP \u0026gt;= 0 \u0026amp;\u0026amp; (c.text += l[c.prefixP]), c.prefixP++) : \u0026#34;forward\u0026#34; === c.direction ? c.skillP \u0026lt; t.length ? (c.text += t[c.skillP], c.skillP++) : c.delay ? c.delay-- : (c.direction = \u0026#34;backward\u0026#34;, c.delay = a) : c.skillP \u0026gt; 0 ? (c.text = c.text.slice(0, -1), c.skillP--) : (c.skillI = (c.skillI + 1) % o.length, c .direction = \u0026#34;forward\u0026#34;)), r.textContent = c.text, r.appendChild(n(c.prefixP \u0026lt; l.length ? Math.min(s, s + c.prefixP) : Math.min(s, t.length - c.skillP))), setTimeout(i, d) } /*以下内容自定义修改*/ var l = \u0026#34;\u0026#34;, o = [\u0026#34;我好菜啊\u0026#34;].map(function (r) { return r + \u0026#34;\u0026#34; }), a = 2, g = 1, s = 5, d = 75, b = [\u0026#34;rgb(110,64,170)\u0026#34;, \u0026#34;rgb(150,61,179)\u0026#34;, \u0026#34;rgb(191,60,175)\u0026#34;, \u0026#34;rgb(228,65,157)\u0026#34;, \u0026#34;rgb(254,75,131)\u0026#34;, \u0026#34;rgb(255,94,99)\u0026#34;, \u0026#34;rgb(255,120,71)\u0026#34;, \u0026#34;rgb(251,150,51)\u0026#34;, \u0026#34;rgb(226,183,47)\u0026#34;, \u0026#34;rgb(198,214,60)\u0026#34;, \u0026#34;rgb(175,240,91)\u0026#34;, \u0026#34;rgb(127,246,88)\u0026#34;, \u0026#34;rgb(82,246,103)\u0026#34;, \u0026#34;rgb(48,239,130)\u0026#34;, \u0026#34;rgb(29,223,163)\u0026#34;, \u0026#34;rgb(26,199,194)\u0026#34;, \u0026#34;rgb(35,171,216)\u0026#34;, \u0026#34;rgb(54,140,225)\u0026#34;, \u0026#34;rgb(76,110,219)\u0026#34;, \u0026#34;rgb(96,84,200)\u0026#34; ], c = { text: \u0026#34;\u0026#34;, prefixP: -s, skillI: 0, skillP: 0, direction: \u0026#34;forward\u0026#34;, delay: a, step: g }; i() }; chakhsu(document.getElementById(\u0026#39;chakhsu\u0026#39;)); \u0026lt;/script\u0026gt; \u0026lt;/span\u0026gt; 左侧边栏导航 {\u0026#34;name\u0026#34;:\u0026#34;留言板\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-liuyan\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://www.2bboy.com/guestbook.html\u0026#34;,\u0026#34;target\u0026#34;:\u0026#34;_self\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;动态\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-dongtai2\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://www.2bboy.com/cross.html\u0026#34;,\u0026#34;target\u0026#34;:\u0026#34;_self\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;归档\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-rili2\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://www.2bboy.com/file.html\u0026#34;,\u0026#34;target\u0026#34;:\u0026#34;_self\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;追番\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-pgc_bangumi\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://www.2bboy.com/bangumi.html\u0026#34;,\u0026#34;target\u0026#34;:\u0026#34;_self\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;云盘\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-yun\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://pan.2bboy.com/Public\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;home\u0026#34;,\u0026#34;status\u0026#34;:\u0026#34;hide\u0026#34;} 顶部导航 {\u0026#34;name\u0026#34;:\u0026#34;bilibili\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-bilibili-fill\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://space.bilibili.com/22411920\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;github\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-github\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://github.com/kizx\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;steam\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;iconfont icon-steam\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://steamcommunity.com/id/kizxmoe\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;talk\u0026#34;,\u0026#34;status\u0026#34;:\u0026#34;hide\u0026#34;} 时光机社交按钮 {\u0026#34;name\u0026#34;:\u0026#34;微博\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;fontello fontello-weibo\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://weibo.com/u/5938819173\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;github\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;fa fa-github\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://github.com/kizx\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;gitee\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;fa fa-git\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://gitee.com/kizx\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;steam\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;fa fa-steam\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://steamcommunity.com/id/kizxmoe\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;bilibili\u0026#34;,\u0026#34;status\u0026#34;:\u0026#34;single\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://space.bilibili.com/22411920\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;网易云\u0026#34;,\u0026#34;status\u0026#34;:\u0026#34;single\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;https://music.163.com/#/user/home?id=111496719\u0026#34;}, {\u0026#34;name\u0026#34;:\u0026#34;bangumi\u0026#34;,\u0026#34;status\u0026#34;:\u0026#34;single\u0026#34;,\u0026#34;class\u0026#34;:\u0026#34;fa fa-heartbeat\u0026#34;,\u0026#34;link\u0026#34;:\u0026#34;http://bangumi.tv/user/305237\u0026#34;} pjax回调函数 \u0026lt;!--彩色标签云--\u0026gt; let tags = document.querySelectorAll(\u0026#34;#tag_cloud-2 a\u0026#34;); let colorArr = [\u0026#34;#428BCA\u0026#34;, \u0026#34;#AEDCAE\u0026#34;, \u0026#34;#ECA9A7\u0026#34;, \u0026#34;#DA99FF\u0026#34;, \u0026#34;#FFB380\u0026#34;, \u0026#34;#D9B999\u0026#34;]; tags.forEach(tag =\u0026gt; { tagsColor = colorArr[Math.floor(Math.random() * colorArr.length)]; tag.style.backgroundColor = tagsColor; }); \u0026lt;!--代码高亮--\u0026gt; if (typeof Prism !== \u0026#39;undefined\u0026#39;) { Prism.highlightAll(true,null);} \u0026lt;!--复制提示--\u0026gt; kaygb_copy(); 博客底部左侧 \u0026lt;div class=\u0026#34;github-badge\u0026#34;\u0026gt; \u0026lt;a href=\u0026#34;./\u0026#34; title=\u0026#34;?2019 kizx\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;badge-subject\u0026#34;\u0026gt;Copyright\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;badge-value bg-blue\u0026#34;\u0026gt;?2019 kizx\u0026lt;/span\u0026gt; \u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; | \u0026lt;div class=\u0026#34;github-badge\u0026#34;\u0026gt; \u0026lt;a href=\u0026#34;http://beian.miit.gov.cn\u0026#34; target=\u0026#34;_blank\u0026#34; title=\u0026#34;陕ICP备19016973号\u0026#34; style=\u0026#34;cursor: url(\u0026#34;/usr/plugins/HoerMouse/static/image/dew/link.cur\u0026#34;), pointer;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;badge-subject\u0026#34;\u0026gt;陕ICP备\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;badge-value bg-green\u0026#34;\u0026gt;19016973号\u0026lt;/span\u0026gt; \u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; 博客底部右侧 \u0026lt;div class=\u0026#34;github-badge\u0026#34;\u0026gt; \u0026lt;a href=\u0026#34;http://www.typecho.org\u0026#34; target=\u0026#34;_blank\u0026#34; title=\u0026#34;由 Typecho 强力驱动\u0026#34; style=\u0026#34;cursor: url(\u0026#34;/usr/plugins/HoerMouse/static/image/dew/link.cur\u0026#34;), pointer;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;badge-subject\u0026#34;\u0026gt;Powered\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;badge-value bg-blue\u0026#34;\u0026gt;Typecho\u0026lt;/span\u0026gt; \u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; | \u0026lt;div class=\u0026#34;github-badge\u0026#34;\u0026gt; \u0026lt;a href=\u0026#34;https://www.ihewro.com/archives/489/\u0026#34; target=\u0026#34;_blank\u0026#34; title=\u0026#34;Handsome主题\u0026#34; style=\u0026#34;cursor: url(\u0026#34;/usr/plugins/HoerMouse/static/image/dew/link.cur\u0026#34;), pointer;\u0026#34;\u0026gt; \u0026lt;span class=\u0026#34;badge-subject\u0026#34;\u0026gt;Theme\u0026lt;/span\u0026gt;\u0026lt;span class=\u0026#34;badge-value bg-orange\u0026#34;\u0026gt;Handsome\u0026lt;/span\u0026gt; \u0026lt;/a\u0026gt; \u0026lt;/div\u0026gt; 自定义css /* 首页文章列表悬停上浮 */ .blog-post .panel:not(article) { transition: all 0.3s; } .blog-post .panel:not(article):hover { transform: translateY(-10px); box-shadow: 0 8px 10px rgba(73, 90, 47, 0.47); } /* 头像呼吸光环和鼠标悬停旋转放大 */ .img-full { width: 100px; border-radius: 50%; animation: light 4s ease-in-out infinite; transition: 0.5s; } .img-square, .img-circle { transition: 0.5s; } .img-square:hover, .img-circle:hover { transform: scale(1.15) rotate(360deg); } .img-full:hover { transform: scale(1.15) rotate(720deg); } @keyframes light { 0% { box-shadow: 0 0 4px #f00; } 25% { box-shadow: 0 0 16px #0f0; } 50% { box-shadow: 0 0 4px #00f; } 75% { box-shadow: 0 0 16px #0f0; } 100% { box-shadow: 0 0 4px #f00; } } /*底部页脚*/ .github-badge { display: inline-block; border-radius: 4px; text-shadow: none; font-size: 12px; color: #fff; line-height: 15px; background-color: #abbac3; margin-bottom: 5px; } .github-badge .badge-subject { display: inline-block; background-color: #4d4d4d; padding: 4px 4px 4px 6px; border-top-left-radius: 4px; border-bottom-left-radius: 4px; } .github-badge .badge-value { display: inline-block; padding: 4px 6px 4px 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; } .github-badge .bg-blue { background-color: #007ec6; } .github-badge .bg-orange { background-color: #ffa500; } .github-badge .bg-red { background-color: #f00; } .github-badge .bg-green { background-color: #3bca6e; } .github-badge .bg-purple { background-color: #ab34e9; } /*Bilibili视频挂载*/ .iframe_video { position: relative; width: 100%; } @media only screen and (max-width: 767px) { .iframe_video { height: 15em; } } @media only screen and (min-width: 768px) and (max-width: 991px) { .iframe_video { height: 20em; } } @media only screen and (min-width: 992px) and (max-width: 1199px) { .iframe_video { height: 30em; } } @media only screen and (min-width: 1200px) { .iframe_video { height: 40em; } } .iframe_cross { position: relative; width: 100%; height: 0; padding-bottom: 75%; } .iframe_cross iframe { position: absolute; width: 100%; height: 100%; left: 0; top: 0; } 自定义javascript /* 彩色标签云 */ let tags = document.querySelectorAll(\u0026#34;#tag_cloud-2 a\u0026#34;); let colorArr = [\u0026#34;#428BCA\u0026#34;, \u0026#34;#AEDCAE\u0026#34;, \u0026#34;#ECA9A7\u0026#34;, \u0026#34;#DA99FF\u0026#34;, \u0026#34;#FFB380\u0026#34;, \u0026#34;#D9B999\u0026#34;]; tags.forEach(tag =\u0026gt; { tagsColor = colorArr[Math.floor(Math.random() * colorArr.length)]; tag.style.backgroundColor = tagsColor; }) /* 复制提示 */ kaygb_copy(); function kaygb_copy(){$(document).ready(function(){$(\u0026#34;body\u0026#34;).bind(\u0026#39;copy\u0026#39;,function(e){hellolayer()})});var sitesurl=window.location.href;function hellolayer(){ $.message({ message: \u0026#34;尊重原创，转载请注明出处！\u0026lt;br\u0026gt; 本文作者：醉后的星星\u0026lt;br\u0026gt;原文链接：\u0026lt;br\u0026gt;\u0026#34;+sitesurl, title: \u0026#34;复制成功\u0026#34;, type: \u0026#34;success\u0026#34;, autoHide: !1, time: \u0026#34;15000\u0026#34; }) }} 自定义Head \u0026lt;!--图标--\u0026gt; \u0026lt;link href=\u0026#34;https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css\u0026#34; rel=\u0026#34;stylesheet\u0026#34;\u0026gt; \u0026lt;!--分享内容--\u0026gt; \u0026lt;meta itemprop=\u0026#34;name\u0026#34; content=\u0026#34;醉后的星星\u0026#34; /\u0026gt; \u0026lt;meta itemprop=\u0026#34;image\u0026#34; content=\u0026#34;https://www.2bboy.com/usr/uploads/txmk.jpg\u0026#34; /\u0026gt; \u0026lt;meta name=\u0026#34;description\u0026#34; itemprop=\u0026#34;description\u0026#34; content=\u0026#34;我好菜啊\u0026#34; /\u0026gt; \u0026lt;!--百度统计--\u0026gt; \u0026lt;!--动态标题--\u0026gt; \u0026lt;script\u0026gt;document.addEventListener(\u0026#39;visibilitychange\u0026#39;, function () { if (document.visibilityState == \u0026#39;hidden\u0026#39;) { normal_title = document.title; document.title = \u0026#39;人呢？快回来！\u0026#39;; } else { document.title = normal_title; } });\u0026lt;/script\u0026gt; pio插件设置 { \u0026#34;welcome\u0026#34;: [\u0026#34;你好，欢迎来到本站！\u0026#34;, \u0026#34;有问题欢迎留言\u0026#34;], \u0026#34;touch\u0026#34;: [ \u0026#34;你这个绅士！\u0026#34;, \u0026#34;别碰我！\u0026#34;, \u0026#34;你在干什么？\u0026#34;, \u0026#34;再摸我就报警了！\u0026#34;, \u0026#34;HENTAI!\u0026#34;, \u0026#34;你够了喔！\u0026#34;, \u0026#34;萝莉是什么呀\u0026#34; ], \u0026#34;skin\u0026#34;: [\u0026#34;想看看我的新服装吗？\u0026#34;, \u0026#34;新衣服真漂亮~\u0026#34;], \u0026#34;home\u0026#34;: \u0026#34;点击这里回到首页\u0026#34;, \u0026#34;link\u0026#34;: \u0026#34;https://docs.paul.ren/pio/#/\u0026#34;, \u0026#34;referer\u0026#34;: \u0026#34;Hi，欢迎来自 %t 的朋友\u0026#34;, \u0026#34;close\u0026#34;: \u0026#34;QWQ 下次再见吧~\u0026#34;, \u0026#34;custom\u0026#34;: [ { \u0026#34;type\u0026#34;: \u0026#34;read\u0026#34;, \u0026#34;selector\u0026#34;: \u0026#34;.post-meta\u0026gt;h2 a\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.music-box\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;你想听歌吗o((;=? 3? =))o～?\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.comment-form-comment\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;填写真实邮箱可以收到回复通知哦(??ω-)～\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.searchform\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;会搜索的人运气不会太差o(≧▽≦)o\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.dropdown:nth-last-child(4)\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;想关注我的bilibili频道吗\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.dropdown:nth-last-child(3)\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;人生苦短\u0026#34; }, { \u0026#34;selector\u0026#34;: \u0026#34;.dropdown:nth-last-child(2)\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34;可以不玩，不能没有\u0026#34; } ] } ","date":"2019-12-28T06:06:00Z","permalink":"https://kizx.github.io/post/typecho+handsome%E4%B8%BB%E9%A2%98%E7%BE%8E%E5%8C%96/","title":"Typecho+Handsome主题美化"},{"content":"使用方法 打开我的电脑，空白处右键添加网络位置，点下一步然后参照示例添加ftp地址 后面就是设置些名称和登录密码，总之要啥填啥就是了，然后就可以点击资源浏览器里新添加的网络位置来连接了。 [scode type=\u0026ldquo;blue\u0026rdquo;]其实这就是个快捷方式，在资源管理器地址栏直接输入ftp地址就可以直接登陆。 另外，在浏览器里直接输入ftp地址也是可以进行访问的。[/scode]\n","date":"2019-12-15T06:21:00Z","permalink":"https://kizx.github.io/post/%E5%88%A9%E7%94%A8windows%E8%87%AA%E5%B8%A6%E7%9A%84%E7%BD%91%E7%BB%9C%E4%BD%8D%E7%BD%AE%E8%BF%9B%E8%A1%8Cftp%E7%99%BB%E5%BD%95/","title":"利用windows自带的网络位置进行ftp登录"},{"content":"开机棒 开机棒是插在路由器LAN口上使用的，如果是校园网那就用不了，因为你根本不知道路由器或者交换机在哪，知道在哪你也不能插个这么个玩意上去，不过你自己单独再整个路由器，然后电脑连路由器上应该可以。 开机棒由一个usb线单独供电，远程开机的原理应该是WOL网络远程唤醒电脑，只要不是古董机，一般电脑主板都有这个功能。其实这个功能本来只能用于局域网唤醒主机，要实现外网唤醒，必须做内网穿透，但开机棒自己就能连接外网，所以内网穿透就不用我们操心了。\n开机插座 开机插座和普通的智能插座没有多大不同，就是可以远程控制电源的开关。电脑的主板上都有一个通电后自启动的功能，这也是我们电脑为什么有时停电来电后能自动开机的原因。插座必须要连无线网，一般只支持2.4GWiFi，这样你才能远程控制插座的开关。开机插座可以和向日葵软件配合，实现电脑系统关机后过一会再断电，比起用一般的智能插座强制断电要好。但我寻思你远程桌面点击关机后再过两分钟关闭智能插座，效果不也一样嘛。\n开机卡 一块插在电脑主板PCI-E口上的板子，PCI-E的接口只有供电的作用。因为主板有系统关机但PCI-E不断电的功能，所以就保证了这块卡在关机状态下也能工作。开机卡也需要联网，板子上有接口和电脑的开机和重启的跳线相接，其实就是模拟你按下开机键进行开关机。通过开机卡的软件客户端可以实现定时开关机和语音唤醒等功能，具体就看厂商支持那些功能了。\n我买回来后才发现我这校园网虽然有2.4G信号，但需要网页验证，所以无法识别成功，没办法我就淘了个路由器利用路由器的WiFi才行。然后我就又发现淘的路由器太辣鸡不支持ipv6，无奈又整了个交换机，这一波投入有点亏，这是后话。\n","date":"2019-12-04T10:16:00Z","permalink":"https://kizx.github.io/post/%E8%BF%9C%E7%A8%8B%E5%BC%80%E6%9C%BA%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E5%BC%8F/","title":"远程开机的几种方式"},{"content":"下载地址：https://rime.im/ 官方说明：https://github.com/rime/home/wiki/UserGuide 输入方案：https://github.com/rime/plum 其他教程： https://www.jianshu.com/p/296bba666604 https://www.bilibili.com/video/av31013072 https://segmentfault.com/a/1190000005754706\n使用入门 简体设置 按F4调出选项，选择西/半/漢，再选择漢字-\u0026gt;汉字，如果你只使用全拼的话，也可以直接使用带简化字的方案\n选择候选方案和主题 右键输入法设定，为需要的方案打上钩，然后点击中选择配色方案，最后再点击中\n添加双拼方案 右键输入法设定，选择更多方案，弹出cmd窗口，输入相应的方案名称如double-pinyin，也可自行下载解压到用户文件夹中。值得一提的是，安装prelude可以下载一些用户配置，方便后面配置不用新建文件了。\n删除错误的候选词 输入法会记住你输入的词组，当你第一次输入一个输入法不认识的词语后，第二次输入同样的词语该词语就会出现在候选词中，也正是如此才叫聪明的输入法，不过有时候会打错词语，等到下次再打相同词语时就会出现错误的候选词，这时可以选中该错误的候选词，按shift+del删除\n改变候选词个数 在用户文件夹下新建default.custom.yaml文件(如果没有的话)，添加以下内容，然后重新部署\npatch: \u0026#34;menu/page_size\u0026#34;: 9 进阶定制 添加符号 新建double_pinyin_mspy.custom.yaml文件（以你使用的输入方案名为准），添加以下内容 # double_pinyin_mspy.custom.yaml patch: \u0026#34;punctuator/import_preset\u0026#34;: symbols \u0026#34;recognizer/patterns/punct\u0026#34;: \u0026#34;^/([A-Z|a-z]*|[0-9]|10)$\u0026#34; 重新部署后输入/fh等字样就可以输入各种符号了，这些符号保存在程序文件夹的data/symbols.yaml文件中。\n自定义符号 如果想添加自定义符号，可以将symbols.yaml文件复制到用户文件夹下，然后在其中按照格式添加自己的符号，但更建议添加在自定义方案设置中，比如我自定义了常用邮箱 #double_pinyin_mspy.custom.yaml patch: punctuator/symbols: \u0026#34;/mail\u0026#34;: [kizxmoe@gmail.com, 3317200497@qq.com, kizx@qq.com, contact@2bboy.com] 然后重新部署，输入/mail即可弹出常用邮箱\n修改符号候选 有时候在打出一个符号时会出现多个候选，这不符合大众习惯，这些设置也在symbols.yaml文件中，同样建议在自定义方案中修改,比如我把书名号改成唯一的样式 patch: \u0026#34;punctuator/import_preset\u0026#34;: symbols \u0026#34;recognizer/patterns/punct\u0026#34;: \u0026#34;^/([A-Z|a-z]*|[0-9]|10)$\u0026#34; punctuator/full_shape: \u0026#34;[\u0026#34;: \u0026#34;【\u0026#34; \u0026#34;]\u0026#34;: \u0026#34;】\u0026#34; punctuator/half_shape: \u0026#34;[\u0026#34;: \u0026#34;【\u0026#34; \u0026#34;]\u0026#34;: \u0026#34;】\u0026#34; 切换英文直接上屏 # default.custom.yaml patch: ascii_composer: good_old_caps_lock: true switch_key: Shift_L: commit_code Shift_R: commit_code Control_L: noop Control_R: noop Caps_Lock: noop Eisu_toggle: clear 定义某些应用默认中英文输入 比如我想让vscode默认是英文输入，可以在任务管理器中查看进程名称，然后注意要小写 # weasel.custom.yaml patch: app_options/code.exe: ascii_mode: true 其实rime输入法能记住不同应用的中英文状态\n其他设置 # weasel.custom.yaml patch: style/horizontal: true # 候选横排显示 style/display_tray_icon: true # 显示托盘图标 [scode type=\u0026ldquo;yellow\u0026rdquo;]以上操作都记得重新部署生效[/scode]\n同步 点击菜单中的用户资料同步即会在sync目录下生成一个同步文件夹，记录了当前电脑上的用户配置文件和词库，只需把这个文件夹同步到另一台电脑上相同的位置下，词库便会自动合并，但用户配置文件不会自动合并，需手动进行替换。文件夹的名字和位置可以在installation.yaml中自行指定。 ","date":"2019-11-27T17:29:00Z","permalink":"https://kizx.github.io/post/rime-%E5%B0%8F%E7%8B%BC%E6%AF%AB%E8%BE%93%E5%85%A5%E6%B3%95%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/","title":"Rime-小狼毫输入法使用指南"},{"content":"https://gitee.com/help/categories/43 https://git-scm.com/book/zh/v2/ https://git-scm.com/book/zh/v2/%E6%9C%8D%E5%8A%A1%E5%99%A8%E4%B8%8A%E7%9A%84-Git-%E7%94%9F%E6%88%90-SSH-%E5%85%AC%E9%92%A5\n初始化 # 设置用户信息 git config --global user.name kizx git config --global user.email kizxmoe@gmail.com # 查看设置 git config --list # 生成密钥 ssh-keygen # 查看公钥 cat ~/.ssh/id_rsa.pub 创建仓库 # 初始化 git init # 添加所有文件 git add . # 提交 git commit -m \u0026#34;first commit\u0026#34; # 添加远程仓库 git remote add origin git@gitee.com:kizx/rime.git # 推送 git push -u origin master ","date":"2019-11-24T02:30:00Z","permalink":"https://kizx.github.io/post/git%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/","title":"Git常用命令"},{"content":" 百分浏览器 https://www.centbrowser.cn/ 压缩 http://www.bandisoft.com/bandizip/ 输入法 https://rime.im/ https://shurufa.baidu.com/\n浏览器插件推荐 https://chrome.zzzmh.cn 鼠标驱动 https://zh.roccat.org/Support 文本编辑器 https://github.com/stefankueng/BowPad http://www.editpadpro.com/screen.html/ http://www.pnotepad.org/ https://www.rizonesoft.com/downloads/notepad3/ office下载管理 https://otp.landian.vip/zh-cn/ 卸载\u0026ndash;geek https://geekuninstaller.com/ 程序类 vs https://visualstudio.microsoft.com/zh-hans/ 网速显示 https://github.com/zhongyang219/TrafficMonitorSkinEditor cmder https://cmder.net/ sqlite数据库管理 https://sqlitebrowser.org/dl/ git管理 https://git-fork.com/ SSH https://www.vandyke.com/products/securecrt/ http://www.hostbuf.com/t/988.html https://www.netsarang.com/zh/free-for-home-school/\n办公类 万彩办公大师 http://www.wofficebox.com/ PDF https://www.sumatrapdfreader.org/downloadafter.html https://www.sumatrapdfreader.org/free-pdf-reader.html https://tools.pdf24.org/zh/\nmarkdown https://www.typora.io/#windows 多媒体类 看图 http://www.bandisoft.com/honeyview/ https://sourceforge.net/projects/jpegview/ http://www.vieas.com/en/software/vieas.html 图片压缩 + https://tuya.xinxiao.tech/ 视频播放器 https://potplayer.daum.net/?lang=zh_CN http://www.dandanplay.com/ 录屏-OBS https://obsproject.com/ 音乐播放器-AIMP https://www.aimp.ru/ 应用类 鼠标手势 https://shuax.com/project/mouseinc/ http://www.yingdev.com/projects/wgestures\n文件管理器TAB http://qttabbar.wikidot.com/ gif录制 https://www.screentogif.com/?l=zh_cn 快速复制 https://fastcopy.jp/ 符号链接 https://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html 文件窗口标签 https://shutters.160.com/ 哈希校检工具 https://www.binaryfortress.com/HashTools/ 文献翻译 http://i.zhiyunwenxian.cn/195.html 复制翻译 https://copytranslator.github.io/download/ 下载 https://v3-beta.6pan.cn/ https://www.kancloud.cn/myzfb/thunderbird/1684667 http://www.internetdownloadmanager.com/ http://www.internetdownloadmanager.com/download.html 软件分享网站 这个网站有超多实用小程序 http://www.nirsoft.net/utils/index.html ","date":"2019-11-22T11:52:00Z","permalink":"https://kizx.github.io/post/%E6%88%91%E7%94%A8%E7%9A%84%E8%BD%AF%E4%BB%B6/","title":"我用的软件"},{"content":"现在handsome主题已经有了微信公众号和浏览器拓展两种方式向时光机发送消息，那么自然就想到QQ端是否也可以做到，所以我就通过对浏览器扩展发送时光机进行抓包，然后基于酷Q和nonebot，实现了通过向QQ小号发送消息的方式向时光机发送消息。 [scode type=\u0026ldquo;share\u0026rdquo;]代码见github[/scode]\n使用方法 和微信公众号的用法大同小异，所有消息需要私聊机器人\n发送帮助 时光机查看帮助信息 发送绑定然后根据提示输入绑定信息，发送解绑取消绑定 发送时光鸡然后根据提示输入你要发送的消息（也可以一次性输入时光鸡 你要发送的消息中间加空格即可） 发送开始然后可以逐条发送消息，发送结束结束混合消息，发送取消取消发送 发送的第一条消息如果以#开头即为私密消息 发送博客获取博客地址 发送图床更改图床\n如有需要，可以直接加群体验我已经搭建好的QQ机器人 [button color=\u0026ldquo;success\u0026rdquo; icon=\u0026ldquo;fa fa-qq\u0026rdquo; url=\u0026quot;//shang.qq.com/wpa/qunwpa?idkey=786f97195ca56ef0a1888eef7e803fabee0b70cb01d6dbf0c2295454797d803b\u0026quot;]QQ群 642739195[/button]\n已知问题 由于QQ可以在一条消息里同时塞进文字和图片，所以发送单条消息也可以达到混合消息的效果，但经我测试在QQ手机客户端如果一条消息同时包含文字和图片，那么图片会无法解析，但是电脑的TIM客户端不存在这个问题。这个问题出在酷Q上，所以要同时发送文字和图片，在手机客户端最好采用逐条发送的模式。 由于handsome_6.0对上传的图片进行了压缩，所以上传gif图片会被压缩成jpg图片，因此图片增加图床功能并默认采用QQ图片的源地址，省去了下载和上传操作，速度更快，但QQ源图片腾讯可能采取限制而无法引用，而且目前已知腾讯对这些图片的缓存会过一段时间就清掉，所以QQ源图床慎用。最好的当然是接入自己的图床，暂时先懒得弄。 安装方法（Windows） 你可以先在自己的电脑上安装和熟悉使用\n1. 准备 所有需要下载的东西已打包-\u0026gt;点击下载 因为是基于酷Q和Python运行的，所以需要先安装酷Q Air-\u0026gt;下载地址，然后打开酷Q，登陆你的作为QQ机器人的QQ小号，熟悉酷Q的使用，尤其是插件的安装和启用，酷Q论坛里也有许多其他插件可供玩耍。 然后下载安装python，建议下载安装Python 3.7.x 32位版本，因为我是基于这个版本开发的，别的版本尤其是最新的3.8版本可能会有未知的不兼容的bug。安装的时候记得勾选环境变量。 2. 安装插件 这里可以参考CoolQ HTTP API官方说明 将io.github.richardchien.coolqhttpapi.cpk移动至酷Q的app文件下，然后重启酷Q或者在应用管理里重载应用，在应用管理里选中HTTP API插件，点击启用，接下来几个弹窗统统选是。启用成功后会弹出控制台窗口。 [scode type=\u0026ldquo;yellow\u0026rdquo;]如果弹窗提示应用加载失败，先安装[ Visual C++ 可再发行软件包]( Visual C++ 可再发行软件包)[/scode] 3.启用nonebot 这里可以参考Nonebot官方说明 如果你之前成功开启了插件，那么酷Q的data/app/io.github.richardchien.coolqhttpapi/config/目录中应该已经有了一个名为 .json 的文件（ 为你登录的 QQ 账号），修改其中的内容如下： [collapse status=\u0026ldquo;false\u0026rdquo; title=\u0026ldquo;json文件内容\u0026rdquo;]\n{ \u0026#34;host\u0026#34;: \u0026#34;[::]\u0026#34;, \u0026#34;port\u0026#34;: 5700, \u0026#34;use_http\u0026#34;: true, \u0026#34;ws_host\u0026#34;: \u0026#34;[::]\u0026#34;, \u0026#34;ws_port\u0026#34;: 6700, \u0026#34;use_ws\u0026#34;: false, \u0026#34;ws_reverse_url\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;ws_reverse_api_url\u0026#34;: \u0026#34;ws://127.0.0.1:8080/ws/api/\u0026#34;, \u0026#34;ws_reverse_event_url\u0026#34;: \u0026#34;ws://127.0.0.1:8080/ws/event/\u0026#34;, \u0026#34;ws_reverse_reconnect_interval\u0026#34;: 3000, \u0026#34;ws_reverse_reconnect_on_code_1000\u0026#34;: true, \u0026#34;use_ws_reverse\u0026#34;: true, \u0026#34;post_url\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;access_token\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;secret\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;post_message_format\u0026#34;: \u0026#34;string\u0026#34;, \u0026#34;serve_data_files\u0026#34;: false, \u0026#34;update_source\u0026#34;: \u0026#34;github\u0026#34;, \u0026#34;update_channel\u0026#34;: \u0026#34;stable\u0026#34;, \u0026#34;auto_check_update\u0026#34;: false, \u0026#34;auto_perform_update\u0026#34;: false, \u0026#34;show_log_console\u0026#34;: true, \u0026#34;log_level\u0026#34;: \u0026#34;info\u0026#34; } [/collapse]\n然后下载找到我写的coolq-cross-bot文件，用python运行该文件夹下的bot.py文件，运行前要先安装依赖库。\n[tabs] [tab name=\u0026ldquo;运行方式\u0026rdquo; active=\u0026ldquo;true\u0026rdquo;] 打开命令提示符窗口，执行以下命令：\npip install nonebot pip install aiohttp 然后在控制台进入coolq-cross-bot文件夹内，输入python bot.py运行该文件，当然也可以用IDE运行。 [/tab] [/tabs] [scode type=\u0026ldquo;yellow\u0026rdquo;]阿里云服务器如果一直卡在下载图片且ping不通c2cpicdw.qpic.cn可能是因为节点问题，需添加host记录113.96.232.144 c2cpicdw.qpic.cn [/scode] 最后重启酷Q软件或者重载插件，弹出来的控制台如下显示成功字样则代表配置成功，这时你就可以私聊机器人发送初始化创建一个数据库后就可以使用了（初始化命令只需执行一次，用于在文件目录下新建bind_info.sqlite文件用于记录绑定信息）,最后要注意两个控制台窗口都不能关闭，你可以选择新建一个桌面单独用于运行他们。 安装方法（Linux） 详细参考：CoolQ HTTP API官方说明 Linux系统需要在docker中运行酷Q，所以要先安装docker，安装教程请自行百度，以下仅供参考，以我的Ubuntu16.04 64位为例，ssh连上服务器后运行以下命令安装docker\n$ curl -fsSL https://get.docker.com -o get-docker.sh $ sudo sh get-docker.sh 然后安装酷Q和HTTP API插件（配置参数无所谓，后面手动替换）\n$ docker pull richardchien/cqhttp:latest $ mkdir coolq # 用于存储 酷Q 的程序文件 $ docker run -ti --rm --name cqhttp-test \\ -v $(pwd)/coolq:/home/user/coolq \\ # 将宿主目录挂载到容器内用于持久化 酷Q 的程序文件 -p 9000:9000 \\ # noVNC 端口，用于从浏览器控制 酷Q -p 5700:5700 \\ # HTTP API 插件开放的端口 -e COOLQ_ACCOUNT=123456 \\ # 要登录的 QQ 账号，可选但建议填 -e CQHTTP_POST_URL=http://example.com:8080 \\ # 事件上报地址 -e CQHTTP_SERVE_DATA_FILES=yes \\ # 允许通过 HTTP 接口访问 酷Q 数据文件 richardchien/cqhttp:latest 然后访问 http://[你的服务器IP]:9000/ 进入 noVNC（默认密码 MAX8char），登录酷Q，即可开始使用（插件已自动启用，配置文件也根据启动命令的环境变量自动生成了） [scode type=\u0026ldquo;yellow\u0026rdquo;]如果阿里云主机注意要先开放相应的端口，默认是9000端口[/scode] 把coolq-cross-bot文件夹上传至服务器，将之前的json文件也上传至服务器并替换掉app/io.github.richardchien.coolqhttpapi/下的ini配置文件（注意将配置文件中127.0.0.1换成172.17.0.1），然后用python3命令运行文件下的bot.py，重启插件\n进阶自定义修改（可选） 1. 自定义命令 其实时光机的触发命令不仅可以是‘时光机’，也可以是‘时光鸡’、‘时光姬’等，具体可以在 coolq-cross-bot/plugins/handsome/timeji.py 源码中找到类似下面的语句自行进行修改。 @on_command('timeji', aliases=('时光鸡', '时光机', '时光姬', '动态', '说说')) 其他命令类似。\n2. 添加消息来源 如上图所示，在时光机消息的来源处，如果不对handsome的源码进行修改，就会显示来自未知浏览器，找到handsome/libs/UA.php文件，在文件的最后加入如下所示的QQ的来源，名称可以自定义。\npublic function returnTimeUa(){ if ($this-\u0026gt;ua == \u0026#34;weixin\u0026#34; || $this-\u0026gt;ua == \u0026#34;weChat\u0026#34;){ return array(\u0026#34;title\u0026#34;=\u0026gt;_mt(\u0026#34;微信公众号\u0026#34;), \u0026#34;icon\u0026#34;=\u0026gt;\u0026#34;compass\u0026#34;); }elseif ($this-\u0026gt;ua == \u0026#34;crx\u0026#34;){ return array(\u0026#34;title\u0026#34;=\u0026gt;_mt(\u0026#34;Chrome扩展\u0026#34;), \u0026#34;icon\u0026#34;=\u0026gt;\u0026#34;chrome\u0026#34;); }elseif ($this-\u0026gt;ua == \u0026#34;qq\u0026#34;){ return array(\u0026#34;title\u0026#34;=\u0026gt;_mt(\u0026#34;QQ时光姬\u0026#34;), \u0026#34;icon\u0026#34;=\u0026gt;\u0026#34;compass\u0026#34;); }else{ $ua = $this-\u0026gt;returnOS(); $ua[\u0026#34;icon\u0026#34;] = \u0026#34;disc\u0026#34;; return $ua; } } 3.添加消息来源前的图标（6.0主题不需要了） 主题默认呈现出来的都是清一色的小圆点图标，要更改消息来源前的小图标，首先要添加fontawesome图标，然后找到handsome/component/say.php，找到下面第一条语句，改成第二句。\n# 找到下面这一句 \u0026lt;i class=\u0026#34;glyphicon glyphicon-record m-l-sm\u0026#34;\u0026gt;\u0026lt;/i\u0026gt;\u0026amp;nbsp; # 改成下面这样 \u0026lt;i class=\u0026#34;\u0026lt;?php echo $ua-\u0026gt;returnTimeUa()[\u0026#39;icon\u0026#39;] ?\u0026gt; m-l-sm\u0026#34;\u0026gt;\u0026lt;/i\u0026gt;\u0026amp;nbsp; ","date":"2019-11-15T12:38:00Z","permalink":"https://kizx.github.io/post/%E5%88%A9%E7%94%A8qq%E6%9C%BA%E5%99%A8%E4%BA%BA%E5%8F%91%E9%80%81%E6%97%B6%E5%85%89%E6%9C%BA/","title":"利用QQ机器人发送时光机"},{"content":"import requests from bs4 import BeautifulSoup from lxml import etree url = \u0026#34;http://www.doutula.com/\u0026#34; headers = { \u0026#39;User-Agent\u0026#39;: \u0026#39;Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36\u0026#39;} response = requests.get(url, headers=headers) soup = BeautifulSoup(response.text, \u0026#39;lxml\u0026#39;) # 保存网页html内容 with open(\u0026#39;content.html\u0026#39;, \u0026#39;w\u0026#39;, encoding=\u0026#34;utf-8\u0026#34;) as f: html = soup.prettify() f.write(html) # 通过find_all()选择 html = soup.find_all(\u0026#39;img\u0026#39;, class_=\u0026#34;img-responsive lazy image_dta\u0026#34;) links = [i[\u0026#39;data-original\u0026#39;] for i in html] # 通过css选择 html = soup.select(\u0026#34;img[data-original]\u0026#34;) links = [i[\u0026#39;data-original\u0026#39;] for i in html] # 通过xpath选择 root = etree.HTML(response.text) links = root.xpath(\u0026#39;//img/@data-original\u0026#39;) # 保存图片 for index, link in enumerate(links): img = requests.get(link) with open(\u0026#39;img/\u0026#39;+str(index)+\u0026#39;.jpg\u0026#39;, \u0026#39;wb+\u0026#39;) as f: f.write(img.content) ","date":"2019-11-06T09:21:00Z","permalink":"https://kizx.github.io/post/python%E7%88%AC%E8%99%AB%E5%AD%A6%E4%B9%A0/","title":"Python爬虫学习"},{"content":"可以在Tool里添加工具来代替某些命令行操作，新建一个工程后，建议使用系统环境解释器，这样安装包时可以直接安装到环境中，这样在别的工程里也能用上，使用虚拟环境的话，虚拟环境变动了就找不到工具了，当然本质上只要在选择程序时选择环境里的程序就行了。添加的地方在setting-\u0026gt;Tools-\u0026gt;External Tools。\n示例 1. Qt Designer 首先确保库中安装了pyqt5，然后如下图配置\nprogram: C:\\Users\\ZXIN\\Anaconda3\\Library\\bin\\designer.exe working directory: $ProjectFileDir$ 也可以安装pyqt5-tools，然后在Scripts中找到程序 2. PyUIC program: C:\\Users\\ZXIN\\Anaconda3\\Scripts\\pyuic5.exe Arguments: $FileName$ -o $FileNameWithoutExtension$.py working directory: $FileDir$ 3. autopep8 program: C:\\Users\\ZXIN\\AppData\\Roaming\\Python\\Python37\\Scripts\\autopep8.exe Arguments: --in-place --aggressive --aggressive $FilePath$ working directory: $ProjectFileDir$ 4. Black 需要先安装black\nprogram: C:\\Users\\ZXIN\\AppData\\Roaming\\Python\\Python37\\Scripts\\black.exe Arguments: $FilePath$ working directory: $FileDir$ ","date":"2019-11-02T06:05:00Z","permalink":"https://kizx.github.io/post/pycharm%E4%B9%8B%E8%87%AA%E5%AE%9A%E4%B9%89%E5%B7%A5%E5%85%B7/","title":"Pycharm之自定义工具"},{"content":"前面已经研究过Python和C++的酷Q应用开发流程了，其中慕晓飞大大的SDK虽然前期配置需要一定经验，但配置好后上手很快很简单的，但这个SDK不支持并发是最大的硬伤，限制了其使用范围。而C++的SDK无疑写起来过于麻烦，好在该SDK的大神richardchien在C++ SDK的基础上开发出了基于HTTP的API接口，由此衍生出了基于该HTTP API的多种语言开发版本，其中就有同样是该作者基于Quart框架开发的Nonebot,支持异步处理是其最大的特点，但也由于对消息封装的过于深入，使得在入手使用Nonebot带来不小的挑战。\n入门 要使用Nonebot得先从HTTP API开始，先根据这篇说明：https://cqhttp.cc/docs/4.12/#/ 完成对HTTP API的成功调用，然后再到我们的Nonebot出场，官方的入门文档写的已经很仔细了：https://nonebot.cqp.moe/guide/installation.html， 走完这篇入门文档，应该很容易就实现了案例中的天气和图灵机器人案例。 接下来来梳理以下Nonebot的编写逻辑，他将消息处理分为on_command，on_natural_language，on_request（其他的暂不清楚）几个类型，command用于处理命令，也是用的最多的类型，这里就不用我们手动检测消息里的命令关键字了，然后未被匹配的消息会送到natural_language中处理，如果没有natural_language消息就会被忽略。request用于处理加群请求等非消息类的任务。 还有许多细节问题就需要慢慢研究了，比如想在群聊中也是用命令，可以加only_to_me=False参数。 要主动调用HTTP API可以使用如下方式：\nbot = session.bot # bot = nonebot.get_bot() await bot.send_private_msg(user_id=12345678, message=\u0026#39;你好～\u0026#39;) 要获得上报事件中的参数，需要访问session.ctx。 然后下面这个例子是发送测试获得该消息的上报内容，发送其他消息则会复读。\nfrom nonebot import on_command, CommandSession from nonebot import on_natural_language, NLPSession, IntentCommand __plugin_name__ = \u0026#39;测试\u0026#39; __plugin_usage__ = \u0026#39;测试 命令\u0026#39; @on_command(\u0026#39;test\u0026#39;, aliases=(\u0026#39;测试\u0026#39;,), only_to_me=False) async def test(session: CommandSession): ctx = session.ctx await session.send(str(ctx)) @on_natural_language(only_to_me=False) async def repeat(session: NLPSession): msg = session.ctx[\u0026#34;message\u0026#34;] await session.send(msg) 还有更多应用后续再研究。。。\n","date":"2019-10-30T13:49:00Z","permalink":"https://kizx.github.io/post/nonebot%E9%85%B7q%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/","title":"Nonebot酷Q应用开发"},{"content":"以前自己的水平不够，这个项目一直搞不懂，现在起码能跑通了，其实也是比较简单的，项目地址：https://github.com/richardchien/coolq-cpp-sdk\n步骤 在该装的东西都装了后，在cmd中依次执行以下命令即可。其中最后一个命令，可能需要先进powershell管理员模式运行Set-ExecutionPolicy并选择是来打开权限。另外由于网络原因，可能会在Unpacking objects这一步卡住，我是通过加速来解决的。\ngit clone https://github.com/richardchien/coolq-cpp-sdk.git my-awesome-app cd my-awesome-app git submodule init git submodule update powershell .\\scripts\\prepare_prebuilt.ps1 然后编译项目，把编译出来的相应文件丢进酷Q的dev文件夹里就行了。\npowershell .\\scripts\\generate.ps1 Release powershell .\\scripts\\build.ps1 Release ","date":"2019-10-26T09:31:00Z","permalink":"https://kizx.github.io/post/c++%E9%85%B7q%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/","title":"C++酷Q应用开发"},{"content":"以下仅为个人理解\n进程——在windows的任务管理器里看到的一个个程序就是进程，最常看见的多进程就是浏览器的多进程，一个程序启动后至少会有一个进程，通常为了效率，会给多核CPU每个核分配几个进程以充分利用CPU。进程之间互不影响，一个进程挂了并不会影响另一个进程。 线程——一个进程至少会有一个线程，线程是最小的执行单位。一个进程可以有多线程，多线程可以提高效率。一个线程挂了会导致该进程挂了从而该进程下的线程都会挂掉。 协程——协程类似于线程，但在控制上稍有不同，是比线程更轻便的一种运行方式，通常和异步IO相关。 并行——并行就是指同时执行多个任务。 并发——和并行差不多意思，应用场合不同。 同步——一个任务执行完了再去执行下一个任务。 异步——一个任务执行到一半转而执行另一个任务收到消息后再回头处理等待的任务 这里有一个更为详细和硬核的教程：https://github.com/denglj/aiotutorial\n2、多进程 Python由于CPython解释器的原因，似乎对多进程并不支持，但是可以通过multiprocessing调用多个解释器来实现多进程。\nfrom multiprocessing import Process import os import time # 子进程要执行的代码 def run_proc(name): print(\u0026#39;Run child process %d (%s)...\u0026#39; % (name, os.getpid())) time.sleep(5) if __name__ == \u0026#39;__main__\u0026#39;: start = time.perf_counter() print(\u0026#39;Parent process %s.\u0026#39; % os.getpid()) p = [] for i in range(5): p.append(Process(target=run_proc, args=(i,))) print(\u0026#39;Child process will start.\u0026#39;) for i in range(5): p[i].start() [x.join() for x in p] print(\u0026#39;Child process end.\u0026#39;) end = time.perf_counter() print(\u0026#39;cost time:\u0026#39;, end - start) 从最后的运行时间可以看出该代码实现了5个进程的并行，从任务管理器里也可以看到多个Python进程。 也可以通过pool模块来开启多进程，其中运行中的进程数和CPU的核数是匹配的。\nfrom multiprocessing import Pool import os, time, random def long_time_task(name): print(\u0026#39;Run task %s (%s)...\u0026#39; % (name, os.getpid())) start = time.time() time.sleep(random.random() * 3) end = time.time() print(\u0026#39;Task %s runs %0.2f seconds.\u0026#39; % (name, (end - start))) if __name__==\u0026#39;__main__\u0026#39;: print(\u0026#39;Parent process %s.\u0026#39; % os.getpid()) p = Pool(4) for i in range(5): p.apply_async(long_time_task, args=(i,)) print(\u0026#39;Waiting for all subprocesses done...\u0026#39;) p.close() p.join() print(\u0026#39;All subprocesses done.\u0026#39;) 3、多线程 实现 多线程要用到threading模块，新线程调用函数的方法一般有两种，一种是直接调用threading.Thread等指定target的参数，一种是通过新写一个对象继承threading.Thread，然后重写run方法。\nimport time import threading def water(): print(\u0026#39;开始烧水\u0026#39;) time.sleep(5) print(\u0026#39;水烧开了\u0026#39;) def rice(): print(\u0026#39;开始煮饭\u0026#39;) time.sleep(10) print(\u0026#39;饭煮熟了\u0026#39;) start = time.time() t1=threading.Thread(target=water) t2=threading.Thread(target=rice) t1.start() t2.start() t1.join() t2.join() stop = time.time() print(stop - start) 锁 一个线程锁的结构通常如下，线程的运行通常是并行的，如果线程之间需要共同处理某个数据，那么该数据可能就会失控，这是我们就希望一个线程在处理数据时别的线程不要插手，这就是锁的作用。\nlock = threading.Lock() def run_thread(n): for i in range(100000): # 先要获取锁: lock.acquire() try: change_it(n) finally: # 释放锁: lock.release() join 在程序末尾经常能看到一个join函数，该函数本来的作用应该是在某处插入一个线程，并且只有当该线程结束时才能继续执行其他命令。被用在程序最后是为了保证所有子线程结束后再结束主线程，没有这句你就会发现你的主线程会比子线程先结束。\n守护线程 一个程序的线程之间可以是不平等的，分为普通线程和守护线程。进程也有守护进程，守护进程会在主进程代码运行结束的情况下，立即挂掉。普通线程在主线程结束后仍然可以继续运行，引用说法“该进程内所有非守护线程全部都运行完毕后,守护线程才会挂掉”。这东西到底有什么用我还没搞清楚。。。 守护线程的实现方法是设置线程的.daemon=True\n4、协程 Python的协程是通过yield来完成的，yield本质是一个生成器，可以通过next()来进行迭代，还可以通过send()来传递参数，多任务并发使用起来很方便。\nimport time def func1(): while True: yield time.sleep(1) print(\u0026#39;func1\u0026#39;) def func2(): g = func1() for i in range(3): next(g) time.sleep(1) print(\u0026#39;func2\u0026#39;) start = time.time() func2() stop = time.time() print(stop - start) 协程想要并行还需要借用其他一些库比如asyncio\nimport threading import time import asyncio @asyncio.coroutine def water(): print(\u0026#39;开始烧水\u0026#39;) yield from asyncio.sleep(5) print(\u0026#39;水烧开了\u0026#39;) @asyncio.coroutine def rice(): print(\u0026#39;开始煮饭\u0026#39;) yield from asyncio.sleep(10) print(\u0026#39;饭煮熟了\u0026#39;) start = time.time() loop = asyncio.get_event_loop() tasks = [water(), rice()] loop.run_until_complete(asyncio.wait(tasks)) loop.close() stop = time.time() print(stop - start) 这个程序最终需要时间仅为10秒多点，因此是并行的，但要注意这利用的是 yield from asyncio.sleep(5)，这里代表的是一个IO阻塞，并不是什么函数放在这里都能够并行的。\n","date":"2019-10-23T12:31:00Z","permalink":"https://kizx.github.io/post/python%E5%A4%9A%E8%BF%9B%E7%A8%8B%E5%A4%9A%E7%BA%BF%E7%A8%8B%E5%8D%8F%E7%A8%8B/","title":"Python多进程，多线程，协程"},{"content":"很久以前就知道windows中这么一种快捷方式，不同于普通的快捷方式，是一种可以和源文件发挥相同功效作用的“快捷方式”，但是一直未深入探索使用过，现在想起来或许这种快捷方式可以为我们的工作带来很大便利。 部分参考资料： mklink_百度百科 Windows硬链接 软链接 符号链接 快捷方式 Windows上创建符号链接的完整指南 Windows下mklink使用, 硬链接, 软链接和快捷方式的区别 windows mklink /d /h /j 精讲 Vista下类型为JUNCTION和SYMLINK的文件夹有什么区别\n实践 看完许多资料，还是对windows下的mklink命令感到有些迷惑，我觉得还是自己实践下比较好。 mklink一共只有3种链接，针对3种方式我分别对文件和文件夹进行如下实验。\n文件测试 mklink /d D:\\d.txt C:\\Users\\ZXIN\\Desktop\\src.txt mklink /h D:\\h.txt C:\\Users\\ZXIN\\Desktop\\src.txt mklink /h C:\\Users\\ZXIN\\Desktop\\opencv\\h.txt C:\\Users\\ZXIN\\Desktop\\src.txt mklink /j D:\\j.txt C:\\Users\\ZXIN\\Desktop\\src.txt 文件夹测试 mklink /d D:\\d C:\\Users\\ZXIN\\Desktop\\src mklink /h D:\\h C:\\Users\\ZXIN\\Desktop\\src mklink /h C:\\Users\\ZXIN\\Desktop\\opencv\\h C:\\Users\\ZXIN\\Desktop\\src mklink /j D:\\j C:\\Users\\ZXIN\\Desktop\\src 占用空间测试 mklink /d D:\\bigd \u0026#34;G:\\ONE PIECE\\820-866\u0026#34; mklink /d G:\\bigd \u0026#34;G:\\ONE PIECE\\820-866\u0026#34; mklink /h G:\\bigh.zip \u0026#34;G:\\NPUBits\\偷星九月天.zip\u0026#34; mklink /j D:\\bigj \u0026#34;G:\\ONE PIECE\\820-866\u0026#34; mklink /j G:\\bigj \u0026#34;G:\\ONE PIECE\\820-866\u0026#34; 以下是实验结果：\n项目 符号链接 硬链接 目录链接 参数 /D /H /J 管理员权限 需要 不需要 不需要 文件 不支持 支持 不支持 文件夹 支持 不支持 支持 空间 不占用 不占用(理应占用) 不占用 跨磁盘 可以 不可以 可以 删除或移动源文件(夹) 无法访问 存在 无法访问 移动链接 秒移，整个文件夹被移动 秒移 跨盘的话会发生复制行为，原地遗留一个空文件夹 和网上的图进行比较： 奇怪的地方来了，在我测试中三种方式都是不占用空间的，硬链接应该是会占用空间的才对，我检查占用空间的方式是右键磁盘查看可用空间，但是三种方式都不改变磁盘剩余空间，右键查看文件的占用空间三种方式也都是一样的，可能这种查看方式并不科学。\n总结 与其叫快捷方式，其实这三种方式更像是文件共享，共同点都是文件的改动都是同步的，但是链接文件或目录的删除不影响源文件。 至于区别首先就是硬链接源文件的删除不影响链接文件，但是硬链接只能链接文件不能链接文件夹，而另两种方式只能链接文件夹，所以硬链接很适合备份数据。 如果什么参数都不加，创建的是文件符号链接。 另两种文件链接方式似乎没有什么大差别，/D需要管理员权限，在移动链接文件夹时是整体移动的，不会留下一个空文件夹。需要注意的是虽然删除目录链接的目录本身不会影响源文件，但是删除删除目录下的文件会导致同步删除。 应用 除了用硬链接备份数据外，因为这种创建链接的方式几乎是瞬间完成的，可以和OneDrive云盘配合使用，也可用作程序间的数据共享。 一个有意思的技巧，如果想使硬链接跨盘符使用该怎么办？可以使用软连接和硬链接相结合的方式，即在一个可以跨盘连接的软链接里创建硬链接，这样硬链接就会同步到另一个盘里。 另外如果每次都用命令行的方式进行操作未免太过极客了，刚好在参考文件里找到一个软件，直接将该功能集成到右键菜单里了，我觉得很赞。 软件下载地址：http://schinagl.priv.at/nt/hardlinkshellext/linkshellextension.html [button color=\u0026ldquo;info\u0026rdquo; icon=\u0026ldquo;fa fa-download\u0026rdquo;]本地下载[/button]\n后记 这个up在视频里讲解了硬链接，本文有些错误懒得改了，建议结合视频观看理解 https://www.bilibili.com/video/BV11b4y1t72B\n","date":"2019-10-19T05:18:00Z","permalink":"https://kizx.github.io/post/windows%E4%B8%AD%E7%9A%84%E9%AB%98%E7%BA%A7%E5%BF%AB%E6%8D%B7%E6%96%B9%E5%BC%8F/","title":"Windows中的高级“快捷方式”"},{"content":" 官方网站 菜鸟教程1 菜鸟教程2 安装 python -m pip install -U matplotlib 练习 import numpy as np import matplotlib.pyplot as plt # 导入 matplotlib 的所有内容（nympy 可以用 np 这个名字来使用） #from pylab import * # 创建一个 8 * 6 点（point）的图，并设置分辨率为 80 plt.figure(figsize=(8,6), dpi=100) X = np.linspace(-np.pi, np.pi, 256,endpoint=True) C,S = np.cos(X), np.sin(X) # 创建一个新的 2 * 2 的子图，接下来的图样绘制在其中的第 1 块 plt.subplot(2,2,1) # 绘制余弦曲线，使用蓝色的、连续的、宽度为 1 （像素）的线条 plt.plot(X, C, color=\u0026#34;blue\u0026#34;, linewidth=1.0, linestyle=\u0026#34;-\u0026#34;) # 绘制正弦曲线，使用绿色的、连续的、宽度为 1 （像素）的线条 plt.subplot(2,2,2) plt.plot(X, S, color=\u0026#34;green\u0026#34;, linewidth=1.0, linestyle=\u0026#34;-\u0026#34;) #回执第三个合并图 plt.subplot(2,2,3) plt.plot(X, C, color=\u0026#34;blue\u0026#34;, linewidth=1.0, linestyle=\u0026#34;-\u0026#34;) plt.plot(X, S, color=\u0026#34;green\u0026#34;, linewidth=1.0, linestyle=\u0026#34;-\u0026#34;) # 设置轴的上下限 xmin ,xmax = X.min(), X.max() ymin, ymax = C.min(), C.max() dx = (xmax - xmin) * 0.1 dy = (ymax - ymin) * 0.1 plt.xlim(xmin - dx, xmax + dx) plt.ylim(ymin - dy, ymax + dy) # 设置横轴记号 plt.xticks(np.linspace(-4,4,9,endpoint=True)) plt.xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi], [r\u0026#39;$-\\pi$\u0026#39;, r\u0026#39;$-\\pi/2$\u0026#39;, r\u0026#39;$0$\u0026#39;, r\u0026#39;$+\\pi/2$\u0026#39;, r\u0026#39;$+\\pi$\u0026#39;]) # 设置纵轴记号 plt.yticks(np.linspace(-1,1,5,endpoint=True)) #改变坐标轴位置 ax = plt.gca() ax.spines[\u0026#39;right\u0026#39;].set_color(\u0026#39;none\u0026#39;) ax.spines[\u0026#39;top\u0026#39;].set_color(\u0026#39;none\u0026#39;) ax.xaxis.set_ticks_position(\u0026#39;bottom\u0026#39;) ax.spines[\u0026#39;bottom\u0026#39;].set_position((\u0026#39;data\u0026#39;,0)) ax.yaxis.set_ticks_position(\u0026#39;left\u0026#39;) ax.spines[\u0026#39;left\u0026#39;].set_position((\u0026#39;data\u0026#39;,0)) #增加图例 plt.plot(X, C, color=\u0026#34;blue\u0026#34;, linewidth=2.5, linestyle=\u0026#34;-\u0026#34;, label=\u0026#34;cosine\u0026#34;) plt.plot(X, S, color=\u0026#34;red\u0026#34;, linewidth=2.5, linestyle=\u0026#34;-\u0026#34;, label=\u0026#34;sine\u0026#34;) plt.legend(loc=\u0026#39;upper left\u0026#39;) #标注特殊点 t = 2*np.pi/3 plt.plot([t,t],[0,np.cos(t)], color =\u0026#39;blue\u0026#39;, linewidth=2.5, linestyle=\u0026#34;--\u0026#34;) plt.scatter([t,],[np.cos(t),], 50, color =\u0026#39;blue\u0026#39;) plt.annotate(r\u0026#39;$\\sin(\\frac{2\\pi}{3})=\\frac{\\sqrt{3}}{2}$\u0026#39;, xy=(t, np.sin(t)), xycoords=\u0026#39;data\u0026#39;, xytext=(+10, +30), textcoords=\u0026#39;offset points\u0026#39;, fontsize=8, arrowprops=dict(arrowstyle=\u0026#34;-\u0026gt;\u0026#34;, connectionstyle=\u0026#34;arc3,rad=.2\u0026#34;)) plt.plot([t,t],[0,np.sin(t)], color =\u0026#39;red\u0026#39;, linewidth=2.5, linestyle=\u0026#34;--\u0026#34;) plt.scatter([t,],[np.sin(t),], 50, color =\u0026#39;red\u0026#39;) plt.annotate(r\u0026#39;$\\cos(\\frac{2\\pi}{3})=-\\frac{1}{2}$\u0026#39;, xy=(t, np.cos(t)), xycoords=\u0026#39;data\u0026#39;, xytext=(-90, -50), textcoords=\u0026#39;offset points\u0026#39;, fontsize=8, arrowprops=dict(arrowstyle=\u0026#34;-\u0026gt;\u0026#34;, connectionstyle=\u0026#34;arc3,rad=.2\u0026#34;)) #文字无遮挡 for label in ax.get_xticklabels() + ax.get_yticklabels(): label.set_fontsize(8) label.set_bbox(dict(facecolor=\u0026#39;green\u0026#39;, edgecolor=\u0026#39;None\u0026#39;, alpha=0.5 )) #保存图片 plt.savefig(\u0026#34;exercice_2.png\u0026#34;,dpi=200) # 在屏幕上显示 plt.show() ","date":"2019-10-14T13:46:00Z","permalink":"https://kizx.github.io/post/matplotlib%E5%AD%A6%E4%B9%A0/","title":"Matplotlib学习"},{"content":"看CMake教程时每次在cmake后都会跟着一个make命令，Linux系统下天然有这个命令。但是我的电脑装了MinGW，也设了环境变量却用不了make命令。\n解决 先去MinGW的安装目录下的bin目录里看看有没有mingw32-make.exe文件，如果没有用以下命令下载： mingw-get install gcc g++ mingw32-make 然后将该文件重命名为make.exe即可。 这样通过CMake利用MinGW编译生成MakeFile相关文件，直接调用make命令就能生成可执行文件了，比起用微软的VS要方便不少。\n","date":"2019-10-13T08:47:03Z","permalink":"https://kizx.github.io/post/windows%E4%B8%8B%E4%BD%BF%E7%94%A8make%E5%91%BD%E4%BB%A4/","title":"Windows下使用make命令"},{"content":"起因来自下面的OpenCVd官方的一个教程，尝试使用CMake。\nhttps://docs.opencv.org/4.1.1/db/df5/tutorial_linux_gcc_cmake.html 但是按照官方的教程会出现很多问题。\n建立工程 先建立下面的这样一个结构 主函数代码 #include \u0026lt;opencv2/core.hpp\u0026gt; #include \u0026lt;opencv2/highgui.hpp\u0026gt; using namespace cv; int main(int argc, char** argv ) { Mat image; image = imread( \u0026#34;C:\\\\Users\\\\ZXIN\\\\Desktop\\\\001.png\u0026#34; ); namedWindow(\u0026#34;Display Image\u0026#34;, WINDOW_AUTOSIZE ); imshow(\u0026#34;Display Image\u0026#34;, image); waitKey(0); return 0; } CMakeLists.txt内容 cmake_minimum_required(VERSION 2.8) project( DisplayImage ) find_package( OpenCV REQUIRED ) add_executable( DisplayImage DisplayImage.cpp ) target_link_libraries( DisplayImage ${OpenCV_LIBS} ) 编译 如果在命令行cmake的话会找不到路径，所以我改用CMake GUI，先选择CMakeLists所在文件夹和编译后的一个空文件夹 点击Configure，按下图配置，点击Finish 这是应该会报错，这是就体现gui的方便之处了，点击替换正确的OpenCV路径 如果还有报错的话，建议gui左上角清除CMake缓存重新开始，没有问题的话继续点击Generate和Open Project，软件自动打开build下的VS工程文件，VS里右键生成解决方案即可。 ","date":"2019-10-11T16:27:00Z","permalink":"https://kizx.github.io/post/cmake+vs2017%E7%BC%96%E8%AF%91opencv%E7%A8%8B%E5%BA%8F/","title":"CMake+VS2017编译OpenCV程序"},{"content":"The teacher of our group introduced us to some research and views about anxiety. Although we are no longer suffering from diseases, hunger and war in the present era, we still need to worry about health, billing, study, work, interpersonal relationships and so on. We are not only anxious for the present, but also for the future.\nAfter the speech, the teacher asked us three questions.\nThe first question is \u0026ldquo;Have you ever experienced mental anxiety, and what are you anxious about?\u0026rdquo;. Some of our team members are anxious about the exam, while others are worried about their relationship with their classmates, and generally we are all anxious about future work.\nThe second question is \u0026ldquo;What do you think are the causes of anxiety?\u0026rdquo;. After our group discussion, we have summarized the following reasons. First of all, we feel anxious because of the lack of knowledge of anxiety and lack of ability and experience. The second reason is our mentality. When we encounter challenging things, an optimistic and confident attitude will help us overcome anxiety. On the contrary, a negative attitude will contribute to our anxiety.\nThe last question is \u0026ldquo;Do you know how to relieve anxiety? Can you recommend some good ways to relieve anxiety?\u0026rdquo;. In response to the anxiety factors we discussed above, our group members believe that to relieve anxiety, we should first learn more and improve our abilities and experience. So that we can have enough confidence and optimism to overcome anxiety. If we are already in anxiety, we can use the means of self-motivation to distract ourselves from anxiety. And we think that proper venting or relaxation is also a good way to relieve anxiety.\nFinally, I hope everyone can stay away from anxiety and enjoy life!\n","date":"2019-10-11T14:50:00Z","permalink":"https://kizx.github.io/post/we-live-in-an-age-of-anxiety/","title":"We live in an “age of anxiety”"},{"content":"先要下载安装Astyle https://sourceforge.net/projects/astyle/files/\n2. 添加Beautifier插件 打开Qt Creator，在帮助-\u0026gt;关于插件中打开Beautifier插件\n3. 配置Astyle 打开工具-\u0026gt;选项-\u0026gt;Beautifier\n设置Astyle的路径\n设置自定义风格\n风格可以参考官方说明http://astyle.sourceforge.net/astyle.html#_Brace%20Style%20Options\n4. 设置快捷键 在选项-\u0026gt;环境-\u0026gt;键盘里搜索format，选择相应项设置快捷键，当然我们设置了保存时自动规范，不用快捷键也行，在工具菜单栏里也可以相应命令\n参考：\nhttps://www.techieliang.com/2018/01/873/ ","date":"2019-10-09T11:55:00Z","permalink":"https://kizx.github.io/post/%E7%94%A8astyle%E4%B8%BAqt-creator%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%A0%81%E8%87%AA%E5%8A%A8%E6%A0%BC%E5%BC%8F%E5%8C%96%E5%8A%9F%E8%83%BD/","title":"用Astyle为Qt Creator添加代码自动格式化功能"},{"content":"假设已经下载安装了OpenCV和Qt并且配置好了OpenCV的环境变量，环境变量设置可以参考以前的文章。\nCMake编译 许多教程都会从CMake编译OpenCV开始，但其实我们下载的安装包解压后已经编译好了，bulid文件下就是编译后的文件，除非有特殊要求，可以不用亲自编译。主要是我尝试用CMake编译Source但是报错失败了，就此作罢。\n编写pri文件 新建一个文件，重命名为opencv.pri，写入以下内容，其实和在VS2017里配置库环境是一样的道理。\nINCLUDEPATH += c:/opencv/build/include Debug: { LIBS += -lc:/opencv/build/x64/vc15/lib/opencv_world411d } Release: { LIBS += -lc:/opencv/build/x64/vc15/lib/opencv_world411 } 新建工程 在Qt里新建一个最普通的工程，编译器选择VS2017 64bit，新建完成后在工程的pro文件最后添加刚才的pri文件路径： include(c:/opencv/opencv.pri)\n测试代码 在main函数里进行测试\n#include \u0026#34;mainwindow.h\u0026#34; #include \u0026lt;QApplication\u0026gt; #include \u0026#34;opencv2/opencv.hpp\u0026#34; int main(int argc, char *argv[]) { QApplication a(argc, argv); using namespace cv; Mat img = imread(\u0026#34;../001.png\u0026#34;); imshow(\u0026#34;TEST\u0026#34;,img); waitKey(0); return a.exec(); } ","date":"2019-10-07T14:20:00Z","permalink":"https://kizx.github.io/post/opencv--+-qt-%E9%85%8D%E7%BD%AE/","title":"OpenCV  + Qt 配置"},{"content":"方案一：Anaconda自带 这个不用细说，进入Anaconda官网下载安装包安装即可，安装完自带jupyter。\n方案二：手动安装 通过pip安装 pip install jupyter notebook 安装完命令行输入命令打开 jupyter notebook 配置 先安装nbextension jupyter contrib nbextension install jupyter contrib nbextension install --user 安装完打开jupyter首页应该就会多出一个Nbextension的插件配置页\n代码自动规范 安装插件 pip install yapf 在插件配置页勾选Code prettify 安装启用完在代码页的菜单栏就会多出一个油漆滚筒的图标，点击即可代码自动格式化 代码提示 虽然在写代码时按Tab键可以进行代码提示，但不是实时的，效率很低，最好能像ide里一样进行自动提示。方法很简单，在Nbextension的插件配置页勾选Hinterland即可。\n","date":"2019-10-07T08:38:00Z","permalink":"https://kizx.github.io/post/jupyter%E5%AE%89%E8%A3%85%E5%92%8C%E9%85%8D%E7%BD%AE/","title":"jupyter安装和配置"},{"content":"Good afternoon everyone, then I will share with you a news about the IG Nobel Prize. This prize is an interesting imitation of the Nobel Prize, and it is awarded to those scientific achievements that first make people laugh, then make them think deeply.\nThis month, the 29th first Ig Nobel Prize was announced, and this year\u0026rsquo;s winners, covering 10 categories. So next I will choose some of them to introduce to you.\nFirst of all. The Medical Prize was awarded to Italian scientists for pizza and illness studies. The researchers showed that “often eat pizza ” seems to have a lower risk of cancer and heart attack. But there\u0026rsquo;s just one catch – the pizza must be made and eaten in Italy. Maybe they only did experiments on Italians.\nThe next prize is very interesting. The award for the Medical Education Prize is to train the surgeon with \u0026ldquo;clicker training\u0026rdquo;. People often use it to train dogs and other animals. But the study found that training a surgeon would be as similar as training a dog.\nThe Biology Prize is more interesting. The researchers placed a group of live cockroaches and dead cockroaches in a strong magnetic field. After 20 minutes, the dead cockroaches could be sucked into the refrigerator like a sticker, but the live group could not. This research may reveal the connection between biology and magnetic fields, and could help in the development of new magnetic sensors.\nThe Engineering Prize was awarded to the invention of an automatic baby-diaper-changing machine. That\u0026rsquo;s sounds like a good invention. unfortunately the machine doesn\u0026rsquo;t actually change the child\u0026rsquo;s diaper. Instead, it is a bit like an oven to dry the diaper.\nThe Chemistry Prize examines how much saliva a 5-year-old child will produce one day. It turned out that the five-year-old child produce about 500 milliliter of saliva a day. But we are still not sure what the significance of this study.\nThe most funny award is the Physics Prize. Researchers had discovered how the wombat manages to produce cube-shaped poo. It\u0026rsquo;s the only animal in the world known to do this, and the team found the secret of the cube-shaped poo is their intestine movement. But the researchers still don\u0026rsquo;t know for sure why wombats evolved to produce cube-shaped poo.\n(Next is the Peace Prize. Tickling will always make you feel good. However, do you know which part of the body can effectively relieve itching? Do you know how to scratch to maximize your body and mind? This research will make you feel comfortable and scratched.\nThe Economics Prize examines which country\u0026rsquo;s banknotes are the most susceptible to dangerous bacteria. Does this have anything to do with the economy?)\nreference https://newatlas.com/science/ig-nobel-awards-2019/ https://mp.weixin.qq.com/s/jcjwCNhju1eK_ehSKHiq7g Questions Do you think the Ig Nobel Prize makes sense, or is it just for fun? Which Prize do you think is the most interesting？ Can you also give a similar interesting research? ","date":"2019-09-30T17:07:00Z","permalink":"https://kizx.github.io/post/ig-nobel-prize/","title":"IG Nobel Prize"},{"content":"1. 加减 得益于广播机制，numpy的算术比较灵活\nimport numpy as np a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]) b = np.array([[10, 20, 30, 40], [50, 60, 70, 80]]) c = a + b d = a + 10 e = a + [1, 2, 3, 4] print(c) print(d) print(e) 注意：当两个数据类型不同的数组相加减时，结果以范围大的为准，比如uint8+float32=float32，uint8超出范围数据溢出时对255取模后减1。\n2. 乘除 import numpy as np a = np.array([1, 2, 0], np.uint8) b = np.array([125, 150, 200], np.uint8) # 乘法 print(a * b) print(np.multiply(2, b)) # 除法 print(b / a) # 矩阵乘法 print(np.dot(a, b.T)) print(a @ b.T) 3. 其他运算 方法 示例 注意事项 转置 A.T 转置 np.transpose(A) 改变形状 A.reshape(4,2) 改变形状 np.resize(A, (4,2)) 迭代 for element in A.flat: 迭代 A.flatten() 迭代 for element in np.nditer(A): 展开 A.ravel() 会改变原数组 分割 np.split(A,3) 添加 np.append(A, [7,8,9],axis=1) 插入 np.insert(A, 2, [7,8,9],axis=1) 删除 np.deleter(A,1,axis = 1) 乘方 np.power(A,2) 乘方 ** ","date":"2019-09-26T10:18:00Z","permalink":"https://kizx.github.io/post/numpy%E5%AD%A6%E4%B9%A0%E4%BA%8C/","title":"NumPy学习（二）"},{"content":"1. 安装和学习 pip安装 pip install numpy Anaconda自带 学习资源 菜鸟NumPy 教程 NumPy中文网 2. ndarray import numpy as np # 一维数列 a1 = np.array([1, 2, 3]) print(a1) # 二维数列 a2 = np.array([[1, 2], [3, 4]]) print(a2) # 定义最小维度 a3 = np.array([1, 2, 3, 4], ndmin=2) print(a3) # 指定数据类型 a4 = np.array([1, 2, 3], dtype=np.float32) print(a4) 3. 数据类型 import numpy as np # 使用标量类型 dt1 = np.dtype(np.int32) print(dt1) # int8, int16, int32, int64 四种数据类型可以使用字符串 \u0026#39;i1\u0026#39;, \u0026#39;i2\u0026#39;,\u0026#39;i4\u0026#39;,\u0026#39;i8\u0026#39; 代替 dt2 = np.dtype(\u0026#39;i4\u0026#39;) print(dt2) # 还可以像结构体一样用 student = np.dtype([(\u0026#39;name\u0026#39;, \u0026#39;S20\u0026#39;), (\u0026#39;age\u0026#39;, \u0026#39;i1\u0026#39;), (\u0026#39;marks\u0026#39;, \u0026#39;f4\u0026#39;)]) a = np.array([(\u0026#39;abc\u0026#39;, 21, 50), (\u0026#39;xyz\u0026#39;, 18, 75)], dtype=student) print(a) print(a[\u0026#39;name\u0026#39;]) print(a[1]) 4. 数组属性 import numpy as np a = np.array([[0, 1, 2, 3], [4, 5, 6, 7]]) # 维度 print(a.ndim) # 各维度大小 print(a.shape) # 现在调整其大小 a.shape = (4, 2) print(a) b = a.reshape(2, 4) print(b) print(b.ndim) # b 现在拥有三个维度 b = a.reshape(2, 1, 4) print(b) print(b.ndim) # 数组元素的字节大小 x = np.array([1,2,3], dtype = np.int8) print (x.itemsize) 5.特殊数组 import numpy as np # 未初始化的数组 x = np.empty([3, 2], dtype=int) print(x) # 元素为零 # 默认为浮点数 x = np.zeros(5) print(x) # 设置类型为整数 y = np.zeros((5, ), dtype=np.int) print(y) # 自定义类型 z = np.zeros((2, 2), dtype=[(\u0026#39;x\u0026#39;, \u0026#39;i4\u0026#39;), (\u0026#39;y\u0026#39;, \u0026#39;f4\u0026#39;)]) print(z) # 对角矩阵 x = np.eye(4) print(x) # 从列表或元组转换 # numpy.asarray(a, dtype = None, order = None) x = [1, 2, 3] a = np.asarray(x) print(a) x[0] = 0 print(x) # 序列 # numpy.arange(start, stop, step, dtype) x = np.arange(10, 20, 2) print(x) # np.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None) x = np.linspace(10, 20, 6) print(x) # 重复 b = np.array([1, 2, 3]) bb = np.tile(b, (2, )) print(bb) 6. 数组切片 import numpy as np a = np.arange(10) print(a) s = slice(2, 7, 2) # 从索引 2 开始到索引 7 停止，间隔为2 print(a[s]) b = a[2:7:2] # 效果同上 print(b) a = np.array([[1, 2, 3], [3, 4, 5], [4, 5, 6]]) print(a) # 从某个索引处开始切割 print(a[1:, 1:]) print(a[1:, [1, 2]]) print(a[:, 0]) #获取列元素 7. 高级索引 import numpy as np x = np.array([[1, 2], [3, 4], [5, 6]]) y = x[[0, 1, 2], [0, 1, 0]] #获取数组中(0,0)，(1,1)和(2,0)位置处的元素 print(y) x = np.array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) rows = np.array([[0, 0], [3, 3]]) cols = np.array([[0, 2], [0, 2]]) # 获取四个角元素 y = x[rows, cols] print(y) # 通过判断布尔 x[x \u0026gt; 5] = 0 print(x) # 通过索引 x = np.arange(32).reshape((8, 4)) print(x[[4, 2, 1, 7]]) x = np.arange(32).reshape((8, 4)) print(x[np.ix_([0, 1, 6, 7], [3, 2, 1, 0])]) ","date":"2019-09-25T08:43:00Z","permalink":"https://kizx.github.io/post/numpy%E5%AD%A6%E4%B9%A0%E4%B8%80/","title":"NumPy学习（一）"},{"content":"1. 获取5T空间 OneDrive当云盘的好处是不限速，但实际速度并不会跑满带宽，具体速度以实际情况为准，我的速度用客户端上传的话最快能跑到7M/s，网页下载配合idm的话有时能跑满带宽，还是相当给力的。其次还有一个优点就是内容不会被和谐。\n但普通邮箱注册只有5G的免费空间，教育邮箱注册可以获得5T的免费空间，但一般正规教育邮箱注册只有1T的可用空间，不过1T也基本上够用了，如果没有教育邮箱可以选择花几块钱买一个5T账号省的麻烦。\n注意我们这里注册的是office365的账号和微软账号通用，可以通过以下方法查看空间大小：登录到office365，进入OneDrive，选择右上角设置-\u0026gt;OneDrive设置，继续选择其他设置-\u0026gt;存储标准即可看到空间大小，或者打开onedrive桌面客户端也可以进行查看。\n2. 桌面客户端使用 win10系统是自带Onedrive客户端的，搜索打开OneDrive并登录后，设置一个文件夹为同步文件夹。\nOneDrive不同于国内的网盘，和国内的坚果云有点类似。他是一个同步云盘，同步文件夹里所有文件都是和云端同步的，上传文件只需把文件拖进同步文件夹内即可。\n但由于是同步的如果本地删除文件云端也会删除，云端删除文件本地也会删除，这点就很坑了，可能国人更喜欢把云盘当一个存储资料的硬盘来使用，我本地删除了云端也没了那还存个屁啊。在这一点上国内云盘就很人性化了，单独有一个同步文件夹可供使用。\n所以微软是怎么解决这个问题的呢，OneDrive有个文件随选功能，具体见官方说明通过适用于 Windows 10 的 OneDrive 文件随选节省磁盘空间。 通过右键文件选择释放空间，文件就会被标注为在联机时下载使用，也就是本地就是一个快捷方式一样的东西，在打开使用这个文件时就会下载这个文件。但要注意的是如果你删除这个“快捷方式”，云端同样会删除文件，坑啊。\n还有一个办法是打开OneDrive设置，找到一个同步选项，去掉你想删除的文件使其不同步，这样一来本地文件就自动删除了而云端数据仍然保留，也就是使这个文件在本地不同步。但这个做法你想要再下载这个文件的话，要么去云端再下载，要么重新勾上同步，这就有点小麻烦了。\n3. 搭建云盘 使用OneDrive还有一个好处就是可以用来搭建个人云盘，也可以用来搭建个人图床，如果你有一台服务器的话，那么你可以选择OneIndex,OLAINDEX,PyOne,CuteOne等方案来部署你的个人云盘，搭建过程和你安装博客程序差不多。\n如果你手头没有空闲的主机，那么也可通过下面的方式利用腾讯云的云函数服务来搭建一个。 我当初是参考这个教程的：https://logi.im/back-end/scf-onedrive-filelistor.html 项目地址：https://github.com/qkqpttgf/OneManager-php 顺便说下学校教育邮箱申请的onedrive可能无法使用这个项目，好像是无法开通api的缘故，但可以用下面的方案通过分享的方式来访问。\n和上面的类似，可以尝试另一个云函数网盘方案onepoint。 这里是使用说明：https://www.onesrc.cn/p/onepoint-configuration-process.html\n附onedrive种类示意图 ","date":"2019-09-23T03:35:00Z","permalink":"https://kizx.github.io/post/onedrive%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/","title":"OneDrive使用指南"},{"content":"Typecho主题推荐 1. PureLoveForTypecho 2. Pinghsu Theme 3. Rinvay Theme 4. VOID 5. ArmxMod 6. AL_lolimeow 7. DUX主题 8. Miracles 9. Typecho-Theme-RAW 10. hufman ","date":"2019-09-15T14:05:00Z","permalink":"https://kizx.github.io/post/typecho%E4%B8%BB%E9%A2%98%E6%8E%A8%E8%8D%90/","title":"Typecho主题推荐"},{"content":"1. SSL配置 默认情况下使用SSL浏览器会提示有危险加载项，而且后台也进不去，这时只需要在后台将在目录下的 config.inc.php文件中添加一下代码即可一切正常\n/** 开启HTTPS */ define(\u0026#39;__TYPECHO_SECURE__\u0026#39;,true); 2. 只显示首页 这个问题比较蛋疼，只有首页和后台可以显示，文章页和其他页面无法显示，点击任何文章或其他链接都只会显示首页，刚开始我还以为是安装过程出错，来回重装了好几次都还是这样，经过大量搜索查阅，都说是当前php不支持pathinfo的缘故，但我发现只要把设置里的永久链接自定义文章路径改成除默认路径以外的路径，点击文章就能够正常打开文章页了。 但问题是文章是可以显示了，还有其他页面比如下一页和分类页面还是无法跳转啊，于是我又继续研读了百度云虚拟主机的官方文档，在尝试了网上各种设置后均失败了。但经过大量尝试发现应该是网址中只要出现index.php就无法正常跳转，于是我灵机一动如果设置伪静态rewrite是不是就可以了，结果尝试了一下果然可以。设置也很简单，在后台开启地址重写，然后ftp登录网站空间，在webroot下新建bcloud_nginx_user.conf文件，并写入以下代码即可： if (!-e $request_filename) { rewrite ^(.*)$ /index.php$1 last; } 参考 https://blog.csdn.net/enweitech/article/details/75108048\n","date":"2019-09-13T17:31:00Z","permalink":"https://kizx.github.io/post/%E7%99%BE%E5%BA%A6%E4%BA%91%E8%99%9A%E6%8B%9F%E4%B8%BB%E6%9C%BAbch-+-typecho%E7%9A%84%E4%B8%80%E4%BA%9B%E5%9D%91/","title":"百度云虚拟主机BCH + Typecho的一些坑"},{"content":"1. 下载安装OpenCV并添加环境变量 下载地址：https://opencv.org/releases/ 安装参考：http://c.biancheng.net/view/1104.html 我安装的是Opencv4.1.1版本，然后管理员cmd命令添加环境变量，其实不用命令手动添加也行,不过这一步似乎不是必须的，但可能会与某些步骤有关联。 setx -m OPENCV_DIR C:\\opencv\\build\\x64\\vc15 然后添加以下OpenCV环境变量到PATH中，VS2017应该对应的是vc15，不过都加进去也不会出错。路径直接填%OPENCV_DIR%\\bin也行。 C:\\opencv\\build\\x64\\vc14\\bin C:\\opencv\\build\\x64\\vc15\\bin\n2. 新建工程 打开vs2017，新建控制台程序，将系统平台改成64位，在项目上右键属性配置下列项目\n点击VC++目录-\u0026gt;包含目录，添加include文件夹目录 点击VC++目录-\u0026gt;库目录，添加lib文件夹目录 点击链接库-\u0026gt;输入-\u0026gt;附加项，添加lib，其中opencv_world411d.lib为debug模式用的，opencv_world411.lib为release模式用的，都可以在lib文件夹下找到 3. 测试代码 打开一张图片进行测试\n#include \u0026lt;iostream\u0026gt; #include \u0026lt;opencv2/core.hpp\u0026gt; #include \u0026lt;opencv2/highgui.hpp\u0026gt; using namespace cv; int main() { Mat img = imread(\u0026#34;C:\\\\Users\\\\ZXIN\\\\Desktop\\\\cv\\\\001.png\u0026#34;); imshow(\u0026#34;001\u0026#34;, img); waitKey(0); return 0; } ","date":"2019-09-11T17:25:00Z","permalink":"https://kizx.github.io/post/opencv-+-visual-studio2017-%E9%85%8D%E7%BD%AE/","title":"OpenCV + Visual Studio2017 配置"},{"content":"我这个搭配有点奇怪，但是顺手最重要嘛，先收藏几个教程 OpenCV教程\n下载安装OpenCV https://opencv.org/releases/\n下载安装Anaconda https://www.anaconda.com/distribution/\n配置文件 如果都是默认安装路径的话，将C:\\opencv\\build\\python\\cv2\\python-3.7\\cv2.cp37-win_amd64.pyd复制到C:\\Users\\ZXIN\\Anaconda3\\Lib目录下\n新建测试文件 打开VSCode，将左下角Python运行环境切换到Anaconda的Python解释器，敲入一下测试代码：\nimport cv2 img = cv2.imread(\u0026#34;001.png\u0026#34;) cv2.imshow(\u0026#34;Image\u0026#34;, img) cv2.waitKey(0) cv2.destroyAllWindows() ","date":"2019-09-11T08:23:00Z","permalink":"https://kizx.github.io/post/opencv-+-anaconda-+-vscode-%E9%85%8D%E7%BD%AE/","title":"OpenCV + Anaconda + VSCode 配置"},{"content":"总览 方案 Hexo WordPress Zblog Typecho 静态 是 否 否 否 后台 无 有 有 有 源生Markdown 是 否 否 是 操作简单 ☆ ☆☆ ☆☆☆ ☆☆☆ 主题美观 ☆☆☆☆ ☆☆☆ ☆☆ ☆☆☆ 风格简洁 ☆☆☆ ☆ ☆☆☆ ☆☆☆☆ 评价 Hexo所有数据都在本地操作，操作完后本地生成静态页面，然后再通过git或者ftp部署上传到服务器空间，但是我试了官方的ftp插件根本就用不了，只能借助第三方的ftp工具或插件，而且上传速度还贼慢，故不建议ftp到服务器上。优点是完全静态的，故不需要数据库和任何语言运行环境，所以可以部署到github或者coding这样的免费数据托管空间。虽然Hexo对服务器的要求最低，但在本地的操作有点繁琐，需要敲一些代码，很有极客范。Hexo的主题大部分都是免费的，不乏很多漂亮的主题，我的Hexo主题搜集，Hexo的主题很时髦精致。\nWordPress作为使用最广泛的建站方案，东西最多也最全，但这也造成其自身的臃肿，安装包有好几十兆，后台的操作也不是特别简洁好懂，对于追求简洁的人来说，WordPress并不是最好选择。WordPress的主题很多，但要想找到一个合适的主题并不容易，我的WordPress主题搜集。\nZblog在使用上和WordPress差不多，但是后台要更简洁明了，本身的体积也比WordPress小得多，只有几兆，运行效率据说也快得多，主题虽然不多但也很多不错的选择，而且Zblog的主题给人一种简洁感，我的Zblog主题搜集，Zblog的主题多偏向于扁平风格，不追求更多功能时在我看来是比WordPress更好地选择。\n说到简介，Typecho显然更胜一筹，安装包只有几百kb大小，后台也简洁到没有一处多余功能，Typecho的主题大都也继承这种简洁风格，可供选择主题的主题还算是蛮多的，我的Typecho主题搜集，虽然简洁但也是五脏俱全，如果能懂一点网页编程的话就能更好的改造出适合自己的主题了。\n","date":"2019-09-06T18:22:00Z","permalink":"https://kizx.github.io/post/hexowordpresszblogtypecho%E6%AF%94%E8%BE%83/","title":"Hexo、WordPress、Zblog、Typecho比较"},{"content":"Zblog主题推荐 1. filmlee https://www.talklee.com/blog/162.html\n2. 免费博客主题Blogs https://app.zblogcn.com/?id=1405\n3. 奇客 http://jiuwanwl.com/post/81.html\n4. 博客CMS图片布局三合一主题 https://app.zblogcn.com/?id=1326\n5. 业余爱好 https://app.zblogcn.com/?id=494\n6. 博客模板 https://app.zblogcn.com/?id=1168\n7. 简单格子列表主题 https://app.zblogcn.com/?id=877\n","date":"2019-09-06T17:20:00Z","permalink":"https://kizx.github.io/post/zblog%E4%B8%BB%E9%A2%98%E6%8E%A8%E8%8D%90/","title":"Zblog主题推荐"},{"content":"WordPress主题推荐 1. Dobby Download: https://github.com/Vtrois/Dobby\n2. Git Demo: https://gitcafe.net/\nDownload: https://gitee.com/yunluo/git\n3. H-Siren Demo: https://haremu.com/\nDownload: https://github.com/galnetwen/H-Siren\n4. Kratos-pjax Demo: https://moedog.org/787.html\nDownload: https://github.com/xb2016/kratos-pjax\n5. lolimoe Demo: https://www.boxmoe.com/\nDownload: https://github.com/baomihuahua/lolimeow\n6. Sakura Demo: https://2heng.xin/\nDownload: https://github.com/mashirozx/Sakura\n7. Memory Demo: http://memory.shawnzeng.com/\nDownload: https://shawnzeng.com/wordpress-theme-memory.html\n8. Amativeness Demo: https://diygod.me/\nDownload: https://github.com/DIYgod/Amativeness\n","date":"2019-09-05T17:19:00Z","permalink":"https://kizx.github.io/post/wordpress%E4%B8%BB%E9%A2%98%E6%8E%A8%E8%8D%90/","title":"WordPress主题推荐"},{"content":"Hexo主题推荐 双栏 1. A-ACE Demo: http://www.sumoon.com/ Download：https://github.com/kinggozhang/hexo-theme-ace\n2. ARIA Demo: https://sh.alynx.moe/ Download: https://github.com/AlynxZhou/hexo-theme-aria/blob/master/README.zh_CN.md\n3. Asnippet Demo: https://www.91h5.cc/ Download: https://github.com/shenliyang/hexo-theme-snippet\n4. Jacman Demo: http://wuchong.me/jacman/ Download: https://github.com/wuchong/jacman/blob/master/README_zh.md\n5. gal Demo: http://sora3.coding.me/ Download: https://github.com/ZEROKISEKI/hexo-theme-gal\n6. Nexmoe Demo: https://nexmoe.com/ Download: https://nexmoe.com/371865617.html\n7. Sakura Demo: https://sakura.hojun.cn/ Download: https://github.com/honjun/hexo-theme-sakura/blob/master/README-zh_cn.md\n8. Diaspora Demo: http://fech.in/ Download: https://github.com/Fechin/hexo-theme-diaspora\n卡片式 1. skapp Demo: http://blog.minfive.com/ Download: https://github.com/Mrminfive/hexo-theme-skapp/blob/master/README-cn.md\n2. flex-block Demo: https://miiiku.xyz/ Download: https://github.com/miiiku/flex-block\n3. Matery Demo: https://blinkfox.github.io Download: https://blinkfox.github.io/2018/09/28/qian-duan/hexo-bo-ke-zhu-ti-zhi-hexo-theme-matery-de-jie-shao/\n4. Hueman Demo: https://blog.zhangruipeng.me/hexo-theme-hueman/ Download: https://github.com/ppoffice/hexo-theme-hueman\n5. Material Flow Demo: https://kntan.coding.me/kntan/ Download: https://github.com/stkevintan/hexo-theme-material-flow\n6. Mic Demo: http://miccall.tech/ Download: https://github.com、miccall/hexo-theme-Mic_Theme\n","date":"2019-09-03T17:18:00Z","permalink":"https://kizx.github.io/post/hexo%E4%B8%BB%E9%A2%98%E6%8E%A8%E8%8D%90/","title":"Hexo主题推荐"},{"content":"前言 酷Q机器人应用一般都是用易语言开发的，但是一方面不想再多学一门易语言，另一方面开发脚本还是用Python比较舒服。关于Python的酷Q的SDK我在论坛找了一下，目前用的比较多的有两个（现在应该是三个了，见文末），一个是基于http的none-bot，功能更强大，但上手有一定难度，所以最简单的我觉得还是慕晓飞大大的 Python酷Q_SDK_X 本站更多关于酷Q的文章：点我 环境配置 首先需要按照文档的说明配置开发环境，这点文档讲的很详细，就不赘述了，需要注意的是：\n酷Q本身是32位程序，开发时只支持32位的Python。 还有一点就是app_id应该按照官方规范来，否则可能会出问题，规范说明。 酷Q升级后开发环境的目录移动至酷Q的dev目录下，如果酷Q没有自动更正的话请手动更正。更正方法为，在dev目录下新建cn.muxiaofei.coolq_sdk_x文件夹，将原来的cn.muxiaofei.coolq_sdk_x.dll和cn.muxiaofei.coolq_sdk_x.json重命名为app.dll和app.json移动至新建的文件夹下，其他不变。 配置完环境，如果不出意外的话，应该就能在酷Q日志的DEBUG里看到输出的hello world。\n编写程序 接下来就是敲自己的代码了，这个SDK的所有事件处理和API调用都在CQPlusHandler.py文件的?MainHandler类中进行编写，关于事件和参数的说明在开发文档中都有说明，API可以通过输入self.api的代码提示进行查看，也可以转到一个_api.py的文件中查看，至于这些API函数和参数的意义基本上看名字就能猜到八九分了，具体使用方法需要自己去尝试。 新手需要注意的是这个CQPlusHandler.py程序是由酷Q软件自动执行的，不需要在Python的IDE里点运行，当然你点了也没用，如果setting里的DEBUG参数你没改的话，只要修改代码并保存，修改的代码就会实时生效。 然后需要说明的就是@和表情，这个需要使用CQ码，CQ码详细介绍。但一般只需在QQ中发一条包含@或表情的消息，然后通过酷Q的日志就能直接进行右键复制了，复制后只需将相应的格式通过字符串的格式和普通消息一样输出就行了。 举个例子，在CQPlusHandler.py文件中写入以下代码就能实现在群聊里复读并@发言的人的功能： # -*- coding:utf-8 -*- import cqplus class MainHandler(cqplus.CQPlusHandler): def handle_event(self, event, params): if event == \u0026#34;on_group_msg\u0026#34;: msg = \u0026#39;[CQ:at,qq=\u0026#39; + str(params[\u0026#39;from_qq\u0026#39;]) + \u0026#39;]\u0026#39; + params[\u0026#39;msg\u0026#39;] self.api.send_group_msg(params[\u0026#39;from_group\u0026#39;], msg) 案例 然后下面是我根据需求给群友写的一个自助Roll游戏的插件，和论坛上我能找到的抽奖插件相比，这个插件的特点在于完全由qq消息进行命令，可以直接丢到服务器上就不用管了，另一个特点是可以同时进行多个Roll游戏活动而互不干扰，以下是一个使用案例。这个应用其实还有一些功能我想过但还没加进去，以后根据需要有时间再看看吧，我把我写的垃圾代码放在了GitHub上，希望可以给有需要的人一点有价值的参考：Github链接 已知问题 打包 最后就是应用的打包，直接使用打包生成的cpk文件会报错，需要像开发应用一样配置好环境并把源程序也放进去，唯一的差别就在于可以不用进入酷Q的开发者模式，所以要丢到服务器上的话，还有一丢丢的麻烦。由于Python的SDK的特性，编写的插件就不能像论坛上别的插件一样只发布cpk文件即可，而且使用者还需配置环境，对于普通用户来说过于麻烦了，所以这个还是只适合开发者自己使用。 消息并发处理 由于Python的GLI锁机制，本插件不支持并发处理。表现为有事件发生时，比如各种消息和定时器事件，插件便会调用一次CQPlusHandler.py进行事件处理，所以当上一次事件还未处理完时，下一个事件又紧接着发，这时便会发生内存报错。虽然报错了程序并不会崩溃，不过如果程序要处理网络请求一类的耗时任务，这个缺陷是致命的。要想避免这种报错，只在CQPlusHandler.py文件里下功夫（比如用多线程）应该是不行的，估计得从源码上想想办法才行。不过我的机器人不需要处理大量消息，消息处理的也很快，所以凑合用用也还行。 后来有大神重新写了个支持并发的python SDK，现在也更推荐使用这个或者更高级的nonebot。 ","date":"2019-09-03T16:59:00Z","permalink":"https://kizx.github.io/post/python%E9%85%B7q%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91/","title":"Python酷Q应用开发"},{"content":"前言 最近懒癌犯了，本来应该紧接着上一个hexo篇写的，这样也好做一个对比，但长时间不操作我也有点忘了，赶紧靠着仅存的记忆记一下wp建站的操作。\n比起hexo建站，wp在操作上可以说是很简单了，但wp的功能和可玩性比hexo更强，毕竟是应用最广泛的建站方案，其主题数量和应用范围远远超过hexo，除了博客网站，各种新闻、商店、图片等网站也大量使用wp。\n本篇主题为零基础不花一分钱建站，建站需要两样东西：主机空间和域名。我这里的不花一分钱主要指免费的主机空间，主机空间一般都有临时域名可以拿来用用，所以买域名的钱我就不算了，而且最便宜的域名也只要1块钱，也不算贵。\n方案一：coding一键部署方案 没错还是hexo里用到的那个coding，依赖于腾讯的在线云平台cloud studio实现免费的主机空间，只需两步即可款速实现一键部署wp。\n这是官方使用指南\n第一步进入cloud studio从模板新建一个wordpress工作空间\n第二步进入工作空间打开右侧的一键部署，点击一键部署，部署完毕后点击打开测试域名就进入到下图所示的wp的初始化界面了，然后填写相应信息网站即创建成功，数据库的信息在一键部署的资源面板里可以查到，注意信息不能填错了。\n第二步补充，如果信息怎么填都不对的话，可以试试主动修改主目录下的wp-config-sample.php文件其中的四个参数，注意主机要填写 mysql.coding.io，填写好后另存为wp-config.php文件即可。\n建议采用补充的方法，这样每次重新部署时就不需要重新再填一遍信息了，不过要注意相应的仓库不能公开，不然别人就知道你的数据库了。\n第三步，如果你有域名的话，可以为域名添加解析，然后在一键部署面板里添加域名绑定，这样就可以用域名来访问网站了，添加解析的操作具体看官方指南这里略过。 评价\n优点：操作简单无脑，在线操作不需要下载上传任何文件，只要cloud stidio不关门应该就能一直用，而且由于coding是香港服务器访问速度也比较快。 缺点：免费必然有限制，coding默认模板的wp版本较低且为英文版，没有中文，而且coding一键部署的网站不能连接外网，导致wp不能更新，更不能在线下载主题和插件，想要更新wp版本和安装主题只能单独下载新版本wp和自己喜欢的主题，然后自己在coding上新开一个仓库把自己下载解压后的wp和主题push到仓库中，然后以这个仓库为模板新建一个php环境的工作空间进行一键部署，还是比较麻烦的。 方案二：免费的网站服务器 虽然coding的一键部署很方便，但是还是有很多的限制，不如白嫖一个服务器来的实在，哎这里并不是在打广告，我之前找到一个叫强人网络的服务商，可以白嫖一年的网站服务器，凑合着玩玩还是相当不错的。注意这是真的免费而不是像国内有些服务商打着免费的旗号骗注册然后发现要免费使用还要帮它宣传，实在是太恶心了。\n第一步：从wordpress官网下载最新安装包，上传到主机上，我白嫖的这个服务器有自己的控制台，所以连ftp都省了，直接从网页控制台上传压缩包然后在线解压就成了。\n第二步：进入服务商提供的临时域名，后面就和方案一没差了，填写相关信息完成网站初始化，相关信息服务商应该会发邮件给你。\n第三步：如果有域名的话，为域名添加解析，并在服务器控制台绑定域名，然后你就可以通过域名访问你创建的网站了。\n评价：\n优点：操作上由于有控制台，免去了ftp和解压的麻烦，还是相当方便的，最重要的是免费哈哈。 缺点：服务器在国外访问速度较慢，但也还能接受啦，只能免费用一年。 和Hexo比较 由于wordpress有自己的后台管理，在功能上比静态的hexo要强大不少，部署的操作上比较简单，但是部署后网站的后台维护和管理感觉会更麻烦，后台里一堆设置看得人眼花。虽然wp的主题多到数不过来，但是优秀的主题如大海捞针，而且好看的主题大部分都是收费的。从操作上我更喜欢wp，hexo每次都要部署实属麻烦，但hexo的主题我倒是更喜欢。一句话喜欢折腾搞花样的选择wp，喜欢轻便只写博客的选择hexo。\n","date":"2019-08-17T17:17:00Z","permalink":"https://kizx.github.io/post/%E9%9B%B6%E5%9F%BA%E7%A1%80%E4%B8%8D%E8%8A%B1%E4%B8%80%E5%88%86%E9%92%B1%E5%BB%BA%E7%AB%99%E4%B9%8Bwordpress%E7%AF%87/","title":"零基础不花一分钱建站之WordPress篇"},{"content":"前言 之前一个偶然的机会b站首页推荐了一个github+hexo建站的视频，虽然我对写博客没什么兴趣，但是对建站本身倒是很感兴趣，于是尝试做了一下，下面只宏观介绍下，不细节展开了。\n建站流程 建站流程大致如下（这只是一般步骤，后面还有更简单的方案）\n注册github账号并新建一个github.io仓库并进行相应设置 下载安装git并配置好ssh连接 下载安装node.js 开始建站 前两步对于大多数接触过github和git的人来说应该不难，但对于新手来说尤其是git操作其实是还蛮复杂的，但好在这方面的教程相当多，网上随便找找都是教程，b站也有很多视频教程，下面是一个写得很好的比较简洁的教程：另一个教程\n后两步也可以参照下面hexo的官网步骤一步步来就好了：Hexo官方文档\n视频教程的话推荐上面官方文档里的视频，视频在b站也有：官方视频教程B站链接\n个人遇到的坑大概就是由于网络不佳，其中有些命令执行后在下载时经常卡住，多来几次就好了(可能需要fq)，建议命令都在git-bash里执行，cmd里可能会卡住。 然后就是让博客换个好看点的主题，官网提供了不少主题，而且都是免费的，主题的使用方法一般主题介绍里会有写。下面是官方所有主题地址：Hexo官方主题\n完成上面的步骤，在浏览器里输入相应的github.io的博客网址应该就能看到属于自己的博客网站了，到这里也就大功告成了。\n域名 如果你还想继续折腾的话，可以去注册一个域名，这个免费的域名我倒没见过，不过最便宜的域名也只要1块钱，去腾讯云、阿里云、百度云都可以，哪个便宜就选哪个。国内域名购买后首先需要上传身份证实名认证一下，由于github服务器在海外，备案就不需要了。然后按照教程给域名添加解析，并在github里添加绑定。如果这一趟下来无误的话，浏览器里输入你的域名就可以重定向到博客网站上了。\n还有一点不得不提的就是github的国内访问速度较慢，可以使用国内的代码托管平台码云或者是coding。个人更推荐coding，因为码云免费版不支持自定义域名，要想绑定域名还得花钱升级pro版才行。而coding支持自定义域名，而且服务器在香港也不用备案。\n一个更简单的方法 说到coding就不得不提一个更骚的操作，因为coding现在好像和腾讯合作，腾讯出了个cloud studio的云平台功能，可以直接用云平台码代码，这也就意味着只要我们有网络，什么环境都不用装，利用腾讯的cloud studio直接从第四步开始建站就行了，这个可以说是最简单的方法了，非常适合小白。具体教程见下面的链接，用云平台的话部署就不用hexo g命令了，因为平台已经向我们提供了一键部署的功能，具体可以看coding的帮助文档。最后在退出的时候别忘了将代码提交和推送，下次再继续写文章时前拉取一下就可以回到上次提交的进度了。\n最快的 Hexo 博客搭建方法 Hexo搭配代码托管平台搭建博客网站的好处是轻量化，文章支持markdown格式，但只能搭建静态网页，没有后台，一切操作都在本地进行，本地编辑完了再生成网页并部署上传到代码托管平台，至于这是优点还是缺点就看个人偏好了。\n","date":"2019-08-16T17:15:00Z","permalink":"https://kizx.github.io/post/%E9%9B%B6%E5%9F%BA%E7%A1%80%E4%B8%8D%E8%8A%B1%E4%B8%80%E5%88%86%E9%92%B1%E5%BB%BA%E7%AB%99%E4%B9%8Bhexo%E7%AF%87/","title":"零基础不花一分钱建站之Hexo篇"},{"content":"前言 注意以下内容均为本人主观操作感受，运行环境为Win10+python3.7_32位，仅供本人日后查阅\n众所周知，python是一门优美而简洁的编程语言，其最大的不足在于运行速度过于感人，而C语言作为最接近底层的高级语言，速度快是他最大的优势。python被誉为胶水语言，应该有办法和C语言胶和起来，我查阅资料发现python调用C语言最普遍的方式大概有三种：\n将C语言的函数编译成dll动态链接库，然后通过python的ctypes模块对dll进行调用。 借由cython先将python代码编译成C语言代码，然后再讲C代码编译成.pyd文件直接在python中导入进行调用，cython本身有一定语法，不过不会一般也不太影响使用。 使用Swig可以将C代码直接封装成python代码，过程略为复杂，优点是可以为多种语言提供接口。 以上几种方法的原理和过程下图很好的解释了：\n本文以斐波拉契函数为例，探究python和C的合璧之法。\nimport time def fib(n): if n == 0: return 0 elif n == 1: return 1 else: return fib(n-1) + fib(n-2) start=time.time() print(\u0026#34;计算结果:%d\u0026#34; % fib(40)) end=time.time() print(\u0026#39;python time cost:\u0026#39;,end-start) #include \u0026lt;stdio.h\u0026gt; #include \u0026lt;stdlib.h\u0026gt; #include \u0026lt;time.h\u0026gt; int fib(int n) { if (n == 0) { return 0; } else if (n == 1) { return 1; } else { return fib(n - 1) + fib(n - 2); } } int main() { clock_t start, end; start = clock(); printf(\u0026#34;计算结果:%d\\n\u0026#34;, fib(40)); end = clock(); printf(\u0026#34;C cost time:%f\u0026#34;, (double)(end - start) / CLOCKS_PER_SEC); system(\u0026#34;pause\u0026#34;); return 0; } 通过运行上面的代码可以得到运行时间：\n纯python：\n计算结果:102334155\npython time cost: 87.49325394630432 纯C语言：\n计算结果:102334155\nC cost time:0.863000 差不多差了两个数量级吧。。。\n1. 通过ctypes调用dll 首先得先生成一个dll，你可以在ide里新建一个dll工程进行创建。更简单的做法是利用下面的gcc命令直接在cmd里进行编译，但前提是你已经装了Mingw或者并Mingw-w64且设置了环境变量，其中有个比较坑的地方就是你编译出来的dll位数要和你的python位数要匹配，像我笔记本上装的是Mingw-w64，而pyhton是32位的，32的python无法调用64位的dll，而这位Mingw-w64虽说同时支持64位和32位，但是前提是安装时勾选的是sjlj而不是seh，seh不支持32位！\n安装Mingw建议用下面这位up的工具，简单快捷。\n【一键】20秒配置VScodeC语言C++开发环境！\n安装Mingw-w64可以参考：Mingw-w64安装\n用于编译dll的c语言代码只需给出函数就好了：\nint fib(int n) { if(n == 0) { return 0; } else if(n == 1) { return 1; } else { return fib(n-1) + fib(n-2); } } 下面是cmd中将C原文件编译成dll的命令：\ngcc -fPIC -shared name.c -o name.dll 如果是sjlj的Mingw-w64加上-m32可以编译出32位dll：\ngcc -fPIC -shared -m32?name.c -o?name.dll 然后在python中导入ctypes模块就可以调用dll了：\nimport ctypes import time start=time.time() fibpy=ctypes.CDLL(\u0026#39;fibpy.dll\u0026#39;) print(\u0026#34;计算结果:%d\u0026#34; % fibpy.fib(40)) end=time.time() print(\u0026#39;dll time cost:\u0026#39;,end-start) ctype调用dll运行时间：\n计算结果:102334155 dll time cost: 0.9999649524688721 因为只有一个函数，还调用的是C语言的，所以速度和纯C差不多。\n2. cython 先给出官方的一个教程：官方教程\n使用cython首先要安装cython模块：\npip install Cython 然后你需要安装Mingw进行一番配置或者直接下载安装Visual Studio安装C++环境，因为我用的是Mingw-win64，所以自然就先抛弃后面那个巨无霸选用前者，一番尝试后发现还是Visual Studio真香。当然可能单纯的是因为Mingw-win64不支持而已，用Mingw的话应该是可以的（但愿）。\n安装完环境后就可以直接把之前的纯python代码中的函数部分进行cython转换，不过需要现将其后缀名改为.pyx，然后需要再创建一个setup.py文件，其中写入代码：\nfrom distutils.core import setup from Cython.Build import cythonize setup( ? ? ext_modules = cythonize(\u0026#34;fibcy.pyx\u0026#34;) ) 然后还是cmd中执行：\npython setup.py build_ext --inplace 这时应该会生成一个.pyd文件，这个文件本质和前面的dll应该差不多，可以通过import在python中使用：\nimport time import fibcy start=time.time() print(\u0026#34;计算结果:%d\u0026#34; % fibcy.fib(40)) end=time.time() print(\u0026#39;cython time cost:\u0026#39;,end-start) 运行结果：\n计算结果:102334155 cython time cost: 15.108871698379517 可以看到即使是在没有使用任何cython语法的情况下，cython的加速能力也是令人惊叹的，运行速度提高了一个数量级左右！\n3. Swig 同样先给出一个教程参考：Swig教程\n其实swig的原理和前面也差不多，但是过程更为复杂。首先当然要安装swig，下载解压后同样添加到系统环境变量。\n然后要准备的有C语言源文件，一个.i文件，还有一个setup.py文件。\n#include \u0026lt;stdio.h\u0026gt; int fib(int n) { if (n == 0) { return 0; } else if (n == 1) { return 1; } else { return fib(n - 1) + fib(n - 2); } } %module fib %{ #include \u0026lt;stdio.h\u0026gt; %} extern int fib(int n); from setuptools import setup,Extension setup( name=\u0026#39;fib\u0026#39;, version=\u0026#39;1.0\u0026#39;, ext_modules=[Extension(\u0026#39;_fib\u0026#39;, [\u0026#39;fib.c\u0026#39;, \u0026#39;fib.i\u0026#39;])] ) 最后在命令行运行setup.py：\npython setup.py build_ext --inplace 最后生成的文件中应该有一个python文件，可以直接进行调用，除此之外我发现还有一个.pyd文件，果然和前面的方法都差不多呢，导入运行方法也和之前相同。\n运行结果：\n计算结果:102334155 swig time cost: 0.6825790405273438 居然比纯C语言还要快！大概是因为去掉了计时模块的缘故，可能python的计时模块比C的要快？结果还是很匪夷所思呢？\n4. namba的@jit加速 namba加速不同于以上3种方法，上面3种方法多多少少会和C语言扯上点关系。numba则是直接在python源文件里通过加上一些代码直接运行并获得加速效果，本质原理也是使数据向静态靠拢，但是实现过程与上面3种方法相比更简单，可以参考官方入门教程\n下面具体看一下实现过程： 首先肯定是要先安装numba包\npip install numba 然后只需在Python代码中导入numba并用jit修饰相应的函\nimport time from numba import jit @jit(nopython=True) def fib(n): if n == 0: return 0 elif n == 1: return 1 else: return fib(n-1) + fib(n-2) start=time.time() print(\u0026#34;计算结果:%d\u0026#34; % fib(40)) end=time.time() print(\u0026#39;numba@jit time cost:\u0026#39;,end-start) 运行结果：\n计算结果:102334155 numba@jit time cost: 1.2832109928131104 加速效果可以说是相当惊人的，比cython要快，而且操作也特别简单，不用导来导去，和numpy相配合使用可以使运行速度得到极大的提升。\n总结 方案 运行时间 纯Python 87.49325394630432 纯C语言 0.863000 ctypes 0.9999649524688721 cython 15.108871698379517 swig 0.6825790405273438 numba 1.2832109928131104 python结合c语言的三种方法中ctypes方法最简单，将C代码直接编译成dll即可使用，cython可以为现有的python代码加速，swig可以直接将C转换为python，就是有点麻烦，但速度是最快的。numba的jit加速比上面三种方法都要更简单，只需在python源码里加几句就行了，而且速度也很可观。\n","date":"2019-08-04T17:12:00Z","permalink":"https://kizx.github.io/post/%E5%8A%A0%E9%80%9Fpython%E7%9A%84%E5%87%A0%E7%A7%8D%E6%96%B9%E6%B3%95/","title":"加速Python的几种方法"}]