diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..89b4ec64 --- /dev/null +++ b/404.html @@ -0,0 +1,14 @@ +404 Page not found | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

嗷呜!

看来你来到了一个神秘的地方...( 错误 404 )

请在页面底部选择一个链接或者 点此回到主页

\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..eeda7e6b --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +blog.ohmykreee.top \ No newline at end of file diff --git a/algolia-logo-light.svg b/algolia-logo-light.svg new file mode 100644 index 00000000..47024234 --- /dev/null +++ b/algolia-logo-light.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/android-chrome-192x192.png b/android-chrome-192x192.png new file mode 100644 index 00000000..a0449b8e Binary files /dev/null and b/android-chrome-192x192.png differ diff --git a/android-chrome-256x256.png b/android-chrome-256x256.png new file mode 100644 index 00000000..658e0550 Binary files /dev/null and b/android-chrome-256x256.png differ diff --git a/apple-touch-icon.png b/apple-touch-icon.png new file mode 100644 index 00000000..03e45bcd Binary files /dev/null and b/apple-touch-icon.png differ diff --git a/archive/index.html b/archive/index.html new file mode 100644 index 00000000..39ff00e6 --- /dev/null +++ b/archive/index.html @@ -0,0 +1,14 @@ +文章列表 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/article/deploy-nextjs-static-page-to-github-pages/featuredImage.jpg b/article/deploy-nextjs-static-page-to-github-pages/featuredImage.jpg new file mode 100644 index 00000000..4b602231 Binary files /dev/null and b/article/deploy-nextjs-static-page-to-github-pages/featuredImage.jpg differ diff --git a/article/deploy-nextjs-static-page-to-github-pages/featuredImage_hue2645b58b5e3e0f217c59b84966cf409_27256_700x350_fill_q95_box_smart1.jpg b/article/deploy-nextjs-static-page-to-github-pages/featuredImage_hue2645b58b5e3e0f217c59b84966cf409_27256_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..9f6db0e4 Binary files /dev/null and b/article/deploy-nextjs-static-page-to-github-pages/featuredImage_hue2645b58b5e3e0f217c59b84966cf409_27256_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/deploy-nextjs-static-page-to-github-pages/index.html b/article/deploy-nextjs-static-page-to-github-pages/index.html new file mode 100644 index 00000000..581ef469 --- /dev/null +++ b/article/deploy-nextjs-static-page-to-github-pages/index.html @@ -0,0 +1,30 @@ +关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项

2021-11-18 +Learning +Kreee

个人主页 www.ohmykreee.top 涅槃重生啦 ,快去围观吧!

(怎么这文案一股营销号的味道)

零、说点废话

本来按照惯例,整完一个项目是要写一篇在做这个项目中学到的东西。但是因为这次懒癌犯了(我不掩饰了,来咬我啊咬我啊~~),这次就只写写如果要将 Next.js 项目渲染为静态网页并发布在 GitHub Pages 时要注意的几点。

(其实是那些知识点有点杂,并且是涉及某个特定的库的问题,没啥太大的参考价值。如果想要一起学习的话可以考虑直接看项目源代码,反正整个项目体量也不是很大。)

一、Next.js 和 静态网页渲染

参考: Static HTML Export - Next.js

使用命令 next build && next export 就可以将整个项目渲染为静态的 HTML 文件,并且输出到 out 文件夹。默认情况下不需要额外的配置。

如果想要进一步简化操作,也可以编辑 package.json 关于 build 的命令:

"scripts": {
+ "build": "next build && next export"
+}
+

然后运行 npm run build 就行了。

二、Jekyll 和 下划线

参考: Bypassing Jekyll on GitHub Pages - GitHub Blog

其实 GitHub Pages 并不是一个单纯的静态网页提供服务,而是一个 Jekyll 服务(用官方的话讲,就是:GitHub Pages is powered by Jekyll.)而 在 Jekyll 生成最终的网站前会忽略所有开头带有 _ 的文件夹和文件

但是好巧不巧:在 Next.js 生成的文件中,一些关键文件是存放在 _next 文件夹中的(我觉得是故意的),导致了如果直接把生成的文件 push 到 GitHub Pages 上时,整个网页将会崩掉。

解决方法嘛,很简单,就在根目录放一个名字为 .nojekyll 的空文件,这样 GitHub Pages 在生成最终的网页时会强制跳过 Jekyll 的处理。

如果使用 GitHub actions,可以在流程文件里这样写:

     - name: Build static page
+       run: |
+         npm run build
+         touch ./out/.nojekyll         
+
\ No newline at end of file diff --git a/article/docker-notes/index.html b/article/docker-notes/index.html new file mode 100644 index 00000000..d179f99e --- /dev/null +++ b/article/docker-notes/index.html @@ -0,0 +1,34 @@ +Docker 学习小记 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

Docker 学习小记

2021-03-01 +Learning +Kreee

本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
Now, let’s begin!


安装 Docker

基于 https://mirrors.tuna.tsinghua.edu.cn/help/docker-ce/

如果是全新安装(并且使用的是 Minimal 安装的话),是没有预装 Docker 的。如果有请先卸载。
查询是否有 Docker :

rpm -qa | grep Docker
+

卸载 Docker :

yum remove docker docker-common docker-selinux docker-engine
+

安装依赖:

yum install -y yum-utils device-mapper-persistent-data lvm2
+

下载 repo 文件:

wget -O /etc/yum.repos.d/docker-ce.repo https://download.docker.com/linux/centos/docker-ce.repo
+

替换软件仓库地址(此处为 TUNA )
(什么时候我们学校也搞一个开源软件镜像库啊?)

sed -i 's+download.docker.com+mirrors.tuna.tsinghua.edu.cn/docker-ce+' /etc/yum.repos.d/docker-ce.repo
+

安装 Docker :

yum makecache fast
+yum install -y docker-ce
+

启动 Docker :

systemctl start docker
+

Docker 的使用

列出所有容器:

docker ps -a
+

启动一个容器(使用容器 ID ):

docker start *containerID*
+

同理,停止 stop ,重启 restart ,清除 rm ,查看映射端口 port ,查看日志 logs

创建容器并后台运行与进入后台容器:

docker run -itd --name *yourname* *container*
+docker exec -it *containerID*
+
\ No newline at end of file diff --git a/article/frontend-dev-with-android-pad/featuredImage.jpg b/article/frontend-dev-with-android-pad/featuredImage.jpg new file mode 100644 index 00000000..1b608f10 Binary files /dev/null and b/article/frontend-dev-with-android-pad/featuredImage.jpg differ diff --git a/article/frontend-dev-with-android-pad/featuredImage_hu22ca3d987e8c00f44bc1d55611c77eaa_53784_700x350_fill_q95_box_smart1.jpg b/article/frontend-dev-with-android-pad/featuredImage_hu22ca3d987e8c00f44bc1d55611c77eaa_53784_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..c4bcacb0 Binary files /dev/null and b/article/frontend-dev-with-android-pad/featuredImage_hu22ca3d987e8c00f44bc1d55611c77eaa_53784_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/frontend-dev-with-android-pad/index.html b/article/frontend-dev-with-android-pad/index.html new file mode 100644 index 00000000..6c3d84e2 --- /dev/null +++ b/article/frontend-dev-with-android-pad/index.html @@ -0,0 +1,36 @@ +使用 Android Pad 进行(前端)开发 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 Android Pad 进行(前端)开发

2021-12-05 +Learning +Kreee

四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。

四舍五入又水了一篇


写在前面

得益于强大的 Termux,我们可以在安卓系统上玩一些 奇奇怪怪 的东西。

一切都开始于那一天:当我刷着B站,主页刷到了一个关于 code-server 的视频,然后从评论区里得知原来 Termux 还可以安装 Linux 发行版。这我就来劲了啊:本来当时买这个板子的时候就想着能不能用它进行一些简单的开发,结果发现 GitHub Web Editor 这个官方的在线编辑器只能进行文本编辑。现在既然 Termux 里能安装(几乎)全功能的 Linux 发行版,那可玩性就不止一点了。而且操作下来也非常的简单,可以说 Termux 永远的神好吧(误)。

当我被告知 Termux 可以安装 Linux 发行版的时候,我就知道,它小命就不保了。
—— Kreee

(如果你还是嫌麻烦的话/不喜欢纯命令行的环境,我也发现了一个别人做的挺好的一个整合:AidLux ,开箱即用的那种,而且初始就配备了图形化界面,并且(好像)配置好了 GPU 加速的 AI 开发环境。至于为啥我不用那个,其实当我知道那个软件的底层就是 Termux 的时候,我就有点没有兴致了:既然就是个整合,为啥我不自己整一个呢?)


安装 Termux 和 proot-distro

安装 Termux 的话, F-Droid(推荐)和 Google Play Store 上都有,再不行酷安上也有得下,这里我就不贴链接了。

安装完之后,直接使用包安装管理器安装 proot-distro 就行了:

pkg install proot proot-distro
+

如果说下载慢的话,可以考虑一下换源为清华镜像源


安装 Linux 发行版

直接执行 proot-distro list 就可以查看可供安装的 Linux 发行版。

如果对储存空间和性能有一定要求的同学,可以考虑使用 Alpine Linux 发行版。这里因为要追求比较完整的 Linux 体验(以及自己对 Ubuntu 比较熟悉),就选择了 Ubuntu 发行版:

proot-distro install ubuntu
+

等它把必要文件下载好了之后,就可以使用 proot-distro login ubuntu 进入 Ubuntu 了!


一些配置,和安装 code-server

这个 Ubuntu 环境拿到手了,第一步当然是换源为国内源了。由于这个环境还没有文本编辑器,还得先安装一个:

apt install vim
+

安装的时候按提示配置好地区后,就可以根据这个文章换清华源了。(注意几点:一是因为是 arm64 环境,要用 ubuntu-ports 的镜像源,二是默认安装的 Ubuntu 版本是最新的(截止写这篇博文的时候是 21.10),改镜像源的时候要注意一下)

之后就是常规的安装一些需要的软件:

apt install git curl
+

安装 code-server 也很傻瓜化,直接下载并运行安装脚本就行:

curl -fsSL https://code-server.dev/install.sh | sh
+

安装完了之后再顺便改一下 code-server 的配置文件:

cd ~/.config/code-server/
+cp config.yaml config.yaml.bak # 修改配置文件前备份原文件是个好习惯
+vim config.yaml
+

整个配置文件的结构是这样的:

bind-addr: 127.0.0.1:8080
+auth: password
+password: mew...22 # 随机生成的密码
+cert: false
+

我个人习惯是保留第一行不变,然后把第二行的 auth 方法改为 none

至于为啥第一行不改的原因是我第二行选择验证方式为不验证,而为了安全(在 VSCode 里是能够直接访问本机的命令行的),仅允许来自本机的连接;而如果我想临时允许局域网内的设备连接的话,我就在运行的时候加上 --bind-addr=0.0.0.0:8080 就行了。如果你有这样的需求的话,也可以直接在配置文件里把第一行改为 0.0.0.0:8080

保存完配置文件后,(可能)要先退出一下 Ubuntu 环境(直接输入 exit 就行),然后再用 proot-distro login ubuntu 进入,运行 code-server 命令,把 Termux 挂在后台,打开任意现代的浏览器访问 localhost:8080,就能愉快玩耍了!


更多玩法!

其实呢,安卓设备的性能毕竟有限,一些大型的项目我猜放这上面开发体验也不是很好。不过前端开发对设备性能要求不高,并且这也是我一开始就想实现的。

其实也不难,直接使用 NVM 的安装脚本 ,重开一下 Ubuntu 环境,安装个 Node.js,项目的话直接用 git 从 GitHub 上 Clone 到本地,就可以愉快玩耍了。

如果想要编辑安卓储存空间里的文件的话,可以使用 termux-setup-storage 来允许 Termux 访问安卓储存空间。具体操作的话因为我也没去搞,大家就看看官方文档就行。

Hugo 的话我没从 Snap Store 上下载,而是直接使用了 apt 里的 Hugo,虽然版本不是最新版的,但是 我懒啊 (而且 Snap 还要自己另外装,试了一遍不知道为啥没成功)

Python 的话我也整了一个。直接在 Ubuntu 环境下安装:

apt install python3
+apt install pip
+

然后在 VSCode 里安装 Python Debugger 插件就行了。首次使用要选择 Python 解释器。虽然我不知道为啥触屏模式下最下面那一栏不能拿手戳(包括设置里的好多下拉菜单),选不了 Python 解释器,最后还是外接了一个鼠标给解决了。运行效率还没有测试,但是谁知道呢,也就写着玩玩,大项目不还得在电脑上跑。

(应某人的需求)按照常理也是可以配置 C 开发环境的,只要安装一个 gcc 和一个 C Debugger 插件就行。但是由于不知为何写这篇博文的时候插件因为网络原因没办法安装,之后再试试。

至于其他玩法嘛,完整的 Linux 环境都摆在这里了,只要软件有 arm64 架构的包,都能安装。甚至你还可以安装一个 termux-api 插件访问安卓系统的一些 API,至于那些玩法就以后去探索吧。

(以及,这篇博文就是在这个开发环境下写的哦!又多了一个不开电脑的理由。)

\ No newline at end of file diff --git a/article/github-action-auto-pub-site/featuredImage.gif b/article/github-action-auto-pub-site/featuredImage.gif new file mode 100644 index 00000000..503f882d Binary files /dev/null and b/article/github-action-auto-pub-site/featuredImage.gif differ diff --git a/article/github-action-auto-pub-site/index.html b/article/github-action-auto-pub-site/index.html new file mode 100644 index 00000000..79bce7f7 --- /dev/null +++ b/article/github-action-auto-pub-site/index.html @@ -0,0 +1,83 @@ +使用 GitHub Action 自动渲染和发布网页 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 GitHub Action 自动渲染和发布网页

2021-06-07 +Learning +Kreee

Why?

根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
So, let’s begin!

废话不多说,上 /.github/workflows/publish-site.yml

name: Publish site to GitHub Pages
+
+on:
+  push:
+    branches:
+      - main
+
+jobs:
+
+  deploy:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Repo
+        uses: actions/checkout@master
+        with:
+          submodules: true
+
+      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: 'latest'
+          # extended: true
+          
+      - name: Build
+        run: hugo
+          
+      - name: Deploy to GitHub Pages
+        if: success()
+        uses: crazy-max/ghaction-github-pages@v2
+        with:
+          target_branch: gh-pages
+          build_dir: public
+          fqdn: blog.ohmykreee.top
+          dry_run: false
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+

流程文件分析

其实本人强烈推荐大家自己去 官方文档 学习相关语法 + 看示例文件。下面就作为本人的学习成果(半吊子程度),分析一下这个 GitHub Action 流程文件。

触发条件

官方文档:触发工作流程的事件

on:
+  push:
+    branches:
+      - main
+

一目了然:在 main 分支有新的 push 事件时触发。

第一步:检验仓库

      - name: Checkout Repo
+        uses: actions/checkout@master
+        with:
+          submodules: true
+

这里有一个关键:submodules 参数一定要记得传递 true, 因为如果你的 Hugo 项目用了模板,并且模板文件同样是托管在 GitHub 上,那么在创建项目和 push 项目时是要将模板设置为 SubModules 的。
然鹅默认情况下 git pull 是不会拉下 SubModules 内的文件(同时也需要自己手动更新 SubModules 的文件),也就导致了如果不声明 SubModules 的存在,到时候在 GitHub Action 的服务器上,准备被渲染的项目文件里就会缺少模板文件,然后就无了。

第二步:准备环境

该包 Action marketplace 主页

      - name: Setup Hugo
+        uses: peaceiris/actions-hugo@v2
+        with:
+          hugo-version: 'latest'
+          # extended: true
+

一目了然,设置好 Hugo 环境。可以传递参数指定 Hugo 版本,以及是否使用 extended 版本。

第三步:开始渲染网页

      - name: Build
+        run: hugo
+

也是一目了然,执行 hugo 命令。

第四步:push 到 gh-pages 分支并发布

该包 Action marketplace 主页
官方文档:GitHub Actions 的上下文和表达式语法
官方文档:工作流程中的身份验证

      - name: Deploy to GitHub Pages
+        if: success()
+        uses: crazy-max/ghaction-github-pages@v2
+        with:
+          target_branch: gh-pages
+          build_dir: public
+          fqdn: blog.ohmykreee.top
+          dry_run: false
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+

还是一目了然(有完没完啊),如果上一步没有返回错误的话,push 生成的文件到 gh-pages 分支。
可以传递参数有:

  • target_branch :目标分支;
  • build_dir :待上传文件夹;
  • fqdn :CNAME file 内容,用于自定义域名;
  • dry_run :测试用,运行但不 push 代码。
\ No newline at end of file diff --git a/article/index.html b/article/index.html new file mode 100644 index 00000000..bc366008 --- /dev/null +++ b/article/index.html @@ -0,0 +1,57 @@ +Articles | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 2.0.0 开发小记

2021-10-27 +Learning +Kreee

万恶之源

接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

项目地址: https://github.com/ohmykreee/wolf-bites-tweets

为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

  1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
  2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
继续阅读
较旧的帖子
\ No newline at end of file diff --git a/article/index.xml b/article/index.xml new file mode 100644 index 00000000..94530945 --- /dev/null +++ b/article/index.xml @@ -0,0 +1,25 @@ +Articles on Kreee's Bloghttps://blog.ohmykreee.top/article/Recent content in Articles on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/article/migrate-to-ubuntu-server/featuredImage.jpg b/article/migrate-to-ubuntu-server/featuredImage.jpg new file mode 100644 index 00000000..8ac2d99e Binary files /dev/null and b/article/migrate-to-ubuntu-server/featuredImage.jpg differ diff --git a/article/migrate-to-ubuntu-server/index.html b/article/migrate-to-ubuntu-server/index.html new file mode 100644 index 00000000..90d45cd8 --- /dev/null +++ b/article/migrate-to-ubuntu-server/index.html @@ -0,0 +1,128 @@ +将后端服务器系统迁移至 Ubuntu server | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

将后端服务器系统迁移至 Ubuntu server

2021-07-16 +Learning +Kreee

What happend?

本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。
So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let’s begin!


目录:


Install OS

安装版本: Ubuntu server 20.04 LTS
跟着指示走就行。 +安装中要求输入的用户名与密码为之后需要登陆用的普通账号,如果需要提权操作需要 sudo 命令,且密码为自己账号的密码。


Config OpenSSH

在安装阶段的时候就提示是否安装 OpenSSH。
同时,需要启用防火墙并设置端口:

sudo ufw enable
+sudo allow ssh
+sudo ufw reload
+

查看当前状态:

sudo ufw status
+

Swap mirror

参考: https://mirrors.tuna.tsinghua.edu.cn/help/ubuntu/

更改包安装管理器设置文件:

sudo vim /etc/apt/sources.list
+

然后根据提示添加 Tuna 源。


First update

sudo apt update
+# 更新软件列表
+sudo apt dist-upgrade
+# 更新软件,单运行 upgrade 可能会导致更新系统
+

Set up auto-update

参考: https://help.ubuntu.com/community/AutomaticSecurityUpdates

sudo dpkg-reconfigure --priority=low unattended-upgrades
+

使用默认设置(一天检查一次)即可。


Set up Router

因为被网络桥接和 NAT 彻底整“破防”,一气之下决定:
在系统里虚拟出一个 OpenWRT !

(2022/2/7 更新)
找到了一个项目:lakinduakash / linux-wifi-hotspot,可以一步部署一个简单的无线路由器。

添加 ppa 包并安装:

sudo add-apt-repository ppa:lakinduakash/lwh
+sudo apt install linux-wifi-hotspot
+

手动安装 dnsmasq (如果使用 NAT 方式):

apt install dnsmasq
+

编辑 /etc/create_ap.conf示例文件

GATEWAY=192.168.6.1
+SHARE_METHOD=nat
+COUNTRY=CN
+WIFI_IFACE=wlp7s0
+INTERNET_IFACE=enp1s0
+SSID=MyAccessPoint
+PASSPHRASE=MyPassword
+

使用 systemctl start create_ap 启动 AP, systemctl enable create_ap 开机启动。


Set up serial login with getty

sudo cp /usr/lib/systemd/system/serial-getty@.service /etc/systemd/system/serial-getty@ttyS0.service
+sudo systemctl daemon-reload
+sudo systemctl start serial-getty@ttyS0.service
+sudo systemctl enable serial-getty@ttyS0.service
+

Usage of ufw

查看当前状态和开放端口:

sudo ufw status
+

开放端口:

sudo ufw allow 8000/tcp
+sudo ufw allow 7000
+sudo ufw allow from 192.168.6.0/24 to any port 25577
+

删除已经添加的规则:

# 列出已有规则的编号
+sudo ufw status numbered
+# 根据编号删除规则
+sudo ufw delete 3
+sudo ufw reload
+

Set up Certbot

参考: https://certbot.eff.org/lets-encrypt/ubuntufocal-other

sudo snap install core; sudo snap refresh core
+sudo snap install --classic certbot
+sudo ln -s /snap/bin/certbot /usr/bin/certbot
+

Set up mumble

参考: https://wiki.mumble.info/

安装:

sudo add-apt-repository ppa:mumble/release
+sudo apt-get update
+sudo apt-get install mumble-server
+sudo dpkg-reconfigure mumble-server
+

开放端口64738
配置 /etc/mumble-server.ini 文件。
服务名为mumble-server


Set up Netdata

参考: https://learn.netdata.cloud/docs/

因为奇奇怪怪的连接问题(指墙 Github),所以使用离线安装模式。

curl -s https://my-netdata.io/kickstart.sh > kickstart.sh
+
+# Netdata tarball
+curl -s https://api.github.com/repos/netdata/netdata/releases/latest | grep "browser_download_url.*tar.gz" | cut -d '"' -f 4 | wget -qi -
+
+# Netdata checksums
+curl -s https://api.github.com/repos/netdata/netdata/releases/latest | grep "browser_download_url.*txt" | cut -d '"' -f 4 | wget -qi -
+
+# Netdata dependency handling script
+# 奇奇怪怪的是经常失败,需要手动创建
+wget -q - https://raw.githubusercontent.com/netdata/netdata/master/packaging/installer/install-required-packages.sh
+
+# go.d plugin 
+# For binaries for OS types and architectures not listed on [go.d releases](https://github.com/netdata/go.d.plugin/releases/latest), kindly open a github issue and we will do our best to serve your request
+export OS=$(uname -s | tr '[:upper:]' '[:lower:]') ARCH=$(uname -m | sed -e 's/i386/386/g' -e 's/i686/386/g' -e 's/x86_64/amd64/g' -e 's/aarch64/arm64/g' -e 's/armv64/arm64/g' -e 's/armv6l/arm/g' -e 's/armv7l/arm/g' -e 's/armv5tel/arm/g') && curl -s https://api.github.com/repos/netdata/go.d.plugin/releases/latest | grep "browser_download_url.*${OS}-${ARCH}.tar.gz" | cut -d '"' -f 4 | wget -qi -
+
+# go.d configuration 
+curl -s https://api.github.com/repos/netdata/go.d.plugin/releases/latest | grep "browser_download_url.*config.tar.gz" | cut -d '"' -f 4 | wget -qi -
+

复制文件到服务器并给予运行权限:

# 不安全,本不应该使用0777权限
+sudo chmod -R 0777 /tmp/netdata
+

运行:

cd /tmp/netdata
+sudo bash ./kickstart.sh --local-files /tmp/netdata/netdata-(version-number-here).tar.gz /tmp/netdata/sha256sums.txt /tmp/netdata/go.d.plugin-(version-number-here).(OS)-(architecture).tar.gz /tmp/netdata/config.tar.gz /tmp/netdata/install-required-packages.sh --disable-telemetry
+

提示:安装时经常出问题的是 install-required-packages.sh ,需要特别关照。
然后就是修改配置文件 /etc/netdata/netdata.conf
在配置 SSL 的时候几率发生无法读取证书文件的问题(主要是 privkey.pem )需要参考 https://certbot.eff.org/docs/using.html#where-are-my-certificates 来配置文件的权限。


Set up NP-Client

参考:https://ehang-io.github.io/

先将提前下好的 npc 文件复制到 /tmp/npc 下,并创建配置文件 /etc/np-client.conf

[common]
+server_addr=cloud.ip:8024
+conn_type=kcp
+vkey=you_vkey_here
+auto_reconnection=true
+crypt=false
+compress=false
+

使用命令安装:

cd /tmp/npc
+sudo ./npc install -config=/etc/np-client.conf
+
sudo npc start
+

Set up Java and Minecraft

安装 openjdk(最新):

sudo apt install default-jdk
+

老版本的 Minecraft 需要 Java 8 ,需要自己去甲骨文官网下载二进制文件。
参考用的 /etc/systemd/system/*.service 文件:
Java 8 :

[Unit]
+Description=Minecraft Server with Java 8
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+User=minecraft
+WorkingDirectory=/usr/local/mc_1_7_10/
+ExecStart=/usr/local/jre1.8.0_271/bin/java -jar /usr/local/mc_1_7_10/forge-1.7.10-10.13.4.1558-1.7.10-universal.jar nogui
+
+[Install]
+WantedBy=multi-user.target
+

OpenJDK :

[Unit]
+Description=Minecraft Server
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+User=minecraft
+WorkingDirectory=/usr/local/mc_1_17/
+ExecStart=/usr/bin/java -jar /usr/local/mc_1_17/server.jar nogui
+
+[Install]
+WantedBy=multi-user.target
+

记得开放端口:

# Minecraft 主端口
+sudo ufw allow 25565
+# Minecraft Rcon 控制端口
+sudo ufw allow 25577
+

Set up Zerotier

懒,没人用,先不整。

参考: https://www.zerotier.com/download/


Set up PPPOE

安装配置程序:

sudo apt install pppoeconf
+

进行配置:

sudo pppoeconf
+

启动与断连:

# 连接
+pon dsl-provider
+# 断开
+poff dsl-provider
+
\ No newline at end of file diff --git a/article/music-player-in-hugo-page/featuredImage.jpg b/article/music-player-in-hugo-page/featuredImage.jpg new file mode 100644 index 00000000..2c7b5ef5 Binary files /dev/null and b/article/music-player-in-hugo-page/featuredImage.jpg differ diff --git a/article/music-player-in-hugo-page/featuredImage_hu92a118604ae76c6bdb9425eabcba13d7_407695_700x350_fill_q95_box_smart1.jpg b/article/music-player-in-hugo-page/featuredImage_hu92a118604ae76c6bdb9425eabcba13d7_407695_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..08c74cd8 Binary files /dev/null and b/article/music-player-in-hugo-page/featuredImage_hu92a118604ae76c6bdb9425eabcba13d7_407695_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/music-player-in-hugo-page/index.html b/article/music-player-in-hugo-page/index.html new file mode 100644 index 00000000..3a9ce300 --- /dev/null +++ b/article/music-player-in-hugo-page/index.html @@ -0,0 +1,38 @@ +在 Hugo 里内嵌音乐播放器(APlayer) | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

在 Hugo 里内嵌音乐播放器(APlayer)

2021-06-07 +Learning +Kreee

就是置顶状态的那个音乐播放器。
想要吗?只需要短短三步哦!

零、工作开始前

  • 使用的 Hugo 版本:0.83.1 ,更高版本的应该也行。
  • 使用的播放器: APlayer ,一个大家都在用我不用不行的看上去还行的播放器小组件。
  • 使用的解析器: MetingJS ,很强大,支持许多音乐平台。本人常用网易云音乐平台。

一、添加依赖

虽然只有短短四个字,但是对于许多萌新(包括我)来说这一步就是个噩梦(误)。

首先,这个东西是因所使用的模板而异。有的模板做的比较好(比如我这个,不得不说德国人是真的严谨),会在配置文件中预留可追加 .css.js 的设置项;而有的模板只会提供 .css ,或者甚至没有。
所以这问题就大了,对于某些人来说添加依赖就是在设置文件里添加三句话的功夫,对于某些人来说就是遥不可及的彼岸(误)。

对于那些模板的配置文件里有位置预留追加 .css.js 的,只需要追加 css 依赖 https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css 和 js 依赖 https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js 即可。

而对于无法在配置文件中直接添加依赖的,就需要 Overwrite 模板文件了:
找到文件 /themes/<你的主题名>/layouts/_default/baseof.html ,并将该文件复制到 /layouts/_default/baseof.html ,并对后者进行修改:
<head></head> 区域间复制粘贴以下代码:

<!-- require APlayer -->
+<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css">
+<script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script>
+<!-- require MetingJS -->
+<script src="https://cdn.jsdelivr.net/npm/meting@2/dist/Meting.min.js"></script>
+

注意,如果你的模板是通过 submodule 方式导入的,并且在非本地环境进行渲染和发布(如 GitHub Action),在每次模板更新后,最好重复以上步骤确保不会出啥奇奇怪怪的问题。

完事后,如何检测依赖成功被加载呢?
只需要启动 Hugo 内置服务器,打开网页,按下高贵的F12按钮打开开发者工具。如果一切顺利,可以在控制台里看到两个 outputs :

   APlayer v1.10.1 af84efb  http://aplayer.js.org 
+   
+   MetingJS v2.0.1  https://github.com/metowolf/MetingJS 
+

如果没有呢?那就是轮到你头痛的时候了😏
也不需要太着急,我也是头痛了一下午才搞定的。毕竟整这东西玩的这就是折腾,不是吗?

二、 (可选) 定义 shortcodes

当然你这步不想做完全可以,只需要在想添加音乐播放器的地方插入这一行就行:

<meting-js server="netease" type="playlist" id="769332917"></meting-js>
+

相关参数的意义可以在 官方文档 查看详细介绍,这里我就不赘述。

然后我们来讲讲我们的 shortcodes 。为啥要有 shortcodes 呢?其实就是方便我们写文章的时候以最快的速度插入音乐。
老样子,我也是强烈推荐各位能够直接去 官方文档:Shortcodes 学习如何写 shortcodes 。下面就来说说我的 shortcodes 是怎么写的。

首先,新建文件 /layouts/shrotcodes/aplayer.html,文件名就是你的 shortcodes 的名字。
然后,文件里写:

<meting-js server="{{ .Get "server" }}" type="{{ .Get "type" }}" id="{{ .Get "id" }}"></meting-js>
+

很简单,不是吗?其中 .Get 就是一个能够得到被传递参数的一个方法,这个想必大家一眼就能看出来。其实大家还可以通过一个判断语句来完成即使不声明参数名也能完成参数传递的 shortcodes ,对着官方的示例代码写就能写出来。我由于没这个需求就简单写了这么一行。
完事了之后,只需要在文章想要插入的地方使用刚刚定义的 shortcodes :

# 前面记得补上两个 {{ ,放代码块里也会触发 shortcodes 我也是没想到
+<aplayer server="netease" type="playlist" id="769332917">}}
+

就能达到之前那行 HTML 语句一样的效果。

三、更改 Goldmark 设置

你以为到这里就完事了?但是我有说需要三步啊。最后一步,也是 Hugo 版本更新遗留问题。
如果你头铁,直接去部署网页;等你部署完了,你就会发现,本来应该出现音乐播放器的地方,竟然一片空白。
不要慌张,和我一起,按下高贵的F12按钮打开开发者工具,使用元素检查选中本应该出现播放器的地方。然后,你就会在代码查看器里看到一行字:

<!-- raw HTML omitted -->
+

好了不卖关子了,问题就在于新的渲染器 Goldmark 不默认渲染 HTML 代码,甚至用 shortcodes 也不行。

所以,解决方法有两个:

  1. 更改 Goldmark 渲染器的设置,使其能够渲染 HTML 代码。只需要在配置文件的 [markup] 部分添加以下内容(以 config.toml 为例,其他格式请参考对应文件的语法):
  [markup.goldmark]
+    [markup.goldmark.renderer]
+      unsafe = true
+
  1. 如果你是那种 Old school style 的人,你可以直接更换到老的渲染器。在配置文件的 [markup] 部分添加以下内容(以 config.toml 为例,其他格式请参考对应文件的语法):
  defaultMarkdownHandler = "blackfriday"
+

四、总结

So,导致播放器组件不起作用的可能原因分这三种:

  1. css 和 js 依赖没有被成功添加 (最有可能)
  2. Goldmark 设置没有更改;
  3. 其他傻X错误比如代码写错了或者传递参数不正确啥的。

如果一切顺利的话,你也可以让自己的博客里充满音乐了!Enjoy! +

\ No newline at end of file diff --git a/article/notes-for-setting-up-backend-server/index.html b/article/notes-for-setting-up-backend-server/index.html new file mode 100644 index 00000000..9b14d275 --- /dev/null +++ b/article/notes-for-setting-up-backend-server/index.html @@ -0,0 +1,248 @@ +Notes for Setting Up Back-end Server | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

Notes for Setting Up Back-end Server

2021-01-13 +Learning +Kreee

Install CentOS

OS: CentOS 7 Minimal

Summary:

  1. Date & Time: Shanghai
  2. Network & Hostname: hostname to kserver.localdomain
    If you want to change hostname later, use:
hostnamectl set-hostname AnythingYouLike.localdomain
+

When installing:

  1. Set a root password

First run & install some software

yum -y update
+yum -y install vim
+yum -y install net-tools
+yum -y install git
+yum -y install unzip
+yum -y install wget
+

Enable yum-cron

yum install -y yum-cron
+

Make it receive security update automatically:

vim /etc/yum/yum-cron.conf
+

Edit the file:

update_cmd = security
+apply_updates = yes
+

Start and auto-run:

systemctl start yum-cron
+systemctl enable yum-cron
+

Set up OpenSSH

vim /etc/ssh/sshd_config
+

Remove # in the following line:

Port 22
+ListenAddress 0.0.0.0
+ListenAddress ::
+PermitRootLogin yes
+

Start and auto-run the SSH service.

systemctl enable sshd
+systemctl start sshd
+

View the local address:

ifconfig -a
+

Set up Serial Port

Check if it is supported

dmesg |grep tty
+

Edit /etc/default/grub and add:

GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 console=ttyS0,9600"
+

Update the grub file:

grub2-mkconfig -o /boot/grub2/grub.cfg
+

Reboot the machine.

Next, enable serial-getty

cp /usr/lib/systemd/system/serial-getty@.service /etc/systemd/system/serial-getty@ttyS0.service
+systemctl daemon-reload
+systemctl start serial-getty@ttyS0.service
+systemctl enable serial-getty@ttyS0.service
+

Set up AP & soft router

ref: https://www.osradar.com/building-your-own-wireless-access-point-on-top-of-centos7/
+

Install the wireless-tools and hostapd.

yum -y install iw
+yum -y install epel-release
+yum -y install hostapd
+

Config hostapd.

vim /etc/hostapd/hostapd.conf
+

Edit the conf file.

interface=wlp7s0
+hw_mode=g
+channel=6
+ssid=K_server
+utf8_ssid=1
+country_code=CN
+bridge=br-AP
+

Remove the # in the following lines:

wpa=3
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+rsn_pairwise=CCMP
+wpa_passphrase=YouPassHere
+

Start and auto-run the hostapd

systemctl start hostapd
+systemctl enable hostapd
+

Change zones.

firewall-cmd --permanent -zone=external --change-interface=enp1s0
+firewall-cmd --permanent -zone=internal --change-interface=???
+firewall-cmd --zone=external --add-masquerade --permanent
+firewall-cmd --set-default-zone=internal
+firewall-cmd --zone=internal --add-service=dns --permanent
+firewall-cmd --complete-reload
+

Set up bridge.

nmcli con add con-name br-AP type bridge ifname br-AP autoconnect yes stp no ip4 192.168.6.1/24
+

Set up dhcp.

yum install -y dhcp
+vim /etc/dhcp/dhcpd.conf
+

Edit the conf file.

subnet 192.168.6.0 netmask 255.255.255.0 {
+	range dynamic-bootp 192.168.6.200 192.168.6.250;
+	option broadcast-address 192.168.6.255;
+	option domain-name-server 223.5.5.5, 223.6.6.6;
+	option routers 192.168.6.1;
+}
+

Start and auto-run the dhcp

systemctl start dhcpd
+systemctl enable dhcpd
+

Post-setup: make it more stable.

yum -y install haveged
+systemctl start havaged
+systemctl enable havaged
+

Set up web-vmstats

cd /usr/local/
+mkdir websocketd
+git clone https://github.com/joewalnes/web-vmstats
+

Copy websocketd.zip to the folder /usr/local/websocketd/ and unzip it:

unzip websocketd.zip
+

Then create webvmstats.

vim /etc/systemd/system/webvmstats.service
+

Add the following content to the file:

[Unit]
+Description=Web-vmstats
+
+[Service]
+ExecStart=/usr/local/websocketd/websocketd --port=8000 --staticdir=/usr/local/web-vmstats/web/ /usr/bin/vmstat -n 1
+
+[Install]
+WantedBy=multi-user.target
+

Reload, enable and start.

systemctl daemon-reload
+systemctl start webvmstats
+systemctl enable webvmstats
+

Add port 8000 to the firewall.

firewall-cmd --add-port=8000/tcp --zone=external --permanent
+firewall-cmd --add-port=8000/tcp --zone=internal --permanent
+

View status:

systemctl status webvmstats -l
+

Or:

journalctl -e -u webvmstats
+

Set up Zerotier

Use the script to install Zerotier:

curl -s https://install.zerotier.com | sudo bash
+

Join network:

zerotier-cli join XXXXXXX
+

Start and auto-run ZeroTier.

systemctl start zerotier-one
+systemctl enable zerotier-one
+

Set up FRP

mkdir /usr/local/frp
+

copy the frp.zip to the new folder. Then unzip it.

Edit the frpc.ini in the client-side. (Stupid error in [ftp]?)

[common]
+server_addr = ?.?.?.?
+server_port = 7000
+pool_count = 2
+authenticate_new_work_conns = true
+authentication_method = token
+token = balabalabalabalabalabala
+
+[minecraft01]
+type = tcp
+local_ip = 127.0.0.1
+local_port = 25565
+remote_port = 25565
+
+[minecraft02]
+type = udp
+local_ip = 127.0.0.1
+local_port = 25565
+remote_port = 25565
+
+[murmur01]
+type = tcp
+local_ip = 127.0.0.1
+local_port = 64738
+remote_port = 64738
+
+[murmur02]
+type = udp
+local_ip = 127.0.0.1
+local_port = 64738
+remote_port = 64738
+
+[ftp01]
+type = tcp
+local_ip = 127.0.0.1
+local_port = 20
+remote_port = 20
+
+[ftp02]
+type = tcp
+local_ip = 127.0.0.1
+local_port = 21
+remote_port = 21
+
+[ftppasv]
+type = udp
+local_ip = 127.0.0.1
+local_port = 20000-23333
+remote_port = 20000-23333
+
+[webvmstat]
+type = tcp
+local_ip = 127.0.0.1
+local_port = 8000
+remote_port = 8000
+

Copy origin .service file and edit it.

cp /usr/local/frp/systemd/frpc.service /etc/systemd/system/
+vim /etc/systemd/system/frpc.service
+

User=nobody

On the server-side, edit the frps.ini.

[common]
+bind_addr = 0.0.0.0
+bind_port = 7000
+dashboard_addr = 0.0.0.0
+dashboard_port = 7500
+authentication_method = token
+authenticate_new_work_conns = true
+token = balabalabalabalabalabala
+dashboard_user = admin
+dashboard_pwd = admin
+

Give permission:

chmod -R 700 /usr/local/frp/
+

Set up mumble server

ref: https://wiki.mumble.info/wiki/Install_CentOS7
+

Set up Minecraft server

Install java:

yum install -y java-latest-openjdk.x86_64
+

Upload the server.zip to the /usr/local/mc_1_16_4 or /opt/mc_1_16_4

mkdir /usr/local/mc_1_16_4/mc_1_16_4
+unzip server.zip
+

Create user:

groupadd -r minecraft
+useradd -r -g minecraft -m -d /var/lib/minecraft -s /sbin/nologin minecraft
+chown -R minecraft:minecraft /usr/local/mc_1_16_4
+chmod -R 0770 /usr/local/mc_1_16_4
+

Create mcserver.service by vim /etc/systemd/system/mcserver.service

[Unit]
+Description=Minecraft Server
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+User=minecraft
+ExecStartPre=/bin/sleep 10
+ExecStart=/usr/bin/java -jar /usr/local/mc_1_16_4/fabric-server-launch.jar nogui
+WorkingDirectory=/usr/local/mc_1_16_4/
+
+[Install]
+WantedBy=multi-user.target
+

Add port:

vim /etc/firewalld/services/minecraft.xml
+
<?xml version="1.0" encoding="utf-8"?>
+<service>
+        <short>Minecraft</short>
+        <description>Minecraft Server</description>
+        <port protocol="tcp" port="25565" />
+        <port protocol="udp" port="25565" />
+</service>
+
vim /etc/firewalld/services/rcon.xml
+
<?xml version="1.0" encoding="utf-8"?>
+<service>
+        <short>RCON</short>
+        <description>Minecraft RCON</description>
+        <port protocol="tcp" port="25577" />
+        <port protocol="udp" port="25577" />
+</service>
+
firewall-cmd --permanent --add-service=minecraft --zone=internal
+firewall-cmd --permanent --add-service=minecraft --zone=external
+firewall-cmd --permanent --add-service=rcon --zone=internal
+firewall-cmd --complete-reload
+

Set up FTP

Install the ftp-daemon

yum -y install vsftpd
+

Edit the conf file:

vim /etc/vsftpd/vsftpd.conf
+
local_enable=NO
+anonymous_enable=YES
+write_enable=YES
+anon_upload_enable=YES
+listen=YES
+

Create a folder for uploading and change the permission:

mkdir /var/ftp/UploadArea
+chown -R ftp:ftp /var/ftp/UploadArea
+chmod -R 777 /var/ftp/UploadArea
+

Can ban users from logging in by adding name in /etc/vsftpd/user_list

Change Selinux settings:

getsebool -a | grep ftp
+setsebool -P ftpd_anon_write on
+setsebool -P ftpd_full_access on
+

Specify the Pasv-port by adding in /etc/vsftpd/vsftpd.conf

pasv_min_port=20000
+pasv_max_port=23333
+

Open port.

firewall-cmd --permanent --add-service=ftp --zone=internal
+firewall-cmd --permanent --add-service=ftp --zone=external
+

Start and auto-run the service.

systemctl start vsftpd
+systemctl enable vsftpd
+

NTP enable

Install the ntp-daemon.

yum install -y ntp
+

Edit the conf file.

vim /etc/ntp.conf
+

Add the following line:

server ntp.ntsc.ac.cn
+server cn.ntp.org.cn
+SYNC_HWCLOCK=yes
+

Start and auto-run the servie.

systemctl start ntpd
+systemctl enable ntpd
+

View stats:

ntpstat
+ntpq -p
+
\ No newline at end of file diff --git a/article/notes-of-developing-wbt-2.0.0/featuredImage.jpg b/article/notes-of-developing-wbt-2.0.0/featuredImage.jpg new file mode 100644 index 00000000..d90bd886 Binary files /dev/null and b/article/notes-of-developing-wbt-2.0.0/featuredImage.jpg differ diff --git a/article/notes-of-developing-wbt-2.0.0/featuredImage_hu3a8a394eb69f675c896dc5f0c47038c0_435393_700x350_fill_q95_box_smart1.jpg b/article/notes-of-developing-wbt-2.0.0/featuredImage_hu3a8a394eb69f675c896dc5f0c47038c0_435393_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..48a8aea7 Binary files /dev/null and b/article/notes-of-developing-wbt-2.0.0/featuredImage_hu3a8a394eb69f675c896dc5f0c47038c0_435393_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/notes-of-developing-wbt-2.0.0/index.html b/article/notes-of-developing-wbt-2.0.0/index.html new file mode 100644 index 00000000..a1d3ea82 --- /dev/null +++ b/article/notes-of-developing-wbt-2.0.0/index.html @@ -0,0 +1,52 @@ +wolf-bites-tweets 2.0.0 开发小记 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 2.0.0 开发小记

2021-10-27 +Learning +Kreee

万恶之源

接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

项目地址: https://github.com/ohmykreee/wolf-bites-tweets

为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

  1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
  2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。

设置代理

因为某些大家都懂的原因,整个开发都需要在代理环境下进行。

但是问题来了:原先用 Python 写的时候执行 GET 命令用的是第三方库,只需要传递环境变量就能完成代理的设置。然鹅在开发 JavaScript actions 包时,有一个原则就是尽量不要引入第三方包(原因之后会提及),所以 GET 方法只能使用内置库完成。结果写的时候死活都无法从代码层面上让程序走本地建立的代理:要么就是 hostname not resolved 或是 connect reject from 127.0.0.1:443 ;也尝试过引入第三方库来解决,结果也是无功而返。

最后忍无可忍,还是使用了 Clash 的 TAP 模式: +Clash TUN 和 TAP 模式 - EdNovas 的小站 讲的挺详细的,再搭配上 官方文档,就能轻松搭建全局的代理。大致流程在这里也提一提:

  1. General 页面的 TAP Device 旁边的 Manage, 点击 Install
  2. Settings 页面 Profile Mixin 部分的 YAML 旁边的 Edit,把官方文档里的配置文件复制进去;
  3. 回到 General,关掉 System Proxy,打开 Mixin
    如果一切顺利,网络应该是显示连接到 clash-tap。

@actions/core

说是说官方推荐的工具包,但是整个项目开发完后我只想说一句话:对它是真的无语

首先, core.setFailed() 方法看名字应该是那种抛出错误同时结束程序的功能对吧?结果本地测试的时候发现程序并没有按预期结束。去翻了翻源码,大无语事件发生了:整个 core.setFailed() 方法就是一行 core.error() 再加上一行设置退出码为 1 ,没了。根本不涉及退出程序的操作。那意思是说我用完 core.setFailed() 之后还要手动 exit() ?那为啥我不直接用 core.error()exit(1) 呢,还能自定义退出码?

其次,所有 core.notice()core.warning()core.error() 方法在本地测试的时候都不会输出内容到调试工作台,就导致本地测试的时候贼痛苦。最后还是开发了 local-run 功能给本地测试用,顺便也给程序添加一个新功能。

最后,最令人无语的事件发生了。你作为官方推荐的工具包,你就应该提前在环境里安装好对吧?结果呢,并没有。再加上 actions 包在运行前是不会执行 npm install --production ,也就导致了要么不要引入第三方包,要么就提前在 node_modules 文件夹里准备好第三方包。最终的解决方法是在 .gitignore 里加了两行:

/node_modules/*/
+!/node_modules/@actions/
+

提醒一下,第一行不能换成 node_modules/,不然整个 node_modules 文件夹都不会被跟踪,第二行排除规则自然也不会生效。使用原文这行就会跟踪 node_modules 文件夹的同时不跟踪其下所有文件(夹),第二行规则才会生效。

(更加无语的是,因为最后一个大无语事件,我的 main 分支多了一串 dirty commits。而且如果要真正测试 actions 包的话一定需要创建 Release 而不能直接在当前项目仓库里测试,所以这些 dirty commits 又是不可避免的,就非常的气)


http GET

直接用的是这里的实现方法:HTTP GET Request in Node.js Express - Stack Overflow

其实本来复制粘贴就没事了,但是在 JavaScript 中,涉及网络和 I/O 等长时间占用操作默认是异步的。而对于从来没有接触过异步的新手来说,是一个比较麻烦的问题。

(据说 Axios 库挺好的,下次一定试试)


异步!异步!异步!

久仰异步大名,听说异步是萌新杀手,今天可是真正见到其真面目。

异步是写 JavaScript 程序必须要过的一个坎,因为很多方法都是异步进行的。而异步问题最关键的一点就是如何判断一个异步方法结束运行了,并得到返回值。主流的话是两种处理方法:Old-style 的 callbacks 方法和最近才被引入的 async/await 方法:

callbacks 方法

参考文档:What are callbacks? - Node.js

function processData (callback) {
+  fetchData(function (err, data) {
+    if (err) {
+      console.log("An error has occurred. Abort everything!");
+      return callback(err);
+    }
+    data += 1;
+    callback(data);
+  });
+}
+

在这段示例代码中,callback 变量以及传递给 fetchData() 方法的那个函数都是使用了 callbacks 方法。而理解 callbacks 的精髓在于把一个方法作为变量传递给异步的方法,而在异步的方法结束并得到数据后传递回原先传递给它的方法。听起来很绕,不是吗?但是如果你真正理解了你就会感觉这个解决方法绝妙极了:

let data
+processData(function beCalled (result) {
+    data = result
+})
+console.log(data)
+

首先,上面的代码中调用了 processData() 方法,并且把名字为 beCalled()(实际应用中可以不用命名,直接省略) 并写有 data = result 的方法传递给 processData()beCalled()processData() 里有了一个新名字: callback()。在 processData() 中运行完成后并调用 callback() 方法,会把变量 data 中的数据重新传回到 beCalled() 并传递给 beCalled() 方法的 result 变量中。这样就完成了一次 callbacks。

async/await 方法

async/await 功能是最近才被引入的,目的就是让你写异步的时候有一种“回到家的感觉”。

首先,在你想使用这个功能的方法前声明 async没有声明 async 的方法是无法使用 await 功能的

然后你就可以快乐地使用 await 啦!await 的功能其实非常简单:在 await 后跟的 Promise 只有运行完成并返回值后,整个程序才会进行下去,否则就会停在那一行代码上:

async function fun_with_async () {
+    ...
+    
+    let a = await this_is_a_promise()
+
+    ...
+}
+

而 Promise 则是一种特殊的方法,会返回方法得到的值以及运行结果,有三种运行状态:pending、fulfilled、rejected。关于怎么写 Promise 可以 直接对着文档抄就行了Promise - MDN Web Docs

以及关于 async/await 的高阶用法以及如何更高效地让程序跑得更快也可以在这里学到:Making asynchronous programming easier with async and await - MDN Web Docs

综上,可以看出真正在 JavaScript 编程中写一些复杂的方法是很少用 return 的,更多的是使用 callbacks(毕竟异步这种东西好是好,就是处理起来有点麻烦)。在实际运用中,也可以考虑 callbacks 方法和 async/await 方法同时使用(比如我,我愿称之为把毕生所学都给整上(误))。


设置环境变量

主要是用来 debug 用,如果用在 local-run 功能上相比直接传递参数还是麻烦了一点。

GitHub actions 转换输入为环境变量的方法(直接从源代码里截的):INPUT_${name.replace(/ /g, '_').toUpperCase()}

比如 bearer-token 就会被转换为 INPUT_BEARER-TOKEN


获取传递的参数

How to parse command line arguments - Node.js

原文档我觉得已经讲得很清楚了,我这里就简单提一下:

  1. process.argv 会直接返回由跟在后面的参数组成的 array;
  2. 第三方包 yargs 可以大大简化这一步骤。

字符拼接小妙招

用反单引号框起来后,用 ${变量名} 来代替变量值,空格都会被保留。

用起来很像 Python 里的 format() 方法。麻麻再也不用担心我用加号痛苦地连接字符串啦。


for in 和 for of

for in 是给 object 用的;
for of 是给 array 用的。

用错了会直接不执行哦。


写入文件

How do I write files in Node.js? - Node.js

原文档也已经讲得很详细了。就是异步要稍微注意一下。如果之前异步整明白的话,读这个文档也没啥太大压力。


当事人 发言

从10月13日开坑,到11月2日 wolf-bites-tweets v2.0.0 推出标志着填坑正式告一段落,这之间长达20多天。20天说长也不长说短也不短,虽然这些天来自学业的压力和部门安排的任务让我并没有大把的时间去做这个项目,在写这个项目的时候也遇到了很多困难和烦心事,但是经历下来我还是挺享受整个过程的。

不知道为啥,我还是挺喜欢解决问题这一过程:从运用搜索引擎寻找资料,到查找一个 bug 背后产生的原因,再到根据已有的资料和别人的解决方法来想出一个适合自己的解决方法。这个过程的确很累,在外人也许看来我在整一些“没用的东西”,但是谁知道呢?或是说,这是因为我在为了实现自己一个小小的需求而“费劲”,是在真正为我自己做一些东西,而不是为了他人或是生计。这何尝不是一种乐趣呢?

20天从入门 JavaScript 到写一个简单的项目,的确有一定的挑战。我也承认我写的项目也有很多不完善的地方,我也有很多东西需要去学习。学习之旅还很长,与君共勉。

到头来,还是 Python 爱我。
—— Kreee

\ No newline at end of file diff --git a/article/notes-of-developing-wbt-and-wct/featuredImage.jpg b/article/notes-of-developing-wbt-and-wct/featuredImage.jpg new file mode 100644 index 00000000..3b6b6d5b Binary files /dev/null and b/article/notes-of-developing-wbt-and-wct/featuredImage.jpg differ diff --git a/article/notes-of-developing-wbt-and-wct/featuredImage_hu964199fd6dd3ba11c85ddad4c388d7a6_1905551_700x350_fill_q95_box_smart1.jpg b/article/notes-of-developing-wbt-and-wct/featuredImage_hu964199fd6dd3ba11c85ddad4c388d7a6_1905551_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..37a3d4ca Binary files /dev/null and b/article/notes-of-developing-wbt-and-wct/featuredImage_hu964199fd6dd3ba11c85ddad4c388d7a6_1905551_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/notes-of-developing-wbt-and-wct/index.html b/article/notes-of-developing-wbt-and-wct/index.html new file mode 100644 index 00000000..6f59bb3f --- /dev/null +++ b/article/notes-of-developing-wbt-and-wct/index.html @@ -0,0 +1,151 @@ +wolf-bites-tweets 和 wolf-chews-tweets 开发小记 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 和 wolf-chews-tweets 开发小记

2021-10-19 +Learning +Kreee

又为:论如何嫖秃 GitHub 服务器

万恶之源

一切都应该从那时说起:在一个月黑风高的夜晚,我翻译博客的 404 页面时,望着空荡荡的页面,心里突发奇想:如果这里能有一个随机展示我喜欢过的推特的一个小组件,是不是很 nice(顺便展示一下我奇怪的 xp )。

说挖坑就挖坑。要实现这个小功能,我打算做两个项目: wolf-bites-tweets 和 wolf-chews-tweets(别问我这个名字咋想出来的)。前者是利用 白嫖 一下 GitHub action 的服务器,每周通过推特官方 API 获取我的推特喜欢列表(顺便也把获取发推列表这个功能也做了,万一我以后也产粮了呢),准备用我最熟悉的 Python 实现;后者就是利用前者获取的数据,把随机抽到的推特展示在网页上。

由于这是我第一次涉及前端的开发,JavaScript 之前也没有涉及过,所以这次填坑之旅最主要也是最难的是 wolf-chews-tweets 这个项目,这篇博文主要的也是这个前端项目。咋说呢,自己开的坑哭着也要自己填完,不是吗😂?


写在前面

声明变量时没有类型标注是个坏习俗。
—— 某位不知名暴论者

遭了,写习惯了咋办?
—— 某位痛苦的初学者

1. 开 PR 前请再三检查!!

是的,很痛苦的教训,非常非常痛苦的教训。

在 wolf-bites-tweets 项目来到 1.0.5 的时候,我顺手就开了一个从 main <– dev-1.0.5 的 PR,很快啊,开完了马上就 merge 了。等一切都完成后,突然发现:我 ** README 忘记更新了,就把 PR 给 merge 了。回想起来,其实只要在 main 那里再加一个更新 README 的 commit 就行了,结果我一顿窒息操作,直接把 main 整到了一个很奇怪的状态。

最后,无奈之下,采取了“核弹级”操作(好孩子不要学):Hard reset 加 Force push:

git reset --hard commit_id
+git push origin HEAD --force
+

后果就是后面想要撤销的 commit 的记录都会被丢失。

但是正确操作也是要学会的是吧,事后还是去谷歌上找了这篇讨论:How to revert multiple git commits? - Stack overflow

如果有一个 branch 长这样,其中想要撤销 commits 直到 A 的状态:

 Z <-- A <-- B <-- C <--D     <-- main <-- HEAD
+

如果这些 commits 中没有 merge 操作时,可以使用 git revert

git revert --no-commit A..HEAD
+# 或者使用:
+# git revert --no-commit B^..HEAD
+# 或者怕出错也可以一步一步 revert:
+# git revert --no-commit D
+# git revert --no-commit C
+# git revert --no-commit B
+git commit -m "the commit message for all of them"
+

最后会变成:

Z <-- A <-- B  <-- C <-- D <-- [(BCD)^-1]     <-- main <-- HEAD
+

另外一种就是使用 git checkout 来恢复,适用于含有 merge 操作的 commits:

git stash #暂存本地修改,如果有的话
+git checkout -f A -- . # 在本地文件上 checkout 到指定 commit 上
+git commit -a
+

最后会变成:

Z <-- A <-- B <-- C <-- D <-- A'     <-- main <-- HEAD
+

Wolf-Bites-Tweets v1

项目仓库:https://github.com/ohmykreee/wolf-bites-tweets

其实就是个比较简单的 Python 程序,写的也很快,花了两个晚上左右就把第一个版本 1.0.0 给写了出来,又花了几天肝 了两个版本。

也没啥技术含量(指很多东西都是对着其他项目照葫芦画瓢),其中一个坑就是在 1.0.0 版本中涉及到了一个关于 list/dict 变量复制的问题:

在 Python 中,如果想要把一个 list 的内容给另外一个变量,想整一些花活时,比如这样:

this_is_a_list = another_list
+

其实这样操作完后在 Python 那里只有一个 list 有着两个不同的名字 this_is_a_listanother_list如果你对其中一个变量进行一些更改时,另外一个变量也会相应发生更改。就很傻逼,不是吗?

正确操作应该是使用 Deep copy:

import copy
+
+this_is_a_list = copy.deepcopy(another_list)
+

这样就会有两个独立互不干扰的 list。

这个操作在版本 1.0.5 以及之后已经弃用了,因为 get_tweets.pypop 删除元素的操作(而且回想起来那种方法好像还存在 bug,有兴趣的可以回看那个版本)改成了 append 添加元素的操作。


Wolf-Chews-Tweets

项目仓库:https://github.com/ohmykreee/wolf-chews-tweets

准备写两个实现方式:一个是插入推特官方的小部件,一个是用别人造好的轮子 nolimits4web +/ +swiper 来写一个直接展示图片的组件。

配置开发环境

对,很痛苦,也绕了一点弯路。

谁叫你用 Windows 做开发呢?
—— 不知名暴论者

mvn 用的是 nvm-windows 这个项目,注意点有这几个:

  1. 安装目录不能包含空格,也就是说不能安装在 Program Files 文件夹下,推荐放在 C:\nvm\ 或者 D:\nvm\ ,不然会得到蜜汁乱码报错(估计是软件不适配中文环境的原因)。Node 的链接文件目录最好也放在这种盘根目录文件夹里。
  2. 可以使用 nvm node_mirror <node_mirror_url>nvm npm_mirror <npm_mirror_url> 命令来添加镜像,加速下载。
  3. 在执行 nvm use <node_version> 时,会遭遇报错 exit code 1 一堆乱码 ,解决方法就是用管理员权限开一个终端,再执行命令。
  4. Node 首次安装完后 VS Code 内置终端可能会无法使用 nodenpm 命令,暂时没有搞明白原因(可能是系统环境变量没有同步?)。重启解。

VS Code 那里又有一个大坑:
如果想在 VS Code 用微软亲儿子 Edge 浏览器调试 Javascript 代码时,里面其实是已经内置了 debugger for Microsoft Edge 的。我本以为这个 debugger 是直接“开箱即用”的:开始调试时,它会启动一个内置本地服务器,然后再打开浏览器开始调试。但事实是它并没有本地服务器这个功能,还得自己整一个本地服务器,不然你就会得到一个第一眼看上去不知所以然的报错:

crbug/1173575, non-JS module files deprecated.
+

还好 VS Code 插件里就有现成的 Live Server 插件。启动了之后在 .vscode/launch.json 里把 url 后面的端口改为开放的端口就行。

只能说这波啊,这波微软欺骗了我单纯的感情(雾)。

使用 Custom Elements

准备使用自定义元素来调用生成我想要的内容。

参考:使用 custom elements - MDN Web Docs

用法大致是用 window.customElements.define 命令来声明一个自定义元素,然后定义一个类来定义这个自定义元素的行为。

不过想说一下,在参考文章里示例代码用的是 constructor() 方法,我认为在某些情况下并不是个好方法:

class WolfChewsElement extends HTMLElement {
+  constructor() {
+    // 必须首先调用 super 方法
+    super();
+
+    // 元素的功能代码写在这里
+    ...
+  }
+}
+

在此之前,我想提醒一下:浏览器渲染 HTML 文件时也是按照从头到尾的顺序读取文件;也就是说,HTML 文件内代码的读取和执行是是受位置先后顺序影响的。

回到这个问题上,constructor() 这个方法是用方法来定义一个类没错,并且是在这个类被创建的时候 立即 执行,也就是说当浏览器读取到这一行的代码时,会立即执行 constructor() 内的代码。于是问题来了:如果你的 constructor() 方法里有读取你自定义元素内属性的代码,并且这个代码执行的时候 DOM 还没有建立,就会无法读取到属性内容并且返回 undifined

于此同时,在Chrome版本76.0.3809.132(正式版本)(64 位)中,如果你在 constructor() 方法内有读取自定义元素内属性的行为,并且在 HTML 引用 js 文件时在 script 标签上没有添加 defer 属性,浏览器会直接返回 undifined。那这个 defer 又是什么东西呢?这个属性是告诉浏览器这个代码要等整个页面加载完成后再执行。(参考文章: Why do I have to defer customElement definitions? - Stack Overflow

较好的方法应该是使用 connectedCallback() ,即在自定义元素首次被插入到文档 DOM 节点上时被调用:

class WolfChewsElement extends HTMLElement {
+  connectedCallback() {
+    // 代码写在这里
+    ...
+  }
+
+  this_is_a_function() {
+    ...
+  }
+}
+

关于其他方法可以参考这里:Web Components - MDN Web Docs

生命周期回调
定义在自定义元素的类定义中的特殊回调函数,影响其行为:

  • connectedCallback: 当自定义元素第一次被连接到文档DOM时被调用。
  • disconnectedCallback: 当自定义元素与文档DOM断开连接时被调用。
  • adoptedCallback: 当自定义元素被移动到新文档时被调用。
  • attributeChangedCallback: 当自定义元素的一个属性被增加、移除或更改时被调用。

(在这里顺便附上我读取自定义元素的属性的方法,虽然方法不是我自己原创的,但是这个方法可以说是非常好,对于可选参数传递也能很好的读取:)

// fetch value
+const config = {}
+const keys = ['url', 'method', 'index', 'container_id']
+for (let i = 0; i < this.attributes.length; i = i + 1) {
+    if (keys.includes(this.attributes[i].name)) {
+        config[this.attributes[i].name] = this.attributes[i].value
+    }
+}
+

跨域问题

本来说是想直接用推特的 API :statuses/oembed 来直接获取 embeded twitter 的 HTML 代码,结果遇到了跨域错误。

简单来说,跨域(跨域资源共享)就是在一个域名下想要用 XMLHttpRequest 访问另外一个域名下的资源时,出现的情况。

默认情况下,浏览器是默认拒绝跨域的,因为会有跨域攻击的可能存在(除非在发出请求的时候加上请求头: Access-Control-Allow-Origin: * 允许所有来源)。于此同时,对方服务器也需要允许跨域,否则这个跨域访问就无法完成。

但现状是,所有的推特 API 都不支持跨域访问,官方的说法是建议推特 API 只用于后端中。无可奈何,只能使用推特的 widgets.js 来渲染推特,缺点就是加入推特自己的分析框架,而且好像关不掉的样子。

更多信息可以去读读这篇文章:跨源资源共享(CORS) - MDN Web Docs

随机整数生成

/**
+* Returns a random integer between min and max
+* Using Math.round() will give you a non-uniform distribution!
+* Both min and max can be randomed
+*/
+_getRandomInt (min, max) {
+    return Math.floor(Math.random() * (max - min + 1)) + min
+}
+

直接从 Stack Overflow 上抄的:Javascript Random Integer Between two Numbers -Stack Overflow,至于原理我还没弄懂(谁叫我数学那么拉呢)。

Ctrl + C, Ctrl + V, work done!
—— 某人的暴言

http_get 方法

_httpGet (theUrl) {
+    try{
+        var xmlHttp = new XMLHttpRequest()
+        xmlHttp.open( "GET", theUrl, false ) // false for synchronous request
+        xmlHttp.send( null )
+        return xmlHttp.responseText
+    } catch (e) {
+        throw this._throwException('http request', e)
+    }
+}
+

也是直接从 Stack Overflow 上抄的:HTTP GET request in JavaScript? - Stack Overflow,自己加了个 try{} 和 脱裤子放屁行为(指 catch 了一个错误又顺手丢出去)

清空一个父 node 里的所有子 node

三个方法,我都觉得不是很优雅。(参考文章: Remove all child elements of a DOM node in JavaScript - Stack Overflow

  1. parent.textContent = ''
    项目中使用的是这个方法。因为原来的父 node 里只有一个 text node,我估计这个方法能行,还没试过父 node 里套了一些奇奇怪怪的东西的情况。

  2. parent.innerHTML = ''
    杀伤力极大,直接父 node 里啥都没有了,就是执行速度上要比上面一个要慢一点。在某些情况下不是很好用。

  3. 循环执行 parentNode.removeChild()
    虽然这个看上去最优雅,但是总觉得这种 暴力 循环哪里看着怪怪的。

while (parentNode.firstChild) {
+    parentNode.removeChild(parentNode).lastChild);
+}
+

让整个 div 可以被超链接

可以说是一个很不错的一个 trick ,具体的话也不好说,直接放链接:Make a div into a link - Stack Overflow

使用 Grunt 完成一些自动化

参考:Getting started - GruntJS

目前只想到自动化来缩小项目文件,所以整个配置都会变得很简单。

在此之前要安装全局的 grunt-cli ,作用是调起项目中的 grunt 并运行,这样运行相应任务只要运行 grunt <任务名> 就行了:

npm install -g grunt-cli
+

然后在项目中安装 gruntgrunt-contrib-uglifygrunt-contrib-cssmin

npm install grunt --save-dev
+npm install grunt-contrib-uglify --save-dev
+npm install grunt-contrib-cssmin --save-dev
+

安装完后可以考虑把 node_modules 添加到 .gitignore 里,如果不对包作直接的修改的话。

直接上官方的示例 Gruntfile.js ,然后自己改改:

module.exports = function(grunt) {
+
+    // Project configuration.
+    grunt.initConfig({
+        pkg: grunt.file.readJSON('package.json'),
+        uglify: {
+            options: {
+            banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n'
+            },
+            build: {
+                src: 'wolf-chews.js',
+                dest: 'wolf-chews.min.js'
+            }
+        },
+        cssmin: {
+            build: {
+                src: 'wolf-chews.css',
+                dest: 'wolf-chews.min.css',
+            }
+        }
+    });
+  
+    // Load the plugins.
+    grunt.loadNpmTasks('grunt-contrib-uglify');
+    grunt.loadNpmTasks('grunt-contrib-cssmin');
+  
+    // Default task(s).
+    grunt.registerTask('build', ['uglify', 'cssmin']);
+  
+  };
+

如果之后想要用 GitHub Action 自动执行 grunt 命令,可以在 package.json 里设置测试用命令:

"scripts": {
+    "test": "node -e \"var g = require('grunt'); g.cli.tasks = ['build']; g.cli()\""
+},
+

这样就不用在 Action 流程里安装 grunt-cli 而直接执行 npm test 就行。

编写 publish-to-npm.yml 用 GitHub Action 帮我完成这些任务并发布在 npm 上:

name: Publish to NPM
+
+on:
+  push:
+    branches:
+      - main
+
+jobs:
+  publish:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v1
+      - uses: actions/setup-node@v1
+        with:
+          node-version: 10
+      - run: npm install
+      - run: npm test
+      - run: rm -rf .vscode .github
+      - uses: JS-DevTools/npm-publish@v1
+        with:
+          token: ${{ secrets.NPM_TOKEN }}
+          dry-run: false
+

于是,这个大坑就这样先告一段落了。

各位看官可以在 404页面 看到这个功能的实装了!


你以为这就结束了吗?

在另外一个夜黑风高的夜晚,当我躺在床上时,脑海里突然涌现一个想法:既然你都会 Javasript 了,要不你把 Wolf-bites-tweets 用 Javascript 重写一遍吧。

于是,下期预告:Wolf-Bites-Tweets v2.0 的开发(Node.js)

开坑不止,填坑不息。
—— Kreee

\ No newline at end of file diff --git a/article/page/1/index.html b/article/page/1/index.html new file mode 100644 index 00000000..cf55f72a --- /dev/null +++ b/article/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/article/ + \ No newline at end of file diff --git a/article/page/2/index.html b/article/page/2/index.html new file mode 100644 index 00000000..557818ea --- /dev/null +++ b/article/page/2/index.html @@ -0,0 +1,36 @@ +Articles | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 GitHub Action 自动渲染和发布网页

2021-06-07 +Learning +Kreee

Why?

根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
So, let’s begin!

继续阅读

Docker 学习小记

2021-03-01 +Learning +Kreee

本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
Now, let’s begin!

继续阅读
较新的帖子
\ No newline at end of file diff --git a/article/python-final-exam-questions/index.html b/article/python-final-exam-questions/index.html new file mode 100644 index 00000000..9a4f736d --- /dev/null +++ b/article/python-final-exam-questions/index.html @@ -0,0 +1,657 @@ +Python 期末编程题题库 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

Python 期末编程题题库

2021-06-04 +Study +Kreee

(据说)Python 期末考的编程题会从这里面抽。
有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。
愿人间没有挂科人。

  1. 从键盘输入三个数值,分别赋值给num1, num2和num3,并求它们的平均值。
# by Kreee
+
+num1 = eval(input('请输入第一个数字:'))
+num2 = eval(input('请输入第二个数字:'))
+num3 = eval(input('请输入第三个数字:'))
+
+averNum = (num1 + num2 + num3) / 3
+print('这三个数的平均数为:{}'.format(averNum))
+

  1. 输入一个三位数,输出它的逆序数,例如:输入123,输出321。
# by Kreee
+
+getInput = int(input('请输入一个三位整数:'))
+
+numBit1 = getInput % 10
+numBit2 = getInput // 10 % 10
+numBit3 = getInput // 100 % 10
+outNum = str(numBit1) + str(numBit2) + str(numBit3)
+
+print('该三位数的逆序数为:{}'.format(outNum))
+

  1. 输入一个华氏温度,输出对应的摄氏温度。
# by Kreee
+
+TempStr = input('请输入华氏度:')
+if TempStr[-1] in ['F', 'f', '℉']:
+    C = (eval(TempStr[0: -1]) - 32) / 1.8
+    print('转换后的温度是{:.2f}℃'.format(C))
+else:
+    C = (eval(TempStr) - 32) / 1.8
+    print('转换后的温度是{:.2f}℃'.format(C))
+

  1. 使用键盘输入一个 Unicode 字符,显示出这个字符对应的 Unicode 编码值。
# by Kreee
+
+getInput = input('请输入一个字符:')
+outOrd = ord(getInput)
+print('字符 {} 的 Unicode 编码值为:{}'.format(getInput, outOrd))
+

  1. 在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系。请使用键盘输入偏移量,并使用偏移量对键盘输入对单个大写英文字母进行加密。如偏移量为3,输入英文字母为Z,则输出为C。
# by 张忆文(文忆天下)
+
+offset = int(input("输入的偏移量为:"))
+inputChar = input("输入单个大写英文字母为:")
+outputCharValue = (ord(inputChar) - ord("A") + offset) % 26
+outputChar = chr(ord("A") + outputCharValue)
+print("经过凯撒加密之后,输出的字符为:" + outputChar)
+
# by Kreee
+
+getShift = input('请输入偏移量(整数):')
+getInput = input('请输入待加密内容(单个英文字母):')
+
+# 检查用户输入
+if getShift.isdigit() == False:
+    print('输入不符合规范:偏移量不是整数!')
+    exit(1)
+if len(getInput) != 1:
+    print('输入不符合规范:未输入单个字符!')
+    exit(1)
+
+# 计算密码
+getShift = int(getShift)
+inOrd = int(ord(getInput))
+if 65 <= inOrd <= 90:
+    outOrd = inOrd + getShift
+    if outOrd > 90:
+        outChr = chr(outOrd - 90 + 64)
+    else:
+        outChr = chr(outOrd)
+elif 97 <= inOrd <= 122:
+    outOrd = inOrd + getShift
+    if outOrd > 122:
+        outChr = chr(outOrd - 122 + 96)
+    else:
+        outChr = chr(outOrd)
+else:
+    print('输入不符合规范:非英文字母!')
+    exit(1)
+print('转换后的字符为: {}'.format(outChr))
+

  1. 使用 random.randint(a, b) 方法,随机生成三个100以内的自然数,求三个数的和。
# by Kreee
+
+import random
+
+num1 = random.randint(0, 100)
+num2 = random.randint(0, 100)
+num3 = random.randint(0, 100)
+averNum = (num1 + num2 + num3) / 3
+
+print('随机产生的三个数为 {}, {}, {}, 它们的平均数为{}'.format(num1, num2, num3, averNum))
+

  1. 使用 round(x, y) 函数,可以将浮点数x保留y位小数。使用键盘,输入两个非零数,求这两个数的商,结果保留两位小数。输出的时候,请注意使用“➗”(十进制Unicode编码:10135)作为连接符表示除号。
# by Kreee
+
+num1 = eval(input("请输入第一个数:"))
+num2 = eval(input("请输入第二个数:"))
+
+outNum = round(num1 / num2, 2)
+
+print(str(num1) + chr(10135) + str(num2) + '=' + str(outNum))
+

  1. 使用 time.time() 方法能够得到目前的时间点,距离1970年1月1日0时0点0分0秒已经过去了多少秒。已知,1970年1月1日星期四,使用计算机计算得出:
    (1)今天距离1970年1月1日,过了多少天
    (2)今天是星期几。
# by Kreee
+
+import time
+
+currTime = time.time()
+dayPassed = int(currTime // (60 * 60 * 24))
+weekPassed = int(dayPassed % 7)
+if weekPassed > 3:
+    currWeek = weekPassed - 3
+else:
+    currWeek = weekPassed + 4
+
+print('今天距离1970年1月1日,过了 {} 天,今天是星期{}'.format(dayPassed, currWeek))
+

  1. 解一元二次方程组,ax** 2 + bx + c = 0,时,有三种可能情况,分别为:
    1、 有两个不等实根
    2、 有两个相等实根
    3、 无实根。
    请使用键盘输入a, b, c的值,并输出一元二次方程的解。
# by 张忆文(文忆天下)
+
+a, b, c = eval(input("输入一元二次方程的 a,b,c 的值以逗号隔开:"))
+if a == 0:
+    if b == 0:
+        if c == 0:
+            print("该方程有任意解")
+        else:
+            print("该方程无解")
+    else:
+        print("该方程有唯一解且解为x1={}".format(-c/b))
+else:
+    delta = b ** 2 - 4 * a * c
+    if delta < 0:
+        print("ax**2+bx+c=0 这个方程无实数解")
+    elif delta == 0:
+        root = (-b) / (2 * a)
+        print("ax**2+bx+c=0 这个方程有两个相等的根,其值为x1=x2={:.2f}".format(root))
+    else:
+        root1 = ((-b) + delta ** 0.5) / (2 * a)
+        root2 = ((-b) - delta ** 0.5) / (2 * a)
+        print("ax**2+bx+c=0 这个方程有两个不同的根: x1 = {:.2f},其值为x2={:.2f}".format(root1, root2))
+

  1. 空气污染指数api的取值与对应的空气质量关系如下:0~50为优, 51~99为良,100~199为轻度污染,200~299为中度污染,300以上为重污染。请编写程序,从键盘输入api值,并输出api值所对应的空气质量。
# by Kreee
+
+getApiNum = int(input('请输入空气污染指数:'))
+
+if getApiNum <= 50:
+    outResult = '优'
+elif 51 <= getApiNum <= 99:
+    outResult = '良'
+elif 100 <= getApiNum <= 199:
+    outResult = '轻度污染'
+elif 200 <= getApiNum <= 299:
+    outResult = '中度污染'
+elif 300 <= getApiNum:
+    outResult = '重度污染'
+
+print('空气质量为:{}'.format(outResult))
+

  1. 蔡勒(Zeller)公式,是一个计算星期的公式,随便给一个日期,就能用这个公式推算出是星期几。蔡勒(Zeller)公式为:

w = (y + [y / 4] + [c / 4] - 2c + [26(m + 1) / 10] + d - 1) % 7

其中:
w:代表星期几;w对7取模得:0-星期日,1-星期一,2-星期二,3-星期三,4-星期四,5-星期五,6-星期六
c:世纪数(注:一般情况下,在公式中取值为已经过的世纪数,也就是年份除以一百的结果,c应该等于所在世纪的编号,如公元2021年,c就等于20)
y:世纪的年数(一般情况下是年份的后两位数,如公元2021年,y就等于21)
m:月份(m大于等于3,小于等于14,即在蔡勒公式中,某年的1、2月要看作上一年的13、14月来计算,比如2003年1月1日要看作2002年的13月1日来计算)
d:日
[ ]代表取整,即只要整数部分。
请使用计算机编写程序,输入年、月、日,输出对应星期几。

# by 张忆文(文忆天下)
+
+year = int(input("输入年份:"))
+month = int(input("输入月份:"))
+day = int(input("输入日:"))
+m = month
+
+if month < 3:
+    m = month + 12
+    year = year - 1
+
+c = year // 100
+y = year % 100
+d = day
+w = (y + (y // 4) + (c // 4) - 2 * c + (26 * (m + 1) // 10) + d - 1) % 7
+
+if(w == 1):
+    message = "星期一"
+elif (w == 2):
+    message = "星期二"
+elif (w == 3):
+    message = "星期三"
+elif (w == 4):
+    message = "星期四"
+elif (w == 5):
+    message = "星期五"
+elif (w == 6):
+    message = "星期六"
+else:
+    message = "星期日"
+print("输入{}{}{}日,输出{}".format(year, month, day, message))
+

  1. 输入两个圆的圆心坐标及这两个圆对应的半径,求这两个圆之间的关系,是内含、内切,相交、外切还是分离?
# by 张忆文(文忆天下)
+
+x1, y1 = eval(input("输入一个圆的圆心坐标:"))
+r1 = eval(input("输入圆的半径:"))
+x2, y2 = eval(input("输入另一个圆的圆心坐标:"))
+r2 = eval(input("输入圆的半径:"))
+
+# distance 代表两个圆心坐标的距离
+distance = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
+
+# 对圆的关系进行判断
+if distance < abs(r1 - r2):
+    print("这两个圆的关系是:内含")
+elif distance == abs(r1 - r2):
+    print("这两个圆的关系是:内切")
+elif distance < r1 + r2:
+    print("这两个圆的关系是:相交")
+elif distance == r1 + r2:
+    print("这两个圆的关系是:外切")
+else:
+    print("这两个圆的关系是:分离")
+

  1. 剪刀、石头布、是一种划拳游戏。剪刀赢布、布赢石头、石头赢剪刀。假设使用三个整数0、1、2来分别代表石头、剪刀、布,计算机随机生成三个整数(0、1、2)中的一个,用户使用键盘输入(0、1、2)中的一个整数,程序判断是计算机赢了,还是用户赢了,还是平局。
# by 张忆文(文忆天下)
+
+import random
+
+computer = random.randint(0,2)
+you = int(input("石头(0), 剪刀(1), 布(2):"))
+message = "电脑出的是:"
+
+if computer == 0:
+    message = message + "石头(0),你出的是:"
+    if you == 0:
+        message = message + "石头(0),是平局!"
+    elif you == 1:
+        message = message + "剪刀(1),你输了!"
+    else:
+        message = message + "布(2),你赢了!"
+elif computer == 1:
+    message = message + "剪刀(1),你出的是:"
+    if you == 0:
+        message = message + "石头(0),你赢了!"
+    elif you == 1:
+        message = message + "剪刀(1),是平局!"
+    else:
+        message = message + "布(2),你输了!"
+else:
+    message = message + "布(2),你出的是:"
+    if you == 0:
+        message = message + "石头(0),你输了!"
+    elif you == 1:
+        message = message + "剪刀(1),你赢了!!"
+    else:
+        message = message + "布(2),是平局!"
+
+print(message)
+
# by Kreee
+
+import random
+
+getInput = int(input('划拳游戏:石头(整数0)剪刀(整数1)布(整数2):'))
+getRandom = random.randint(0, 2)
+flag = ''
+outUser = ''
+outCom = ''
+
+if getInput == 0:
+    outUser = '石头(0)'
+    if getRandom == 0:
+        outCom = '石头(0)'
+        flag = 'tie'
+    elif getRandom == 1:
+        outCom = '剪刀(1)'
+        flag = 'user'
+    elif getRandom == 2:
+        outCom = '布(2)'
+        flag = 'com'
+elif getInput == 1:
+    outUser = '剪刀(1)'
+    if getRandom == 0:
+        outCom = '石头(0)'
+        flag = 'com'
+    elif getRandom == 1:
+        outCom = '剪刀(1)'
+        flag = 'tie'
+    elif getRandom == 2:
+        outCom = '布(2)'
+        flag = 'user'
+elif getInput == 2:
+    outUser = '布(3)'
+    if getRandom == 0:
+        outCom = '石头(0)'
+        flag = 'user'
+    elif getRandom == 1:
+        outCom = '剪刀(1)'
+        flag = 'com'
+    elif getRandom == 2:
+        outCom = '布(2)'
+        flag = 'tie'
+else:
+    print('非法输入!')
+
+if flag == 'user':
+    print('电脑出的是:{},你出的是:{},你赢了!'.format(outCom, outUser))
+elif flag == 'com':
+    print('电脑出的是:{},你出的是:{},你输了!'.format(outCom, outUser))
+elif flag == 'tie':
+    print('电脑出的是:{},你出的是:{},平局!'.format(outCom, outUser))
+

  1. 某公司进行绩效分配的时候,需要编制一个计算机程序帮助计算奖金。假设一个部门经理的全部门拿到了500万元以上的订单,则部门经理获得总订单额度的1%作为个人绩效奖励,如果没有达到这个额度,则只能获得订单额度的0.5%作为个人绩效奖励;一个普通员工如果能够拿到50万元以上的订单,则该员工获得订单额度的2%作为个人绩效奖励,如果没有达到这个目标,则该员工仅获得订单额度的1%作为个人绩效奖励。编制一个程序,使用键盘输入必要参数,计算出某公司员工的绩效。
# by 张忆文(文忆天下)
+
+position = input("输入职位,经理或普通员工:")
+order = eval(input("输入订单总额(单位:万元):"))
+
+if position == "经理":
+    if order > 500:
+        bonus = order * 0.01
+    else:
+        bonus = order * 0.005
+else:
+    if order > 50:
+        bonus = order * 0.02
+    else:
+        bonus = order * 0.01
+
+print("该员工的职位为{},绩效奖金为{}万元".format(position, bonus))
+

  1. 随机生成一个取值范围介于[0, 51]的整数,用以模拟从52张扑克牌中随机抽取一张扑克牌的操作。在本程序中,需要在用牌花色(黑桃、红心、梅花、方片)和牌面(“A”, “2”, “3”, “4”, “5”, “6”, “7”, “8”, “9”, “10”, “J”, “Q”, “K”)在控制台显示出随机抽到的牌。
# by 张忆文(文忆天下)
+
+import random
+
+card = random.randint(0, 51)
+message = "你抽到的牌是:"
+
+# suit 代表花色,黑桃(0)、红桃(1)、梅花(2)、方片(3),输出花色
+suit = card % 4
+if suit == 0:
+    message = message + "黑桃"
+elif suit == 1:
+    message = message + "红桃"
+elif suit == 2:
+    message = message + "梅花"
+else:
+    message = message + "方片"
+
+# 接下来输出牌面
+cardnumber = (card % 13 + 1)
+if cardnumber == 1:
+    message = message + "A"
+elif cardnumber == 11:
+    message = message + "J"
+elif cardnumber == 12:
+    message = message + "Q"
+elif cardnumber == 13:
+    message = message + "K"
+else:
+    message = message + str(cardnumber)
+
+print(message)
+
# by Kreee
+
+import random
+getRandom = random.randint(0, 51)
+
+pokerList = []
+for suit in ['黑桃', '红桃', '梅花', '方片']:
+    for num in ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']:
+        pokerList.append(suit + num)
+
+print('你抽到的牌是:{}'.format(pokerList[getRandom]))
+

  1. 我国使用的是阶梯电价制度。按照用电的电量情况可以分为三个档次:
    第一档,电量每户每月210度及以下
    第二档,电量每户每月210-400度之间
    第三档,电量每户每月400度以上。
    一档、二档、三档就是根据不同用电量规定的电价,用电量大,电价就高,比如第一档电量每户每月执行电价,每度0.5469元,第二档电量每户每月在第一档电价基础上,每度加价0.05元,即每度0.5969元,第三档电量每户每月在第一档电价基础上,每度加价0.3元,即每度0.8469元。
    如:某用户一个月用电800度,则计算公式可以表达为:

电费 = 第一档用电量(210度)* 第一档电价+第二档用电量(400 - 210度)* 第二档电价+第三档用电量(800 - 400度)* 第三档电价

使用键盘输入某用户的一个月用电量,求该用户需要缴纳多少电费。

# by Kreee
+
+getInput = eval(input('请输入这个月所用电度数:'))
+
+if getInput <= 210:
+    outMoney = getInput * 0.5469
+elif 210 < getInput <= 400:
+    outMoney = 210 * 0.5469 + (getInput - 210) * 0.5969
+elif 400 < getInput:
+    outMoney = 210 * 0.5469 + (400 - 210) * 0.5969 + (getInput - 400) * 0.8469
+
+print('这个月的电费为:{}'.format(outMoney))
+

  1. 输出100以内所有7的倍数。
# by Kreee
+
+outNum = 7
+i = 1
+while outNum < 100:
+    print(outNum, end=' ')
+    i = i + 1
+    outNum = 7 * i
+

  1. 输出以下由“*”组成的图形:

(1)

*
+**
+***
+****
+*****
+

(2)

    *
+   **
+  ***
+ ****
+*****
+

(3)

    *
+   ***
+  *****
+ *******
+*********
+
# by Kreee
+# ps:想改又不愿意改,累了,就这样
+
+print('(1)')
+for i in range(1, 6):
+    printLine = '*' * i
+    print(printLine)
+
+print('(2)')
+for j in range(1, 6):
+    printLine = ' ' * (5 - j) + '*' * j
+    print(printLine)
+
+print('(3)')
+for k in range(1, 6):
+    printLine = ' ' * (5 - k) + '*' * (2 * k - 1)
+    print(printLine)
+

  1. 使用键盘输入10个数,求这10个数的平均数。
# by 张忆文(文忆天下)
+
+number = 10
+count, sum = 0, 0
+
+while count < number:
+    num = eval(input("输入一个数: "))
+    sum += num
+    count += 1
+
+print("十个数的平均数是:" + str(sum / number))
+
# by Kreee
+
+def CalAverage(Inputnum):
+    getResult = 0.0
+    for i in Inputnum:
+        getResult = getResult + i
+    return getResult / len(Inputnum)
+
+
+print(CalAverage(eval(input('输入一组数,用逗号隔开:'))))
+

  1. (1)假设某门面出租,在租赁合同中规定的首年租金为100000块,租金每年涨5%。在控制台打印出10年时间,每一年租金会分别涨到多少钱?
    (2) 如果某打工人想租下了该店面,花费了30万进行装修,开始通过销售服装获取收入。第一个月刨除房租、水电、人工开销,能有收入5000块。生意越来越好做,假设能够勉强维持每月收入7%递增,那需要多久的辛勤劳动,就能收回成本?
    本题中,所有金额保留两位小数。
# by 张忆文(文忆天下)
+
+rental, year = 100000, 1
+income, month, deposit = 10000, 1, 300000
+
+while year <= 10:
+    print("第{}年的租金为¥{:.2f}".format(year, rental))
+    rental *= 1.05
+    year += 1
+
+while deposit > 0:
+    deposit = deposit - income
+    month += 1
+    income *= 1.07
+
+print("第{}月后能够收回投资".format(month))
+
# by Kreee
+
+# 计算门面租金
+for i in range(0, 10):
+    rent = 100000.00 * pow(1.05, i)
+    print('第{}年的租金为:{:.2f}'.format(i + 1, rent))
+
+# 计算劳动月数
+getMonth = 0
+addMoney = 0
+while addMoney < 300000:
+    addMoney = addMoney + 10000 * pow(1.07, getMonth)
+    getMonth = getMonth + 1
+print('第{}个月能够收回投资。'.format(getMonth + 1))
+

  1. 输出以下由数字组成的图形:

(1)

1
+12
+123
+1234
+12345
+123456
+

(2)

654321
+ 54321
+  4321
+   321
+    21
+     1
+

(3)

     1
+    12
+   123
+ 12345
+123456
+
# by Kreee
+print('(1)')
+result1 = ''
+for i in range(1, 7):
+    for num in range(1, i + 1):
+        if num == i:
+            result1 = result1 + str(num) + '\n'
+        else:
+            result1 = result1 + str(num)
+print(result1)
+
+# 方法很屎,没力气想其他更好的方法了,就这样
+print('(2)')
+result2 = ''
+for j in range(6, 0, -1):
+    result2 = result2 + ' ' * (6 - j)
+    for num in range(j, 0, -1):
+        if num == 1:
+            result2 = result2 + str(num) + '\n'
+        else:
+            result2 = result2 + str(num)
+print(result2)
+
+print('(3)')
+result3 = ''
+for k in range(1, 7):
+    result3 = result3 + ' ' * (6 - k)
+    for num in range(1, k + 1):
+        if num == k:
+            result3 = result3 + str(num) + '\n'
+        else:
+            result3 = result3 + str(num)
+print(result3)
+

  1. 使用键盘输入一个年份,并在控制台输出这一年,每个月1日是星期几。
# by Kreee
+
+def zeller(year, month, date):
+    if month <= 2:
+        month = month + 12
+        year = year - 1
+    week = (date + 26 * (month + 1) // 10 + year % 100 + year % 100 // 4 + year // 100 // 4 + year // 100 * 5 - 1) % 7
+    if week == 1:
+        weekDay = "星期一"
+    elif week == 2:
+        weekDay = "星期二"
+    elif week == 3:
+        weekDay = "星期三"
+    elif week == 4:
+        weekDay = "星期四"
+    elif week == 5:
+        weekDay = "星期五"
+    elif week == 6:
+        weekDay = "星期六"
+    elif week == 0:
+        weekDay = "星期日"
+    return weekDay
+
+
+getYear = int(input('请输入一个年份:'))
+for i in range(1, 13):
+    outWeek = zeller(getYear, i, 1)
+    print('{} 年的 {} 月 1 日是{}'.format(getYear, i, outWeek))
+

  1. 写一个程序,键盘输入一个十进制数,将十进制数转换为二进制数,输出到控制台。
# by Kreee
+
+getInput = eval(input('请输入需要转换为二进制的整数:'))
+outBinary = ''
+
+if getInput == 0:
+    outBinary = '0'
+else:
+    divResult = getInput
+    while divResult != 1:
+        if divResult % 2 == 0:
+            outBinary = '0' + outBinary
+            divResult = divResult / 2
+            continue
+        else:
+            outBinary = '1' + outBinary
+            divResult = divResult // 2
+            continue
+    outBinary = '1' + outBinary
+
+print(outBinary)
+

  1. 如果一个正整数等于除了他本身之外的所有正因子的和,那么这个数被称为是完全数。如:6 = 3 * 2 * 1 = 3 + 2 + 1,因此6是一个完全数。求10000以内所有的完全数。
# by 张忆文(文忆天下)
+
+for i in range(1, 10000):
+    sum = 0
+    for j in range(1, i // 2 + 1):
+        if i % j == 0:
+            sum = sum + j
+    if sum == i:
+        print(i, end=" ")
+
# by Kreee
+
+perfectNum = []
+getInput = 10000
+
+for num in range(1, getInput + 1):
+    divisor = []
+    for i in range(1, num):
+        if (num / i) % 1 == 0:
+            divisor.append(i)
+    addDivisor = 0
+    for j in divisor:
+        addDivisor = addDivisor + j
+    if addDivisor == num:
+        perfectNum.append(num)
+
+for k in perfectNum:
+    print(k, end=" ")
+

  1. 定义一个名为 isLeapYear(year) 的函数,参数为一个年份,如果该年份是闰年,则返回值为True,否则,返回值为False。在同一源文件中,使用键盘输入年份,验证该函数是否能够正确返回该年份是否为闰年。
# by 张忆文(文忆天下)
+
+def isLeapYear(year):
+    if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
+        return True
+    else:
+        return False
+
+
+year = int(input("输入一个年份:"))
+print(isLeapYear(year))
+

  1. 定义一个名为 zeller(year, month, date) 的函数,参数为年、月、日。通过这个函数计算并返回该日期是星期几。在同一源程序中,使用键盘输入年、月、日,验证该函数是否能正确计算出输入的日期为星期几。
# by 张忆文(文忆天下)
+
+def zeller(year, month, date):
+    if month <= 2:
+        month += 12
+        year -= 1
+    weekDay = (date + 26 * (month + 1) // 10 + year % 100 + year % 100 // 4 + year // 100 // 4 + year // 100 * 5 - 1) % 7
+    return weekDay
+
+
+year, month, date = eval(input("一次输入年,月,日:"))
+weekDay = zeller(year, month, date)
+print(weekDay)
+

  1. 定义一个名为 isPrime(number) 的函数,参数为一个正整数。通过使用这个函数,能够判断一个正整数,是否为素数,是素数则返回True,不是素数则返回False。在同一源程序中,使用键盘输入一个正整数,验证该函数是否能够正确判断输入数为素数。
# by Kreee
+
+def isPrime(number):
+	# 质数判断方法见下一题。
+    for factor in range(2, number // 2 + 1):
+        if number % factor == 0:
+            return False
+        else:
+            return True
+
+
+getInput = int(input('请输入一个正整数:'))
+ifPrime = isPrime(getInput)
+if ifPrime:
+    print('正整数 {} 是质数。'.format(getInput))
+else:
+    print('正整数 {} 不是质数。'.format(getInput))
+

  1. 定义一个名为 primeNumbers(number) 的函数,参数为一个正整数。通过使用这个函数,能够输出小于number的所有素数,输出的时候,每行10个素数。在同一源文件中,使用键盘输入一个正整数,验证该函数的输出结果。
# by 张忆文(文忆天下)
+
+def primeNumbers(number):
+    message = str(number) + "以内的质数有:\n"
+    count = 0
+    # 外层循环,从2开始,到number结束
+    for num in range(2, number):
+        # 使用一个标志,这个标志为True,假设number是质数
+        flag = True
+        # 内层循环从2开始,到num//2结束,寻找有没有num的因数
+        for factor in range(2, num // 2 + 1):
+            # 如果num可以被2到num//2之间的某个自然数整除
+            if num % factor == 0:
+                # 将标志设为False,意义为:number不是质数
+                flag = False
+        # 如果内层循环结束后,没有找到任何因数,标志保持True状态
+        # 说明num的确是一个质数
+        if flag:
+            count = count + 1
+            # 将这个质数记录到message中。
+            if count % 10 == 0:
+                message = message + str(num) + "\n"
+            else:
+                message = message + str(num) + "\t"
+    print(message)
+
+
+number = int(input("请输入一个正整数:"))
+primeNumbers(number)
+

客官,都看到最后了,何不来一张福瑞图呢👍 (误)

\ No newline at end of file diff --git a/article/python-final-exam-questions/python-questions-bonus.jpg b/article/python-final-exam-questions/python-questions-bonus.jpg new file mode 100644 index 00000000..14fb167a Binary files /dev/null and b/article/python-final-exam-questions/python-questions-bonus.jpg differ diff --git a/article/self-use-cheatsheet/featuredImage.jpg b/article/self-use-cheatsheet/featuredImage.jpg new file mode 100644 index 00000000..693d73ce Binary files /dev/null and b/article/self-use-cheatsheet/featuredImage.jpg differ diff --git a/article/self-use-cheatsheet/featuredImage_hu6ea1ac35861fa017287e8f224b838c0e_53687_700x350_fill_q95_box_smart1.jpg b/article/self-use-cheatsheet/featuredImage_hu6ea1ac35861fa017287e8f224b838c0e_53687_700x350_fill_q95_box_smart1.jpg new file mode 100644 index 00000000..00405efe Binary files /dev/null and b/article/self-use-cheatsheet/featuredImage_hu6ea1ac35861fa017287e8f224b838c0e_53687_700x350_fill_q95_box_smart1.jpg differ diff --git a/article/self-use-cheatsheet/index.html b/article/self-use-cheatsheet/index.html new file mode 100644 index 00000000..72ed0d9e --- /dev/null +++ b/article/self-use-cheatsheet/index.html @@ -0,0 +1,49 @@ +自用备忘录表 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

自用备忘录表

2021-06-06 +Learning +Kreee

一个自用的备忘录表,记录一下要用但是又容易忘记的命令。
不断更新中…


目录


Git

初始化

git init
+

关联远程仓库

git remote add origin <remote address>
+git -M main # 切换默认分支到main(master 不再用)
+git pull <local> <remote>
+

提交修改

git add <file>
+git commit -m 'descriptions'
+git push origin main
+

分支管理

git branch <branch name>            # 创建<branch name>分支
+git checkout <branch name>          # 切换至<branch name>分支
+git switch <branch name>            # 切换至<branch name>分支
+git checkout -b <branch name>       # 创建并切换至<branch name>分支
+git switch -c <branch name>         # 创建并切换至<branch name>分支
+git branch                          # 查看已有分支(* 表示当前分支)
+git merge <branch name>             # 合并<branch name>到当前分支(通常在master分支下操作)
+git branch -d <branch name>         # 删除分支(本地)
+git push <local> --delete <remote>  # 删除分支(远程)
+

子模块

git submodule add <submodule address> <local folder> # 添加子库,使用 --force 强制使用本地已有文件
+git submodule foreach git pull    #子模块更新
+

Linux (Ubuntu) 操作相关

更改当前环境的 Java 版本

sudo update-alternatives --config java
+

创建无 Shell 的用户

根据 nobody - Ubuntu Wiki,不建议将程序的运行权限设置为 nobody:nogroup,而是额外创建一个新的用户组。

(没办法偷懒了呜呜呜)

(方法来自 How can I create a non-login user? - superuser

sudo useradd -r <username>
+

将会创建一个组名和用户名都为 <username> 的用户,且无用户目录。


Certbot

dns-challenge 自签名

certbot certonly --manual --preferred-challenges dns --email xxxxxx.xxxxx@outlook.com --agree-tos -d *.ohmykreee.top
+

pppoe-setup

设置拨号

pppoe-setup # 开始交互式操作
+

连接和断连

ifup ppp0
+ifdown ppp0
+

状态

ifconfig ppp0
+pppoe-status
+

docker

列出容器

docker ps -a
+

管理容器

docker start/stop/restart/rm/port/logs <container>
+

后台运行容器

docker run -itd --name <name> <container>  # -it: 使用交互模式并分配一个伪终端
+docker exec -it <container>                # -d: 后台运行容器,并返回容器ID
+
\ No newline at end of file diff --git a/article/setup-pve-with-opnsense-ubuntu-notes/featuredImage.jpg b/article/setup-pve-with-opnsense-ubuntu-notes/featuredImage.jpg new file mode 100644 index 00000000..903e1a95 Binary files /dev/null and b/article/setup-pve-with-opnsense-ubuntu-notes/featuredImage.jpg differ diff --git a/article/setup-pve-with-opnsense-ubuntu-notes/index.html b/article/setup-pve-with-opnsense-ubuntu-notes/index.html new file mode 100644 index 00000000..29fe2436 --- /dev/null +++ b/article/setup-pve-with-opnsense-ubuntu-notes/index.html @@ -0,0 +1,265 @@ +PVE、OPNsense、Ubuntu Server设置小记 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

PVE、OPNsense、Ubuntu Server设置小记

2022-12-24 +Learning +Kreee

注意! 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。


目录:


安装 PVE

直接在官网上下载 ISO 镜像,然后按照提示安装上去就行。

安装中记得记录一下 Summary 与 Install Successful 中的信息,之后可能会用到。

首次安装完成后如果想要访问 ssh、WebGUI 等,需要先连接到安装时指定的管理网口(这里是 enp6s0),再设置电脑网卡将 IP 设置为安装时设置的同子网但是与 pve 主机不同的 IP。如果还是访问不了的话可以试试关闭其他网络连接(比如 WiFi 等)。

设置 PVE

设置硬件直通

由于想要将部分网卡直通给 OPNsense,所以要修改一下设置让 pve 支持硬件直通。

在 WebGUI 的 node 处登录 Shell,修改 grub 文件 /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT=quite 一栏的值为 quite intel_iommu=on(AMD 的就是amd_iommu=on)。保存后使用 update-grub 更新。

修改 /etc/modules 文件,添加以下内容:

vfio
+vfio_iommu_type1
+vfio_pci
+vfio_virqfd
+

保存后,重启机器。

运行以下命令行来列出所有 IOMMU 组:

#!/bin/bash
+shopt -s nullglob
+for g in `find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V`; do
+    echo "IOMMU Group ${g##*/}:"
+    for d in $g/devices/*; do
+        echo -e "\t$(lspci -nns ${d##*/})"
+    done;
+done;
+

硬件直通故障排除

由于我有一张无线网卡,想要直通到 OPNsense 所在的虚拟机中。而直接设置直通的话 qemu 会报错:failed to add PCI capability 0x11[0x70]@0x90: table & pba overlap, or they don't fit in BARs, or don't align

这里就需要多做一步:修改 pve 的 /etc/pve/qemu-server/[虚拟机ID].conf,在文件一行加上:

# 这里无线网卡在虚拟机中分配到的是 hostpci4,按需修改
+args: -set device.hostpci4.x-msix-relocation=bar2
+

更多信息可以参考:Failed to PCI passthrough SSD with SMI SM2262 controller. - Kernel.org BugzillaPCIe Passthrough of Atheros AR9280 - Promox Forums


安装和设置 OPNsense

安装 OPNsense

进入 pve WebGUI,上传 OPNsense 的 ISO 安装包。

在 pve 节点处新建一个网卡桥接,选择一个与管理网卡不同的网卡,且只填写 Bridge Ports 字段。这里名字为 vmbr1。

新建一个虚拟机,设置参数(记得在 CPU 设置里把 aes 功能打开),添加网络设备 vmbr1 ,在 Hardware 里添加 PCI 设备,先只添加 enp1s0。

注意! 建议在新建虚拟机的时候先不要设置自动启动,以便如果出现了 OPNsense 配置错误导致的 pve WebGUI 访问不了,可以通过强制重启机器来恢复。等全部配置完成并确认没有问题后再设置 OPNsense 虚拟机自动启动。

启动虚拟机,首先进入的是 live mode(演示模式),其中在进入演示模式前会配置网络信息,这里建议手动配置设置好WAN口与LAN口,这里是把连接到光猫的 enp1s0 端口设置为 WAN,桥接网卡 vtnet0 设置为 LAN 口。

在成功进入演示模式后,使用用户名 installer 与密码 opnsense 登录,就能进入安装模式,完成接下来的安装,与设置管理员密码。

安装完成后,重启虚拟机,移除安装介质。

初步设置

将电脑连接到 enp5s0 对应的网口上,并将电脑的手动地址改回为 DHCP 自动获取地址。使用默认地址 192.168.1.1 登录上 OPNsense 的 WebGUI 后,完成初始设置向导。在设置向导里可以更改 LAN 口地址,防止与光猫的 192.168.1.1 冲突(建议与 pve 的子网相同,原因后面会提及)。应用设置后,等待一段时间(比较长),重新用新的地址访问 WebGUI 界面。

配置多网口

参考:How to set up a LAN Bridge - OPNsense Docs

将网线重新插回 enp6s0 对应网口,重新设置电脑地址,将 OPNsense 虚拟机关闭,并添加 enp2s0、enp3s0、enp4s0 网卡。重新启动虚拟机。

按上面的方法回到 OPNsense 的 WebGUI。在 Interfaces ‣ Assignments 把刚刚添加的所有端口都新建一遍,保存设置。再在 Interfaces ‣ [刚刚添加的各网口],把刚刚添加的网口都启用,并应用更改。

在 Interfaces ‣ Other Types ‣ Bridge 里,新建一个 br-LAN 网桥,然后把除最开始添加的 LAN 口外的其他网口全部添加进去。回到 Interface ‣ Assignments,把 LAN 口(即在标识名字后面是 lan 字样的)换到 br-LAN,保存并应用。此时将断开与 OPNsense 的连接,将电脑连接到其他的 LAN 口上可以重新连接。

连接成功后,按照以上的操作方式把最开始的网口添加进 br-LAN ,保存并测试是否可以访问 OPNsense WebGUI。

在 System ‣ Settings ‣ Tunables 里,将 net.link.bridge.pfil_member 改为 0,net.link.bridge.pfil_bridge改为 1,修改防火墙行为。

配置 pve 可从内网访问

没找到什么其他的好办法。

目前的解决方法是将 OPNsense 与 pve 的 IP 范围设置为同一个子网(比如 192.168.3.x/24),然后将 pve 的管理端口所在的网桥 vmbr0 添加进 OPNsense VM,在 OPNsense 中将该网口启用并加入到 br-LAN 中。因为 OPNSesne 的 DHCP 服务器默认从 192.168.3.10/24 开始分配 IP 地址,所以给予 pve 静态 IP 地址 192.168.3.2/24。这样就能从内网通过访问 https://192.168.3.2:8006 来访问 pve WebGUI 了。

当 OPNsense 挂了后,就可以连接管理端口,手动配置 IP 地址在同一子网,来应急连接。

配置 AP

在 Interfaces ‣ Wireless 里创建一个无线网卡的克隆后,再到 Interfaces ‣ Assignments 里添加无线网卡的网口,保存应用。

添加网口成功后,在对应网口设置里启用,并设置以下内容:

SettingValue
Standard802.11na
ModeAccess Point
SSIDWiFi名字
Allow intra-BSS communicationTrue
WPAEnable WPA
WPA Pre-Shared Key/EAP PasswordWiFi密码
WPA ModeWPA2
WPA Key Management ModePre-Shared Keys
WPA PairwiseAES

最后将该无线网口添加到 br-LAN 里就完成了。


配置透明代理

参考: 在opnsense中使用透明代理科学上网的一种方法 - OPNsense Forum

安装 Clash

首先开启 OPNsense 的 ssh 连接方式:在 System ‣ Settings ‣ Administration 里 Enable Secure Shell,并允许 root 登录与密码登录,保存并应用设置。

使用 ssh 登录 OPNsense,新建一个文件夹 /usr/local/clash,将 freebsd 版的二进制文件、配置文件、yacd面板文件都放进去。

使用 pw user add clash -c "Clash" -s /usr/sbin/nologin 创建一个无登录的账号,并给予文件所有者为刚刚创建的用户 clash:clash 。完成后就地运行一次进行初始化。

创建系统服务

新建文件 /usr/local/etc/rc.d/clash

#!/bin/sh
+# $FreeBSD$
+
+# PROVIDE: clash
+# REQUIRE: LOGIN cleanvar
+# KEYWORD: shutdown
+
+# Add the following lines to /etc/rc.conf to enable clash:
+# clash_enable (bool):  Set to "NO" by default.
+#      Set to "YES" to enable clash.
+# clash_config (path): Clash config dir.
+#      Defaults to "/usr/local/etc/clash"
+
+
+. /etc/rc.subr
+
+name="clash"
+rcvar=clash_enable
+
+
+load_rc_config $name
+
+: ${clash_enable:="NO"}
+: ${clash_config="/usr/local/clash"}
+
+command="/usr/local/clash/clash"
+#pidfile="/var/run/clash.pid"
+required_files="${clash_config}"
+clash_group="clash"
+clash_user="clash"
+
+command_args="-d $clash_config"
+
+run_rc_command "$1"
+

并给予运行权限 chmod +x /usr/local/etc/rc.d/clash

新建文件 /usr/local/opnsense/service/conf/actions.d/actions_clash.conf

[start]
+command:/usr/local/etc/rc.d/clash onestart
+type:script
+message:starting clash
+
+[stop]
+command:/usr/local/etc/rc.d/clash stop
+type:script
+message:stoping clash
+
+[status]
+command:/usr/local/etc/rc.d/clash statusexit 0
+type:script_output
+message:get clash status
+
+[restart]
+command:/usr/local/etc/rc.d/clash onerestart
+type:script
+message:restarting clash
+

并启用 service configd restart

最后,前往 Services ‣ Monit ‣ Settings 里启用 Monit,并在 Service Test Settings 里添加两个:

SettingValue
NameClash
Conditionfailed host 127.0.0.1 port 7890 type tcp
ActionRestart

第二个,避免重启死循环

SettingValue
NameRestartLimit4
Condition5 restarts within 5 cycles
ActionUnmonitor

在 Service Settings 里添加:

SettingValue
NameClash
Matchclash
Start/usr/local/sbin/configctl clash start
Stop/usr/local/sbin/configctl clash stop
TestsClash,RestartLimit4

最后等待一段时间,在 Monit ‣ Status 里查看是否运行。

配置透明代理

在 Services ‣ Web Proxy ‣ Administration 的 General Proxy Settings 里启用代理,在 Forward Proxy 里启用 Enable Transparent HTTP proxyEnable SSL inspectionLog SNI information only,并点击每一栏 (i) 按钮中提示文字的 Add a new firewall rule(注意!添加完 NAT 项目后记得应用!)。

再前往 System ‣ Trust ‣ Authorities 处新建一个证书,使用下面的设置:

SettingValue
Descriptive nameOPNsense-SSL
MethodCreate an internal Certificate Authority
Key length (bits)2048
Digest AlgorithmSHA256
Lifetime (days)356
Country CodeNL (Netherlands)
State or ProvinceZuid Holland
CityMiddelharnis
OrganizationOPNsense
Email Addressspam (at) opnsense.org
Common Nameopnsense-ssl-ca

创建证书完成后,回到 Services ‣ Web Proxy ‣ Administration 的 Forward Proxy 里的 CA to use 选择刚刚创建的证书。

设置完成后先不设置上游代理,随便访问一下网页,然后在 Web Proxy ‣ Access Log 里看有没有访问日志。(提醒一点:如果半天发现没有反应,可能是 NAT 创建了项目但是没有应用)

最后,设置上游代理。在 Web Proxy ‣ General Proxy Settings ‣ Parent Proxy Settings 里,启用,并设置为 127.0.0.1:7890

一个自动更新核心和配置文件的脚本

偷了一个小懒,请 ChatGPT (3.5) 帮我写了一个这个脚本 update.sh。只需要把这个脚本放置于任意位置,并配置好,就可以方便快捷更新核心和配置文件。

以下是这个脚本需要修改的地方:

  • current_directory 为需要执行更新的文件夹,如果按照之前步骤操作则该部分不需要改动;download_config_url则为配置文件的下载地址,按需求更新;
  • update_core_proxyupdate_config_proxy 分别是更新内核和配置时所用的 http/socks5 代理,为空则不使用;
  • download_ui_url 为下载 ui.zip 的链接,文件中的链接为 MetaCubeX/metacubexd 面板的下载链接。下载完成后需要自己解压 ui.zip 到相应目录。遵循 update_core_proxy 的设定;
  • 仓库信息部分分别为仓库拥有者 repo_owner,仓库名 repo_name,文件中提供的是 Clash.Meta 的 Stable 版;
  • repo_filename<version> 会替换为实时获取的最新版本。
#!/bin/sh
+
+# 设置当前工作目录的变量
+current_directory="/usr/local/clash"
+
+# 定义下载config.yaml的链接
+download_config_url="http://openmediavault:25500/getprofile?name=profiles/default.ini&token=xxx"
+
+# 定义下载ui.zip的链接
+download_ui_url="https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip"
+
+# 定义Clash core GitHub仓库信息
+repo_owner="MetaCubeX"
+repo_name="Clash.Meta"
+repo_filename="clash.meta-freebsd-amd64-<version>.gz"
+
+# 添加代理变量
+update_core_proxy="socks5://opnsense:7891"
+update_config_proxy=""
+
+# 定义当前所要执行的更新命令
+current_command=$1
+
+# 帮助文档函数
+print_help() {
+  echo "Usage: $0 [config|core|stop|help]"
+  echo "Commands:"
+  echo "  config   更新config.yaml文件"
+  echo "  core     下载最新的clash可执行文件并替换"
+  echo "  ui       下载最新的ui.zip文件"
+  echo "  stop     停止clash进程"
+  echo "  help     显示帮助文档"
+}
+
+# 备份并替换文件函数
+backup_file() {
+  if [ -f "$1" ]; then
+    mv -f "$1" "$1.bak"
+  fi
+}
+
+# 停止进程并设置权限
+stop_and_cleanup() {
+  echo "停止 Clash 进程:"
+  chown -R clash:clash $current_directory
+  /usr/local/sbin/configctl clash stop
+}
+
+# 定义信号处理函数
+interrupt_handler() {
+  echo "下载被中止。"
+
+  # 根据当前执行的命令来选择是否替换文件
+  if [ "$current_command" = "core" ]; then
+    # 如果是下载 core,还原备份的clash(如果存在)
+    if [ -f "$current_directory/clash.bak" ]; then
+      cp -f "$current_directory/clash.bak" "$current_directory/clash"
+      echo "已还原备份的Clash。"
+    fi
+  elif [ "$current_command" = "config" ]; then
+    # 如果是下载 config,还原备份的config.yaml.bak(如果存在)
+    if [ -f "$current_directory/config.yaml.bak" ]; then
+      cp -f "$current_directory/config.yaml.bak" "$current_directory/config.yaml"
+      echo "已还原备份的config.yaml.bak。"
+    fi
+  fi
+
+  stop_and_cleanup
+  exit 1
+}
+
+# 设置信号处理程序
+trap interrupt_handler SIGINT
+
+# 获取最新版本的clash可执行文件下载链接函数
+get_core_latest_version() {
+  local proxy_option="$1"  # 接受传入的core_proxy作为参数
+
+  # 获取最新发布版本信息
+  release_url="https://api.github.com/repos/$repo_owner/$repo_name/releases/latest"
+  latest_release_info=$(curl $proxy_option -s "$release_url")
+
+  # 从版本信息中提取最新版本号
+  latest_version=$(echo "$latest_release_info" | grep -oE '"tag_name": "[^"]+"' | head -n 1 | cut -d '"' -f 4)
+
+  # 返回最新版本号
+  echo "$latest_version"
+}
+
+# 处理config命令
+if [ "$current_command" = "config" ]; then
+  # 备份并覆盖config.yaml.bak
+  backup_file "$current_directory/config.yaml"
+
+  # 设置代理,如果有的话
+  config_proxy=""
+  [ -n "$update_config_proxy" ] && config_proxy="-x $update_config_proxy"
+
+  # 使用curl下载文件并重命名为config.yaml
+  curl $config_proxy -# -fSL -o "$current_directory/config.yaml" "$download_config_url"
+  download_result=$?  # 保存curl命令的退出码
+
+  # 检查下载是否成功
+  if [ $download_result -eq 0 ]; then
+    echo "config.yaml 更新成功!"
+  else
+    echo "下载失败。请检查URL是否正确或网络连接是否正常。"
+    # 如果下载失败,还原备份的config.yaml.bak(如果存在)
+    if [ -f "$current_directory/config.yaml.bak" ]; then
+      cp -f "$current_directory/config.yaml.bak" "$current_directory/config.yaml"
+      echo "已还原备份的config.yaml.bak。"
+    fi
+  fi
+  stop_and_cleanup
+
+# 处理core命令
+elif [ "$current_command" = "core" ]; then
+  # 备份并替换clash文件
+  backup_file "$current_directory/clash"
+
+  # 设置代理,如果有的话
+  core_proxy=""
+  [ -n "$update_core_proxy" ] && core_proxy="-x $update_core_proxy"
+
+  # 获取最新版本的clash可执行文件下载链接
+  latest_version=$(get_core_latest_version "$core_proxy")
+  # 更新 repo_filename,将 <version> 替换为实际的版本号
+  repo_filename=$(echo "$repo_filename" | sed "s/<version>/$latest_version/")
+  # 构建下载链接
+  download_core_url="https://github.com/$repo_owner/$repo_name/releases/download/$latest_version/$repo_filename"
+  echo "下载链接:$download_core_url"
+
+  # 下载最新的clash可执行文件并解压
+  curl $core_proxy -# -fSL "$download_core_url" | gunzip > "$current_directory/clash"
+  download_result=$?  # 保存curl命令的退出码
+  chmod +x "$current_directory/clash"
+
+  # 检查是否更新成功
+  if [ $download_result -eq 0 ]; then
+    echo "Clash core 更新成功!"
+    echo "最新版本:$latest_version"
+  else
+    echo "Clash 更新失败。"
+    # 如果更新失败,还原备份的clash(如果存在)
+    if [ -f "$current_directory/clash" ]; then
+      cp -f "$current_directory/clash.bak" "$current_directory/clash"
+      echo "已还原备份的clash。"
+    fi
+  fi
+  stop_and_cleanup
+
+# 处理ui命令
+elif [ "$current_command" = "ui" ]; then
+  # 备份并覆盖ui.zip.bak
+  backup_file "$current_directory/ui.zip"
+
+  # 设置代理,如果有的话
+  ui_proxy=""
+  [ -n "$update_core_proxy" ] && ui_proxy="-x $update_core_proxy"
+
+  # 使用curl下载ui.zip文件到当前目录
+  curl $ui_proxy -# -fSL -o "$current_directory/ui.zip" "$download_ui_url"
+  download_result=$?  # 保存curl命令的退出码
+
+  # 检查下载是否成功
+  if [ $download_result -eq 0 ]; then
+    echo "ui.zip 更新成功!请自行解压到指定文件夹中。"
+  else
+    echo "下载 ui.zip 失败。请检查URL是否正确或网络连接是否正常。"
+    [ -f "$current_directory/ui.zip" ] && rm "$current_directory/ui.zip"  # 如果下载失败并且文件存在,则删除它
+  fi  
+
+# 处理stop命令
+elif [ "$current_command" = "stop" ]; then
+  stop_and_cleanup
+
+# 处理help命令或未知命令
+else
+  print_help
+fi
+

(说实话在和 ChatGPT 协作这个脚本的时候,前期还没太复杂的情况下一切进展得非常顺利,也非常舒心。可等到需求越来越多,代码越来越复杂,ChatGPT 就开始犯各种各样的小问题,最后还是我自己完成了最后代码的修改和整合,可能是我用的模型不太强大吧,等一手某人让我白嫖一个 4.0 模型使用权(误))

设置网站绕过代理

有些服务很奇葩,即使在 Clash 规则里设置了直连,也不能用(说的就是你学习xx),估计是拥有某种方法检测透明代理。这里选择创建 NAT 规则将该域名绕过代理。

首先在 Firewall ‣ Aliases 里创建一个条目 NoRedirect1,类型选择 Hosts,内容为域名或 IP 地址,保存并应用。可以在 Firewall ‣ Diagnostics ‣ Aliases 里选择对应规则集查看域名是否成功解析为IP地址。

其次在 Firewall ‣ NAT 里,在透明代理那两个规则之前再创建一个规则:

SettingValue
No RDR (NOT)True
InterfaceLAN
ProtocolTCP/UDP
SourceLAN net
Source port rangeany to any
DestinationNoRedirect1
Destination port rangeany to any

设置仅指定设备通过代理

与上一步类似,在 Firewall ‣ Aliases 里创建一个条目 ProxyMAC1,类型选择 MAC address,内容为需要走代理设备的 MAC 地址(设备记得关闭随机 MAC 地址功能),保存并应用。

然后在前几步创建的两个 NAT 规则中,Source 条目从 LAN net 改为 ProxyMAC1,就可以保存应用了。


安装和设置 Ubuntu Server

没有什么特别的注意点,只是在新建虚拟机的时候选择 vmbr1 作为网络设备,就可以访问互联网。


设置安装有 OpenWRT 的路由器为纯 AP 模式

在 LuCI 的 Network ‣ Interfaces 里删除所有的 WAN 端口。

配置 LAN 端口:

General Settings:

SettingValue
ProtocolStatic address
Devicebr-lan
IPv4 address192.168.3.3/24
IPv4 gateway192.168.3.1

Advanced Settings:

SettingValue
Use custom DNS servers192.168.3.1
Delegate IPv6 prefixesFalse

Firewall Settings:

SettingValue
Create / Assign firewall-zoneunspecified

DHCP Server:

SettingValue
Ignore interfaceTrue

然后把从软路由出来的网线插进无线路由器的 LAN 口就行。

最后常规设置配置 WiFi 就完成了。

\ No newline at end of file diff --git a/article/setup-pve-with-opnsense-ubuntu-notes/network-topology.jpg b/article/setup-pve-with-opnsense-ubuntu-notes/network-topology.jpg new file mode 100644 index 00000000..a2485b76 Binary files /dev/null and b/article/setup-pve-with-opnsense-ubuntu-notes/network-topology.jpg differ diff --git a/author/index.html b/author/index.html new file mode 100644 index 00000000..360be8ef --- /dev/null +++ b/author/index.html @@ -0,0 +1,16 @@ +Author | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/author/index.xml b/author/index.xml new file mode 100644 index 00000000..fbe12457 --- /dev/null +++ b/author/index.xml @@ -0,0 +1 @@ +Author on Kreee's Bloghttps://blog.ohmykreee.top/author/Recent content in Author on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800Kreeehttps://blog.ohmykreee.top/author/kreee/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/author/kreee/ \ No newline at end of file diff --git a/author/kreee/index.html b/author/kreee/index.html new file mode 100644 index 00000000..0681456e --- /dev/null +++ b/author/kreee/index.html @@ -0,0 +1,57 @@ +Kreee | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 2.0.0 开发小记

2021-10-27 +Learning +Kreee

万恶之源

接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

项目地址: https://github.com/ohmykreee/wolf-bites-tweets

为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

  1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
  2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
继续阅读
较旧的帖子
\ No newline at end of file diff --git a/author/kreee/index.xml b/author/kreee/index.xml new file mode 100644 index 00000000..bbc770bc --- /dev/null +++ b/author/kreee/index.xml @@ -0,0 +1,25 @@ +Kreee on Kreee's Bloghttps://blog.ohmykreee.top/author/kreee/Recent content in Kreee on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p><link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item><item><title>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/author/kreee/page/1/index.html b/author/kreee/page/1/index.html new file mode 100644 index 00000000..f94389fe --- /dev/null +++ b/author/kreee/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/author/kreee/ + \ No newline at end of file diff --git a/author/kreee/page/2/index.html b/author/kreee/page/2/index.html new file mode 100644 index 00000000..2121df07 --- /dev/null +++ b/author/kreee/page/2/index.html @@ -0,0 +1,44 @@ +Kreee | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 GitHub Action 自动渲染和发布网页

2021-06-07 +Learning +Kreee

Why?

根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
So, let’s begin!

继续阅读

Docker 学习小记

2021-03-01 +Learning +Kreee

本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
Now, let’s begin!

继续阅读
较新的帖子
\ No newline at end of file diff --git a/avatar.jpg b/avatar.jpg new file mode 100644 index 00000000..af2a46be Binary files /dev/null and b/avatar.jpg differ diff --git a/browserconfig.xml b/browserconfig.xml new file mode 100644 index 00000000..b3930d0f --- /dev/null +++ b/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #da532c + + + diff --git a/categories/code/index.html b/categories/code/index.html new file mode 100644 index 00000000..8cc750a4 --- /dev/null +++ b/categories/code/index.html @@ -0,0 +1,21 @@ +Code | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/categories/code/index.xml b/categories/code/index.xml new file mode 100644 index 00000000..8e4eddcc --- /dev/null +++ b/categories/code/index.xml @@ -0,0 +1 @@ +Code on Kreee's Bloghttps://blog.ohmykreee.top/categories/code/Recent content in Code on Kreee's BlogHugo -- gohugo.iozh-cnSat, 26 Jun 2021 10:40:42 +0800模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p> \ No newline at end of file diff --git a/categories/code/page/1/index.html b/categories/code/page/1/index.html new file mode 100644 index 00000000..17b89a38 --- /dev/null +++ b/categories/code/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/categories/code/ + \ No newline at end of file diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 00000000..9fea1ee9 --- /dev/null +++ b/categories/index.html @@ -0,0 +1,16 @@ +Categories | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/categories/index.xml b/categories/index.xml new file mode 100644 index 00000000..732fcf77 --- /dev/null +++ b/categories/index.xml @@ -0,0 +1 @@ +Categories on Kreee's Bloghttps://blog.ohmykreee.top/categories/Recent content in Categories on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800Learninghttps://blog.ohmykreee.top/categories/learning/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/categories/learning/Codehttps://blog.ohmykreee.top/categories/code/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/categories/code/Musichttps://blog.ohmykreee.top/categories/music/Sun, 06 Jun 2021 16:58:19 +0800https://blog.ohmykreee.top/categories/music/Studyhttps://blog.ohmykreee.top/categories/study/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/categories/study/ \ No newline at end of file diff --git a/categories/learning/index.html b/categories/learning/index.html new file mode 100644 index 00000000..16a9c79e --- /dev/null +++ b/categories/learning/index.html @@ -0,0 +1,57 @@ +Learning | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 2.0.0 开发小记

2021-10-27 +Learning +Kreee

万恶之源

接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

项目地址: https://github.com/ohmykreee/wolf-bites-tweets

为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

  1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
  2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
继续阅读
较旧的帖子
\ No newline at end of file diff --git a/categories/learning/index.xml b/categories/learning/index.xml new file mode 100644 index 00000000..5ec7dd3a --- /dev/null +++ b/categories/learning/index.xml @@ -0,0 +1,23 @@ +Learning on Kreee's Bloghttps://blog.ohmykreee.top/categories/learning/Recent content in Learning on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/categories/learning/page/1/index.html b/categories/learning/page/1/index.html new file mode 100644 index 00000000..10023c73 --- /dev/null +++ b/categories/learning/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/categories/learning/ + \ No newline at end of file diff --git a/categories/learning/page/2/index.html b/categories/learning/page/2/index.html new file mode 100644 index 00000000..7450cff4 --- /dev/null +++ b/categories/learning/page/2/index.html @@ -0,0 +1,32 @@ +Learning | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 GitHub Action 自动渲染和发布网页

2021-06-07 +Learning +Kreee

Why?

根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
So, let’s begin!

继续阅读

Docker 学习小记

2021-03-01 +Learning +Kreee

本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
Now, let’s begin!

继续阅读
较新的帖子
\ No newline at end of file diff --git a/categories/music/index.html b/categories/music/index.html new file mode 100644 index 00000000..9dd4937d --- /dev/null +++ b/categories/music/index.html @@ -0,0 +1,19 @@ +Music | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/categories/music/index.xml b/categories/music/index.xml new file mode 100644 index 00000000..39da91bd --- /dev/null +++ b/categories/music/index.xml @@ -0,0 +1 @@ +Music on Kreee's Bloghttps://blog.ohmykreee.top/categories/music/Recent content in Music on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 16:58:19 +0800<link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item></channel></rss> \ No newline at end of file diff --git a/categories/music/page/1/index.html b/categories/music/page/1/index.html new file mode 100644 index 00000000..bf646eea --- /dev/null +++ b/categories/music/page/1/index.html @@ -0,0 +1,2 @@ +<!doctype html><html lang=zh-cn><head><title>https://blog.ohmykreee.top/categories/music/ + \ No newline at end of file diff --git a/categories/study/index.html b/categories/study/index.html new file mode 100644 index 00000000..8ccb3cf1 --- /dev/null +++ b/categories/study/index.html @@ -0,0 +1,20 @@ +Study | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/categories/study/index.xml b/categories/study/index.xml new file mode 100644 index 00000000..b174646a --- /dev/null +++ b/categories/study/index.xml @@ -0,0 +1,3 @@ +Study on Kreee's Bloghttps://blog.ohmykreee.top/categories/study/Recent content in Study on Kreee's BlogHugo -- gohugo.iozh-cnFri, 04 Jun 2021 14:24:37 +0800Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p> \ No newline at end of file diff --git a/categories/study/page/1/index.html b/categories/study/page/1/index.html new file mode 100644 index 00000000..2629bab0 --- /dev/null +++ b/categories/study/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/categories/study/ + \ No newline at end of file diff --git a/code/index.html b/code/index.html new file mode 100644 index 00000000..57fb3e70 --- /dev/null +++ b/code/index.html @@ -0,0 +1,21 @@ +Codes | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/code/index.xml b/code/index.xml new file mode 100644 index 00000000..2d3f691c --- /dev/null +++ b/code/index.xml @@ -0,0 +1 @@ +Codes on Kreee's Bloghttps://blog.ohmykreee.top/code/Recent content in Codes on Kreee's BlogHugo -- gohugo.iozh-cnSat, 26 Jun 2021 10:40:42 +0800模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p> \ No newline at end of file diff --git a/code/page/1/index.html b/code/page/1/index.html new file mode 100644 index 00000000..a7ed8794 --- /dev/null +++ b/code/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/code/ + \ No newline at end of file diff --git a/code/sim-keyboard-stroke/index.html b/code/sim-keyboard-stroke/index.html new file mode 100644 index 00000000..46f13a99 --- /dev/null +++ b/code/sim-keyboard-stroke/index.html @@ -0,0 +1,51 @@ +模拟键盘输入 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

模拟键盘输入

2021-06-26 +Code +Kreee

懂的都懂这是干啥用的。

requirements.txt

pynput==1.7.3
+six==1.16.0
+

大佬建议直接用 requirements.txt 安装依赖。

安装方法(建议使用Pycharm):
新建项目,将代码复制粘贴。
然后在下面的 Terminal 标签页里运行:

pip install pynput
+

话不多说,直接上代码:

import pynput
+import time
+
+# Setting are here:
+timeOfSleep = 5
+timeOfKeyStroke = 0.01
+
+f = open('input.txt', 'w+')
+f.close()
+input('Please edit the input.txt file. When ready, press ENTER...')
+
+inputFile = open('input.txt', 'r', encoding='utf-8')
+inputContents = inputFile.read()
+inputFile.close()
+simKeys = list(inputContents)
+
+print('Will execute key stroke after {} secs...'.format(timeOfSleep))
+time.sleep(timeOfSleep)
+ctr = pynput.keyboard.Controller()
+for i in simKeys:
+    ctr.press(i)
+    time.sleep(timeOfKeyStroke)
+    ctr.release(i)
+
+input('Finished!' + '\n' + 'Warning: text in input.txt will be deleted! Press ENTER to continue...')
+
+f = open('input.txt', 'r+')
+f.truncate()
+f.close()
+
\ No newline at end of file diff --git a/favicon-16x16.png b/favicon-16x16.png new file mode 100644 index 00000000..5d1de2d9 Binary files /dev/null and b/favicon-16x16.png differ diff --git a/favicon-32x32.png b/favicon-32x32.png new file mode 100644 index 00000000..96c62852 Binary files /dev/null and b/favicon-32x32.png differ diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 00000000..ac597b5d Binary files /dev/null and b/favicon.ico differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.eot b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.eot new file mode 100644 index 00000000..54ad8d72 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.eot differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.svg b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.svg new file mode 100644 index 00000000..2c8659c1 --- /dev/null +++ b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.svg @@ -0,0 +1,3637 @@ + + + + + +Created by FontForge 20200314 at Wed Jul 15 11:59:41 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf new file mode 100644 index 00000000..16852bfd Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.ttf differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff new file mode 100644 index 00000000..6cf6fb38 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2 b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2 new file mode 100644 index 00000000..f2a4e36f Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-brands-400.woff2 differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.eot b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.eot new file mode 100644 index 00000000..479b32ce Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.eot differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.svg b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.svg new file mode 100644 index 00000000..7947ca8f --- /dev/null +++ b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.svg @@ -0,0 +1,805 @@ + + + + + +Created by FontForge 20200314 at Wed Jul 15 11:59:40 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.ttf b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.ttf new file mode 100644 index 00000000..42a04fde Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.ttf differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff new file mode 100644 index 00000000..c390c60e Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2 b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2 new file mode 100644 index 00000000..11c71d28 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-regular-400.woff2 differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot new file mode 100644 index 00000000..52883b93 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.eot differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg new file mode 100644 index 00000000..d5e4d521 --- /dev/null +++ b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.svg @@ -0,0 +1,5015 @@ + + + + + +Created by FontForge 20200314 at Wed Jul 15 11:59:41 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf new file mode 100644 index 00000000..7c59512f Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.ttf differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff new file mode 100644 index 00000000..aff125d6 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff differ diff --git a/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2 b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2 new file mode 100644 index 00000000..aa2b7910 Binary files /dev/null and b/fonts/_vendor/@fortawesome/fontawesome-free/webfa-solid-900.woff2 differ diff --git a/fonts/_vendor/flexslider/flexslider-icon.eot b/fonts/_vendor/flexslider/flexslider-icon.eot new file mode 100644 index 00000000..97c4196f Binary files /dev/null and b/fonts/_vendor/flexslider/flexslider-icon.eot differ diff --git a/fonts/_vendor/flexslider/flexslider-icon.svg b/fonts/_vendor/flexslider/flexslider-icon.svg new file mode 100644 index 00000000..89fd1ab8 --- /dev/null +++ b/fonts/_vendor/flexslider/flexslider-icon.svg @@ -0,0 +1,19 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/fonts/_vendor/flexslider/flexslider-icon.ttf b/fonts/_vendor/flexslider/flexslider-icon.ttf new file mode 100644 index 00000000..05432986 Binary files /dev/null and b/fonts/_vendor/flexslider/flexslider-icon.ttf differ diff --git a/fonts/_vendor/flexslider/flexslider-icon.woff b/fonts/_vendor/flexslider/flexslider-icon.woff new file mode 100644 index 00000000..10c4eeb8 Binary files /dev/null and b/fonts/_vendor/flexslider/flexslider-icon.woff differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.eot b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.eot new file mode 100644 index 00000000..3f99e784 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.eot differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.svg b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.svg new file mode 100644 index 00000000..817a6380 --- /dev/null +++ b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.svg @@ -0,0 +1,445 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.ttf b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.ttf new file mode 100644 index 00000000..35a71114 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.ttf differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff new file mode 100644 index 00000000..a601c985 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff2 b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff2 new file mode 100644 index 00000000..6f3dec69 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-700.woff2 differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.eot b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.eot new file mode 100644 index 00000000..08070f32 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.eot differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.svg b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.svg new file mode 100644 index 00000000..825357ee --- /dev/null +++ b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.svg @@ -0,0 +1,444 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.ttf b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.ttf new file mode 100644 index 00000000..650d53b5 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.ttf differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff new file mode 100644 index 00000000..f2340b43 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff differ diff --git a/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff2 b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff2 new file mode 100644 index 00000000..d724f5b7 Binary files /dev/null and b/fonts/comfortaa-v28-greek_latin-ext_vietnamese_cyrillic-ext-regular.woff2 differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.eot b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.eot new file mode 100644 index 00000000..12164861 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.eot differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.svg b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.svg new file mode 100644 index 00000000..e184d096 --- /dev/null +++ b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.svg @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.ttf b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.ttf new file mode 100644 index 00000000..87bf28e2 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.ttf differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff new file mode 100644 index 00000000..4676556c Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff2 b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff2 new file mode 100644 index 00000000..c6145ff1 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-700.woff2 differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.eot b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.eot new file mode 100644 index 00000000..4b1cc7db Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.eot differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.svg b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.svg new file mode 100644 index 00000000..fb09045e --- /dev/null +++ b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.svg @@ -0,0 +1,342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.ttf b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.ttf new file mode 100644 index 00000000..a92993a5 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.ttf differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff new file mode 100644 index 00000000..63de3d34 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff differ diff --git a/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff2 b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff2 new file mode 100644 index 00000000..8611a6a7 Binary files /dev/null and b/fonts/fira-code-v8-latin-ext_cyrillic-ext_greek-ext-regular.woff2 differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.eot b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.eot new file mode 100644 index 00000000..c21c2006 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.eot differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.svg b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.svg new file mode 100644 index 00000000..8e6b61ad --- /dev/null +++ b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.svg @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.ttf b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.ttf new file mode 100644 index 00000000..a0864672 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.ttf differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff new file mode 100644 index 00000000..18788e84 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff2 b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff2 new file mode 100644 index 00000000..421a1ab2 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700.woff2 differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.eot b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.eot new file mode 100644 index 00000000..381bece6 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.eot differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.svg b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.svg new file mode 100644 index 00000000..80b56353 --- /dev/null +++ b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.svg @@ -0,0 +1,342 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.ttf b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.ttf new file mode 100644 index 00000000..9904ea99 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.ttf differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff new file mode 100644 index 00000000..f5f7974e Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff2 b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff2 new file mode 100644 index 00000000..12ce3d20 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-700italic.woff2 differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.eot b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.eot new file mode 100644 index 00000000..c6ee21fb Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.eot differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.svg b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.svg new file mode 100644 index 00000000..e6a951f4 --- /dev/null +++ b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.svg @@ -0,0 +1,349 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.ttf b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.ttf new file mode 100644 index 00000000..2d9c801d Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.ttf differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff new file mode 100644 index 00000000..34f3eae8 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff2 b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff2 new file mode 100644 index 00000000..398b68a0 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-italic.woff2 differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.eot b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.eot new file mode 100644 index 00000000..db9210be Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.eot differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.svg b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.svg new file mode 100644 index 00000000..78eb653a --- /dev/null +++ b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.svg @@ -0,0 +1,336 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.ttf b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.ttf new file mode 100644 index 00000000..be29eca2 Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.ttf differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff new file mode 100644 index 00000000..799305af Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff differ diff --git a/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff2 b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff2 new file mode 100644 index 00000000..8383e94c Binary files /dev/null and b/fonts/open-sans-v17-latin-ext_vietnamese_cyrillic-ext_greek-ext-regular.woff2 differ diff --git a/google7810b4f3823815e3.html b/google7810b4f3823815e3.html new file mode 100644 index 00000000..49e5c763 --- /dev/null +++ b/google7810b4f3823815e3.html @@ -0,0 +1 @@ +google-site-verification: google7810b4f3823815e3.html \ No newline at end of file diff --git a/index.html b/index.html new file mode 100644 index 00000000..d165df1f --- /dev/null +++ b/index.html @@ -0,0 +1,60 @@ +Code with love ❤ and paws 🐾! | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

wolf-bites-tweets 2.0.0 开发小记

2021-10-27 +Learning +Kreee

万恶之源

接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

项目地址: https://github.com/ohmykreee/wolf-bites-tweets

为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

  1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
  2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
继续阅读
\ No newline at end of file diff --git a/index.json b/index.json new file mode 100644 index 00000000..1a7cdd81 --- /dev/null +++ b/index.json @@ -0,0 +1 @@ +[{"iconClass":"fa-folder","objectID":"https://blog.ohmykreee.top/categories/code","title":"Code","type":"category","url":"https://blog.ohmykreee.top/categories/code"},{"iconClass":"fa-folder","objectID":"https://blog.ohmykreee.top/categories/learning","title":"Learning","type":"category","url":"https://blog.ohmykreee.top/categories/learning"},{"iconClass":"fa-folder","objectID":"https://blog.ohmykreee.top/categories/music","title":"Music","type":"category","url":"https://blog.ohmykreee.top/categories/music"},{"iconClass":"fa-folder","objectID":"https://blog.ohmykreee.top/categories/study","title":"Study","type":"category","url":"https://blog.ohmykreee.top/categories/study"},{"iconClass":"fa-user","objectID":"https://blog.ohmykreee.top/author/kreee","title":"Kreee","type":"author","url":"https://blog.ohmykreee.top/author/kreee"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/2021","title":"2021st","type":"tag","url":"https://blog.ohmykreee.top/tags/2021"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/2022","title":"2022nd","type":"tag","url":"https://blog.ohmykreee.top/tags/2022"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/backend","title":"Backend","type":"tag","url":"https://blog.ohmykreee.top/tags/backend"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/code-server","title":"Code server","type":"tag","url":"https://blog.ohmykreee.top/tags/code-server"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/code-sharing","title":"Code sharing","type":"tag","url":"https://blog.ohmykreee.top/tags/code-sharing"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/favorite","title":"Favorite","type":"tag","url":"https://blog.ohmykreee.top/tags/favorite"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/frontend","title":"Frontend","type":"tag","url":"https://blog.ohmykreee.top/tags/frontend"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/github","title":"Github","type":"tag","url":"https://blog.ohmykreee.top/tags/github"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/hugo","title":"Hugo","type":"tag","url":"https://blog.ohmykreee.top/tags/hugo"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/javascript","title":"Javascript","type":"tag","url":"https://blog.ohmykreee.top/tags/javascript"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/learning","title":"Learning","type":"tag","url":"https://blog.ohmykreee.top/tags/learning"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/life","title":"Life","type":"tag","url":"https://blog.ohmykreee.top/tags/life"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/music","title":"Music","type":"tag","url":"https://blog.ohmykreee.top/tags/music"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/next.js","title":"Next.js","type":"tag","url":"https://blog.ohmykreee.top/tags/next.js"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/python","title":"Python","type":"tag","url":"https://blog.ohmykreee.top/tags/python"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/react","title":"React","type":"tag","url":"https://blog.ohmykreee.top/tags/react"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/selfhosted","title":"Selfhosted","type":"tag","url":"https://blog.ohmykreee.top/tags/selfhosted"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/study","title":"Study","type":"tag","url":"https://blog.ohmykreee.top/tags/study"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/termux","title":"Termux","type":"tag","url":"https://blog.ohmykreee.top/tags/termux"},{"iconClass":"fa-tag","objectID":"https://blog.ohmykreee.top/tags/vscode","title":"Vscode","type":"tag","url":"https://blog.ohmykreee.top/tags/vscode"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"a0b69e1a94d9be2b291c2e6be3b8b1be","tags":["Selfhosted","Learning","2022"],"title":"PVE、OPNsense、Ubuntu Server设置小记","type":"article","url":"https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"349d6da16b274ea313ed5c9448b13702","tags":["Termux","Frontend","Learning","VSCode","code-server","2021"],"title":"使用 Android Pad 进行(前端)开发","type":"article","url":"https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"a1f7662143df123db1760107a228ca72","tags":["JavaScript","Frontend","GitHub","Learning","React","Next.js","2021"],"title":"关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项","type":"article","url":"https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"2eb1f5a7a7c1a3b1f5594f55eb5273c3","tags":["JavaScript","Backend","GitHub","Learning","2021"],"title":"wolf-bites-tweets 2.0.0 开发小记","type":"article","url":"https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"9f9777e44365178b9eeec5c435ea68b6","tags":["Python","JavaScript","Frontend","GitHub","Learning","2021"],"title":"wolf-bites-tweets 和 wolf-chews-tweets 开发小记","type":"article","url":"https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"e6dbace253adb3373354a78ad1a29e68","tags":["Selfhosted","Learning","2021"],"title":"将后端服务器系统迁移至 Ubuntu server","type":"article","url":"https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/"},{"author":"Kreee","categories":["Code"],"iconClass":"fa-code","language":"zh-cn","objectID":"db358e2ac81b37a7b10f32b34f42937f","tags":["Python","Study","Code Sharing","2021"],"title":"模拟键盘输入","type":"code","url":"https://blog.ohmykreee.top/code/sim-keyboard-stroke/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"a51d96f533a686cda290d193ba1c0bc6","tags":["Hugo","Selfhosted","Learning","2021"],"title":"在 Hugo 里内嵌音乐播放器(APlayer)","type":"article","url":"https://blog.ohmykreee.top/article/music-player-in-hugo-page/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"8d5931b6c1a0e7144fc479b8eca4015e","tags":["GitHub","Learning","2021"],"title":"使用 GitHub Action 自动渲染和发布网页","type":"article","url":"https://blog.ohmykreee.top/article/github-action-auto-pub-site/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"ee654f8dbe96735e9203d36c59a4552e","tags":["Selfhosted","Learning","2021"],"title":"自用备忘录表","type":"article","url":"https://blog.ohmykreee.top/article/self-use-cheatsheet/"},{"author":"Kreee","categories":["Study"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"edf5c1ff99971349fcef8966b2b45baa","tags":["Python","Study","2021"],"title":"Python 期末编程题题库","type":"article","url":"https://blog.ohmykreee.top/article/python-final-exam-questions/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"74b99ea3be2fe586da507f166e68478a","tags":["Selfhosted","Learning","2021"],"title":"Docker 学习小记","type":"article","url":"https://blog.ohmykreee.top/article/docker-notes/"},{"author":"Kreee","categories":["Learning"],"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"021615f12fbb1a01f12fd34671e19134","tags":["Selfhosted","Learning","2021"],"title":"Notes for Setting Up Back-end Server","type":"article","url":"https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/"},{"author":null,"categories":null,"iconClass":"fa-pencil-alt","language":"zh-cn","objectID":"3dd84c6f01eac77339eb33e764e000a5","tags":null,"title":"文章列表","type":"archive","url":"https://blog.ohmykreee.top/archive/"}] \ No newline at end of file diff --git a/index.xml b/index.xml new file mode 100644 index 00000000..2d77d5b5 --- /dev/null +++ b/index.xml @@ -0,0 +1,25 @@ +Kreee's Bloghttps://blog.ohmykreee.top/Recent content on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p><link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item><item><title/><link>https://blog.ohmykreee.top/status/ready-to-go/</link><pubDate>Sat, 05 Jun 2021 22:36:46 +0800</pubDate><guid>https://blog.ohmykreee.top/status/ready-to-go/</guid><description>决定建立一个独立的个人博客,撒花🎉🎉</description></item><item><title>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/js/clarity-tracker.js b/js/clarity-tracker.js new file mode 100644 index 00000000..c2596269 --- /dev/null +++ b/js/clarity-tracker.js @@ -0,0 +1,5 @@ +(function(c,l,a,r,i,t,y){ + c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)}; + t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i; + y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y); +})(window, document, "clarity", "script", "71ylksj5qp"); \ No newline at end of file diff --git a/js/init-cookieconsent.js b/js/init-cookieconsent.js new file mode 100644 index 00000000..a15d7b64 --- /dev/null +++ b/js/init-cookieconsent.js @@ -0,0 +1,17 @@ +window.cookieconsent.initialise({ + "palette": { + "popup": { + "background": "#2d3642" + }, + "button": { + "background": "#444984" + } + }, + "theme": "edgeless", + "position": "bottom-right", + "content": { + "message": "该网站储存诸如cookie之类的数据,以启用基本的网站功能以及个性化和分析功能。", + "dismiss": "明白", + "link": "了解更多" + } +}); \ No newline at end of file diff --git a/js/init-sakana.js b/js/init-sakana.js new file mode 100644 index 00000000..b7404470 --- /dev/null +++ b/js/init-sakana.js @@ -0,0 +1,27 @@ +var loadSakanaWidget = () => { + import('/js/sakana-widget/sakana.min.js') + .then(() => { + const sakanaDiv = document.createElement('div') + sakanaDiv.setAttribute('id', 'sakana-widget') + sakanaDiv.style.cssText = 'position:fixed;bottom:5px;left:0;z-index:10;' + document.body.insertBefore(sakanaDiv, document.body.firstChild) + const SakanaWidgetClass = new SakanaWidget() + SakanaWidgetClass.mount('#sakana-widget') + addEventListener('unload', () => { + SakanaWidgetClass.unmount() + }) + }) +} + +if (window.matchMedia("(min-width: 800px)").matches) { + loadSakanaWidget() +} else { + if (document.getElementById('ifLoadSakana')) { + const loaderDiv = document.getElementById('ifLoadSakana') + const loaderA = document.createElement('a') + loaderA.innerHTML = '点此加载左下角的小组件...' + loaderA.setAttribute('href','#') + loaderA.setAttribute('onclick', `loadSakanaWidget();document.getElementById('ifLoadSakana').remove();return false;`) + loaderDiv.appendChild(loaderA) + } +} \ No newline at end of file diff --git a/js/sakana-widget/characters/index.d.ts b/js/sakana-widget/characters/index.d.ts new file mode 100644 index 00000000..d872877b --- /dev/null +++ b/js/sakana-widget/characters/index.d.ts @@ -0,0 +1,39 @@ +export interface SakanaWidgetState { + /** + * inertia + */ + i: number; + /** + * stickiness + */ + s: number; + /** + * decay + */ + d: number; + /** + * angle + */ + r: number; + /** + * height + */ + y: number; + /** + * vertical speed + */ + t: number; + /** + * horizontal speed + */ + w: number; +} +export interface SakanaWidgetCharacter { + image: string; + initialState: SakanaWidgetState; +} +declare const _default: { + chisato: SakanaWidgetCharacter; + takina: SakanaWidgetCharacter; +}; +export default _default; diff --git a/js/sakana-widget/icons/index.d.ts b/js/sakana-widget/icons/index.d.ts new file mode 100644 index 00000000..2fdc96a2 --- /dev/null +++ b/js/sakana-widget/icons/index.d.ts @@ -0,0 +1,4 @@ +export { default as svgClose } from './close.svg'; +export { default as svgGitHub } from './github.svg'; +export { default as svgPerson } from './person.svg'; +export { default as svgSync } from './sync.svg'; diff --git a/js/sakana-widget/index.d.ts b/js/sakana-widget/index.d.ts new file mode 100644 index 00000000..8449253d --- /dev/null +++ b/js/sakana-widget/index.d.ts @@ -0,0 +1,171 @@ +/*! sakana-widget | DSRKafuU (https://dsrkafuu.net) | Copyright (c) MIT License */ +import './index.scss'; +import type { SakanaWidgetCharacter, SakanaWidgetState } from './characters'; +interface SakanaWidgetOptions { + /** + * widget size, default to `200` + */ + size?: number; + /** + * auto fit size (120px minimum), default to `false` + */ + autoFit?: boolean; + /** + * default character, default to `chisato` + */ + character?: 'chisato' | 'takina' | string; + /** + * controls bar, default to `true` + */ + controls?: boolean; + /** + * canvas stroke settings, default to `#b4b4b4` & `10` + */ + stroke?: { + color?: string; + width?: number; + }; + /** + * motion stop threshold, default to `0.1` + */ + threshold?: number; + /** + * rotate origin, default to `0` + */ + rotate?: number; +} +/** + * widget instance class + */ +declare class SakanaWidget { + private _options; + private _imageSize; + private _canvasSize; + private _limit; + private _lastRunUnix; + private _frameUnix; + private _running; + private _magicForceTimeout; + private _magicForceEnabled; + private _char; + private _image; + private _state; + private _domWrapper; + private _domApp; + private _domCanvas; + private _domCanvasCtx; + private _domMain; + private _domImage; + private _domCtrlPerson; + private _domCtrlMagic; + private _domCtrlClose; + private _resizeObserver; + /** + * @public + * @static + * get data of a registered character + */ + static getCharacter: (name: string) => SakanaWidgetCharacter | null; + /** + * @public + * @static + * get all registered character + */ + static getCharacters: () => { + [key: string]: SakanaWidgetCharacter; + }; + /** + * @public + * @static + * registered a new character + */ + static registerCharacter: (name: string, character: SakanaWidgetCharacter) => void; + constructor(options?: SakanaWidgetOptions); + /** + * @private + * calculate limit and update from size + */ + private _updateLimit; + /** + * @private + * refresh widget size + */ + private _updateSize; + /** + * @private + * create widget dom elements + */ + private _updateDom; + /** + * @private + * calculate center of the image + */ + private _calcCenterPoint; + /** + * @private + * draw a frame + */ + private _draw; + /** + * @private + * run the widget in animation frame + */ + private _run; + /** + * @private + * manually move the widget + */ + private _move; + /** + * @private + * handle mouse down event + */ + private _onMouseDown; + /** + * @private + * handle touch start event + */ + private _onTouchStart; + /** + * @private + * do a force on widget (for auto mode) + */ + private _magicForce; + /** + * @public + * switch the auto mode + */ + triggetAutoMode: () => void; + /** + * @public + * set current state of widget + */ + setState: (state: Partial) => this; + /** + * @public + * set current character of widget + */ + setCharacter: (name: string) => this; + /** + * @public + * set to next character of widget + */ + nextCharacter: () => this; + /** + * @private + * handle widget resize + */ + _onResize: (rect: DOMRect) => void; + /** + * @public + * mount the widget + */ + mount: (el: HTMLElement | string) => this; + /** + * @public + * unmount the widget + */ + unmount: () => this; +} +export default SakanaWidget; +export type { SakanaWidgetCharacter, SakanaWidgetState, SakanaWidgetOptions }; diff --git a/js/sakana-widget/index.esm.js b/js/sakana-widget/index.esm.js new file mode 100644 index 00000000..ef29c87d --- /dev/null +++ b/js/sakana-widget/index.esm.js @@ -0,0 +1,1651 @@ +/******/ var __webpack_modules__ = ({ + +/***/ 800: +/***/ ((module, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Z": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(918); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(267); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); +// Imports + + +var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); +// Module +___CSS_LOADER_EXPORT___.push([module.id, ".sakana-widget *,.sakana-widget *::before,.sakana-widget *::after{box-sizing:border-box}.sakana-widget-wrapper{pointer-events:none;position:relative;width:100%;height:100%}.sakana-widget-app{pointer-events:none;position:relative}.sakana-widget-canvas{z-index:10;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.sakana-widget-main{z-index:20;pointer-events:none;position:absolute;display:flex;flex-direction:column;justify-content:space-between;align-items:center}.sakana-widget-img{z-index:40;cursor:move;pointer-events:auto;position:relative;background:no-repeat 50% 50%;background-size:cover}.sakana-widget-ctrl{z-index:30;cursor:pointer;pointer-events:auto;position:relative;height:24px;width:112px;display:flex;border-radius:4px;background-color:#ddd;box-shadow:0 8px 24px rgba(0,0,0,.1)}.sakana-widget-ctrl-item{height:24px;width:28px;display:flex;justify-content:center;align-items:center;color:#555;background-color:rgba(0,0,0,0)}.sakana-widget-ctrl-item:hover{color:#555;background-color:rgba(255,255,255,.25)}.sakana-widget-icon{height:18px;width:18px}.sakana-widget-icon--rotate{animation:sakana-widget-spin 2s linear infinite}@keyframes sakana-widget-spin{100%{transform:rotate(360deg)}}", ""]); +// Exports +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); + + +/***/ }), + +/***/ 267: +/***/ ((module) => { + + +module.exports = function(cssWithMappingToString) { + var list = []; + list.toString = function toString() { + return this.map(function(item) { + var content = ""; + var needLayer = typeof item[5] !== "undefined"; + if (item[4]) { + content += "@supports (".concat(item[4], ") {"); + } + if (item[2]) { + content += "@media ".concat(item[2], " {"); + } + if (needLayer) { + content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {"); + } + content += cssWithMappingToString(item); + if (needLayer) { + content += "}"; + } + if (item[2]) { + content += "}"; + } + if (item[4]) { + content += "}"; + } + return content; + }).join(""); + }; + list.i = function i(modules, media, dedupe, supports, layer) { + if (typeof modules === "string") { + modules = [[null, modules, void 0]]; + } + var alreadyImportedModules = {}; + if (dedupe) { + for (var k = 0; k < this.length; k++) { + var id = this[k][0]; + if (id != null) { + alreadyImportedModules[id] = true; + } + } + } + for (var _k = 0; _k < modules.length; _k++) { + var item = [].concat(modules[_k]); + if (dedupe && alreadyImportedModules[item[0]]) { + continue; + } + if (typeof layer !== "undefined") { + if (typeof item[5] === "undefined") { + item[5] = layer; + } else { + item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}"); + item[5] = layer; + } + } + if (media) { + if (!item[2]) { + item[2] = media; + } else { + item[1] = "@media ".concat(item[2], " {").concat(item[1], "}"); + item[2] = media; + } + } + if (supports) { + if (!item[4]) { + item[4] = "".concat(supports); + } else { + item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}"); + item[4] = supports; + } + } + list.push(item); + } + }; + return list; +}; + + +/***/ }), + +/***/ 918: +/***/ ((module) => { + + +module.exports = function(i) { + return i[1]; +}; + + +/***/ }), + +/***/ 379: +/***/ ((module) => { + + + +var stylesInDOM = []; + +function getIndexByIdentifier(identifier) { + var result = -1; + + for (var i = 0; i < stylesInDOM.length; i++) { + if (stylesInDOM[i].identifier === identifier) { + result = i; + break; + } + } + + return result; +} + +function modulesToDom(list, options) { + var idCountMap = {}; + var identifiers = []; + + for (var i = 0; i < list.length; i++) { + var item = list[i]; + var id = options.base ? item[0] + options.base : item[0]; + var count = idCountMap[id] || 0; + var identifier = "".concat(id, " ").concat(count); + idCountMap[id] = count + 1; + var indexByIdentifier = getIndexByIdentifier(identifier); + var obj = { + css: item[1], + media: item[2], + sourceMap: item[3], + supports: item[4], + layer: item[5] + }; + + if (indexByIdentifier !== -1) { + stylesInDOM[indexByIdentifier].references++; + stylesInDOM[indexByIdentifier].updater(obj); + } else { + var updater = addElementStyle(obj, options); + options.byIndex = i; + stylesInDOM.splice(i, 0, { + identifier: identifier, + updater: updater, + references: 1 + }); + } + + identifiers.push(identifier); + } + + return identifiers; +} + +function addElementStyle(obj, options) { + var api = options.domAPI(options); + api.update(obj); + + var updater = function updater(newObj) { + if (newObj) { + if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) { + return; + } + + api.update(obj = newObj); + } else { + api.remove(); + } + }; + + return updater; +} + +module.exports = function (list, options) { + options = options || {}; + list = list || []; + var lastIdentifiers = modulesToDom(list, options); + return function update(newList) { + newList = newList || []; + + for (var i = 0; i < lastIdentifiers.length; i++) { + var identifier = lastIdentifiers[i]; + var index = getIndexByIdentifier(identifier); + stylesInDOM[index].references--; + } + + var newLastIdentifiers = modulesToDom(newList, options); + + for (var _i = 0; _i < lastIdentifiers.length; _i++) { + var _identifier = lastIdentifiers[_i]; + + var _index = getIndexByIdentifier(_identifier); + + if (stylesInDOM[_index].references === 0) { + stylesInDOM[_index].updater(); + + stylesInDOM.splice(_index, 1); + } + } + + lastIdentifiers = newLastIdentifiers; + }; +}; + +/***/ }), + +/***/ 569: +/***/ ((module) => { + + + +var memo = {}; +/* istanbul ignore next */ + +function getTarget(target) { + if (typeof memo[target] === "undefined") { + var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself + + if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { + try { + // This will throw an exception if access to iframe is blocked + // due to cross-origin restrictions + styleTarget = styleTarget.contentDocument.head; + } catch (e) { + // istanbul ignore next + styleTarget = null; + } + } + + memo[target] = styleTarget; + } + + return memo[target]; +} +/* istanbul ignore next */ + + +function insertBySelector(insert, style) { + var target = getTarget(insert); + + if (!target) { + throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid."); + } + + target.appendChild(style); +} + +module.exports = insertBySelector; + +/***/ }), + +/***/ 216: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function insertStyleElement(options) { + var element = document.createElement("style"); + options.setAttributes(element, options.attributes); + options.insert(element, options.options); + return element; +} + +module.exports = insertStyleElement; + +/***/ }), + +/***/ 565: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + + + +/* istanbul ignore next */ +function setAttributesWithoutAttributes(styleElement) { + var nonce = true ? __webpack_require__.nc : 0; + + if (nonce) { + styleElement.setAttribute("nonce", nonce); + } +} + +module.exports = setAttributesWithoutAttributes; + +/***/ }), + +/***/ 795: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function apply(styleElement, options, obj) { + var css = ""; + + if (obj.supports) { + css += "@supports (".concat(obj.supports, ") {"); + } + + if (obj.media) { + css += "@media ".concat(obj.media, " {"); + } + + var needLayer = typeof obj.layer !== "undefined"; + + if (needLayer) { + css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {"); + } + + css += obj.css; + + if (needLayer) { + css += "}"; + } + + if (obj.media) { + css += "}"; + } + + if (obj.supports) { + css += "}"; + } + + var sourceMap = obj.sourceMap; + + if (sourceMap && typeof btoa !== "undefined") { + css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */"); + } // For old IE + + /* istanbul ignore if */ + + + options.styleTagTransform(css, styleElement, options.options); +} + +function removeStyleElement(styleElement) { + // istanbul ignore if + if (styleElement.parentNode === null) { + return false; + } + + styleElement.parentNode.removeChild(styleElement); +} +/* istanbul ignore next */ + + +function domAPI(options) { + var styleElement = options.insertStyleElement(options); + return { + update: function update(obj) { + apply(styleElement, options, obj); + }, + remove: function remove() { + removeStyleElement(styleElement); + } + }; +} + +module.exports = domAPI; + +/***/ }), + +/***/ 589: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function styleTagTransform(css, styleElement) { + if (styleElement.styleSheet) { + styleElement.styleSheet.cssText = css; + } else { + while (styleElement.firstChild) { + styleElement.removeChild(styleElement.firstChild); + } + + styleElement.appendChild(document.createTextNode(css)); + } +} + +module.exports = styleTagTransform; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ id: moduleId, +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/nonce */ +/******/ (() => { +/******/ __webpack_require__.nc = undefined; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "Z": () => (/* binding */ src_0) +}); + +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js +var injectStylesIntoStyleTag = __webpack_require__(379); +var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleDomAPI.js +var styleDomAPI = __webpack_require__(795); +var styleDomAPI_default = /*#__PURE__*/__webpack_require__.n(styleDomAPI); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertBySelector.js +var insertBySelector = __webpack_require__(569); +var insertBySelector_default = /*#__PURE__*/__webpack_require__.n(insertBySelector); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js +var setAttributesWithoutAttributes = __webpack_require__(565); +var setAttributesWithoutAttributes_default = /*#__PURE__*/__webpack_require__.n(setAttributesWithoutAttributes); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertStyleElement.js +var insertStyleElement = __webpack_require__(216); +var insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(insertStyleElement); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleTagTransform.js +var styleTagTransform = __webpack_require__(589); +var styleTagTransform_default = /*#__PURE__*/__webpack_require__.n(styleTagTransform); +// EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/index.scss +var cjs_js_src = __webpack_require__(800); +;// CONCATENATED MODULE: ./src/index.scss + + + + + + + + + + + +var options = {}; + +options.styleTagTransform = (styleTagTransform_default()); +options.setAttributes = (setAttributesWithoutAttributes_default()); + + options.insert = insertBySelector_default().bind(null, "head"); + +options.domAPI = (styleDomAPI_default()); +options.insertStyleElement = (insertStyleElement_default()); + +var update = injectStylesIntoStyleTag_default()(cjs_js_src/* default */.Z, options); + + + + + /* harmony default export */ const src = (cjs_js_src/* default */.Z && cjs_js_src/* default.locals */.Z.locals ? cjs_js_src/* default.locals */.Z.locals : undefined); + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/resizeObservers.js +var resizeObservers = []; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/hasActiveObservations.js + +var hasActiveObservations = function() { + return resizeObservers.some(function(ro) { + return ro.activeTargets.length > 0; + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/hasSkippedObservations.js + +var hasSkippedObservations = function() { + return resizeObservers.some(function(ro) { + return ro.skippedTargets.length > 0; + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/deliverResizeLoopError.js +var msg = "ResizeObserver loop completed with undelivered notifications."; +var deliverResizeLoopError = function() { + var event; + if (typeof ErrorEvent === "function") { + event = new ErrorEvent("error", { + message: msg + }); + } else { + event = document.createEvent("Event"); + event.initEvent("error", false, false); + event.message = msg; + } + window.dispatchEvent(event); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverBoxOptions.js +var ResizeObserverBoxOptions; +(function(ResizeObserverBoxOptions2) { + ResizeObserverBoxOptions2["BORDER_BOX"] = "border-box"; + ResizeObserverBoxOptions2["CONTENT_BOX"] = "content-box"; + ResizeObserverBoxOptions2["DEVICE_PIXEL_CONTENT_BOX"] = "device-pixel-content-box"; +})(ResizeObserverBoxOptions || (ResizeObserverBoxOptions = {})); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/freeze.js +var freeze = function(obj) { + return Object.freeze(obj); +}; + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverSize.js + +var ResizeObserverSize = function() { + function ResizeObserverSize2(inlineSize, blockSize) { + this.inlineSize = inlineSize; + this.blockSize = blockSize; + freeze(this); + } + return ResizeObserverSize2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/DOMRectReadOnly.js + +var DOMRectReadOnly = function() { + function DOMRectReadOnly2(x, y, width, height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.top = this.y; + this.left = this.x; + this.bottom = this.top + this.height; + this.right = this.left + this.width; + return freeze(this); + } + DOMRectReadOnly2.prototype.toJSON = function() { + var _a = this, x = _a.x, y = _a.y, top = _a.top, right = _a.right, bottom = _a.bottom, left = _a.left, width = _a.width, height = _a.height; + return { x, y, top, right, bottom, left, width, height }; + }; + DOMRectReadOnly2.fromRect = function(rectangle) { + return new DOMRectReadOnly2(rectangle.x, rectangle.y, rectangle.width, rectangle.height); + }; + return DOMRectReadOnly2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/element.js +var isSVG = function(target) { + return target instanceof SVGElement && "getBBox" in target; +}; +var isHidden = function(target) { + if (isSVG(target)) { + var _a = target.getBBox(), width = _a.width, height = _a.height; + return !width && !height; + } + var _b = target, offsetWidth = _b.offsetWidth, offsetHeight = _b.offsetHeight; + return !(offsetWidth || offsetHeight || target.getClientRects().length); +}; +var isElement = function(obj) { + var _a; + if (obj instanceof Element) { + return true; + } + var scope = (_a = obj === null || obj === void 0 ? void 0 : obj.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView; + return !!(scope && obj instanceof scope.Element); +}; +var isReplacedElement = function(target) { + switch (target.tagName) { + case "INPUT": + if (target.type !== "image") { + break; + } + case "VIDEO": + case "AUDIO": + case "EMBED": + case "OBJECT": + case "CANVAS": + case "IFRAME": + case "IMG": + return true; + } + return false; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/global.js +var global = typeof window !== "undefined" ? window : {}; + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/calculateBoxSize.js + + + + + + +var cache = /* @__PURE__ */ new WeakMap(); +var scrollRegexp = /auto|scroll/; +var verticalRegexp = /^tb|vertical/; +var IE = /msie|trident/i.test(global.navigator && global.navigator.userAgent); +var parseDimension = function(pixel) { + return parseFloat(pixel || "0"); +}; +var size = function(inlineSize, blockSize, switchSizes) { + if (inlineSize === void 0) { + inlineSize = 0; + } + if (blockSize === void 0) { + blockSize = 0; + } + if (switchSizes === void 0) { + switchSizes = false; + } + return new ResizeObserverSize((switchSizes ? blockSize : inlineSize) || 0, (switchSizes ? inlineSize : blockSize) || 0); +}; +var zeroBoxes = freeze({ + devicePixelContentBoxSize: size(), + borderBoxSize: size(), + contentBoxSize: size(), + contentRect: new DOMRectReadOnly(0, 0, 0, 0) +}); +var calculateBoxSizes = function(target, forceRecalculation) { + if (forceRecalculation === void 0) { + forceRecalculation = false; + } + if (cache.has(target) && !forceRecalculation) { + return cache.get(target); + } + if (isHidden(target)) { + cache.set(target, zeroBoxes); + return zeroBoxes; + } + var cs = getComputedStyle(target); + var svg = isSVG(target) && target.ownerSVGElement && target.getBBox(); + var removePadding = !IE && cs.boxSizing === "border-box"; + var switchSizes = verticalRegexp.test(cs.writingMode || ""); + var canScrollVertically = !svg && scrollRegexp.test(cs.overflowY || ""); + var canScrollHorizontally = !svg && scrollRegexp.test(cs.overflowX || ""); + var paddingTop = svg ? 0 : parseDimension(cs.paddingTop); + var paddingRight = svg ? 0 : parseDimension(cs.paddingRight); + var paddingBottom = svg ? 0 : parseDimension(cs.paddingBottom); + var paddingLeft = svg ? 0 : parseDimension(cs.paddingLeft); + var borderTop = svg ? 0 : parseDimension(cs.borderTopWidth); + var borderRight = svg ? 0 : parseDimension(cs.borderRightWidth); + var borderBottom = svg ? 0 : parseDimension(cs.borderBottomWidth); + var borderLeft = svg ? 0 : parseDimension(cs.borderLeftWidth); + var horizontalPadding = paddingLeft + paddingRight; + var verticalPadding = paddingTop + paddingBottom; + var horizontalBorderArea = borderLeft + borderRight; + var verticalBorderArea = borderTop + borderBottom; + var horizontalScrollbarThickness = !canScrollHorizontally ? 0 : target.offsetHeight - verticalBorderArea - target.clientHeight; + var verticalScrollbarThickness = !canScrollVertically ? 0 : target.offsetWidth - horizontalBorderArea - target.clientWidth; + var widthReduction = removePadding ? horizontalPadding + horizontalBorderArea : 0; + var heightReduction = removePadding ? verticalPadding + verticalBorderArea : 0; + var contentWidth = svg ? svg.width : parseDimension(cs.width) - widthReduction - verticalScrollbarThickness; + var contentHeight = svg ? svg.height : parseDimension(cs.height) - heightReduction - horizontalScrollbarThickness; + var borderBoxWidth = contentWidth + horizontalPadding + verticalScrollbarThickness + horizontalBorderArea; + var borderBoxHeight = contentHeight + verticalPadding + horizontalScrollbarThickness + verticalBorderArea; + var boxes = freeze({ + devicePixelContentBoxSize: size(Math.round(contentWidth * devicePixelRatio), Math.round(contentHeight * devicePixelRatio), switchSizes), + borderBoxSize: size(borderBoxWidth, borderBoxHeight, switchSizes), + contentBoxSize: size(contentWidth, contentHeight, switchSizes), + contentRect: new DOMRectReadOnly(paddingLeft, paddingTop, contentWidth, contentHeight) + }); + cache.set(target, boxes); + return boxes; +}; +var calculateBoxSize = function(target, observedBox, forceRecalculation) { + var _a = calculateBoxSizes(target, forceRecalculation), borderBoxSize = _a.borderBoxSize, contentBoxSize = _a.contentBoxSize, devicePixelContentBoxSize = _a.devicePixelContentBoxSize; + switch (observedBox) { + case ResizeObserverBoxOptions.DEVICE_PIXEL_CONTENT_BOX: + return devicePixelContentBoxSize; + case ResizeObserverBoxOptions.BORDER_BOX: + return borderBoxSize; + default: + return contentBoxSize; + } +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverEntry.js + + +var ResizeObserverEntry = function() { + function ResizeObserverEntry2(target) { + var boxes = calculateBoxSizes(target); + this.target = target; + this.contentRect = boxes.contentRect; + this.borderBoxSize = freeze([boxes.borderBoxSize]); + this.contentBoxSize = freeze([boxes.contentBoxSize]); + this.devicePixelContentBoxSize = freeze([boxes.devicePixelContentBoxSize]); + } + return ResizeObserverEntry2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/calculateDepthForNode.js + +var calculateDepthForNode = function(node) { + if (isHidden(node)) { + return Infinity; + } + var depth = 0; + var parent = node.parentNode; + while (parent) { + depth += 1; + parent = parent.parentNode; + } + return depth; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/broadcastActiveObservations.js + + + + +var broadcastActiveObservations = function() { + var shallowestDepth = Infinity; + var callbacks = []; + resizeObservers.forEach(function processObserver(ro) { + if (ro.activeTargets.length === 0) { + return; + } + var entries = []; + ro.activeTargets.forEach(function processTarget(ot) { + var entry = new ResizeObserverEntry(ot.target); + var targetDepth = calculateDepthForNode(ot.target); + entries.push(entry); + ot.lastReportedSize = calculateBoxSize(ot.target, ot.observedBox); + if (targetDepth < shallowestDepth) { + shallowestDepth = targetDepth; + } + }); + callbacks.push(function resizeObserverCallback() { + ro.callback.call(ro.observer, entries, ro.observer); + }); + ro.activeTargets.splice(0, ro.activeTargets.length); + }); + for (var _i = 0, callbacks_1 = callbacks; _i < callbacks_1.length; _i++) { + var callback = callbacks_1[_i]; + callback(); + } + return shallowestDepth; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/gatherActiveObservationsAtDepth.js + + +var gatherActiveObservationsAtDepth = function(depth) { + resizeObservers.forEach(function processObserver(ro) { + ro.activeTargets.splice(0, ro.activeTargets.length); + ro.skippedTargets.splice(0, ro.skippedTargets.length); + ro.observationTargets.forEach(function processTarget(ot) { + if (ot.isActive()) { + if (calculateDepthForNode(ot.target) > depth) { + ro.activeTargets.push(ot); + } else { + ro.skippedTargets.push(ot); + } + } + }); + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/process.js + + + + + +var process = function() { + var depth = 0; + gatherActiveObservationsAtDepth(depth); + while (hasActiveObservations()) { + depth = broadcastActiveObservations(); + gatherActiveObservationsAtDepth(depth); + } + if (hasSkippedObservations()) { + deliverResizeLoopError(); + } + return depth > 0; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/queueMicroTask.js +var trigger; +var callbacks = []; +var notify = function() { + return callbacks.splice(0).forEach(function(cb) { + return cb(); + }); +}; +var queueMicroTask = function(callback) { + if (!trigger) { + var toggle_1 = 0; + var el_1 = document.createTextNode(""); + var config = { characterData: true }; + new MutationObserver(function() { + return notify(); + }).observe(el_1, config); + trigger = function() { + el_1.textContent = "".concat(toggle_1 ? toggle_1-- : toggle_1++); + }; + } + callbacks.push(callback); + trigger(); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/queueResizeObserver.js + +var queueResizeObserver = function(cb) { + queueMicroTask(function ResizeObserver() { + requestAnimationFrame(cb); + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/scheduler.js + + + +var watching = 0; +var isWatching = function() { + return !!watching; +}; +var CATCH_PERIOD = 250; +var observerConfig = { attributes: true, characterData: true, childList: true, subtree: true }; +var events = [ + "resize", + "load", + "transitionend", + "animationend", + "animationstart", + "animationiteration", + "keyup", + "keydown", + "mouseup", + "mousedown", + "mouseover", + "mouseout", + "blur", + "focus" +]; +var time = function(timeout) { + if (timeout === void 0) { + timeout = 0; + } + return Date.now() + timeout; +}; +var scheduled = false; +var Scheduler = function() { + function Scheduler2() { + var _this = this; + this.stopped = true; + this.listener = function() { + return _this.schedule(); + }; + } + Scheduler2.prototype.run = function(timeout) { + var _this = this; + if (timeout === void 0) { + timeout = CATCH_PERIOD; + } + if (scheduled) { + return; + } + scheduled = true; + var until = time(timeout); + queueResizeObserver(function() { + var elementsHaveResized = false; + try { + elementsHaveResized = process(); + } finally { + scheduled = false; + timeout = until - time(); + if (!isWatching()) { + return; + } + if (elementsHaveResized) { + _this.run(1e3); + } else if (timeout > 0) { + _this.run(timeout); + } else { + _this.start(); + } + } + }); + }; + Scheduler2.prototype.schedule = function() { + this.stop(); + this.run(); + }; + Scheduler2.prototype.observe = function() { + var _this = this; + var cb = function() { + return _this.observer && _this.observer.observe(document.body, observerConfig); + }; + document.body ? cb() : global.addEventListener("DOMContentLoaded", cb); + }; + Scheduler2.prototype.start = function() { + var _this = this; + if (this.stopped) { + this.stopped = false; + this.observer = new MutationObserver(this.listener); + this.observe(); + events.forEach(function(name) { + return global.addEventListener(name, _this.listener, true); + }); + } + }; + Scheduler2.prototype.stop = function() { + var _this = this; + if (!this.stopped) { + this.observer && this.observer.disconnect(); + events.forEach(function(name) { + return global.removeEventListener(name, _this.listener, true); + }); + this.stopped = true; + } + }; + return Scheduler2; +}(); +var scheduler = new Scheduler(); +var updateCount = function(n) { + !watching && n > 0 && scheduler.start(); + watching += n; + !watching && scheduler.stop(); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObservation.js + + + +var skipNotifyOnElement = function(target) { + return !isSVG(target) && !isReplacedElement(target) && getComputedStyle(target).display === "inline"; +}; +var ResizeObservation = function() { + function ResizeObservation2(target, observedBox) { + this.target = target; + this.observedBox = observedBox || ResizeObserverBoxOptions.CONTENT_BOX; + this.lastReportedSize = { + inlineSize: 0, + blockSize: 0 + }; + } + ResizeObservation2.prototype.isActive = function() { + var size = calculateBoxSize(this.target, this.observedBox, true); + if (skipNotifyOnElement(this.target)) { + this.lastReportedSize = size; + } + if (this.lastReportedSize.inlineSize !== size.inlineSize || this.lastReportedSize.blockSize !== size.blockSize) { + return true; + } + return false; + }; + return ResizeObservation2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverDetail.js +var ResizeObserverDetail = function() { + function ResizeObserverDetail2(resizeObserver, callback) { + this.activeTargets = []; + this.skippedTargets = []; + this.observationTargets = []; + this.observer = resizeObserver; + this.callback = callback; + } + return ResizeObserverDetail2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverController.js + + + + +var observerMap = /* @__PURE__ */ new WeakMap(); +var getObservationIndex = function(observationTargets, target) { + for (var i = 0; i < observationTargets.length; i += 1) { + if (observationTargets[i].target === target) { + return i; + } + } + return -1; +}; +var ResizeObserverController = function() { + function ResizeObserverController2() { + } + ResizeObserverController2.connect = function(resizeObserver, callback) { + var detail = new ResizeObserverDetail(resizeObserver, callback); + observerMap.set(resizeObserver, detail); + }; + ResizeObserverController2.observe = function(resizeObserver, target, options) { + var detail = observerMap.get(resizeObserver); + var firstObservation = detail.observationTargets.length === 0; + if (getObservationIndex(detail.observationTargets, target) < 0) { + firstObservation && resizeObservers.push(detail); + detail.observationTargets.push(new ResizeObservation(target, options && options.box)); + updateCount(1); + scheduler.schedule(); + } + }; + ResizeObserverController2.unobserve = function(resizeObserver, target) { + var detail = observerMap.get(resizeObserver); + var index = getObservationIndex(detail.observationTargets, target); + var lastObservation = detail.observationTargets.length === 1; + if (index >= 0) { + lastObservation && resizeObservers.splice(resizeObservers.indexOf(detail), 1); + detail.observationTargets.splice(index, 1); + updateCount(-1); + } + }; + ResizeObserverController2.disconnect = function(resizeObserver) { + var _this = this; + var detail = observerMap.get(resizeObserver); + detail.observationTargets.slice().forEach(function(ot) { + return _this.unobserve(resizeObserver, ot.target); + }); + detail.activeTargets.splice(0, detail.activeTargets.length); + }; + return ResizeObserverController2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserver.js + + +var ResizeObserver = function() { + function ResizeObserver2(callback) { + if (arguments.length === 0) { + throw new TypeError("Failed to construct 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (typeof callback !== "function") { + throw new TypeError("Failed to construct 'ResizeObserver': The callback provided as parameter 1 is not a function."); + } + ResizeObserverController.connect(this, callback); + } + ResizeObserver2.prototype.observe = function(target, options) { + if (arguments.length === 0) { + throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (!isElement(target)) { + throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element"); + } + ResizeObserverController.observe(this, target, options); + }; + ResizeObserver2.prototype.unobserve = function(target) { + if (arguments.length === 0) { + throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (!isElement(target)) { + throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': parameter 1 is not of type 'Element"); + } + ResizeObserverController.unobserve(this, target); + }; + ResizeObserver2.prototype.disconnect = function() { + ResizeObserverController.disconnect(this); + }; + ResizeObserver2.toString = function() { + return "function ResizeObserver () { [polyfill code] }"; + }; + return ResizeObserver2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/exports/resize-observer.js + + + + +;// CONCATENATED MODULE: ./src/characters/chisato.png +const chisato_namespaceObject = "data:image/png;base64,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"; +;// CONCATENATED MODULE: ./src/characters/takina.png +const takina_namespaceObject = "data:image/png;base64,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"; +;// CONCATENATED MODULE: ./src/characters/index.ts + + +const chisato = { + image: chisato_namespaceObject, + initialState: { + i: 0.08, + s: 0.1, + d: 0.99, + r: 1, + y: 40, + t: 0, + w: 0 + } +}; +const takina = { + image: takina_namespaceObject, + initialState: { + i: 0.08, + s: 0.1, + d: 0.988, + r: 12, + y: 2, + t: 0, + w: 0 + } +}; +/* harmony default export */ const characters = ({ + chisato, + takina +}); + +;// CONCATENATED MODULE: ./src/icons/close.svg +const close_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/github.svg +const github_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/person.svg +const person_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/sync.svg +const sync_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/index.ts + + + + + +;// CONCATENATED MODULE: ./src/utils.ts +function isObject(value) { + const type = typeof value; + return value != null && (type === "object" || type === "function"); +} +function cloneDeep(value) { + if (typeof window.structuredClone === "function") { + return window.structuredClone(value); + } else { + return JSON.parse(JSON.stringify(value)); + } +} +function mergeDeep(target, source) { + const _target = cloneDeep(target); + const _source = cloneDeep(source); + if (!isObject(_target) || !isObject(_source)) { + return _target; + } + Object.keys(_source).forEach((key) => { + if (isObject(_source[key])) { + if (!isObject(_target[key])) { + _target[key] = {}; + } + _target[key] = mergeDeep(_target[key], _source[key]); + } else { + _target[key] = _source[key]; + } + }); + return _target; +} +function throttle(callback) { + let requestId = null; + let lastArgs; + const later = (context) => () => { + requestId = null; + callback.apply(context, lastArgs); + }; + const throttled = function(...args) { + lastArgs = args; + if (requestId === null) { + requestId = requestAnimationFrame(later(this)); + } + }; + return throttled; +} +function getCanvasCtx(canvas, appSize, devicePixelRatio = (window.devicePixelRatio || 1) * 2) { + const canvasRenderSize = appSize * devicePixelRatio; + canvas.width = canvasRenderSize; + canvas.height = canvasRenderSize; + const ctx = canvas.getContext("2d"); + if (!ctx) { + return null; + } + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.scale(devicePixelRatio, devicePixelRatio); + return ctx; +} + +;// CONCATENATED MODULE: ./src/index.ts +/*! sakana-widget | DSRKafuU (https://dsrkafuu.net) | Copyright (c) MIT License */ + + + + + +const defaultOptions = { + size: 200, + autoFit: false, + character: "chisato", + controls: true, + stroke: { + color: "#b4b4b4", + width: 10 + }, + threshold: 0.1, + rotate: 0 +}; +const _characters = {}; +Object.keys(characters).forEach((key) => { + const _char = characters[key]; + _characters[key] = cloneDeep(_char); +}); +const _SakanaWidget = class { + constructor(options = {}) { + this._lastRunUnix = Date.now(); + this._frameUnix = 1e3 / 60; + this._running = true; + this._magicForceTimeout = 0; + this._magicForceEnabled = false; + this._resizeObserver = null; + this._updateLimit = (size) => { + let maxR = size / 5; + if (maxR < 30) { + maxR = 30; + } else if (maxR > 60) { + maxR = 60; + } + const maxY = size / 4; + const minY = -maxY; + this._limit = { maxR, maxY, minY }; + }; + this._updateSize = (size) => { + this._options.size = size; + this._imageSize = this._options.size / 1.25; + this._canvasSize = this._options.size * 1.5; + this._domApp.style.width = `${size}px`; + this._domApp.style.height = `${size}px`; + this._domCanvas.style.width = `${this._canvasSize}px`; + this._domCanvas.style.height = `${this._canvasSize}px`; + const ctx = getCanvasCtx(this._domCanvas, this._canvasSize); + if (!ctx) { + throw new Error("Invalid canvas context"); + } + this._domCanvasCtx = ctx; + this._draw(); + this._domMain.style.width = `${size}px`; + this._domMain.style.height = `${size}px`; + this._domImage.style.width = `${this._imageSize}px`; + this._domImage.style.height = `${this._imageSize}px`; + this._domImage.style.transformOrigin = `50% ${size}px`; + }; + this._updateDom = () => { + const wrapper = document.createElement("div"); + wrapper.className = "sakana-widget-wrapper"; + this._domWrapper = wrapper; + const app = document.createElement("div"); + app.className = "sakana-widget-app"; + this._domApp = app; + wrapper.appendChild(app); + const canvas = document.createElement("canvas"); + canvas.className = "sakana-widget-canvas"; + this._domCanvas = canvas; + app.appendChild(canvas); + const main = document.createElement("div"); + main.className = "sakana-widget-main"; + this._domMain = main; + app.appendChild(main); + const img = document.createElement("div"); + img.className = "sakana-widget-img"; + img.style.backgroundImage = `url('${this._image}')`; + this._domImage = img; + main.appendChild(img); + const ctrl = document.createElement("div"); + ctrl.className = "sakana-widget-ctrl"; + if (this._options.controls) { + main.appendChild(ctrl); + } + const itemClass = "sakana-widget-ctrl-item"; + const person = document.createElement("div"); + person.className = itemClass; + person.innerHTML = person_namespaceObject; + this._domCtrlPerson = person; + ctrl.appendChild(person); + const magic = document.createElement("div"); + magic.className = itemClass; + magic.innerHTML = sync_namespaceObject; + this._domCtrlMagic = magic; + ctrl.appendChild(magic); + const github = document.createElement("a"); + github.className = itemClass; + github.href = "//github.com/dsrkafuu/sakana-widget"; + github.target = "_blank"; + github.innerHTML = github_namespaceObject; + ctrl.appendChild(github); + const close = document.createElement("div"); + close.className = itemClass; + close.innerHTML = close_namespaceObject; + this._domCtrlClose = close; + ctrl.appendChild(close); + }; + this._calcCenterPoint = (degree, radius, x, y) => { + const radian = Math.PI / 180 * degree; + const cos = Math.cos(radian); + const sin = Math.sin(radian); + const nx = sin * radius + cos * x - sin * y; + const ny = cos * radius - cos * y - sin * x; + return { nx, ny }; + }; + this._draw = () => { + const { r, y } = this._state; + const { size, controls, stroke } = this._options; + const img = this._domImage; + const imgSize = this._imageSize; + const ctx = this._domCanvasCtx; + const x = r * 1; + img.style.transform = `rotate(${r}deg) translateX(${x}px) translateY(${y}px)`; + ctx.clearRect(0, 0, this._canvasSize, this._canvasSize); + ctx.save(); + ctx.translate(this._canvasSize / 2, size + (this._canvasSize - size) / 2); + ctx.strokeStyle = stroke.color; + ctx.lineWidth = stroke.width; + ctx.lineCap = "round"; + ctx.beginPath(); + if (controls) { + ctx.moveTo(0, -10); + } else { + ctx.moveTo(0, 10); + } + const radius = size - imgSize / 2; + const { nx, ny } = this._calcCenterPoint(r, radius, x, y); + ctx.lineTo(nx, -ny); + ctx.stroke(); + ctx.restore(); + }; + this._run = () => { + let originRotate = this._options.rotate; + originRotate = Math.min(120, Math.max(0, originRotate)); + const cut = this._options.threshold; + if (!this._running) { + return; + } + let { r, y, t, w } = this._state; + const { d, i } = this._state; + const thisRunUnix = Date.now(); + let _inertia = i; + const lastRunUnixDiff = thisRunUnix - this._lastRunUnix; + if (lastRunUnixDiff < 16) { + _inertia = i / this._frameUnix * lastRunUnixDiff; + } + this._lastRunUnix = thisRunUnix; + w = w - r * 2 - originRotate; + r = r + w * _inertia * 1.2; + this._state.w = w * d; + this._state.r = r; + t = t - y * 2; + y = y + t * _inertia * 2; + this._state.t = t * d; + this._state.y = y; + if (Math.max( + Math.abs(this._state.w), + Math.abs(this._state.r), + Math.abs(this._state.t), + Math.abs(this._state.y) + ) < cut) { + this._running = false; + return; + } + this._draw(); + requestAnimationFrame(this._run); + }; + this._move = (x, y) => { + const { maxR, maxY, minY } = this._limit; + let r = x * this._state.s; + r = Math.max(-maxR, r); + r = Math.min(maxR, r); + y = y * this._state.s * 2; + y = Math.max(minY, y); + y = Math.min(maxY, y); + this._state.r = r; + this._state.y = y; + this._state.w = 0; + this._state.t = 0; + this._draw(); + }; + this._onMouseDown = (e) => { + e.preventDefault(); + this._running = false; + const { pageY } = e; + const _downPageY = pageY; + this._state.w = 0; + this._state.t = 0; + const onMouseMove = (e2) => { + const rect = this._domMain.getBoundingClientRect(); + const leftCenter = rect.left + rect.width / 2; + const { pageX, pageY: pageY2 } = e2; + const x = pageX - leftCenter; + const y = pageY2 - _downPageY; + this._move(x, y); + }; + const onMouseUp = () => { + document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("mouseup", onMouseUp); + this._running = true; + requestAnimationFrame(this._run); + }; + document.addEventListener("mousemove", onMouseMove); + document.addEventListener("mouseup", onMouseUp); + }; + this._onTouchStart = (e) => { + e.preventDefault(); + this._running = false; + if (!e.touches[0]) { + return; + } + const { pageY } = e.touches[0]; + const _downPageY = pageY; + this._state.w = 0; + this._state.t = 0; + const onTouchMove = (e2) => { + if (!e2.touches[0]) { + return; + } + const rect = this._domMain.getBoundingClientRect(); + const leftCenter = rect.left + rect.width / 2; + const { pageX, pageY: pageY2 } = e2.touches[0]; + const x = pageX - leftCenter; + const y = pageY2 - _downPageY; + this._move(x, y); + }; + const onTouchEnd = () => { + document.removeEventListener("touchmove", onTouchMove); + document.removeEventListener("touchend", onTouchEnd); + this._running = true; + requestAnimationFrame(this._run); + }; + document.addEventListener("touchmove", onTouchMove); + document.addEventListener("touchend", onTouchEnd); + }; + this._magicForce = () => { + if (Math.random() < 0.1) { + const available = Object.keys(_characters); + const index = Math.floor(Math.random() * available.length); + const _char = available[index]; + this.setCharacter(_char); + } else { + this._state.t = this._state.t + (Math.random() - 0.5) * 150; + this._state.w = this._state.w + (Math.random() - 0.5) * 200; + } + if (!this._running) { + this._running = true; + requestAnimationFrame(this._run); + } + this._magicForceTimeout = window.setTimeout( + this._magicForce, + Math.random() * 3e3 + 2e3 + ); + }; + this.triggetAutoMode = () => { + this._magicForceEnabled = !this._magicForceEnabled; + const icon = this._domCtrlMagic.querySelector("svg"); + if (this._magicForceEnabled) { + icon.classList.add("sakana-widget-icon--rotate"); + } else { + icon.classList.remove("sakana-widget-icon--rotate"); + } + clearTimeout(this._magicForceTimeout); + if (this._magicForceEnabled) { + this._magicForceTimeout = window.setTimeout( + this._magicForce, + Math.random() * 1e3 + 500 + ); + } + }; + this.setState = (state) => { + if (!this._state) { + this._state = {}; + } + this._state = mergeDeep(this._state, cloneDeep(state)); + return this; + }; + this.setCharacter = (name) => { + const targetChar = _characters[name]; + if (!targetChar) { + throw new Error(`invalid character ${name}`); + } + this._char = name; + this._image = targetChar.image; + this.setState(targetChar.initialState); + if (this._domImage) { + this._domImage.style.backgroundImage = `url('${this._image}')`; + } + return this; + }; + this.nextCharacter = () => { + const _chars = Object.keys(_SakanaWidget.getCharacters()).sort(); + const curCharIdx = _chars.indexOf(this._char); + const nextCharIdx = (curCharIdx + 1) % _chars.length; + const nextChar = _chars[nextCharIdx]; + this.setCharacter(nextChar); + return this; + }; + this._onResize = (rect) => { + let newSize = Math.min(rect.width, rect.height); + newSize = Math.max(120, newSize); + this._updateSize(newSize); + this._updateLimit(newSize); + }; + this.mount = (el) => { + let _el = null; + if (typeof el === "string") { + _el = document.querySelector(el); + } + if (!_el) { + throw new Error("Invalid mounting element"); + } + const parent = _el.parentNode; + if (!parent) { + throw new Error("Invalid mounting element parent"); + } + this._domImage.addEventListener("mousedown", this._onMouseDown); + this._domImage.addEventListener("touchstart", this._onTouchStart); + this._domCtrlPerson.addEventListener("click", this.nextCharacter); + this._domCtrlMagic.addEventListener("click", this.triggetAutoMode); + this._domCtrlClose.addEventListener("click", this.unmount); + if (this._options.autoFit) { + this._onResize(this._domWrapper.getBoundingClientRect()); + this._resizeObserver = new ResizeObserver( + throttle((entries) => { + if (!entries || !entries[0]) + return; + this._onResize(entries[0].contentRect); + }) + ); + this._resizeObserver.observe(this._domWrapper); + } + const _newEl = _el.cloneNode(false); + _newEl.appendChild(this._domWrapper); + parent.replaceChild(_newEl, _el); + requestAnimationFrame(this._run); + return this; + }; + this.unmount = () => { + this._domImage.removeEventListener("mousedown", this._onMouseDown); + this._domImage.removeEventListener("touchstart", this._onTouchStart); + this._domCtrlPerson.removeEventListener("click", this.nextCharacter); + this._domCtrlMagic.removeEventListener("click", this.triggetAutoMode); + this._domCtrlClose.removeEventListener("click", this.unmount); + this._resizeObserver && this._resizeObserver.disconnect(); + const _el = this._domWrapper.parentNode; + if (!_el) { + throw new Error("Invalid mounting element"); + } + _el.removeChild(this._domWrapper); + return this; + }; + this._options = cloneDeep( + defaultOptions + ); + this._options = mergeDeep(this._options, options); + this.setCharacter(this._options.character); + this._updateDom(); + this._updateSize(this._options.size); + this._updateLimit(this._options.size); + } +}; +let SakanaWidget = _SakanaWidget; +SakanaWidget.getCharacter = (name) => { + const _char = _characters[name]; + return _char ? cloneDeep(_char) : null; +}; +SakanaWidget.getCharacters = () => { + return cloneDeep(_characters); +}; +SakanaWidget.registerCharacter = (name, character) => { + const _char = cloneDeep(character); + let inertia = _char.initialState.i; + inertia = Math.min(0.5, Math.max(0, inertia)); + _char.initialState.i = inertia; + _characters[name] = _char; +}; +/* harmony default export */ const src_0 = (SakanaWidget); + +})(); + +var __webpack_exports__default = __webpack_exports__.Z; +export { __webpack_exports__default as default }; diff --git a/js/sakana-widget/index.js b/js/sakana-widget/index.js new file mode 100644 index 00000000..25a35bd0 --- /dev/null +++ b/js/sakana-widget/index.js @@ -0,0 +1,1666 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define("SakanaWidget", [], factory); + else if(typeof exports === 'object') + exports["SakanaWidget"] = factory(); + else + root["SakanaWidget"] = factory(); +})(self, () => { +return /******/ (() => { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ 800: +/***/ ((module, __webpack_exports__, __webpack_require__) => { + +/* harmony export */ __webpack_require__.d(__webpack_exports__, { +/* harmony export */ "Z": () => (__WEBPACK_DEFAULT_EXPORT__) +/* harmony export */ }); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(918); +/* harmony import */ var _node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0__); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(267); +/* harmony import */ var _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1__); +// Imports + + +var ___CSS_LOADER_EXPORT___ = _node_modules_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_1___default()((_node_modules_css_loader_dist_runtime_noSourceMaps_js__WEBPACK_IMPORTED_MODULE_0___default())); +// Module +___CSS_LOADER_EXPORT___.push([module.id, ".sakana-widget *,.sakana-widget *::before,.sakana-widget *::after{box-sizing:border-box}.sakana-widget-wrapper{pointer-events:none;position:relative;width:100%;height:100%}.sakana-widget-app{pointer-events:none;position:relative}.sakana-widget-canvas{z-index:10;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.sakana-widget-main{z-index:20;pointer-events:none;position:absolute;display:flex;flex-direction:column;justify-content:space-between;align-items:center}.sakana-widget-img{z-index:40;cursor:move;pointer-events:auto;position:relative;background:no-repeat 50% 50%;background-size:cover}.sakana-widget-ctrl{z-index:30;cursor:pointer;pointer-events:auto;position:relative;height:24px;width:112px;display:flex;border-radius:4px;background-color:#ddd;box-shadow:0 8px 24px rgba(0,0,0,.1)}.sakana-widget-ctrl-item{height:24px;width:28px;display:flex;justify-content:center;align-items:center;color:#555;background-color:rgba(0,0,0,0)}.sakana-widget-ctrl-item:hover{color:#555;background-color:rgba(255,255,255,.25)}.sakana-widget-icon{height:18px;width:18px}.sakana-widget-icon--rotate{animation:sakana-widget-spin 2s linear infinite}@keyframes sakana-widget-spin{100%{transform:rotate(360deg)}}", ""]); +// Exports +/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___); + + +/***/ }), + +/***/ 267: +/***/ ((module) => { + + +module.exports = function(cssWithMappingToString) { + var list = []; + list.toString = function toString() { + return this.map(function(item) { + var content = ""; + var needLayer = typeof item[5] !== "undefined"; + if (item[4]) { + content += "@supports (".concat(item[4], ") {"); + } + if (item[2]) { + content += "@media ".concat(item[2], " {"); + } + if (needLayer) { + content += "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {"); + } + content += cssWithMappingToString(item); + if (needLayer) { + content += "}"; + } + if (item[2]) { + content += "}"; + } + if (item[4]) { + content += "}"; + } + return content; + }).join(""); + }; + list.i = function i(modules, media, dedupe, supports, layer) { + if (typeof modules === "string") { + modules = [[null, modules, void 0]]; + } + var alreadyImportedModules = {}; + if (dedupe) { + for (var k = 0; k < this.length; k++) { + var id = this[k][0]; + if (id != null) { + alreadyImportedModules[id] = true; + } + } + } + for (var _k = 0; _k < modules.length; _k++) { + var item = [].concat(modules[_k]); + if (dedupe && alreadyImportedModules[item[0]]) { + continue; + } + if (typeof layer !== "undefined") { + if (typeof item[5] === "undefined") { + item[5] = layer; + } else { + item[1] = "@layer".concat(item[5].length > 0 ? " ".concat(item[5]) : "", " {").concat(item[1], "}"); + item[5] = layer; + } + } + if (media) { + if (!item[2]) { + item[2] = media; + } else { + item[1] = "@media ".concat(item[2], " {").concat(item[1], "}"); + item[2] = media; + } + } + if (supports) { + if (!item[4]) { + item[4] = "".concat(supports); + } else { + item[1] = "@supports (".concat(item[4], ") {").concat(item[1], "}"); + item[4] = supports; + } + } + list.push(item); + } + }; + return list; +}; + + +/***/ }), + +/***/ 918: +/***/ ((module) => { + + +module.exports = function(i) { + return i[1]; +}; + + +/***/ }), + +/***/ 379: +/***/ ((module) => { + + + +var stylesInDOM = []; + +function getIndexByIdentifier(identifier) { + var result = -1; + + for (var i = 0; i < stylesInDOM.length; i++) { + if (stylesInDOM[i].identifier === identifier) { + result = i; + break; + } + } + + return result; +} + +function modulesToDom(list, options) { + var idCountMap = {}; + var identifiers = []; + + for (var i = 0; i < list.length; i++) { + var item = list[i]; + var id = options.base ? item[0] + options.base : item[0]; + var count = idCountMap[id] || 0; + var identifier = "".concat(id, " ").concat(count); + idCountMap[id] = count + 1; + var indexByIdentifier = getIndexByIdentifier(identifier); + var obj = { + css: item[1], + media: item[2], + sourceMap: item[3], + supports: item[4], + layer: item[5] + }; + + if (indexByIdentifier !== -1) { + stylesInDOM[indexByIdentifier].references++; + stylesInDOM[indexByIdentifier].updater(obj); + } else { + var updater = addElementStyle(obj, options); + options.byIndex = i; + stylesInDOM.splice(i, 0, { + identifier: identifier, + updater: updater, + references: 1 + }); + } + + identifiers.push(identifier); + } + + return identifiers; +} + +function addElementStyle(obj, options) { + var api = options.domAPI(options); + api.update(obj); + + var updater = function updater(newObj) { + if (newObj) { + if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) { + return; + } + + api.update(obj = newObj); + } else { + api.remove(); + } + }; + + return updater; +} + +module.exports = function (list, options) { + options = options || {}; + list = list || []; + var lastIdentifiers = modulesToDom(list, options); + return function update(newList) { + newList = newList || []; + + for (var i = 0; i < lastIdentifiers.length; i++) { + var identifier = lastIdentifiers[i]; + var index = getIndexByIdentifier(identifier); + stylesInDOM[index].references--; + } + + var newLastIdentifiers = modulesToDom(newList, options); + + for (var _i = 0; _i < lastIdentifiers.length; _i++) { + var _identifier = lastIdentifiers[_i]; + + var _index = getIndexByIdentifier(_identifier); + + if (stylesInDOM[_index].references === 0) { + stylesInDOM[_index].updater(); + + stylesInDOM.splice(_index, 1); + } + } + + lastIdentifiers = newLastIdentifiers; + }; +}; + +/***/ }), + +/***/ 569: +/***/ ((module) => { + + + +var memo = {}; +/* istanbul ignore next */ + +function getTarget(target) { + if (typeof memo[target] === "undefined") { + var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself + + if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) { + try { + // This will throw an exception if access to iframe is blocked + // due to cross-origin restrictions + styleTarget = styleTarget.contentDocument.head; + } catch (e) { + // istanbul ignore next + styleTarget = null; + } + } + + memo[target] = styleTarget; + } + + return memo[target]; +} +/* istanbul ignore next */ + + +function insertBySelector(insert, style) { + var target = getTarget(insert); + + if (!target) { + throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid."); + } + + target.appendChild(style); +} + +module.exports = insertBySelector; + +/***/ }), + +/***/ 216: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function insertStyleElement(options) { + var element = document.createElement("style"); + options.setAttributes(element, options.attributes); + options.insert(element, options.options); + return element; +} + +module.exports = insertStyleElement; + +/***/ }), + +/***/ 565: +/***/ ((module, __unused_webpack_exports, __webpack_require__) => { + + + +/* istanbul ignore next */ +function setAttributesWithoutAttributes(styleElement) { + var nonce = true ? __webpack_require__.nc : 0; + + if (nonce) { + styleElement.setAttribute("nonce", nonce); + } +} + +module.exports = setAttributesWithoutAttributes; + +/***/ }), + +/***/ 795: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function apply(styleElement, options, obj) { + var css = ""; + + if (obj.supports) { + css += "@supports (".concat(obj.supports, ") {"); + } + + if (obj.media) { + css += "@media ".concat(obj.media, " {"); + } + + var needLayer = typeof obj.layer !== "undefined"; + + if (needLayer) { + css += "@layer".concat(obj.layer.length > 0 ? " ".concat(obj.layer) : "", " {"); + } + + css += obj.css; + + if (needLayer) { + css += "}"; + } + + if (obj.media) { + css += "}"; + } + + if (obj.supports) { + css += "}"; + } + + var sourceMap = obj.sourceMap; + + if (sourceMap && typeof btoa !== "undefined") { + css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */"); + } // For old IE + + /* istanbul ignore if */ + + + options.styleTagTransform(css, styleElement, options.options); +} + +function removeStyleElement(styleElement) { + // istanbul ignore if + if (styleElement.parentNode === null) { + return false; + } + + styleElement.parentNode.removeChild(styleElement); +} +/* istanbul ignore next */ + + +function domAPI(options) { + var styleElement = options.insertStyleElement(options); + return { + update: function update(obj) { + apply(styleElement, options, obj); + }, + remove: function remove() { + removeStyleElement(styleElement); + } + }; +} + +module.exports = domAPI; + +/***/ }), + +/***/ 589: +/***/ ((module) => { + + + +/* istanbul ignore next */ +function styleTagTransform(css, styleElement) { + if (styleElement.styleSheet) { + styleElement.styleSheet.cssText = css; + } else { + while (styleElement.firstChild) { + styleElement.removeChild(styleElement.firstChild); + } + + styleElement.appendChild(document.createTextNode(css)); + } +} + +module.exports = styleTagTransform; + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ id: moduleId, +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ (() => { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = (module) => { +/******/ var getter = module && module.__esModule ? +/******/ () => (module['default']) : +/******/ () => (module); +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ (() => { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = (exports, definition) => { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ })(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ (() => { +/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) +/******/ })(); +/******/ +/******/ /* webpack/runtime/nonce */ +/******/ (() => { +/******/ __webpack_require__.nc = undefined; +/******/ })(); +/******/ +/************************************************************************/ +var __webpack_exports__ = {}; +// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk. +(() => { + +// EXPORTS +__webpack_require__.d(__webpack_exports__, { + "default": () => (/* binding */ src_0) +}); + +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js +var injectStylesIntoStyleTag = __webpack_require__(379); +var injectStylesIntoStyleTag_default = /*#__PURE__*/__webpack_require__.n(injectStylesIntoStyleTag); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleDomAPI.js +var styleDomAPI = __webpack_require__(795); +var styleDomAPI_default = /*#__PURE__*/__webpack_require__.n(styleDomAPI); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertBySelector.js +var insertBySelector = __webpack_require__(569); +var insertBySelector_default = /*#__PURE__*/__webpack_require__.n(insertBySelector); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js +var setAttributesWithoutAttributes = __webpack_require__(565); +var setAttributesWithoutAttributes_default = /*#__PURE__*/__webpack_require__.n(setAttributesWithoutAttributes); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/insertStyleElement.js +var insertStyleElement = __webpack_require__(216); +var insertStyleElement_default = /*#__PURE__*/__webpack_require__.n(insertStyleElement); +// EXTERNAL MODULE: ./node_modules/style-loader/dist/runtime/styleTagTransform.js +var styleTagTransform = __webpack_require__(589); +var styleTagTransform_default = /*#__PURE__*/__webpack_require__.n(styleTagTransform); +// EXTERNAL MODULE: ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./src/index.scss +var cjs_js_src = __webpack_require__(800); +;// CONCATENATED MODULE: ./src/index.scss + + + + + + + + + + + +var options = {}; + +options.styleTagTransform = (styleTagTransform_default()); +options.setAttributes = (setAttributesWithoutAttributes_default()); + + options.insert = insertBySelector_default().bind(null, "head"); + +options.domAPI = (styleDomAPI_default()); +options.insertStyleElement = (insertStyleElement_default()); + +var update = injectStylesIntoStyleTag_default()(cjs_js_src/* default */.Z, options); + + + + + /* harmony default export */ const src = (cjs_js_src/* default */.Z && cjs_js_src/* default.locals */.Z.locals ? cjs_js_src/* default.locals */.Z.locals : undefined); + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/resizeObservers.js +var resizeObservers = []; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/hasActiveObservations.js + +var hasActiveObservations = function() { + return resizeObservers.some(function(ro) { + return ro.activeTargets.length > 0; + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/hasSkippedObservations.js + +var hasSkippedObservations = function() { + return resizeObservers.some(function(ro) { + return ro.skippedTargets.length > 0; + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/deliverResizeLoopError.js +var msg = "ResizeObserver loop completed with undelivered notifications."; +var deliverResizeLoopError = function() { + var event; + if (typeof ErrorEvent === "function") { + event = new ErrorEvent("error", { + message: msg + }); + } else { + event = document.createEvent("Event"); + event.initEvent("error", false, false); + event.message = msg; + } + window.dispatchEvent(event); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverBoxOptions.js +var ResizeObserverBoxOptions; +(function(ResizeObserverBoxOptions2) { + ResizeObserverBoxOptions2["BORDER_BOX"] = "border-box"; + ResizeObserverBoxOptions2["CONTENT_BOX"] = "content-box"; + ResizeObserverBoxOptions2["DEVICE_PIXEL_CONTENT_BOX"] = "device-pixel-content-box"; +})(ResizeObserverBoxOptions || (ResizeObserverBoxOptions = {})); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/freeze.js +var freeze = function(obj) { + return Object.freeze(obj); +}; + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverSize.js + +var ResizeObserverSize = function() { + function ResizeObserverSize2(inlineSize, blockSize) { + this.inlineSize = inlineSize; + this.blockSize = blockSize; + freeze(this); + } + return ResizeObserverSize2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/DOMRectReadOnly.js + +var DOMRectReadOnly = function() { + function DOMRectReadOnly2(x, y, width, height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.top = this.y; + this.left = this.x; + this.bottom = this.top + this.height; + this.right = this.left + this.width; + return freeze(this); + } + DOMRectReadOnly2.prototype.toJSON = function() { + var _a = this, x = _a.x, y = _a.y, top = _a.top, right = _a.right, bottom = _a.bottom, left = _a.left, width = _a.width, height = _a.height; + return { x, y, top, right, bottom, left, width, height }; + }; + DOMRectReadOnly2.fromRect = function(rectangle) { + return new DOMRectReadOnly2(rectangle.x, rectangle.y, rectangle.width, rectangle.height); + }; + return DOMRectReadOnly2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/element.js +var isSVG = function(target) { + return target instanceof SVGElement && "getBBox" in target; +}; +var isHidden = function(target) { + if (isSVG(target)) { + var _a = target.getBBox(), width = _a.width, height = _a.height; + return !width && !height; + } + var _b = target, offsetWidth = _b.offsetWidth, offsetHeight = _b.offsetHeight; + return !(offsetWidth || offsetHeight || target.getClientRects().length); +}; +var isElement = function(obj) { + var _a; + if (obj instanceof Element) { + return true; + } + var scope = (_a = obj === null || obj === void 0 ? void 0 : obj.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView; + return !!(scope && obj instanceof scope.Element); +}; +var isReplacedElement = function(target) { + switch (target.tagName) { + case "INPUT": + if (target.type !== "image") { + break; + } + case "VIDEO": + case "AUDIO": + case "EMBED": + case "OBJECT": + case "CANVAS": + case "IFRAME": + case "IMG": + return true; + } + return false; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/global.js +var global = typeof window !== "undefined" ? window : {}; + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/calculateBoxSize.js + + + + + + +var cache = /* @__PURE__ */ new WeakMap(); +var scrollRegexp = /auto|scroll/; +var verticalRegexp = /^tb|vertical/; +var IE = /msie|trident/i.test(global.navigator && global.navigator.userAgent); +var parseDimension = function(pixel) { + return parseFloat(pixel || "0"); +}; +var size = function(inlineSize, blockSize, switchSizes) { + if (inlineSize === void 0) { + inlineSize = 0; + } + if (blockSize === void 0) { + blockSize = 0; + } + if (switchSizes === void 0) { + switchSizes = false; + } + return new ResizeObserverSize((switchSizes ? blockSize : inlineSize) || 0, (switchSizes ? inlineSize : blockSize) || 0); +}; +var zeroBoxes = freeze({ + devicePixelContentBoxSize: size(), + borderBoxSize: size(), + contentBoxSize: size(), + contentRect: new DOMRectReadOnly(0, 0, 0, 0) +}); +var calculateBoxSizes = function(target, forceRecalculation) { + if (forceRecalculation === void 0) { + forceRecalculation = false; + } + if (cache.has(target) && !forceRecalculation) { + return cache.get(target); + } + if (isHidden(target)) { + cache.set(target, zeroBoxes); + return zeroBoxes; + } + var cs = getComputedStyle(target); + var svg = isSVG(target) && target.ownerSVGElement && target.getBBox(); + var removePadding = !IE && cs.boxSizing === "border-box"; + var switchSizes = verticalRegexp.test(cs.writingMode || ""); + var canScrollVertically = !svg && scrollRegexp.test(cs.overflowY || ""); + var canScrollHorizontally = !svg && scrollRegexp.test(cs.overflowX || ""); + var paddingTop = svg ? 0 : parseDimension(cs.paddingTop); + var paddingRight = svg ? 0 : parseDimension(cs.paddingRight); + var paddingBottom = svg ? 0 : parseDimension(cs.paddingBottom); + var paddingLeft = svg ? 0 : parseDimension(cs.paddingLeft); + var borderTop = svg ? 0 : parseDimension(cs.borderTopWidth); + var borderRight = svg ? 0 : parseDimension(cs.borderRightWidth); + var borderBottom = svg ? 0 : parseDimension(cs.borderBottomWidth); + var borderLeft = svg ? 0 : parseDimension(cs.borderLeftWidth); + var horizontalPadding = paddingLeft + paddingRight; + var verticalPadding = paddingTop + paddingBottom; + var horizontalBorderArea = borderLeft + borderRight; + var verticalBorderArea = borderTop + borderBottom; + var horizontalScrollbarThickness = !canScrollHorizontally ? 0 : target.offsetHeight - verticalBorderArea - target.clientHeight; + var verticalScrollbarThickness = !canScrollVertically ? 0 : target.offsetWidth - horizontalBorderArea - target.clientWidth; + var widthReduction = removePadding ? horizontalPadding + horizontalBorderArea : 0; + var heightReduction = removePadding ? verticalPadding + verticalBorderArea : 0; + var contentWidth = svg ? svg.width : parseDimension(cs.width) - widthReduction - verticalScrollbarThickness; + var contentHeight = svg ? svg.height : parseDimension(cs.height) - heightReduction - horizontalScrollbarThickness; + var borderBoxWidth = contentWidth + horizontalPadding + verticalScrollbarThickness + horizontalBorderArea; + var borderBoxHeight = contentHeight + verticalPadding + horizontalScrollbarThickness + verticalBorderArea; + var boxes = freeze({ + devicePixelContentBoxSize: size(Math.round(contentWidth * devicePixelRatio), Math.round(contentHeight * devicePixelRatio), switchSizes), + borderBoxSize: size(borderBoxWidth, borderBoxHeight, switchSizes), + contentBoxSize: size(contentWidth, contentHeight, switchSizes), + contentRect: new DOMRectReadOnly(paddingLeft, paddingTop, contentWidth, contentHeight) + }); + cache.set(target, boxes); + return boxes; +}; +var calculateBoxSize = function(target, observedBox, forceRecalculation) { + var _a = calculateBoxSizes(target, forceRecalculation), borderBoxSize = _a.borderBoxSize, contentBoxSize = _a.contentBoxSize, devicePixelContentBoxSize = _a.devicePixelContentBoxSize; + switch (observedBox) { + case ResizeObserverBoxOptions.DEVICE_PIXEL_CONTENT_BOX: + return devicePixelContentBoxSize; + case ResizeObserverBoxOptions.BORDER_BOX: + return borderBoxSize; + default: + return contentBoxSize; + } +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverEntry.js + + +var ResizeObserverEntry = function() { + function ResizeObserverEntry2(target) { + var boxes = calculateBoxSizes(target); + this.target = target; + this.contentRect = boxes.contentRect; + this.borderBoxSize = freeze([boxes.borderBoxSize]); + this.contentBoxSize = freeze([boxes.contentBoxSize]); + this.devicePixelContentBoxSize = freeze([boxes.devicePixelContentBoxSize]); + } + return ResizeObserverEntry2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/calculateDepthForNode.js + +var calculateDepthForNode = function(node) { + if (isHidden(node)) { + return Infinity; + } + var depth = 0; + var parent = node.parentNode; + while (parent) { + depth += 1; + parent = parent.parentNode; + } + return depth; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/broadcastActiveObservations.js + + + + +var broadcastActiveObservations = function() { + var shallowestDepth = Infinity; + var callbacks = []; + resizeObservers.forEach(function processObserver(ro) { + if (ro.activeTargets.length === 0) { + return; + } + var entries = []; + ro.activeTargets.forEach(function processTarget(ot) { + var entry = new ResizeObserverEntry(ot.target); + var targetDepth = calculateDepthForNode(ot.target); + entries.push(entry); + ot.lastReportedSize = calculateBoxSize(ot.target, ot.observedBox); + if (targetDepth < shallowestDepth) { + shallowestDepth = targetDepth; + } + }); + callbacks.push(function resizeObserverCallback() { + ro.callback.call(ro.observer, entries, ro.observer); + }); + ro.activeTargets.splice(0, ro.activeTargets.length); + }); + for (var _i = 0, callbacks_1 = callbacks; _i < callbacks_1.length; _i++) { + var callback = callbacks_1[_i]; + callback(); + } + return shallowestDepth; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/algorithms/gatherActiveObservationsAtDepth.js + + +var gatherActiveObservationsAtDepth = function(depth) { + resizeObservers.forEach(function processObserver(ro) { + ro.activeTargets.splice(0, ro.activeTargets.length); + ro.skippedTargets.splice(0, ro.skippedTargets.length); + ro.observationTargets.forEach(function processTarget(ot) { + if (ot.isActive()) { + if (calculateDepthForNode(ot.target) > depth) { + ro.activeTargets.push(ot); + } else { + ro.skippedTargets.push(ot); + } + } + }); + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/process.js + + + + + +var process = function() { + var depth = 0; + gatherActiveObservationsAtDepth(depth); + while (hasActiveObservations()) { + depth = broadcastActiveObservations(); + gatherActiveObservationsAtDepth(depth); + } + if (hasSkippedObservations()) { + deliverResizeLoopError(); + } + return depth > 0; +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/queueMicroTask.js +var trigger; +var callbacks = []; +var notify = function() { + return callbacks.splice(0).forEach(function(cb) { + return cb(); + }); +}; +var queueMicroTask = function(callback) { + if (!trigger) { + var toggle_1 = 0; + var el_1 = document.createTextNode(""); + var config = { characterData: true }; + new MutationObserver(function() { + return notify(); + }).observe(el_1, config); + trigger = function() { + el_1.textContent = "".concat(toggle_1 ? toggle_1-- : toggle_1++); + }; + } + callbacks.push(callback); + trigger(); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/queueResizeObserver.js + +var queueResizeObserver = function(cb) { + queueMicroTask(function ResizeObserver() { + requestAnimationFrame(cb); + }); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/utils/scheduler.js + + + +var watching = 0; +var isWatching = function() { + return !!watching; +}; +var CATCH_PERIOD = 250; +var observerConfig = { attributes: true, characterData: true, childList: true, subtree: true }; +var events = [ + "resize", + "load", + "transitionend", + "animationend", + "animationstart", + "animationiteration", + "keyup", + "keydown", + "mouseup", + "mousedown", + "mouseover", + "mouseout", + "blur", + "focus" +]; +var time = function(timeout) { + if (timeout === void 0) { + timeout = 0; + } + return Date.now() + timeout; +}; +var scheduled = false; +var Scheduler = function() { + function Scheduler2() { + var _this = this; + this.stopped = true; + this.listener = function() { + return _this.schedule(); + }; + } + Scheduler2.prototype.run = function(timeout) { + var _this = this; + if (timeout === void 0) { + timeout = CATCH_PERIOD; + } + if (scheduled) { + return; + } + scheduled = true; + var until = time(timeout); + queueResizeObserver(function() { + var elementsHaveResized = false; + try { + elementsHaveResized = process(); + } finally { + scheduled = false; + timeout = until - time(); + if (!isWatching()) { + return; + } + if (elementsHaveResized) { + _this.run(1e3); + } else if (timeout > 0) { + _this.run(timeout); + } else { + _this.start(); + } + } + }); + }; + Scheduler2.prototype.schedule = function() { + this.stop(); + this.run(); + }; + Scheduler2.prototype.observe = function() { + var _this = this; + var cb = function() { + return _this.observer && _this.observer.observe(document.body, observerConfig); + }; + document.body ? cb() : global.addEventListener("DOMContentLoaded", cb); + }; + Scheduler2.prototype.start = function() { + var _this = this; + if (this.stopped) { + this.stopped = false; + this.observer = new MutationObserver(this.listener); + this.observe(); + events.forEach(function(name) { + return global.addEventListener(name, _this.listener, true); + }); + } + }; + Scheduler2.prototype.stop = function() { + var _this = this; + if (!this.stopped) { + this.observer && this.observer.disconnect(); + events.forEach(function(name) { + return global.removeEventListener(name, _this.listener, true); + }); + this.stopped = true; + } + }; + return Scheduler2; +}(); +var scheduler = new Scheduler(); +var updateCount = function(n) { + !watching && n > 0 && scheduler.start(); + watching += n; + !watching && scheduler.stop(); +}; + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObservation.js + + + +var skipNotifyOnElement = function(target) { + return !isSVG(target) && !isReplacedElement(target) && getComputedStyle(target).display === "inline"; +}; +var ResizeObservation = function() { + function ResizeObservation2(target, observedBox) { + this.target = target; + this.observedBox = observedBox || ResizeObserverBoxOptions.CONTENT_BOX; + this.lastReportedSize = { + inlineSize: 0, + blockSize: 0 + }; + } + ResizeObservation2.prototype.isActive = function() { + var size = calculateBoxSize(this.target, this.observedBox, true); + if (skipNotifyOnElement(this.target)) { + this.lastReportedSize = size; + } + if (this.lastReportedSize.inlineSize !== size.inlineSize || this.lastReportedSize.blockSize !== size.blockSize) { + return true; + } + return false; + }; + return ResizeObservation2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverDetail.js +var ResizeObserverDetail = function() { + function ResizeObserverDetail2(resizeObserver, callback) { + this.activeTargets = []; + this.skippedTargets = []; + this.observationTargets = []; + this.observer = resizeObserver; + this.callback = callback; + } + return ResizeObserverDetail2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserverController.js + + + + +var observerMap = /* @__PURE__ */ new WeakMap(); +var getObservationIndex = function(observationTargets, target) { + for (var i = 0; i < observationTargets.length; i += 1) { + if (observationTargets[i].target === target) { + return i; + } + } + return -1; +}; +var ResizeObserverController = function() { + function ResizeObserverController2() { + } + ResizeObserverController2.connect = function(resizeObserver, callback) { + var detail = new ResizeObserverDetail(resizeObserver, callback); + observerMap.set(resizeObserver, detail); + }; + ResizeObserverController2.observe = function(resizeObserver, target, options) { + var detail = observerMap.get(resizeObserver); + var firstObservation = detail.observationTargets.length === 0; + if (getObservationIndex(detail.observationTargets, target) < 0) { + firstObservation && resizeObservers.push(detail); + detail.observationTargets.push(new ResizeObservation(target, options && options.box)); + updateCount(1); + scheduler.schedule(); + } + }; + ResizeObserverController2.unobserve = function(resizeObserver, target) { + var detail = observerMap.get(resizeObserver); + var index = getObservationIndex(detail.observationTargets, target); + var lastObservation = detail.observationTargets.length === 1; + if (index >= 0) { + lastObservation && resizeObservers.splice(resizeObservers.indexOf(detail), 1); + detail.observationTargets.splice(index, 1); + updateCount(-1); + } + }; + ResizeObserverController2.disconnect = function(resizeObserver) { + var _this = this; + var detail = observerMap.get(resizeObserver); + detail.observationTargets.slice().forEach(function(ot) { + return _this.unobserve(resizeObserver, ot.target); + }); + detail.activeTargets.splice(0, detail.activeTargets.length); + }; + return ResizeObserverController2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/ResizeObserver.js + + +var ResizeObserver = function() { + function ResizeObserver2(callback) { + if (arguments.length === 0) { + throw new TypeError("Failed to construct 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (typeof callback !== "function") { + throw new TypeError("Failed to construct 'ResizeObserver': The callback provided as parameter 1 is not a function."); + } + ResizeObserverController.connect(this, callback); + } + ResizeObserver2.prototype.observe = function(target, options) { + if (arguments.length === 0) { + throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (!isElement(target)) { + throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element"); + } + ResizeObserverController.observe(this, target, options); + }; + ResizeObserver2.prototype.unobserve = function(target) { + if (arguments.length === 0) { + throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': 1 argument required, but only 0 present."); + } + if (!isElement(target)) { + throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': parameter 1 is not of type 'Element"); + } + ResizeObserverController.unobserve(this, target); + }; + ResizeObserver2.prototype.disconnect = function() { + ResizeObserverController.disconnect(this); + }; + ResizeObserver2.toString = function() { + return "function ResizeObserver () { [polyfill code] }"; + }; + return ResizeObserver2; +}(); + + +;// CONCATENATED MODULE: ./node_modules/@juggle/resize-observer/lib/exports/resize-observer.js + + + + +;// CONCATENATED MODULE: ./src/characters/chisato.png +const chisato_namespaceObject = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAMAAAAL34HQAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAMAUExURQAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDAwAAAAEBAQAAAAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkJCA8YExERESAfHf///wAAACVAU0FBQf/43iQ/UiVBVClHXSZDVydEWStKYChGWz8/P0ZGRkNDQwICAkJCQgMICggPE0tLS0hISB42R//23Do6OgwWHQYMD///8QMFBRgXFwgGBSE6SwoTGDExMSMjJD09PS1NZCwrKhISER4dHA8cJP//9//64S0uMEVFRQ0MCzc2N//95B0zQ05OTxsaGSEgHxgrNyI9TxIhLCcoKxswPicmJAkJCA8PDv//6QABBjMzNBQUFRAfKBgtOxQkLwsZIv///P//7cutgMamefDw7zY0MxUnMwUcLo6OjlNTUgEOGOrm0TE1Ounp6ZiYlmNdUg8oOQAGENLR0WZmZ9CwgnVzb+jGk4aGhvX19W1ucFpaWhwfI+/Ll+LBkCchGVtXUMfCsOPj4/v6+tna29O1iOO8QQEQIcrJyPPu1qijk8LCw/rPSN7e3v/cTZyYikxALra2tNu5iImFeaioplRPSBIKA765pmJhXPv13IYPAOnUsHOdcTo9QDQoC7bB1FlJNZ2ensYbADyPyTMBANLMuHl5epWQgkE1J29rYObOpr2ietrVwLOunTQvKTFSahI1UnVjSpF6W929joCBgHFaGhIuQ+PeyK2trXikdtvDm7u6u/3vzqOjolgGALYWAHaBkOC8iaexxoVsIaWLZ5V3IhUuIvPmx3IKANi1hDeEu0IDADFNNoJtT2dVQJeCZdOtNxsWCcnItvnitCEBAJymuIGLnPLIRESe3UxHPkZBOKIUAD1ARzQpHR1GNLOYcSBij4N7ai94qyQ7KWmRaFt/W0xvTlRZZOnBQ+7EQVVEDkFXREpmeYqVpSRSPi5mUB9AV3tvXaWGJ//sUrmZMv/0VtvW0y1smSs6R66aWqSdC5MAAAAkdFJOUwDgDo0W+Gfx6QWYMNUpyiGpP3k4RnFaoPxhw1CBvbex+P7p3teKBtoAABoESURBVHjazZwHVFTX1oBFwEFE7ILdvHc3MHPnzp1emMr0AgPDzDB96EXpIKgoKlbUYIm9x9heYosaY080JqaXl97by0vP/3r7y1r/uQMiA+QlizJ5ewnODC7vxz777L3POXufESMGKSMnTI1PSEiIC8n06EmjR/wHyLgps+NieQKhxlJaXeop1sjjZk3+xaHGxscBT1gsobvpDCbBZBIMusQSmxTzy0Il0UBeKqEzcBZJEkwGyWIZDCzCpZw18hekGhXHk5W4CRwnUugp6A9JXK+peZxgsUqU438xqAmzeGV2RhcTJSRZw8vgLbpOsHAPTPiFLH1OrMzOxElGF1MKnSA69j//9tvPr0FcasEvM4wzouQuJotkpHQLg1wIL27fvv2BF++7bmDKYVJEeUZPo4ZnYrLFzSLvjl5IiL93/PEP2++/f/vb79QYCFmksaJok2LilSUkzuwJlUInH1907aOP7r//gfvf6cDJatrYiGKNcfrjooQSpKpwoeOPF7z4wH8hrD8c7SDJ6qhxEcWa6sw2goxloNP7Yv2TwvroD3+s+TtpmR5ZjzrTzBHpoIzAU8LHkM66q62PjtYYWLLxEY2MMQl5XFG2EzQEi96DCQUew12st/fXXEyRT42osuaAP5ut55pBRuJdTCkMJkmSTF8HXHtg+x8e2P48CDTy5DERtSyewMtd2ybiq8CCU1x0BkESJKn2aJQA+/97+wPbPzoKSKZH0pvGRFVXW21L19VZxeYQF4Ii6b5SjQBC8s61569RVDyIaEycIae7jNaD6ae9HHEQSlk4iUssciWES8AYBFp8BE0+3kMv83v1hypFXlFqEDykRCa4h8PLsR7xft7SsqKQAp0dsWEcPV3C1Pi9eQ3YlkKbQ8oDjbwTSJnhrDq44mpT7dI6ts1WlRH6cHak9DU60U3K8wpVexT5B71ckbVzyPyiZU/crr26tMUhKjSbegzmtIhpy45rzFLVQQW2xWbjiP3o2aJly04tbWljW4O8XiYGiZEaxqlCX7FOv3JfLra5zsvncHQARo4tD/qXyFn9HIFQl6037XtXsdTLTs3mWAPwY5I8M3Kua0wcmMWiDPgkbQ/CYnNEUl1Gf0wZzoxpkfRcE2hOjrgIbKfbbKlI+CKO1BqEQLjSBI+98EbGqMgmNqpUsVWXqtfzU0PCdzjMgcu/v/zGpTMgyFM5zV6rdeWlVZfktIgmXJNoenEqny1ld2GlcrNXrnn2vVWtrfN2mqTZqVyRQ2Q9vuRMQVF8ROPPXKmYz03tIdnaoku7W6/sXjV/jdfB5fJTOeyinQdXmnMimURE5+jF7J5UlLrgdy+svtLaulOX3fmBztnSpjXNjOAKI0GVykkNl2zKf/3u8urWnStDWHybaFldi0MXFbm8OSZKx+X2wmKLODkrHdKdbxqtXMri+IWO223L2oyqyPmIMTQjpzdWqsgPJ7CtP8CKU1I9hSXlrDi1uC3PH7l8fjJNK+5NxeUUBRZj2AZT7S6ujVIXm6t3NPGN2vER8/NTY6XdFs9mp4a8BFccDCzAsAU54iccVZQq+VybN89k9EZHzpvO7Z6IfHahNGRL1CDuxbDloqV7RYVdCuR6zUHllIhhTSti352IetFBaWEqn5/KzuYGbeuRuhZc1WobETQfKbDO4Q0kRmy3cqLpLhaab+v26LxsNp/PFttUtcsx7ITXu3atrfGIniuWGv15QYidESlvqrqLxS3Uv5u2I9tr1SNbyq7SrqhdsVL71fxzzezGxkZdsDNoRyowTuzG4ttsWxSZJ5eKrVa9Xi/1FhU99uYLrz67+9wLl/8h7U4mImT10UG2+K7Fa1s2lysOndzD1a30is4u3XHg0dYl8+cvQWiXurESIuPpo7ttKzXba2vITK9QpK/bcXrHugb0Kuvlw4cP37x58/DNx7pWjPt+HZlRnNKtrVSuVrquIistK1+RmZmpyM/PzcrNz6+oOLR5c3ruyX0hrLMHIoQ1KkMv6sLi6wuXpinS09OycnNzs7LS0tLT0rKyQm/yy9NOI4V90rAlQrtvY2k6EeeuP7VybijSEA4laZ3S9SJLkXnj9J7N2NkI2daImTytqCtWc22FO/Lz7wKFSXpaLhpaTPFppOLP6MSAtDtYW+s2Z/aLhbSGLC3zhjNS/nTEJFCJu8Ii12bdouhfXRRYBfZVbOTWGTNBx8lmd1kX+3xmVnp/g5iWpsAOBCf+/P925KQxg/sdxoPR0cnF1XvPHirvxRV6l5uJZZ40//zFT8yoOVEJiTMHc1IUk5ihFXVx2bx7Npfn352Iob+zKhSI6caWs/6fuyU4dsbU6cZLb1y+dCZ5MMuScQnKQkfnagJxnX03X5Hbpamsiszy8s3n3z2xohQg8WfmzFOjANoa3nt29aorxwd1sjY2IVAoEonFHA5HrDfqdzRUlGdWICIMazj/btOfrHkZ7/zx2tGkn+sK9+xxHsAenb9x96p5awa1WTeGpix2WRulR44c4R/Rag9uWXdyc8O7u/bWirRr3n8f9v/z7f++BrSfl53ONDdgpw82vDd/3ryNqy7DoFzK7EceeX+/QKiRaWRlZfXyRfKVzWvPHH1//yO/feWZZ95/58U/wqJ9Toj+OT5+9r5D2ObmA7kb5y+Zd+XKmTmD2tx95TefvfJbSh6h5LeP/PbpVx588JnfPPPMZw8+jYK0RnQh80AOJI79Gf75gqIid8v58kcpdbW+NXcw1jX9/Vc+e+Y33fIMwvnsswcffOXppx8Bgf+TpSdRVlF+QQoJP5nOj4s6j+Ue2nKj/FBIXRsfSxo41VRhx6JHKP10CqJBPO/vVwoKCqxXD9xQoAmQm56LVeyD5J9aWkcnr8MqcvetVWAhda2+PHB1jYyysyRl9YICXuc+bkFBgWBRfT0PVjY2HjyZX44pslBSocDKDxQC/HvDj9cJmrMyFXtgB1ZxE3Fdad054B2oiRomiyD/fn1hTUg8CxcutLtJ0iUPGrki8dILDRWZ+fnY5h3Ne1q8AKNGjBw7rv8Fdkz8wU06OFmer2hGXNjh+fOvbNw5fcDKKsEZKQRBslgsAyv0jaTeGVjVgiJrodV68MKNCuzkpwUrdTqd1M9Liv914viJk8PNf2TM2BmjZrUtx6RwAUvLPGSE5tvrbm5sfcE00POiiQI3nsJEUCl0uhqJW00gNNwtUdvrAUxOE0BO8x5t44fP/QBwaoFW2bRpmcMMUTOnTpsyZdRESqKjx8+KMn7qP9hefgLOllekZTasDTh3HHp0yU7eQG0rUcZA6pGUuGRCALlQrgSZy253yeQCQUB4nxICeqtTx5P9ZcOxv6hyuO21IMYwbHFLEHgmU5HZbNaZqNOY5i0N5QeCV5dXLuVtwXLTFYqGhtynVr0BSQN28faLTM+ighxk74KFjz9+fWFxAbW//NJLL33x17/97Qtezl5s+fJa0N059py47aqUG4BliAurBfOWAwfWrXv3/AW0VMpXVCiw89C4rbK9zXwAy8xHy5SXV51bkzDQ9CZJg0vQMGn9IF/4fw8//NrDH3+5yL8vB77421//+sUX37wkB9UuDNuAFtanjjnYlW3AzVFuQ1iVwaLz5YqKLkE+NK0iy1+wqbJ9QUvVgfz0lx+9smrJmbhxAzZ4mQVUtdv28BZ9/XCI6ut66TZsVxBeekmOHJdAVlYAtRiWLaqDz1dC+/LCvVehjlLXMmhGyUZuaOWWS61LcjO3gKh9W/uCFRnH561a/eq54wM/v5oQC9DSji0+UvMlgvr6tY+/hjUL0ENvOUFQ6imR0Jk4cxE0LU5twupA19iyvhLbCnArpC5oKE/vklB+lq84C22V7e3b2mDn5TfedMLA956iAZZiWBPAlx9//PBrrz38Wsf+TZQusMU5wDAQJE4SOF4DPMdWDBPdea7oNobtyoC69ehf6OBCeVZYvp+p+ASWLdiwYcHWFpWpAAa+lz81mdeEnvCEGRY9/uXXD3/8Wv3+/8U65TbUs3A6JbihgxpHbMUPz/0gRtpSAVDoqdB8qCI9LMEuz/0UmtYjrg23aosGvjc9iQanQgyVJ/aZoODxL2t467C7shQ8LEZnxQ3eYUJ2v0z3lw+U6LdgA6wIGVdVgyI88c/CGvzyJyo3tGPtB2MHvE03NgqklXcpFi/9FHnOJuyeSEHNooeqEAyGRarF2N7AnWNWPYbxC3iUum7BmgZFrwVJbvl5P9xe376VDwMu6RiZAC3Le2CUb9rTkwrbyutA6iJxusQusYNufXtOy7EVwcWYsaOUUvImnrOh93o3Pau84VPH7RYVbTDmXtWTqq84QIIz3CUWjUagqYfacmPjsQ9UtZi2QwL+5VilKnCjDxZKgLDTyoQpAz8iGkujNuD/nTzBqzEwy5Sy6hK3T1i/8lZ20QfPORybOB2lKt0JDLOibCHc5LOy8hWKzc2Jgyn3SuqMIv9GlucVsAiLxm1gXTTINDVeqfXOsQ+daz/vkO/da92A6WEdlt5jnyI/Pyu/4uW31iQOYmNn5GRaHfZT0gYSg10oYaklPqHSXu+UfnjsAy9YFhZswor2Ypy7WNS2GHL1h5566r1zZyBuEGd8o2fzVBt+EmuvoOZiilBWLBQIhFCthiKE9TnI3PUrdvl3YTbe+XKKiAo/WYc2v/xo6+5L+2PHD2YEJ4FxA9b+U1gLzItYpIUntJS46UIhs56HsBxQxlwIGdpKzLrmEKZQVFB6evnwzdWrl7ywk5Y0uBLVaOdibNOKpp9SmBRSWC4oYSHP5QFJifIOpa1Sw0UqfC/X5VxouLGZ2vldvXH3s6++sHPurEHWzcZEIXOvvNUmOrG1H5WtL7/7agVcN0iULgODTvrARZf/8NxzWii585f79OuxDU6QOsRrm/c1vzXv2d2/P56TOOgq9pkZW0ODtMuh8i/b1tt7beh2/bsCyLg0MjdBx+mCYqLM+sFzTpDcuaNE8X2xCgq1XqO1UMpufuvNdxImDnpndXRU2/rO57ZvXVGkszVtW9/Tu2/qfrfY1IE8l1BN0kmmRkaWwIcfBAuYf64GFCKfyDCJudkcDkevk2cMARRaVsDWexSLa3WQIb61rbILZpfonpdd7kc275FLcDrBkAkZ9IKWO8F68s+yADLKU2B0cDjZUl0gNnHqUJyBTqK1hU+42wf9Kqfj6lYKrMn4RI8fsQsYLLvAx6IzyVK5mpR9LgrU/PmY1oxSRb6SK2IbnQHa7MlDcjA7Oim4qbeVt29tajl1YhuVrtSGOdRFEoNb4DLgLJZLKDFUB4o01z88EUSe+ETAbMvLSU6YOXaIDrHHxbb05wzWV1ai+BvIC/twmbzEQNcUM+gSl1yoNqgBqvE/l8IJbJMJcgIJ8ROG7gQhhqav/FG/jp7YU5qECw0Mi1wj4IHQh/J6Aagvkii5rzUBLWny0J5qjKLpt/0IVh2/sjcWi+HzWIpdkhScQTDkZQTu1oAKEqKHvrxlOuj29kvVZO2V6yAsPIUgqOJdt0+NqzV2twxpbny/iho9ITppMNvxiTkAdf0kW7esT/Tm1CAsJl1SrdHIZGqDRGavtpTIk/qz8rETE7028yAKACbHFrJVkNHWeyQrrSt6g54SXGcxXMUuu09iF/oMLou9zI7L++7UxkyZ9SunSi8yD/y4avSsALvOYcsBk+hWuGHZ+kwFToEbTyn20FmGi7i8FK8uVctKi3vvt4+cNj7BrGVrg0HTIAYxHoJsTqrIoQX04uq9SFNLhZRemY1zEUnSLS6SdEuqeT68zKXWlJbyerZmjJ4xPiFPq6/yq+bOmjmIno0pAOZUDpvNRdHMnKHSebVNC9o3LC+/be6bRO/l1bBIuqysWiaQC9H6TGYv0ajtsWPuGXl84q+MepvRPHf6qDGD8Rcj44LBPHZnyRjHwS3MU0KRtsrv1epu950DHJ6bJBlyuUVWarcI1G6LpFjGcMV1JaCTKCap1JoXTJg5aZA+LD5QWHSvmozLEYs4qrzTB76CQHkfql1QxqJSGg/DbTAUa9Quj1rjwS2hmqmxE2f9Sidla/NMUfGD96tjk/P0ARU3u0dplL7xdCaWFVzZ1/WL0LilkD6B/SITZwjKUmTVDLnPIJwyIoZisrELdUVx8TOGotsmmidNDZh7FrmxtftOVmTeMKX2oVoGHuS0mKVClNjgEihNEfrcGjU9OSk+Ic/Gthmdc+dMGxpfPzoxyGEre2qLK7Vefio/syFY2Dc+FhChREvjJhhkNfgImaREbhHm5GnZUqszJ3HUmKEqNZtE8zvYPBO3u1KRz27cN/+p3MxcP7XRFeZJgRpCOrJ4GYPJJCxytbqsWK5UGfV6LTLyiUOYPIyIBmldakB5r5yM29j41u738jMvmADWLriXzl+VAkiojSRcrbQQBIvQyEo0ApW/SlqoM0VFzxjS4/TRCaZUEdcJRnGncfFTpdbm+a8eLs/8pEBSD/7aBZ1p9No8QKtUnEFPYSCL9xkIooRXUKTTVlX5i+aOnzHULWVjaH4ul2ODgJRLqYutb0RUu199CruQU2MgPQBGbl0dn6qZL7OTiIpOJ3CP0E33CIPmx2w2vylYJhiGkpZpyVoxn8POAN2RI1KptLGR/495rbtXp590Ap1FsCRlncVHZSVuEidC/VEsQiiQCZ3+x6qM5hyNp8Q1HGXXEzOkYjaXuxJ2nt0nFvPXvnXuyqrdbx1f+ycAO5nCwHG33We3u/FQDyWTQB7eJwMTYrKaTUKov77QIgDa0Od/MwPI2NliKe/4ko3nzp2bt2rV7nPHc4Kvf28GDYNMSWEQOJJOJoJk2ouFJrPWhiaesHhhDRQsyuABxA19syJVW53K5vAFa1a/1/rqqy+8eeZ3v3vp9e+ffPIb4Knv9bcxKEWpS4VCp7FK63fK6mWyjo4COPr8tQBA7NBra3woGvKztc6dOxHRGqXgpde/e/KhJx+6D8DFIpidQpA4vVojVOU9pjWaEYhSKBNkHL324tvbn0eGN/QmP3q8mY+w2HyHFeC+b17/0/ffIaSHnvz2dfQ4C26gBhB90V1laPCMWpQaUP1RoUPZ5+9/YPu/th8dngrBeCeFlcoWFcLr34aIHnrooe9eF+Ts+YpXYPF4SkstMk+xMKgyao06U49mn/33/88D27e/SH0y1IOI0pGZzs6UhiPN+ebJJ7996KFvv//+GyXsv5yvqOpqUwFQGY1Gvyq8x+3oR/96+5/XMqgTR94Q94vMjI+Z0VVpyhXnwZ++/e671++jOhGP//7Z97DT1NNNRmkR5GmdfRprkLUfRaoSlqp9gqShLVFP5CWOn6vvrG7jSIOB++6TwzvH33zj96tbd8//Ss8L6gq5dW1aHq+/Xh/0VV/sUpMGhmCIG3TnBLxFOYUcfmdPTyGsoZCutLau3jhv9fwMsHIddSKpV9UflbK+w+OjU16WJDVD3GUdn8HhaKV8fmdvQyNcWk0hbVyyZMm83UvOyEV1VTpVTl8kgdBT4lMzcRbBYKTQmYQHhrYWfEqyUSTidmY0yNMLjl9ZTSEhmb+k9R+BImeYnpQ8pVxm8VS70BqfhRNMRmdLP4MoGeLS+Um0IFfUlWexxaKid861hpjmz79yOKvhMQCNx2OxFFuKiz0ej8tX4pPQmSwWFYsYjHvXDJBqwRAXes6GQtHd7E9vFMClZ5cgpo03Dz+lwMrPgIUwsFAkJJBLpWgQD6Wjnkihw0WmcM7QtmVMA1N2p7o4UpPZD8GbTz366OGX0yswbF1zBqgNDEZX+GEw+vDcuylCNsThJyYK8kShdFlcyNPW5cHZtHIFWh1WbFmKoozcjdNTfkzuMSKbH+r27xkAfhEVFDlsk9nhUMLZrIrz67Y0AwRUIGMQP8qEEgpmN5aLN9RtGTMRF0r/0GLaGNCZ0Xz7ZC0VZkxWjhGqScaPMOEspqTER++aiqRPOeTtikkAZr4oG6krGAjqtEWUX9LZsh1iE0jw/kwphWTRfR6h3OJjdOmLUMuHvnErGgU+LUfE4VZZ9SIRh22r4os5XDE7o55B9kPFZKk9QoReLCGY96bixCHHGjGFBjxzFVckQjR8LofDyUZ+X1wFC3FGf1QSAQrQ1W783giTdPmsYSicnzCeBkqnNVUsDnl8fmjfJo8nYdH7oSpB68VqBotk9vCnKfLhuU1jcvR0GhQ5dV3tWWhicnMEarwfKh+AD0WeMA+GtDVsTdbTEgCcti4sagw1fdwDorJTGX6vCcog7YLhau2MiU7Ms3G6u2k4eVDSx7QYLLUALKzePpZBliiHq4VyMgQL+SIHVV6dnZ3t4OQI6H1cPM5AU9BCkPTewccCw9b9MCpKGdRZC21SPZutTzWix/caQzpJWiAxCSxMIqV3qB7Gu0fGRE9HqXDQpFKpitASx473MSwXxI1D7lfCCv8J6RYMa2PNyGnxcxLikiE5LipZ08uX0pkGOy9uAjLCuNK7frTLtAifcthvOxg3edqUqZPjk13h063TjYYsaI7QHaZIJlEaqSsr5gjcYb6UTrDsyq62vym9RpFJFENk+jpnJBeHGTydwEuU0NWwPIYWpkk6ScgidNvOdF5Y8oB05QLobqNOlNHJsIkoj8xFTmNiw50ASVHdWzlH89wX8S4hCRL52Mj0DI8P9w4E6YLkHpnLZJqLLukStZvOKOVNGxGBzu8xyUIGK7S06BwkVinQepYbjo0SdItGJpPJYXrS7OiY4VdWNY4TBMEkQsXyuIs3PexUcExUf/ePDPdlb+NoYKkuReIp9VHbuaWQHD7/+8ca7psEJ9D6PHLifyZW+D1Nk+J+iUGc1BcrvBJybH9Yw35jXz/a6nUhRUI/WMN+Y1I/2uq1ITMqFmLDBWjDft3OuL5YvYukp04ZFS5TIhCrZ/emio3sTY8/ltZH0eLCZDiWNf8PRiV7OvorOVEAAAAASUVORK5CYII="; +;// CONCATENATED MODULE: ./src/characters/takina.png +const takina_namespaceObject = "data:image/png;base64,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"; +;// CONCATENATED MODULE: ./src/characters/index.ts + + +const chisato = { + image: chisato_namespaceObject, + initialState: { + i: 0.08, + s: 0.1, + d: 0.99, + r: 1, + y: 40, + t: 0, + w: 0 + } +}; +const takina = { + image: takina_namespaceObject, + initialState: { + i: 0.08, + s: 0.1, + d: 0.988, + r: 12, + y: 2, + t: 0, + w: 0 + } +}; +/* harmony default export */ const characters = ({ + chisato, + takina +}); + +;// CONCATENATED MODULE: ./src/icons/close.svg +const close_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/github.svg +const github_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/person.svg +const person_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/sync.svg +const sync_namespaceObject = ""; +;// CONCATENATED MODULE: ./src/icons/index.ts + + + + + +;// CONCATENATED MODULE: ./src/utils.ts +function isObject(value) { + const type = typeof value; + return value != null && (type === "object" || type === "function"); +} +function cloneDeep(value) { + if (typeof window.structuredClone === "function") { + return window.structuredClone(value); + } else { + return JSON.parse(JSON.stringify(value)); + } +} +function mergeDeep(target, source) { + const _target = cloneDeep(target); + const _source = cloneDeep(source); + if (!isObject(_target) || !isObject(_source)) { + return _target; + } + Object.keys(_source).forEach((key) => { + if (isObject(_source[key])) { + if (!isObject(_target[key])) { + _target[key] = {}; + } + _target[key] = mergeDeep(_target[key], _source[key]); + } else { + _target[key] = _source[key]; + } + }); + return _target; +} +function throttle(callback) { + let requestId = null; + let lastArgs; + const later = (context) => () => { + requestId = null; + callback.apply(context, lastArgs); + }; + const throttled = function(...args) { + lastArgs = args; + if (requestId === null) { + requestId = requestAnimationFrame(later(this)); + } + }; + return throttled; +} +function getCanvasCtx(canvas, appSize, devicePixelRatio = (window.devicePixelRatio || 1) * 2) { + const canvasRenderSize = appSize * devicePixelRatio; + canvas.width = canvasRenderSize; + canvas.height = canvasRenderSize; + const ctx = canvas.getContext("2d"); + if (!ctx) { + return null; + } + ctx.setTransform(1, 0, 0, 1, 0, 0); + ctx.scale(devicePixelRatio, devicePixelRatio); + return ctx; +} + +;// CONCATENATED MODULE: ./src/index.ts +/*! sakana-widget | DSRKafuU (https://dsrkafuu.net) | Copyright (c) MIT License */ + + + + + +const defaultOptions = { + size: 200, + autoFit: false, + character: "chisato", + controls: true, + stroke: { + color: "#b4b4b4", + width: 10 + }, + threshold: 0.1, + rotate: 0 +}; +const _characters = {}; +Object.keys(characters).forEach((key) => { + const _char = characters[key]; + _characters[key] = cloneDeep(_char); +}); +const _SakanaWidget = class { + constructor(options = {}) { + this._lastRunUnix = Date.now(); + this._frameUnix = 1e3 / 60; + this._running = true; + this._magicForceTimeout = 0; + this._magicForceEnabled = false; + this._resizeObserver = null; + this._updateLimit = (size) => { + let maxR = size / 5; + if (maxR < 30) { + maxR = 30; + } else if (maxR > 60) { + maxR = 60; + } + const maxY = size / 4; + const minY = -maxY; + this._limit = { maxR, maxY, minY }; + }; + this._updateSize = (size) => { + this._options.size = size; + this._imageSize = this._options.size / 1.25; + this._canvasSize = this._options.size * 1.5; + this._domApp.style.width = `${size}px`; + this._domApp.style.height = `${size}px`; + this._domCanvas.style.width = `${this._canvasSize}px`; + this._domCanvas.style.height = `${this._canvasSize}px`; + const ctx = getCanvasCtx(this._domCanvas, this._canvasSize); + if (!ctx) { + throw new Error("Invalid canvas context"); + } + this._domCanvasCtx = ctx; + this._draw(); + this._domMain.style.width = `${size}px`; + this._domMain.style.height = `${size}px`; + this._domImage.style.width = `${this._imageSize}px`; + this._domImage.style.height = `${this._imageSize}px`; + this._domImage.style.transformOrigin = `50% ${size}px`; + }; + this._updateDom = () => { + const wrapper = document.createElement("div"); + wrapper.className = "sakana-widget-wrapper"; + this._domWrapper = wrapper; + const app = document.createElement("div"); + app.className = "sakana-widget-app"; + this._domApp = app; + wrapper.appendChild(app); + const canvas = document.createElement("canvas"); + canvas.className = "sakana-widget-canvas"; + this._domCanvas = canvas; + app.appendChild(canvas); + const main = document.createElement("div"); + main.className = "sakana-widget-main"; + this._domMain = main; + app.appendChild(main); + const img = document.createElement("div"); + img.className = "sakana-widget-img"; + img.style.backgroundImage = `url('${this._image}')`; + this._domImage = img; + main.appendChild(img); + const ctrl = document.createElement("div"); + ctrl.className = "sakana-widget-ctrl"; + if (this._options.controls) { + main.appendChild(ctrl); + } + const itemClass = "sakana-widget-ctrl-item"; + const person = document.createElement("div"); + person.className = itemClass; + person.innerHTML = person_namespaceObject; + this._domCtrlPerson = person; + ctrl.appendChild(person); + const magic = document.createElement("div"); + magic.className = itemClass; + magic.innerHTML = sync_namespaceObject; + this._domCtrlMagic = magic; + ctrl.appendChild(magic); + const github = document.createElement("a"); + github.className = itemClass; + github.href = "//github.com/dsrkafuu/sakana-widget"; + github.target = "_blank"; + github.innerHTML = github_namespaceObject; + ctrl.appendChild(github); + const close = document.createElement("div"); + close.className = itemClass; + close.innerHTML = close_namespaceObject; + this._domCtrlClose = close; + ctrl.appendChild(close); + }; + this._calcCenterPoint = (degree, radius, x, y) => { + const radian = Math.PI / 180 * degree; + const cos = Math.cos(radian); + const sin = Math.sin(radian); + const nx = sin * radius + cos * x - sin * y; + const ny = cos * radius - cos * y - sin * x; + return { nx, ny }; + }; + this._draw = () => { + const { r, y } = this._state; + const { size, controls, stroke } = this._options; + const img = this._domImage; + const imgSize = this._imageSize; + const ctx = this._domCanvasCtx; + const x = r * 1; + img.style.transform = `rotate(${r}deg) translateX(${x}px) translateY(${y}px)`; + ctx.clearRect(0, 0, this._canvasSize, this._canvasSize); + ctx.save(); + ctx.translate(this._canvasSize / 2, size + (this._canvasSize - size) / 2); + ctx.strokeStyle = stroke.color; + ctx.lineWidth = stroke.width; + ctx.lineCap = "round"; + ctx.beginPath(); + if (controls) { + ctx.moveTo(0, -10); + } else { + ctx.moveTo(0, 10); + } + const radius = size - imgSize / 2; + const { nx, ny } = this._calcCenterPoint(r, radius, x, y); + ctx.lineTo(nx, -ny); + ctx.stroke(); + ctx.restore(); + }; + this._run = () => { + let originRotate = this._options.rotate; + originRotate = Math.min(120, Math.max(0, originRotate)); + const cut = this._options.threshold; + if (!this._running) { + return; + } + let { r, y, t, w } = this._state; + const { d, i } = this._state; + const thisRunUnix = Date.now(); + let _inertia = i; + const lastRunUnixDiff = thisRunUnix - this._lastRunUnix; + if (lastRunUnixDiff < 16) { + _inertia = i / this._frameUnix * lastRunUnixDiff; + } + this._lastRunUnix = thisRunUnix; + w = w - r * 2 - originRotate; + r = r + w * _inertia * 1.2; + this._state.w = w * d; + this._state.r = r; + t = t - y * 2; + y = y + t * _inertia * 2; + this._state.t = t * d; + this._state.y = y; + if (Math.max( + Math.abs(this._state.w), + Math.abs(this._state.r), + Math.abs(this._state.t), + Math.abs(this._state.y) + ) < cut) { + this._running = false; + return; + } + this._draw(); + requestAnimationFrame(this._run); + }; + this._move = (x, y) => { + const { maxR, maxY, minY } = this._limit; + let r = x * this._state.s; + r = Math.max(-maxR, r); + r = Math.min(maxR, r); + y = y * this._state.s * 2; + y = Math.max(minY, y); + y = Math.min(maxY, y); + this._state.r = r; + this._state.y = y; + this._state.w = 0; + this._state.t = 0; + this._draw(); + }; + this._onMouseDown = (e) => { + e.preventDefault(); + this._running = false; + const { pageY } = e; + const _downPageY = pageY; + this._state.w = 0; + this._state.t = 0; + const onMouseMove = (e2) => { + const rect = this._domMain.getBoundingClientRect(); + const leftCenter = rect.left + rect.width / 2; + const { pageX, pageY: pageY2 } = e2; + const x = pageX - leftCenter; + const y = pageY2 - _downPageY; + this._move(x, y); + }; + const onMouseUp = () => { + document.removeEventListener("mousemove", onMouseMove); + document.removeEventListener("mouseup", onMouseUp); + this._running = true; + requestAnimationFrame(this._run); + }; + document.addEventListener("mousemove", onMouseMove); + document.addEventListener("mouseup", onMouseUp); + }; + this._onTouchStart = (e) => { + e.preventDefault(); + this._running = false; + if (!e.touches[0]) { + return; + } + const { pageY } = e.touches[0]; + const _downPageY = pageY; + this._state.w = 0; + this._state.t = 0; + const onTouchMove = (e2) => { + if (!e2.touches[0]) { + return; + } + const rect = this._domMain.getBoundingClientRect(); + const leftCenter = rect.left + rect.width / 2; + const { pageX, pageY: pageY2 } = e2.touches[0]; + const x = pageX - leftCenter; + const y = pageY2 - _downPageY; + this._move(x, y); + }; + const onTouchEnd = () => { + document.removeEventListener("touchmove", onTouchMove); + document.removeEventListener("touchend", onTouchEnd); + this._running = true; + requestAnimationFrame(this._run); + }; + document.addEventListener("touchmove", onTouchMove); + document.addEventListener("touchend", onTouchEnd); + }; + this._magicForce = () => { + if (Math.random() < 0.1) { + const available = Object.keys(_characters); + const index = Math.floor(Math.random() * available.length); + const _char = available[index]; + this.setCharacter(_char); + } else { + this._state.t = this._state.t + (Math.random() - 0.5) * 150; + this._state.w = this._state.w + (Math.random() - 0.5) * 200; + } + if (!this._running) { + this._running = true; + requestAnimationFrame(this._run); + } + this._magicForceTimeout = window.setTimeout( + this._magicForce, + Math.random() * 3e3 + 2e3 + ); + }; + this.triggetAutoMode = () => { + this._magicForceEnabled = !this._magicForceEnabled; + const icon = this._domCtrlMagic.querySelector("svg"); + if (this._magicForceEnabled) { + icon.classList.add("sakana-widget-icon--rotate"); + } else { + icon.classList.remove("sakana-widget-icon--rotate"); + } + clearTimeout(this._magicForceTimeout); + if (this._magicForceEnabled) { + this._magicForceTimeout = window.setTimeout( + this._magicForce, + Math.random() * 1e3 + 500 + ); + } + }; + this.setState = (state) => { + if (!this._state) { + this._state = {}; + } + this._state = mergeDeep(this._state, cloneDeep(state)); + return this; + }; + this.setCharacter = (name) => { + const targetChar = _characters[name]; + if (!targetChar) { + throw new Error(`invalid character ${name}`); + } + this._char = name; + this._image = targetChar.image; + this.setState(targetChar.initialState); + if (this._domImage) { + this._domImage.style.backgroundImage = `url('${this._image}')`; + } + return this; + }; + this.nextCharacter = () => { + const _chars = Object.keys(_SakanaWidget.getCharacters()).sort(); + const curCharIdx = _chars.indexOf(this._char); + const nextCharIdx = (curCharIdx + 1) % _chars.length; + const nextChar = _chars[nextCharIdx]; + this.setCharacter(nextChar); + return this; + }; + this._onResize = (rect) => { + let newSize = Math.min(rect.width, rect.height); + newSize = Math.max(120, newSize); + this._updateSize(newSize); + this._updateLimit(newSize); + }; + this.mount = (el) => { + let _el = null; + if (typeof el === "string") { + _el = document.querySelector(el); + } + if (!_el) { + throw new Error("Invalid mounting element"); + } + const parent = _el.parentNode; + if (!parent) { + throw new Error("Invalid mounting element parent"); + } + this._domImage.addEventListener("mousedown", this._onMouseDown); + this._domImage.addEventListener("touchstart", this._onTouchStart); + this._domCtrlPerson.addEventListener("click", this.nextCharacter); + this._domCtrlMagic.addEventListener("click", this.triggetAutoMode); + this._domCtrlClose.addEventListener("click", this.unmount); + if (this._options.autoFit) { + this._onResize(this._domWrapper.getBoundingClientRect()); + this._resizeObserver = new ResizeObserver( + throttle((entries) => { + if (!entries || !entries[0]) + return; + this._onResize(entries[0].contentRect); + }) + ); + this._resizeObserver.observe(this._domWrapper); + } + const _newEl = _el.cloneNode(false); + _newEl.appendChild(this._domWrapper); + parent.replaceChild(_newEl, _el); + requestAnimationFrame(this._run); + return this; + }; + this.unmount = () => { + this._domImage.removeEventListener("mousedown", this._onMouseDown); + this._domImage.removeEventListener("touchstart", this._onTouchStart); + this._domCtrlPerson.removeEventListener("click", this.nextCharacter); + this._domCtrlMagic.removeEventListener("click", this.triggetAutoMode); + this._domCtrlClose.removeEventListener("click", this.unmount); + this._resizeObserver && this._resizeObserver.disconnect(); + const _el = this._domWrapper.parentNode; + if (!_el) { + throw new Error("Invalid mounting element"); + } + _el.removeChild(this._domWrapper); + return this; + }; + this._options = cloneDeep( + defaultOptions + ); + this._options = mergeDeep(this._options, options); + this.setCharacter(this._options.character); + this._updateDom(); + this._updateSize(this._options.size); + this._updateLimit(this._options.size); + } +}; +let SakanaWidget = _SakanaWidget; +SakanaWidget.getCharacter = (name) => { + const _char = _characters[name]; + return _char ? cloneDeep(_char) : null; +}; +SakanaWidget.getCharacters = () => { + return cloneDeep(_characters); +}; +SakanaWidget.registerCharacter = (name, character) => { + const _char = cloneDeep(character); + let inertia = _char.initialState.i; + inertia = Math.min(0.5, Math.max(0, inertia)); + _char.initialState.i = inertia; + _characters[name] = _char; +}; +/* harmony default export */ const src_0 = (SakanaWidget); + +})(); + +__webpack_exports__ = __webpack_exports__["default"]; +/******/ return __webpack_exports__; +/******/ })() +; +}); \ No newline at end of file diff --git a/js/sakana-widget/sakana.min.js b/js/sakana-widget/sakana.min.js new file mode 100644 index 00000000..54d70758 --- /dev/null +++ b/js/sakana-widget/sakana.min.js @@ -0,0 +1,3 @@ +(function(V,A){typeof exports=="object"&&typeof module=="object"?module.exports=A():typeof define=="function"&&define.amd?define("SakanaWidget",[],A):typeof exports=="object"?exports.SakanaWidget=A():V.SakanaWidget=A()})(self,()=>(()=>{"use strict";var et={800:(v,d,u)=>{u.d(d,{Z:()=>y});var b=u(918),h=u.n(b),s=u(267),c=u.n(s),l=c()(h());l.push([v.id,".sakana-widget *,.sakana-widget *::before,.sakana-widget *::after{box-sizing:border-box}.sakana-widget-wrapper{pointer-events:none;position:relative;width:100%;height:100%}.sakana-widget-app{pointer-events:none;position:relative}.sakana-widget-canvas{z-index:10;pointer-events:none;position:absolute;top:50%;left:50%;transform:translate(-50%, -50%)}.sakana-widget-main{z-index:20;pointer-events:none;position:absolute;display:flex;flex-direction:column;justify-content:space-between;align-items:center}.sakana-widget-img{z-index:40;cursor:move;pointer-events:auto;position:relative;background:no-repeat 50% 50%;background-size:cover}.sakana-widget-ctrl{z-index:30;cursor:pointer;pointer-events:auto;position:relative;height:24px;width:112px;display:flex;border-radius:4px;background-color:#ddd;box-shadow:0 8px 24px rgba(0,0,0,.1)}.sakana-widget-ctrl-item{height:24px;width:28px;display:flex;justify-content:center;align-items:center;color:#555;background-color:rgba(0,0,0,0)}.sakana-widget-ctrl-item:hover{color:#555;background-color:rgba(255,255,255,.25)}.sakana-widget-icon{height:18px;width:18px}.sakana-widget-icon--rotate{animation:sakana-widget-spin 2s linear infinite}@keyframes sakana-widget-spin{100%{transform:rotate(360deg)}}",""]);const y=l},267:v=>{v.exports=function(d){var u=[];return u.toString=function(){return this.map(function(h){var s="",c=typeof h[5]!="undefined";return h[4]&&(s+="@supports (".concat(h[4],") {")),h[2]&&(s+="@media ".concat(h[2]," {")),c&&(s+="@layer".concat(h[5].length>0?" ".concat(h[5]):""," {")),s+=d(h),c&&(s+="}"),h[2]&&(s+="}"),h[4]&&(s+="}"),s}).join("")},u.i=function(h,s,c,l,y){typeof h=="string"&&(h=[[null,h,void 0]]);var S={};if(c)for(var x=0;x0?" ".concat(p[5]):""," {").concat(p[1],"}")),p[5]=y),s&&(p[2]&&(p[1]="@media ".concat(p[2]," {").concat(p[1],"}")),p[2]=s),l&&(p[4]?(p[1]="@supports (".concat(p[4],") {").concat(p[1],"}"),p[4]=l):p[4]="".concat(l)),u.push(p))}},u}},918:v=>{v.exports=function(d){return d[1]}},379:v=>{var d=[];function u(s){for(var c=-1,l=0;l{var d={};function u(h){if(typeof d[h]=="undefined"){var s=document.querySelector(h);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(c){s=null}d[h]=s}return d[h]}function b(h,s){var c=u(h);if(!c)throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");c.appendChild(s)}v.exports=b},216:v=>{function d(u){var b=document.createElement("style");return u.setAttributes(b,u.attributes),u.insert(b,u.options),b}v.exports=d},565:(v,d,u)=>{function b(h){var s=u.nc;s&&h.setAttribute("nonce",s)}v.exports=b},795:v=>{function d(h,s,c){var l="";c.supports&&(l+="@supports (".concat(c.supports,") {")),c.media&&(l+="@media ".concat(c.media," {"));var y=typeof c.layer!="undefined";y&&(l+="@layer".concat(c.layer.length>0?" ".concat(c.layer):""," {")),l+=c.css,y&&(l+="}"),c.media&&(l+="}"),c.supports&&(l+="}");var S=c.sourceMap;S&&typeof btoa!="undefined"&&(l+=` +/*# sourceMappingURL=data:application/json;base64,`.concat(btoa(unescape(encodeURIComponent(JSON.stringify(S))))," */")),s.styleTagTransform(l,h,s.options)}function u(h){if(h.parentNode===null)return!1;h.parentNode.removeChild(h)}function b(h){var s=h.insertStyleElement(h);return{update:function(l){d(s,h,l)},remove:function(){u(s)}}}v.exports=b},589:v=>{function d(u,b){if(b.styleSheet)b.styleSheet.cssText=u;else{for(;b.firstChild;)b.removeChild(b.firstChild);b.appendChild(document.createTextNode(u))}}v.exports=d}},V={};function A(v){var d=V[v];if(d!==void 0)return d.exports;var u=V[v]={id:v,exports:{}};return et[v](u,u.exports,A),u.exports}A.n=v=>{var d=v&&v.__esModule?()=>v.default:()=>v;return A.d(d,{a:d}),d},A.d=(v,d)=>{for(var u in d)A.o(d,u)&&!A.o(v,u)&&Object.defineProperty(v,u,{enumerable:!0,get:d[u]})},A.o=(v,d)=>Object.prototype.hasOwnProperty.call(v,d),A.nc=void 0;var P={};return(()=>{A.d(P,{default:()=>Gt});var v=A(379),d=A.n(v),u=A(795),b=A.n(u),h=A(569),s=A.n(h),c=A(565),l=A.n(c),y=A(216),S=A.n(y),x=A(589),O=A.n(x),E=A(800),p={};p.styleTagTransform=O(),p.setAttributes=l(),p.insert=s().bind(null,"head"),p.domAPI=b(),p.insertStyleElement=S();var T=d()(E.Z,p);const z=E.Z&&E.Z.locals?E.Z.locals:void 0;var R=[],yt=function(){return R.some(function(n){return n.activeTargets.length>0})},Et=function(){return R.some(function(n){return n.skippedTargets.length>0})},nt="ResizeObserver loop completed with undelivered notifications.",Rt=function(){var n;typeof ErrorEvent=="function"?n=new ErrorEvent("error",{message:nt}):(n=document.createEvent("Event"),n.initEvent("error",!1,!1),n.message=nt),window.dispatchEvent(n)},F;(function(n){n.BORDER_BOX="border-box",n.CONTENT_BOX="content-box",n.DEVICE_PIXEL_CONTENT_BOX="device-pixel-content-box"})(F||(F={}));var M=function(n){return Object.freeze(n)},Ot=function(){function n(t,e){this.inlineSize=t,this.blockSize=e,M(this)}return n}(),rt=function(){function n(t,e,r,i){return this.x=t,this.y=e,this.width=r,this.height=i,this.top=this.y,this.left=this.x,this.bottom=this.top+this.height,this.right=this.left+this.width,M(this)}return n.prototype.toJSON=function(){var t=this,e=t.x,r=t.y,i=t.top,a=t.right,o=t.bottom,m=t.left,f=t.width,g=t.height;return{x:e,y:r,top:i,right:a,bottom:o,left:m,width:f,height:g}},n.fromRect=function(t){return new n(t.x,t.y,t.width,t.height)},n}(),X=function(n){return n instanceof SVGElement&&"getBBox"in n},it=function(n){if(X(n)){var t=n.getBBox(),e=t.width,r=t.height;return!e&&!r}var i=n,a=i.offsetWidth,o=i.offsetHeight;return!(a||o||n.getClientRects().length)},st=function(n){var t;if(n instanceof Element)return!0;var e=(t=n==null?void 0:n.ownerDocument)===null||t===void 0?void 0:t.defaultView;return!!(e&&n instanceof e.Element)},Lt=function(n){switch(n.tagName){case"INPUT":if(n.type!=="image")break;case"VIDEO":case"AUDIO":case"EMBED":case"OBJECT":case"CANVAS":case"IFRAME":case"IMG":return!0}return!1},N=typeof window!="undefined"?window:{},W=new WeakMap,at=/auto|scroll/,Tt=/^tb|vertical/,Ut=/msie|trident/i.test(N.navigator&&N.navigator.userAgent),L=function(n){return parseFloat(n||"0")},I=function(n,t,e){return n===void 0&&(n=0),t===void 0&&(t=0),e===void 0&&(e=!1),new Ot((e?t:n)||0,(e?n:t)||0)},ot=M({devicePixelContentBoxSize:I(),borderBoxSize:I(),contentBoxSize:I(),contentRect:new rt(0,0,0,0)}),ct=function(n,t){if(t===void 0&&(t=!1),W.has(n)&&!t)return W.get(n);if(it(n))return W.set(n,ot),ot;var e=getComputedStyle(n),r=X(n)&&n.ownerSVGElement&&n.getBBox(),i=!Ut&&e.boxSizing==="border-box",a=Tt.test(e.writingMode||""),o=!r&&at.test(e.overflowY||""),m=!r&&at.test(e.overflowX||""),f=r?0:L(e.paddingTop),g=r?0:L(e.paddingRight),C=r?0:L(e.paddingBottom),w=r?0:L(e.paddingLeft),k=r?0:L(e.borderTopWidth),$t=r?0:L(e.borderRightWidth),te=r?0:L(e.borderBottomWidth),ee=r?0:L(e.borderLeftWidth),bt=w+g,xt=f+C,$=ee+$t,tt=k+te,Ct=m?n.offsetHeight-tt-n.clientHeight:0,wt=o?n.offsetWidth-$-n.clientWidth:0,ne=i?bt+$:0,re=i?xt+tt:0,Y=r?r.width:L(e.width)-ne-wt,Z=r?r.height:L(e.height)-re-Ct,ie=Y+bt+wt+$,se=Z+xt+Ct+tt,St=M({devicePixelContentBoxSize:I(Math.round(Y*devicePixelRatio),Math.round(Z*devicePixelRatio),a),borderBoxSize:I(ie,se,a),contentBoxSize:I(Y,Z,a),contentRect:new rt(w,f,Y,Z)});return W.set(n,St),St},dt=function(n,t,e){var r=ct(n,e),i=r.borderBoxSize,a=r.contentBoxSize,o=r.devicePixelContentBoxSize;switch(t){case F.DEVICE_PIXEL_CONTENT_BOX:return o;case F.BORDER_BOX:return i;default:return a}},Mt=function(){function n(t){var e=ct(t);this.target=t,this.contentRect=e.contentRect,this.borderBoxSize=M([e.borderBoxSize]),this.contentBoxSize=M([e.contentBoxSize]),this.devicePixelContentBoxSize=M([e.devicePixelContentBoxSize])}return n}(),ht=function(n){if(it(n))return 1/0;for(var t=0,e=n.parentNode;e;)t+=1,e=e.parentNode;return t},kt=function(){var n=1/0,t=[];R.forEach(function(o){if(o.activeTargets.length!==0){var m=[];o.activeTargets.forEach(function(g){var C=new Mt(g.target),w=ht(g.target);m.push(C),g.lastReportedSize=dt(g.target,g.observedBox),wn?e.activeTargets.push(i):e.skippedTargets.push(i))})})},It=function(){var n=0;for(ut(n);yt();)n=kt(),ut(n);return Et()&&Rt(),n>0},j,lt=[],Bt=function(){return lt.splice(0).forEach(function(n){return n()})},zt=function(n){if(!j){var t=0,e=document.createTextNode(""),r={characterData:!0};new MutationObserver(function(){return Bt()}).observe(e,r),j=function(){e.textContent="".concat(t?t--:t++)}}lt.push(n),j()},Ft=function(n){zt(function(){requestAnimationFrame(n)})},Q=0,Nt=function(){return!!Q},Vt=250,Pt={attributes:!0,characterData:!0,childList:!0,subtree:!0},vt=["resize","load","transitionend","animationend","animationstart","animationiteration","keyup","keydown","mouseup","mousedown","mouseover","mouseout","blur","focus"],pt=function(n){return n===void 0&&(n=0),Date.now()+n},q=!1,Wt=function(){function n(){var t=this;this.stopped=!0,this.listener=function(){return t.schedule()}}return n.prototype.run=function(t){var e=this;if(t===void 0&&(t=Vt),!q){q=!0;var r=pt(t);Ft(function(){var i=!1;try{i=It()}finally{if(q=!1,t=r-pt(),!Nt())return;i?e.run(1e3):t>0?e.run(t):e.start()}})}},n.prototype.schedule=function(){this.stop(),this.run()},n.prototype.observe=function(){var t=this,e=function(){return t.observer&&t.observer.observe(document.body,Pt)};document.body?e():N.addEventListener("DOMContentLoaded",e)},n.prototype.start=function(){var t=this;this.stopped&&(this.stopped=!1,this.observer=new MutationObserver(this.listener),this.observe(),vt.forEach(function(e){return N.addEventListener(e,t.listener,!0)}))},n.prototype.stop=function(){var t=this;this.stopped||(this.observer&&this.observer.disconnect(),vt.forEach(function(e){return N.removeEventListener(e,t.listener,!0)}),this.stopped=!0)},n}(),J=new Wt,ft=function(n){!Q&&n>0&&J.start(),Q+=n,!Q&&J.stop()},Qt=function(n){return!X(n)&&!Lt(n)&&getComputedStyle(n).display==="inline"},Dt=function(){function n(t,e){this.target=t,this.observedBox=e||F.CONTENT_BOX,this.lastReportedSize={inlineSize:0,blockSize:0}}return n.prototype.isActive=function(){var t=dt(this.target,this.observedBox,!0);return Qt(this.target)&&(this.lastReportedSize=t),this.lastReportedSize.inlineSize!==t.inlineSize||this.lastReportedSize.blockSize!==t.blockSize},n}(),Ht=function(){function n(t,e){this.activeTargets=[],this.skippedTargets=[],this.observationTargets=[],this.observer=t,this.callback=e}return n}(),D=new WeakMap,At=function(n,t){for(var e=0;e=0&&(a&&R.splice(R.indexOf(r),1),r.observationTargets.splice(i,1),ft(-1))},n.disconnect=function(t){var e=this,r=D.get(t);r.observationTargets.slice().forEach(function(i){return e.unobserve(t,i.target)}),r.activeTargets.splice(0,r.activeTargets.length)},n}(),_t=function(){function n(t){if(arguments.length===0)throw new TypeError("Failed to construct 'ResizeObserver': 1 argument required, but only 0 present.");if(typeof t!="function")throw new TypeError("Failed to construct 'ResizeObserver': The callback provided as parameter 1 is not a function.");H.connect(this,t)}return n.prototype.observe=function(t,e){if(arguments.length===0)throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': 1 argument required, but only 0 present.");if(!st(t))throw new TypeError("Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element");H.observe(this,t,e)},n.prototype.unobserve=function(t){if(arguments.length===0)throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': 1 argument required, but only 0 present.");if(!st(t))throw new TypeError("Failed to execute 'unobserve' on 'ResizeObserver': parameter 1 is not of type 'Element");H.unobserve(this,t)},n.prototype.disconnect=function(){H.disconnect(this)},n.toString=function(){return"function ResizeObserver () { [polyfill code] }"},n}();const mt={chisato:{image:"data:image/png;base64,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",initialState:{i:.08,s:.1,d:.99,r:1,y:40,t:0,w:0}},takina:{image:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAMAAAAL34HQAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAMAUExURQAAAAAAAAAAAAAAAAAAAAEBAQAAAAEBAQAAAAAAAAAAAAEBAQAAAAABAQAAAAAAAAAAAAAAAAAAAAICAgEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAvLwgJChAODAQIC0FBQf///wAAAP/53z8/QCVAU0dHR0JCQUNDQ0lJSSpIXURERDw9PUxMS0ZGRipKYChGWyZCVgECAydDWAEECCM+UShFWiVBVP/33ggIBxEQD///7Dc3NwYMDTQ0NA4aIg0MCyA5SytMYxQUFCopKgYEBAgPEx4eHhgsOSQlJhAdJTEwMP//8hobG//23Tk6OyI8Th42RiMiIQwXHRYpNP//9v/95BEgKhovPhsyQv//+k5OTxgYFy5PZv//6C8zOAoTGCwsLQAJFOPBjlRSTxwVD//64TQ4PBMkL8+xhConJAMYJgEIDyZHXdm4iMipfcSkdm1oXQMOFicCAJORj5uGaSwvNIh2Xe7Ll1xWTO7t7bQZAECX1LOZcwIRHRYFAwwqQ8zKycyugXBtaQkgMd+9jGBgYfby3FhaXHhzZfn4+K6urePk5tTS0SM2OS4lHJeAXt/axNHLt0BDSoyHeby6unt5d4KCgnV0c+DJoxs/L9m0gKeilO7q1MjDsOTElZ+Zi/z7+nqld/Py8mVeVZ2cm//jT6WPbzs0LBEoHn15b58XAL0dADiHvzUrC6ako9nY1zw/Q/fqzLStm/LSoeXhzNfRvPbjvJUTAKoYAHELAFYFAGNnbjBSakREQUM/NvvWn4cNAKGqvcPFyZSQg+Df3XtpU7ixoEA0Hh0oK1Z4VnGbb//bS+bRrjgGACcrM9S4j1JGNU1HQNaxfHBeSICIl//40WtygZGaqmaMZNGtfNiyO2lVFL64prazsVdFEnqAjoSzgRVOdzNPN6mLLntmHiFNOEMFAGJRPEZfQylBL9CtPDhWPP/0VZZ6KvvPRhtfkO7GRiJPOylcRkRlSSpypNUhAP/tUztNPS5NTIJrLqGHRyU6R9SooFgAAAAjdFJOUwDFLkBd0RO9CiWI5bDya4+mN1Pe+Px8m+1kckoaBJTs9fHs+txt3gAAE09JREFUeNrtmmd0E9e2x+Nu4447LUU6jEeakUajbiSr92pVF9mybGEbG2wMNq70ZjqhBkioAQKEJCR0EkIgN6QX0ntPbnv33fbqp3dGFlguJHAfC/JBf3stL2nJMz//zz777L3H990XVVRRRRVVVFFFFVVUUUUVVVRRRRVVVFFFFVVUUUUVVVRRRRXVvVJySlx28m8NKjsjKTU3N+W3BRWblsfXmqVTfltURelAa0VpD8TFFuXn50/Iz5gY+xugGgf4ZpQgdOmpUqnfL9VKJaAwqyjuHgdaJtBbCZTJtJplDISD0lhMmc7uV4GkjEn3kCoeACvBQhAajcnhcFiUOCiBycx2fULGPXMssRCYIRWNRmMwGbRBMZhMFlxVh1GfNOmeBZYWRRHaKDGZCpnCD2LujV8puUCBMUZT0RgcmSo1ISfr3mBNAEaUNQYVDWES5tTYxMn3Zg1j+Gws0qMILhZmLLo3cRWfnCNlRUYWg8Wi3XiJMqRx94Bqop6fmapDmUNhjsgcMHMxw2BMTBdzDxYxyW8EuWw0wiuG1axTOFjYIBgC7Zp494uGdB0m0dOGrSGCKOx+swwdjDcWak6761j5QNFo1rI5w7IVBy6kX2JkYgxIi2AO/fi7jZWlYmNsK5s5PC8wUJRplUodBFxIhMUxJtzlxJWY4Ien8uichSBEI+bWylCYLBBClneXoys71Q6hmKPTO0NmNrvh+Q25EJStGnd3scbnGZlj5XcmauT7tVqVjgOPbhbL/atBn3xHk1s8GBuLhlq1shqUKidgmBHBhMRfi9G8jDvpVq59bCwmZtSyMBaDiQQdRKMs91eCa4o7mJ5yJ926CRYNs0p0GIwrplTlRpmS/F+8TIaKUyMtuJNuSSMzfIRYDJWUg3JqCG1altauz/rFninXCruAvDvXksTmqBxjY9Ewt95Rg1jd+piYPABSxxXd9K6TY+wEjcZR3Tm7JidJHNjYbtU4JFK7BAB5vbLF4qmX81OTxmWPXa7pHcRLDMx8B+3KAgpijPKPgWJsPwDC+hafWlQi5omcarVJKSxMKhq+JZOzM8YVpJtrzB3H2WxJTlJMSFmZBeOKiibGxqZMnvyvVR8TgBtljkrxHAKxA1BvUvO4JMkVC8RcHCe5JU6Th5+TPwSWXZDwkMUrlDAw6Z6tbJodtHiVUBalQW4Q5qWnFqYmJMRkZWUWTUy83eAqlCIjg4uFwW0IOn0CTa1Gg0MiKIoLvuC5LMKcCWEHxj/U4hKRLuCu0QW3nOU4FKCSFJfweLwSkYiy12cyeS0WS71BnpuadpvpNo2viAwuhIYSqMMP2qrIS7VctWlla+d0Sm2drSurRBoNKVZb+DGDQVRQSdbWkp16Wo2wv/xso4KjEvI0Aigxl8vFSRIXc8U8Aa+kuNhpqs/Lv70UAfwsTiQUE3ZgQi/3ksbVygdAIvXPoqRza1VtwsUuEtrnM6SH6vuJchdZ64Nmsfnb6YEVZswNqrjFEeKV8ChIMU7iXG/e7fcXSDjQMYJlVQF+pai21iUE+lmNXd8ue3Xd4+vWrXt8/sZHumqkYLpLg5MllSAz1AbIvaZOCVJjNO6jl283cxzAIhYUj5CoGJqG11bl3h5WHHBjoYaahmHsIISyOMlL4sWgadW36+gj9NwOI1iJwxWq4lM1xeQEAOBvE6CfXl56QIGwpHKuJrRqESrB1a2LRcXy2x1QZeipdgy2XrCvB0KLE8dr1QAc3kAfS/M7wGKuQKDxCYtCtS3QswlE379vS/WBIBubBXw8kYCkdq+YVwIFqTRL206cUNbn3O5mvK9AS2PBBlohFXZ6S0ixWGMCqmfpN1MX3G8lPI2LOpqzc4EdJWRaPjhN366Dda5eaPBYWkxVLrVIDMMQGlu7VPjdO18tyb2tnZgyfsKUzKw87UkWpjCsFOE43OCQqmnZEMahjY8P53oC+HCRQOONSYbHDoCdiIIP7OdWEz00Dgdmu5DkhnpLixfiOZcKv/77X3/WT7idXTgFBofKHezv7Wdj7s7ZpAC6rvEB/8Yhhl3PjsTqAos1PJGYq4THd5of5TAdOkXN9g4FQmOgVjBMfLkBfPf3I/88cRu9U3wSOHZ8z+lvtm4JfHpUxvZ7SGoX4SIgDVOtZzMx9q5lIxZxbedSuZpLfdBQlFEog8UPE0NpwSCNKq8RvsQ4nKzpqyPv/P7Wx8TZaeDy6b3V9OpqW7Xt/FykR1vJ5RUXC/A28MjgrsN0L+7YuXFkaHWAfzxTb+HyRDzSlAe0oSkBg0FjI4O1thuwd+1AJUN+/e3IkZ/1t1y5jk+XbF9NL6+YNnXqjNJTDUdZOpWXW1JcQraAHeEIkj4yOt6XHQM/LnxmqYQnKObN9r43z8wZdqAiHFQr4TTuWr9+FdwGlN54569/acq65aQA3Pvo1TPKppWVTS1dvX9O/8mgsApiCXCgmg9vv4EAbPhz53Cy+SuA8B8Ln1moAWpxsVjU+fLFNzkjznmUowVAu2bFzq6dq4x8PfjuyF9O3NLUbtKEWHjizDpLD5RBqmkVkGp3d/M2ndAFA4brA6vg/XcAaRfFsWZnJNVGK1j5DKR6phW4uCViX9PL73lHTetQjp9ySeVgIwSHYZeckKbdUu+bBlIzUyEVtGpa2YxA4NT7u+cQdahRCB3g4a1gPX0dDWCDyfTZxsikugwsXUhRrQTuKoFg9sr3Lsx7mBg12kQJdziutEa7Cv6Iv7UxKZR0yyBVRWD1u8u/HOitQzhNnQIBXMPp4Dn6KtB1fdWC6yOwHj8GsRb+d1vTs2sWl4hnt/7xqXkPY6MnrjXmTcci92LqLQR8fuiTV+EKhqjOvz93d0O3o5nFaTJwBaF9uG4+2HWDRFcTuYrE9IULfwRNG+k103nc2YsvPj8WFqfHv7mv1x8JlnlrVKq9dEg1LRB4d87c9oFudh1snP2d4pBb+ldXgaFUtRNEpq0d039cCj7cQD/E6BTg6rYXFoyFhRmbFl3pm/Mnya1zDVKBjtLSshDV3Lnt7b3NdTQGC9EqxTwYW0o+WwKeuAGyQbIiAusRAHQHqLVlQSyf8IUFS8bC0kl6zww09HWrbpVrQvhD++hTy6YFZjw6Z047jCtIReOwpRbYSHBrW4Fq+6xVQySrjIci6hrHitBBNB/rFJAm/ssX9BFYbGRwU7KYWunmvoH9fR/ItfobXON+ncq4tzpENXfOzIHu5jqYo8NYOLkSXN5afVm3LmL37Yg4tcPvv6poFcOPXnh+yC0Gch0LNuJt4OOBM32bzSdlD6Re54q/eXkc1gFbRVlpBUXVsOilntDFQlhkyXTQYaOv9oOItECA+aNy/SPCpTjeqr8wtIgMRNbRKAvnMAxz89/YPHOzsbkxWFCUlhu6aXr2zaakg1As3fbyQCBE1d7ecQ25gVVLCsH2cnrpVT+ISAuvgjWjsK4CNcQCFFY4bzGs2NbtQSQ8ymdY7ULpG5uCNEKWBEv+zKT0my9j0SCVtUsHztGnUVQzG446mgf/QojVolkMYDxPPdCsAKwIhhXglRFUj1uFYjHZuuSpBUvCWZ7JNnbR91gdg8MLs1QqsffY7UwOxk4YHH7lTymIu9kxCOpbKuutMAc3njoDqZa3zzzccz3ZsP0WJeig0z+dc6yHkPCfi6Aw60ZgPQs6YS+7eN7zC+ZdPxODjXvppxEFY7CIMCNmYK7BmAimSPqlLqKgIGNKDqjkkRqxhbKsu2H5zOWUWY7rWIidD2atpp//sr8OXiwiodLpr4AVwyNLCixc3Nk576kF71lCYyiGo+d0tW0LGmRRgzG7VKFzUyUPjckx/8IOnFgISeorLTyyxMnlGuCLTe0Ny0NmhfcRQh389rPlZ778uI7NYHGA/VBklSyJLCS6VOBJ2IeEsP5Yf5LqMRFdx+rSwIwOIzWxRmV+o92vk8FtgCI5N38UmUJRyZ1VXrFAYKqqbaHs2rwfRlb3DbNo0CDJPlvfl6/1NMMrY8OCHvoz9GrZSwA89od6FymCWE9flJyktqIjuKd8xgzbOabRwWQyMaPKKPFDJgZmvXmllRxDcVRxPZUCAddUKRBJBu0amNNYd716w9hAuy+w/6PNdRQVDb6sGR7k4cpmh0wPWg2PPWaowslWiPUCeJiaFCiwrbapZTNsWxt1QYWMqZBK9HaEw2CgitSbpquCUCfCLZa3QLdcFldtKLo2Xxl4Da7X4ENDrMZo/2bqwO6j7LrBjUWo+CNK+HUbnnsCg8cJbBIhltyLa1rnXXj6Kb0FZdGQnjVbSqfCk9+2+iqikCkUQXNPc3NdM8JCrfqCSTfbgFDeSz6+CVerRR5vrVpI2TWzt84RTg4c1Ojed37ml8sPXwu7RyhA4/C6FFGpgLDVJyBrncInIVatS6h/+enn57XRUBpiPj4jMI2qSGyBLa8f2HF8xeEPGRyUVufgEDJpasYYI664PIpK6LxUxXcJTC7coKwlPdRbClaYisUyS8CmMw1zG7qvg9JQJtAPy1aN0KelAg3sjbgQ6w9yU60SLIFYF/nNGINtPlBeQZUkZWUBW2kF7A72vr9o0fJF/fC4JZhuScyE2BEF6qSckFkWgabKUCJqUWs8Bh7po6p/IQ0ND7OoDkq6aKB9ZkcPMlQGgODQZjy0E1g0OCkWiYoHsZSuKpVd/sLTC14Ab2JM80vnYGhNowSL8ECgtNRWcX5g9+7lvbSeZg7hUIHchPjho9HB1O7DuS6LQF2pJlsMamdJyK4gEbKGYAPJn/8NvLa/YRHRPFTLYZIbm3H+E1bQ5jNVKn1Ud0th/ceTlW3uZiHEugA8mELxemnFIFXIMSgId+rRmR/tXnSYXbdNRtURw/rXKeHW24nznFVcn1JNeg0uta+Kii4pB6YcBsHRg7d+eAu80dB3FHEMVU2EDJjD9fwsANoMQk+LUInDRlIsMjz5n08CKbqt7eLzC56a13bNero8cIPquioCFacebd89t/twaDWGFRDhYxC0wMa0RICb6tVkFey7KtVK6l0dwWARbCHQfvHDF3L93L6jjAgsRo0OKGDt8MoqPuis9HkspKbeALvDYrHAUv+YRO+oaRbC02fBRfDmHltp2SissqlU9/Lu/oH2XqoczEkeGe5UwJPFxSU83GRwkWp+C1mprgqVzghB6IB1z6yfDr79E/j4yhx47kQ80iesQNa1SwVWcklSbKmsrYVYYoFYI6IiU1fT00gsefl/YOZ6qbp8NBUlCFZadv7TRdS9Ip6TJuZcN4syv7gYN3mceIlcyTX5RHLqfXOjEVj30hvlXxx8CzS19/Vec4Qa95BbKMGAf6ZwJY/kinEcYl1SesjZPOdioNr1Igj2NG7Za553cd4SEAzYxqQKOTbDVr0C3iniQUJi2vWyz6UJjeVwr0Usxj0GsdPiNIXs0oL+1XT66+DfD74Ng/7K8v6eOgcbCmGiqMJuUAoXk7UaHMcFTk+919LWsnQ64CuOL6N3ASNtK53eDyQnvj6hfx1WlYMaDVZGPysFICl5ZB6FUvIEYSylQMy1GEoE9U5xuNeopgc+fbRJ/vbBL8Cm/X1z1hLsurpmNhNl6yxCT63HoPZ5Ky2eeoPc0AmtM65aAah5HA1w9sEscAD8/p9HfoYXKa2ASSFQUTF1BFtZWXn1ipykcYnD//dpUCaNiEdNWnGThScQe+vV4krXSv3aPcc/3F5KL3u0vf1P4L8OHvwJ9J7pG5iz6Gh3d/drmyT1lR7vJa/cYJBDJo/SIzTU7FwPq7Cda1Z0PaFlb6HbAtV7tV8fOfIVuFZNt5XbqG8bBTf1hnFlZdXVx2NShqfS5KwQVF6e75JYzIOOCXxeAQ8mLx+ubgGX6XTb6nIbbF/nNixvMrx98OBjYHNfX9+Vhrm9HwRVfGWL14lz1SaTyVu5uLMNAHfjrm83vko/xIbXtJ+jV9tsVO7/6n/f+Rpc3btnLfFhx55vtgQoNkgXCC3rDHppR+qoyVZyKJdmjqvkik0GpZgUwAqCi+M+F5c0gX46vZxOP7X7o4GB/Ve6YXT98LZH/8HHHxzbZNROb/X6XE4uCTs0l9djeHPbNmvdtjU1zdd6iFUM67YXP1vTsZbScSv4/TtH/gbALElhQkKhROu+3H9131m4oKUUXDl9deNYjUUi5CpMTEw3GAqTCj1OLi7yOUUupwAn1ULJ2q3ntp47vbl70cxFvb2bhG+99Wc3yINXh3qo3lDv8VS2KOVye/Oa7z//HaXPP//8k8++XwN6fvfKhk8Ks8Yl5aRlTkmSnHijKWFCXHbKpEkpcRkFCYV87axjlxvXvg7LQtvWYzljtjvJ4xJgwoiPyYy9b2KOXOl5IFf+AN9gcpkMMPdo/fDrwQf9xqa8wgcL5ZL0rLjYlMTESYmJKbFx8fHx4yckFabnGqE533/yyWerarZta77//vsTHrx28sUXjXH3JU+CMZOYXxCfHRHQiSnZ1Iw4My0nCD/7YNrNatPQr4RiblJc0fjsifFxE1LTH0qPyZiSkJSZlpQfmzK+qCg+NiUlPnN0Z5KYkjIxPj8rKSYpKSlrXEb8xNiUSYnZ+Wk5DyT8yiw0OQVeMjb2Hv3fV1RRRRVVVFFFFVVUUUUVVVRR/T/1f8zgwCe5ax55AAAAAElFTkSuQmCC",initialState:{i:.08,s:.1,d:.988,r:12,y:2,t:0,w:0}}},Kt='',Yt='',Zt='',Xt='';function _(n){const t=typeof n;return n!=null&&(t==="object"||t==="function")}function U(n){return typeof window.structuredClone=="function"?window.structuredClone(n):JSON.parse(JSON.stringify(n))}function G(n,t){const e=U(n),r=U(t);return!_(e)||!_(r)||Object.keys(r).forEach(i=>{_(r[i])?(_(e[i])||(e[i]={}),e[i]=G(e[i],r[i])):e[i]=r[i]}),e}function jt(n){let t=null,e;const r=a=>()=>{t=null,n.apply(a,e)};return function(...a){e=a,t===null&&(t=requestAnimationFrame(r(this)))}}function qt(n,t,e=(window.devicePixelRatio||1)*2){const r=t*e;n.width=r,n.height=r;const i=n.getContext("2d");return i?(i.setTransform(1,0,0,1,0,0),i.scale(e,e),i):null}const Jt={size:200,autoFit:!1,character:"chisato",controls:!0,stroke:{color:"#b4b4b4",width:10},threshold:.1,rotate:0},B={};Object.keys(mt).forEach(n=>{const t=mt[n];B[n]=U(t)});const gt=class{constructor(n={}){this._lastRunUnix=Date.now(),this._frameUnix=1e3/60,this._running=!0,this._magicForceTimeout=0,this._magicForceEnabled=!1,this._resizeObserver=null,this._updateLimit=t=>{let e=t/5;e<30?e=30:e>60&&(e=60);const r=t/4,i=-r;this._limit={maxR:e,maxY:r,minY:i}},this._updateSize=t=>{this._options.size=t,this._imageSize=this._options.size/1.25,this._canvasSize=this._options.size*1.5,this._domApp.style.width=`${t}px`,this._domApp.style.height=`${t}px`,this._domCanvas.style.width=`${this._canvasSize}px`,this._domCanvas.style.height=`${this._canvasSize}px`;const e=qt(this._domCanvas,this._canvasSize);if(!e)throw new Error("Invalid canvas context");this._domCanvasCtx=e,this._draw(),this._domMain.style.width=`${t}px`,this._domMain.style.height=`${t}px`,this._domImage.style.width=`${this._imageSize}px`,this._domImage.style.height=`${this._imageSize}px`,this._domImage.style.transformOrigin=`50% ${t}px`},this._updateDom=()=>{const t=document.createElement("div");t.className="sakana-widget-wrapper",this._domWrapper=t;const e=document.createElement("div");e.className="sakana-widget-app",this._domApp=e,t.appendChild(e);const r=document.createElement("canvas");r.className="sakana-widget-canvas",this._domCanvas=r,e.appendChild(r);const i=document.createElement("div");i.className="sakana-widget-main",this._domMain=i,e.appendChild(i);const a=document.createElement("div");a.className="sakana-widget-img",a.style.backgroundImage=`url('${this._image}')`,this._domImage=a,i.appendChild(a);const o=document.createElement("div");o.className="sakana-widget-ctrl",this._options.controls&&i.appendChild(o);const m="sakana-widget-ctrl-item",f=document.createElement("div");f.className=m,f.innerHTML=Zt,this._domCtrlPerson=f,o.appendChild(f);const g=document.createElement("div");g.className=m,g.innerHTML=Xt,this._domCtrlMagic=g,o.appendChild(g);const C=document.createElement("a");C.className=m,C.href="//github.com/dsrkafuu/sakana-widget",C.target="_blank",C.innerHTML=Yt,o.appendChild(C);const w=document.createElement("div");w.className=m,w.innerHTML=Kt,this._domCtrlClose=w,o.appendChild(w)},this._calcCenterPoint=(t,e,r,i)=>{const a=Math.PI/180*t,o=Math.cos(a),m=Math.sin(a),f=m*e+o*r-m*i,g=o*e-o*i-m*r;return{nx:f,ny:g}},this._draw=()=>{const{r:t,y:e}=this._state,{size:r,controls:i,stroke:a}=this._options,o=this._domImage,m=this._imageSize,f=this._domCanvasCtx,g=t*1;o.style.transform=`rotate(${t}deg) translateX(${g}px) translateY(${e}px)`,f.clearRect(0,0,this._canvasSize,this._canvasSize),f.save(),f.translate(this._canvasSize/2,r+(this._canvasSize-r)/2),f.strokeStyle=a.color,f.lineWidth=a.width,f.lineCap="round",f.beginPath(),i?f.moveTo(0,-10):f.moveTo(0,10);const C=r-m/2,{nx:w,ny:k}=this._calcCenterPoint(t,C,g,e);f.lineTo(w,-k),f.stroke(),f.restore()},this._run=()=>{let t=this._options.rotate;t=Math.min(120,Math.max(0,t));const e=this._options.threshold;if(!this._running)return;let{r,y:i,t:a,w:o}=this._state;const{d:m,i:f}=this._state,g=Date.now();let C=f;const w=g-this._lastRunUnix;if(w<16&&(C=f/this._frameUnix*w),this._lastRunUnix=g,o=o-r*2-t,r=r+o*C*1.2,this._state.w=o*m,this._state.r=r,a=a-i*2,i=i+a*C*2,this._state.t=a*m,this._state.y=i,Math.max(Math.abs(this._state.w),Math.abs(this._state.r),Math.abs(this._state.t),Math.abs(this._state.y)){const{maxR:r,maxY:i,minY:a}=this._limit;let o=t*this._state.s;o=Math.max(-r,o),o=Math.min(r,o),e=e*this._state.s*2,e=Math.max(a,e),e=Math.min(i,e),this._state.r=o,this._state.y=e,this._state.w=0,this._state.t=0,this._draw()},this._onMouseDown=t=>{t.preventDefault(),this._running=!1;const{pageY:e}=t,r=e;this._state.w=0,this._state.t=0;const i=o=>{const m=this._domMain.getBoundingClientRect(),f=m.left+m.width/2,{pageX:g,pageY:C}=o,w=g-f,k=C-r;this._move(w,k)},a=()=>{document.removeEventListener("mousemove",i),document.removeEventListener("mouseup",a),this._running=!0,requestAnimationFrame(this._run)};document.addEventListener("mousemove",i),document.addEventListener("mouseup",a)},this._onTouchStart=t=>{if(t.preventDefault(),this._running=!1,!t.touches[0])return;const{pageY:e}=t.touches[0],r=e;this._state.w=0,this._state.t=0;const i=o=>{if(!o.touches[0])return;const m=this._domMain.getBoundingClientRect(),f=m.left+m.width/2,{pageX:g,pageY:C}=o.touches[0],w=g-f,k=C-r;this._move(w,k)},a=()=>{document.removeEventListener("touchmove",i),document.removeEventListener("touchend",a),this._running=!0,requestAnimationFrame(this._run)};document.addEventListener("touchmove",i),document.addEventListener("touchend",a)},this._magicForce=()=>{if(Math.random()<.1){const t=Object.keys(B),e=Math.floor(Math.random()*t.length),r=t[e];this.setCharacter(r)}else this._state.t=this._state.t+(Math.random()-.5)*150,this._state.w=this._state.w+(Math.random()-.5)*200;this._running||(this._running=!0,requestAnimationFrame(this._run)),this._magicForceTimeout=window.setTimeout(this._magicForce,Math.random()*3e3+2e3)},this.triggetAutoMode=()=>{this._magicForceEnabled=!this._magicForceEnabled;const t=this._domCtrlMagic.querySelector("svg");this._magicForceEnabled?t.classList.add("sakana-widget-icon--rotate"):t.classList.remove("sakana-widget-icon--rotate"),clearTimeout(this._magicForceTimeout),this._magicForceEnabled&&(this._magicForceTimeout=window.setTimeout(this._magicForce,Math.random()*1e3+500))},this.setState=t=>(this._state||(this._state={}),this._state=G(this._state,U(t)),this),this.setCharacter=t=>{const e=B[t];if(!e)throw new Error(`invalid character ${t}`);return this._char=t,this._image=e.image,this.setState(e.initialState),this._domImage&&(this._domImage.style.backgroundImage=`url('${this._image}')`),this},this.nextCharacter=()=>{const t=Object.keys(gt.getCharacters()).sort(),r=(t.indexOf(this._char)+1)%t.length,i=t[r];return this.setCharacter(i),this},this._onResize=t=>{let e=Math.min(t.width,t.height);e=Math.max(120,e),this._updateSize(e),this._updateLimit(e)},this.mount=t=>{let e=null;if(typeof t=="string"&&(e=document.querySelector(t)),!e)throw new Error("Invalid mounting element");const r=e.parentNode;if(!r)throw new Error("Invalid mounting element parent");this._domImage.addEventListener("mousedown",this._onMouseDown),this._domImage.addEventListener("touchstart",this._onTouchStart),this._domCtrlPerson.addEventListener("click",this.nextCharacter),this._domCtrlMagic.addEventListener("click",this.triggetAutoMode),this._domCtrlClose.addEventListener("click",this.unmount),this._options.autoFit&&(this._onResize(this._domWrapper.getBoundingClientRect()),this._resizeObserver=new _t(jt(a=>{!a||!a[0]||this._onResize(a[0].contentRect)})),this._resizeObserver.observe(this._domWrapper));const i=e.cloneNode(!1);return i.appendChild(this._domWrapper),r.replaceChild(i,e),requestAnimationFrame(this._run),this},this.unmount=()=>{this._domImage.removeEventListener("mousedown",this._onMouseDown),this._domImage.removeEventListener("touchstart",this._onTouchStart),this._domCtrlPerson.removeEventListener("click",this.nextCharacter),this._domCtrlMagic.removeEventListener("click",this.triggetAutoMode),this._domCtrlClose.removeEventListener("click",this.unmount),this._resizeObserver&&this._resizeObserver.disconnect();const t=this._domWrapper.parentNode;if(!t)throw new Error("Invalid mounting element");return t.removeChild(this._domWrapper),this},this._options=U(Jt),this._options=G(this._options,n),this.setCharacter(this._options.character),this._updateDom(),this._updateSize(this._options.size),this._updateLimit(this._options.size)}};let K=gt;K.getCharacter=n=>{const t=B[n];return t?U(t):null},K.getCharacters=()=>U(B),K.registerCharacter=(n,t)=>{const e=U(t);let r=e.initialState.i;r=Math.min(.5,Math.max(0,r)),e.initialState.i=r,B[n]=e};const Gt=K})(),P=P.default,P})()); +/*! sakana-widget | DSRKafuU (https://dsrkafuu.net) | Copyright (c) MIT License */ diff --git a/js/sakana-widget/utils.d.ts b/js/sakana-widget/utils.d.ts new file mode 100644 index 00000000..db2c7e16 --- /dev/null +++ b/js/sakana-widget/utils.d.ts @@ -0,0 +1,24 @@ +export declare type RequiredDeep = { + [K in keyof T]: RequiredDeep; +} & Required; +/** + * simple is object + */ +export declare function isObject(value: any): boolean; +/** + * simple deep clone + */ +export declare function cloneDeep(value: T): T; +/** + * simple deep merge + */ +export declare function mergeDeep(target: T, source: U): T & U; +/** + * throttle a func with requestAnimationFrame, + * https://github.com/wuct/raf-throttle/blob/master/rafThrottle.js + */ +export declare function throttle any>(callback: T): T; +/** + * get the canvas context with device pixel ratio + */ +export declare function getCanvasCtx(canvas: HTMLCanvasElement, appSize: number, devicePixelRatio?: number): CanvasRenderingContext2D | null; diff --git a/modernizr-simple.js b/modernizr-simple.js new file mode 100644 index 00000000..d6e95f47 --- /dev/null +++ b/modernizr-simple.js @@ -0,0 +1,3 @@ +/*! modernizr 3.6.0 (Custom Build) | MIT * + * https://modernizr.com/download/?-setclasses !*/ +!function(n,e,s){function o(n,e){return typeof n===e}function a(){var n,e,s,a,i,l,r;for(var c in f)if(f.hasOwnProperty(c)){if(n=[],e=f[c],e.name&&(n.push(e.name.toLowerCase()),e.options&&e.options.aliases&&e.options.aliases.length))for(s=0;shttps://blog.ohmykreee.top/ + \ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 00000000..5091c454 --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,41 @@ +Code with love ❤ and paws 🐾! | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

使用 GitHub Action 自动渲染和发布网页

2021-06-07 +Learning +Kreee

Why?

根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
So, let’s begin!

继续阅读
2021-06-05

决定建立一个独立的个人博客,撒花🎉🎉

Docker 学习小记

2021-03-01 +Learning +Kreee

本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
Now, let’s begin!

继续阅读
\ No newline at end of file diff --git a/page/about/index.html b/page/about/index.html new file mode 100644 index 00000000..b3558c36 --- /dev/null +++ b/page/about/index.html @@ -0,0 +1,15 @@ +关于我 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

关于我

2021-06-05

我是 Kreee

(说些什么呢,也没想好,就先放一个个人主页吧:www.ohmykreee.top

干饭人,干饭魂,干饭人都是仌!

\ No newline at end of file diff --git a/page/donate/index.html b/page/donate/index.html new file mode 100644 index 00000000..cf90f2b2 --- /dev/null +++ b/page/donate/index.html @@ -0,0 +1,14 @@ +❤❤❤ | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

❤❤❤

2021-06-06

富婆,饿饿,饭饭.jpg


(非实时)捐赠名单

\ No newline at end of file diff --git a/page/index.html b/page/index.html new file mode 100644 index 00000000..9cc390ca --- /dev/null +++ b/page/index.html @@ -0,0 +1,16 @@ +Pages | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/page/index.xml b/page/index.xml new file mode 100644 index 00000000..93ab3147 --- /dev/null +++ b/page/index.xml @@ -0,0 +1,3 @@ +Pages on Kreee's Bloghttps://blog.ohmykreee.top/page/Recent content in Pages on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 17:20:33 +0800关于我https://blog.ohmykreee.top/page/about/Sat, 05 Jun 2021 23:05:37 +0800https://blog.ohmykreee.top/page/about/我是 Kreee (说些什么呢,也没想好,就先放一个个人主页吧:www.ohmykreee.top) +干饭人,干饭魂,干饭人都是仌!文章列表https://blog.ohmykreee.top/page/more-articles/Sun, 06 Jun 2021 11:10:41 +0800https://blog.ohmykreee.top/page/more-articles/❤❤❤https://blog.ohmykreee.top/page/donate/Sun, 06 Jun 2021 17:20:33 +0800https://blog.ohmykreee.top/page/donate/富婆,饿饿,饭饭.jpg (非实时)捐赠名单福瑞控?https://blog.ohmykreee.top/page/is-furry/Sat, 05 Jun 2021 23:15:12 +0800https://blog.ohmykreee.top/page/is-furry/是,咋了? +(兽设在做了在做了,或者永远都: ) \ No newline at end of file diff --git a/page/is-furry/index.html b/page/is-furry/index.html new file mode 100644 index 00000000..b8a9bed0 --- /dev/null +++ b/page/is-furry/index.html @@ -0,0 +1,15 @@ +福瑞控? | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

福瑞控?

2021-06-05

是,咋了?

(兽设在做了在做了,或者永远都:

\ No newline at end of file diff --git a/page/more-articles/index.html b/page/more-articles/index.html new file mode 100644 index 00000000..beeca05e --- /dev/null +++ b/page/more-articles/index.html @@ -0,0 +1,14 @@ +文章列表 | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!
\ No newline at end of file diff --git a/page/page/1/index.html b/page/page/1/index.html new file mode 100644 index 00000000..5a830a91 --- /dev/null +++ b/page/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/page/ + \ No newline at end of file diff --git a/res/page/about-me/about-me-01.gif b/res/page/about-me/about-me-01.gif new file mode 100644 index 00000000..bc1b9d94 Binary files /dev/null and b/res/page/about-me/about-me-01.gif differ diff --git a/res/page/donate/donate.json b/res/page/donate/donate.json new file mode 100644 index 00000000..4aaaed91 --- /dev/null +++ b/res/page/donate/donate.json @@ -0,0 +1,24 @@ +{ + "sponsor": [ + { + "date": "2021-06-06", + "comment": "不成敬意。", + "notes": "" + }, + { + "date": "2021-06-07", + "comment": "买包辣条犒劳一下自己", + "notes": "" + }, + { + "date": "2021-06-08", + "comment": "我是杨**我最牛逼", + "notes": "汤少爷留" + }, + { + "date": "2021-12-24", + "comment": "merry X_mas", + "notes": "太感谢了🥰🥰,大家也要圣诞快乐哦!" + } + ] +} \ No newline at end of file diff --git a/res/page/donate/donate.png b/res/page/donate/donate.png new file mode 100644 index 00000000..afd98dac Binary files /dev/null and b/res/page/donate/donate.png differ diff --git a/res/page/is-furry/is-furry-01.jpg b/res/page/is-furry/is-furry-01.jpg new file mode 100644 index 00000000..94e798a0 Binary files /dev/null and b/res/page/is-furry/is-furry-01.jpg differ diff --git a/res/page/is-furry/is-furry-02.jpg b/res/page/is-furry/is-furry-02.jpg new file mode 100644 index 00000000..4406e0af Binary files /dev/null and b/res/page/is-furry/is-furry-02.jpg differ diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..4f9540ba --- /dev/null +++ b/robots.txt @@ -0,0 +1 @@ +User-agent: * \ No newline at end of file diff --git a/safari-pinned-tab.svg b/safari-pinned-tab.svg new file mode 100644 index 00000000..2236b088 --- /dev/null +++ b/safari-pinned-tab.svg @@ -0,0 +1,30 @@ + + + + +Created by potrace 1.14, written by Peter Selinger 2001-2017 + + + + + diff --git a/series/index.html b/series/index.html new file mode 100644 index 00000000..c393a72b --- /dev/null +++ b/series/index.html @@ -0,0 +1,16 @@ +Series | Kreee's Blog +

Kreee's Blog

Code with love ❤ and paws 🐾!

series


    \ No newline at end of file diff --git a/series/index.xml b/series/index.xml new file mode 100644 index 00000000..5d6644c7 --- /dev/null +++ b/series/index.xml @@ -0,0 +1 @@ +Series on Kreee's Bloghttps://blog.ohmykreee.top/series/Recent content in Series on Kreee's BlogHugo -- gohugo.iozh-cn \ No newline at end of file diff --git a/site.webmanifest b/site.webmanifest new file mode 100644 index 00000000..de65106f --- /dev/null +++ b/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "", + "short_name": "", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-256x256.png", + "sizes": "256x256", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..4f8ce81d --- /dev/null +++ b/sitemap.xml @@ -0,0 +1 @@ +https://blog.ohmykreee.top/page/about/2021-06-05T23:05:37+08:00https://blog.ohmykreee.top/page/more-articles/2021-06-06T11:10:41+08:00https://blog.ohmykreee.top/page/donate/2021-06-06T17:20:33+08:00https://blog.ohmykreee.top/tags/2022/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/article/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/author/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/categories/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/author/kreee/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/tags/learning/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/categories/learning/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/tags/selfhosted/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/tags/2022-12-24T18:39:00+08:00https://blog.ohmykreee.top/tags/2021/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/tags/code-server/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/tags/frontend/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/tags/termux/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/tags/vscode/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/2021-12-05T09:48:10+08:00https://blog.ohmykreee.top/tags/github/2021-11-18T16:17:41+08:00https://blog.ohmykreee.top/tags/javascript/2021-11-18T16:17:41+08:00https://blog.ohmykreee.top/tags/next.js/2021-11-18T16:17:41+08:00https://blog.ohmykreee.top/tags/react/2021-11-18T16:17:41+08:00https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/2021-11-18T16:17:41+08:00https://blog.ohmykreee.top/tags/backend/2021-10-27T22:59:38+08:00https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/2021-10-27T22:59:38+08:00https://blog.ohmykreee.top/tags/python/2021-10-19T12:29:53+08:00https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/2021-10-19T12:29:53+08:00https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/2021-07-16T14:31:14+08:00https://blog.ohmykreee.top/categories/code/2021-06-26T10:40:42+08:00https://blog.ohmykreee.top/tags/code-sharing/2021-06-26T10:40:42+08:00https://blog.ohmykreee.top/code/2021-06-26T10:40:42+08:00https://blog.ohmykreee.top/tags/study/2021-06-26T10:40:42+08:00https://blog.ohmykreee.top/code/sim-keyboard-stroke/2021-06-26T10:40:42+08:00https://blog.ohmykreee.top/tags/hugo/2021-06-07T11:10:33+08:00https://blog.ohmykreee.top/article/music-player-in-hugo-page/2021-06-07T11:10:33+08:00https://blog.ohmykreee.top/article/github-action-auto-pub-site/2021-06-07T10:21:29+08:00https://blog.ohmykreee.top/article/self-use-cheatsheet/2021-06-06T19:53:42+08:00https://blog.ohmykreee.top/page/2021-06-06T17:20:33+08:00https://blog.ohmykreee.top/status/fav-music/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/tags/favorite/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/tags/life/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/tags/music/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/categories/music/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/status/2021-06-06T16:58:19+08:00https://blog.ohmykreee.top/page/is-furry/2021-06-05T23:15:12+08:00https://blog.ohmykreee.top/status/ready-to-go/2021-06-05T22:36:46+08:00https://blog.ohmykreee.top/article/python-final-exam-questions/2021-06-04T14:24:37+08:00https://blog.ohmykreee.top/categories/study/2021-06-04T14:24:37+08:00https://blog.ohmykreee.top/article/docker-notes/2021-03-01T15:44:08+08:00https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/2021-01-13T22:58:38+08:00https://blog.ohmykreee.top/series/https://blog.ohmykreee.top/archive/ \ No newline at end of file diff --git a/status/fav-music/index.html b/status/fav-music/index.html new file mode 100644 index 00000000..5ec29d66 --- /dev/null +++ b/status/fav-music/index.html @@ -0,0 +1,17 @@ +Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/status/index.html b/status/index.html new file mode 100644 index 00000000..bdf85cf0 --- /dev/null +++ b/status/index.html @@ -0,0 +1,19 @@ +Statuses | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    2021-06-05

    决定建立一个独立的个人博客,撒花🎉🎉

    \ No newline at end of file diff --git a/status/index.xml b/status/index.xml new file mode 100644 index 00000000..8e2cc92b --- /dev/null +++ b/status/index.xml @@ -0,0 +1 @@ +Statuses on Kreee's Bloghttps://blog.ohmykreee.top/status/Recent content in Statuses on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 16:58:19 +0800<link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item><item><title/><link>https://blog.ohmykreee.top/status/ready-to-go/</link><pubDate>Sat, 05 Jun 2021 22:36:46 +0800</pubDate><guid>https://blog.ohmykreee.top/status/ready-to-go/</guid><description>决定建立一个独立的个人博客,撒花🎉🎉</description></item></channel></rss> \ No newline at end of file diff --git a/status/page/1/index.html b/status/page/1/index.html new file mode 100644 index 00000000..cf0bad08 --- /dev/null +++ b/status/page/1/index.html @@ -0,0 +1,2 @@ +<!doctype html><html lang=zh-cn><head><title>https://blog.ohmykreee.top/status/ + \ No newline at end of file diff --git a/status/ready-to-go/index.html b/status/ready-to-go/index.html new file mode 100644 index 00000000..30e25b21 --- /dev/null +++ b/status/ready-to-go/index.html @@ -0,0 +1,14 @@ +Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    2021-06-05

    决定建立一个独立的个人博客,撒花🎉🎉

    \ No newline at end of file diff --git a/tags/2021/index.html b/tags/2021/index.html new file mode 100644 index 00000000..56360938 --- /dev/null +++ b/tags/2021/index.html @@ -0,0 +1,58 @@ +2021 | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    wolf-bites-tweets 2.0.0 开发小记

    2021-10-27 +Learning +Kreee

    万恶之源

    接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

    项目地址: https://github.com/ohmykreee/wolf-bites-tweets

    为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

    1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
    2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
    继续阅读
    \ No newline at end of file diff --git a/tags/2021/index.xml b/tags/2021/index.xml new file mode 100644 index 00000000..28409cca --- /dev/null +++ b/tags/2021/index.xml @@ -0,0 +1,25 @@ +2021 on Kreee's Bloghttps://blog.ohmykreee.top/tags/2021/Recent content in 2021 on Kreee's BlogHugo -- gohugo.iozh-cnSun, 05 Dec 2021 09:48:10 +0800使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/tags/2021/page/1/index.html b/tags/2021/page/1/index.html new file mode 100644 index 00000000..f3509552 --- /dev/null +++ b/tags/2021/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/2021/ + \ No newline at end of file diff --git a/tags/2021/page/2/index.html b/tags/2021/page/2/index.html new file mode 100644 index 00000000..1b7633c0 --- /dev/null +++ b/tags/2021/page/2/index.html @@ -0,0 +1,36 @@ +2021 | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    使用 GitHub Action 自动渲染和发布网页

    2021-06-07 +Learning +Kreee

    Why?

    根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
    然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
    所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
    So, let’s begin!

    继续阅读

    Docker 学习小记

    2021-03-01 +Learning +Kreee

    本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
    其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
    以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
    但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
    Now, let’s begin!

    继续阅读
    \ No newline at end of file diff --git a/tags/2022/index.html b/tags/2022/index.html new file mode 100644 index 00000000..91733392 --- /dev/null +++ b/tags/2022/index.html @@ -0,0 +1,20 @@ +2022 | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/2022/index.xml b/tags/2022/index.xml new file mode 100644 index 00000000..e3232d31 --- /dev/null +++ b/tags/2022/index.xml @@ -0,0 +1 @@ +2022 on Kreee's Bloghttps://blog.ohmykreee.top/tags/2022/Recent content in 2022 on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p> \ No newline at end of file diff --git a/tags/2022/page/1/index.html b/tags/2022/page/1/index.html new file mode 100644 index 00000000..54aa8277 --- /dev/null +++ b/tags/2022/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/2022/ + \ No newline at end of file diff --git a/tags/backend/index.html b/tags/backend/index.html new file mode 100644 index 00000000..6b61c2b0 --- /dev/null +++ b/tags/backend/index.html @@ -0,0 +1,22 @@ +Backend | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    wolf-bites-tweets 2.0.0 开发小记

    2021-10-27 +Learning +Kreee

    万恶之源

    接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

    项目地址: https://github.com/ohmykreee/wolf-bites-tweets

    为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

    1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
    2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
    继续阅读
    \ No newline at end of file diff --git a/tags/backend/index.xml b/tags/backend/index.xml new file mode 100644 index 00000000..6f13db98 --- /dev/null +++ b/tags/backend/index.xml @@ -0,0 +1,8 @@ +Backend on Kreee's Bloghttps://blog.ohmykreee.top/tags/backend/Recent content in Backend on Kreee's BlogHugo -- gohugo.iozh-cnWed, 27 Oct 2021 22:59:38 +0800wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol> \ No newline at end of file diff --git a/tags/backend/page/1/index.html b/tags/backend/page/1/index.html new file mode 100644 index 00000000..e17c5837 --- /dev/null +++ b/tags/backend/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/backend/ + \ No newline at end of file diff --git a/tags/code-server/index.html b/tags/code-server/index.html new file mode 100644 index 00000000..90f1874e --- /dev/null +++ b/tags/code-server/index.html @@ -0,0 +1,23 @@ +code-server | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/code-server/index.xml b/tags/code-server/index.xml new file mode 100644 index 00000000..7a69a818 --- /dev/null +++ b/tags/code-server/index.xml @@ -0,0 +1,2 @@ +code-server on Kreee's Bloghttps://blog.ohmykreee.top/tags/code-server/Recent content in code-server on Kreee's BlogHugo -- gohugo.iozh-cnSun, 05 Dec 2021 09:48:10 +0800使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p> \ No newline at end of file diff --git a/tags/code-server/page/1/index.html b/tags/code-server/page/1/index.html new file mode 100644 index 00000000..d3bdafaf --- /dev/null +++ b/tags/code-server/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/code-server/ + \ No newline at end of file diff --git a/tags/code-sharing/index.html b/tags/code-sharing/index.html new file mode 100644 index 00000000..483ecf89 --- /dev/null +++ b/tags/code-sharing/index.html @@ -0,0 +1,21 @@ +Code Sharing | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/code-sharing/index.xml b/tags/code-sharing/index.xml new file mode 100644 index 00000000..af5988a5 --- /dev/null +++ b/tags/code-sharing/index.xml @@ -0,0 +1 @@ +Code Sharing on Kreee's Bloghttps://blog.ohmykreee.top/tags/code-sharing/Recent content in Code Sharing on Kreee's BlogHugo -- gohugo.iozh-cnSat, 26 Jun 2021 10:40:42 +0800模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p> \ No newline at end of file diff --git a/tags/code-sharing/page/1/index.html b/tags/code-sharing/page/1/index.html new file mode 100644 index 00000000..de0b85d0 --- /dev/null +++ b/tags/code-sharing/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/code-sharing/ + \ No newline at end of file diff --git a/tags/favorite/index.html b/tags/favorite/index.html new file mode 100644 index 00000000..a398d039 --- /dev/null +++ b/tags/favorite/index.html @@ -0,0 +1,19 @@ +Favorite | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/favorite/index.xml b/tags/favorite/index.xml new file mode 100644 index 00000000..49060e76 --- /dev/null +++ b/tags/favorite/index.xml @@ -0,0 +1 @@ +Favorite on Kreee's Bloghttps://blog.ohmykreee.top/tags/favorite/Recent content in Favorite on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 16:58:19 +0800<link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item></channel></rss> \ No newline at end of file diff --git a/tags/favorite/page/1/index.html b/tags/favorite/page/1/index.html new file mode 100644 index 00000000..286b8cf1 --- /dev/null +++ b/tags/favorite/page/1/index.html @@ -0,0 +1,2 @@ +<!doctype html><html lang=zh-cn><head><title>https://blog.ohmykreee.top/tags/favorite/ + \ No newline at end of file diff --git a/tags/frontend/index.html b/tags/frontend/index.html new file mode 100644 index 00000000..36c73cba --- /dev/null +++ b/tags/frontend/index.html @@ -0,0 +1,38 @@ +Frontend | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/frontend/index.xml b/tags/frontend/index.xml new file mode 100644 index 00000000..b8071b32 --- /dev/null +++ b/tags/frontend/index.xml @@ -0,0 +1,3 @@ +Frontend on Kreee's Bloghttps://blog.ohmykreee.top/tags/frontend/Recent content in Frontend on Kreee's BlogHugo -- gohugo.iozh-cnSun, 05 Dec 2021 09:48:10 +0800使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p> \ No newline at end of file diff --git a/tags/frontend/page/1/index.html b/tags/frontend/page/1/index.html new file mode 100644 index 00000000..c045bed7 --- /dev/null +++ b/tags/frontend/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/frontend/ + \ No newline at end of file diff --git a/tags/github/index.html b/tags/github/index.html new file mode 100644 index 00000000..4fc8fc17 --- /dev/null +++ b/tags/github/index.html @@ -0,0 +1,41 @@ +GitHub | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    wolf-bites-tweets 2.0.0 开发小记

    2021-10-27 +Learning +Kreee

    万恶之源

    接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

    项目地址: https://github.com/ohmykreee/wolf-bites-tweets

    为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

    1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
    2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
    继续阅读

    使用 GitHub Action 自动渲染和发布网页

    2021-06-07 +Learning +Kreee

    Why?

    根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
    然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
    所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
    So, let’s begin!

    继续阅读
    \ No newline at end of file diff --git a/tags/github/index.xml b/tags/github/index.xml new file mode 100644 index 00000000..d14ebdac --- /dev/null +++ b/tags/github/index.xml @@ -0,0 +1,13 @@ +GitHub on Kreee's Bloghttps://blog.ohmykreee.top/tags/github/Recent content in GitHub on Kreee's BlogHugo -- gohugo.iozh-cnThu, 18 Nov 2021 16:17:41 +0800关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p> \ No newline at end of file diff --git a/tags/github/page/1/index.html b/tags/github/page/1/index.html new file mode 100644 index 00000000..64c652d7 --- /dev/null +++ b/tags/github/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/github/ + \ No newline at end of file diff --git a/tags/hugo/index.html b/tags/hugo/index.html new file mode 100644 index 00000000..6e39eb9b --- /dev/null +++ b/tags/hugo/index.html @@ -0,0 +1,21 @@ +Hugo | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/hugo/index.xml b/tags/hugo/index.xml new file mode 100644 index 00000000..8fc80186 --- /dev/null +++ b/tags/hugo/index.xml @@ -0,0 +1,2 @@ +Hugo on Kreee's Bloghttps://blog.ohmykreee.top/tags/hugo/Recent content in Hugo on Kreee's BlogHugo -- gohugo.iozh-cnMon, 07 Jun 2021 11:10:33 +0800在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p> \ No newline at end of file diff --git a/tags/hugo/page/1/index.html b/tags/hugo/page/1/index.html new file mode 100644 index 00000000..975e87ab --- /dev/null +++ b/tags/hugo/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/hugo/ + \ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 00000000..b5f87d2a --- /dev/null +++ b/tags/index.html @@ -0,0 +1,16 @@ +Tags | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/index.xml b/tags/index.xml new file mode 100644 index 00000000..5b8abbdd --- /dev/null +++ b/tags/index.xml @@ -0,0 +1 @@ +Tags on Kreee's Bloghttps://blog.ohmykreee.top/tags/Recent content in Tags on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +08002022https://blog.ohmykreee.top/tags/2022/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/tags/2022/Learninghttps://blog.ohmykreee.top/tags/learning/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/tags/learning/Selfhostedhttps://blog.ohmykreee.top/tags/selfhosted/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/tags/selfhosted/2021https://blog.ohmykreee.top/tags/2021/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/tags/2021/code-serverhttps://blog.ohmykreee.top/tags/code-server/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/tags/code-server/Frontendhttps://blog.ohmykreee.top/tags/frontend/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/tags/frontend/Termuxhttps://blog.ohmykreee.top/tags/termux/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/tags/termux/VSCodehttps://blog.ohmykreee.top/tags/vscode/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/tags/vscode/GitHubhttps://blog.ohmykreee.top/tags/github/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/tags/github/JavaScripthttps://blog.ohmykreee.top/tags/javascript/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/tags/javascript/Next.jshttps://blog.ohmykreee.top/tags/next.js/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/tags/next.js/Reacthttps://blog.ohmykreee.top/tags/react/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/tags/react/Backendhttps://blog.ohmykreee.top/tags/backend/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/tags/backend/Pythonhttps://blog.ohmykreee.top/tags/python/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/tags/python/Code Sharinghttps://blog.ohmykreee.top/tags/code-sharing/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/tags/code-sharing/Studyhttps://blog.ohmykreee.top/tags/study/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/tags/study/Hugohttps://blog.ohmykreee.top/tags/hugo/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/tags/hugo/Favoritehttps://blog.ohmykreee.top/tags/favorite/Sun, 06 Jun 2021 16:58:19 +0800https://blog.ohmykreee.top/tags/favorite/Lifehttps://blog.ohmykreee.top/tags/life/Sun, 06 Jun 2021 16:58:19 +0800https://blog.ohmykreee.top/tags/life/Musichttps://blog.ohmykreee.top/tags/music/Sun, 06 Jun 2021 16:58:19 +0800https://blog.ohmykreee.top/tags/music/ \ No newline at end of file diff --git a/tags/javascript/index.html b/tags/javascript/index.html new file mode 100644 index 00000000..0012a2c7 --- /dev/null +++ b/tags/javascript/index.html @@ -0,0 +1,37 @@ +JavaScript | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    wolf-bites-tweets 2.0.0 开发小记

    2021-10-27 +Learning +Kreee

    万恶之源

    接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

    项目地址: https://github.com/ohmykreee/wolf-bites-tweets

    为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

    1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
    2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
    继续阅读
    \ No newline at end of file diff --git a/tags/javascript/index.xml b/tags/javascript/index.xml new file mode 100644 index 00000000..b7ef4b7f --- /dev/null +++ b/tags/javascript/index.xml @@ -0,0 +1,9 @@ +JavaScript on Kreee's Bloghttps://blog.ohmykreee.top/tags/javascript/Recent content in JavaScript on Kreee's BlogHugo -- gohugo.iozh-cnThu, 18 Nov 2021 16:17:41 +0800关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p> \ No newline at end of file diff --git a/tags/javascript/page/1/index.html b/tags/javascript/page/1/index.html new file mode 100644 index 00000000..c7eff436 --- /dev/null +++ b/tags/javascript/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/javascript/ + \ No newline at end of file diff --git a/tags/learning/index.html b/tags/learning/index.html new file mode 100644 index 00000000..d23c60f0 --- /dev/null +++ b/tags/learning/index.html @@ -0,0 +1,57 @@ +Learning | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    wolf-bites-tweets 2.0.0 开发小记

    2021-10-27 +Learning +Kreee

    万恶之源

    接上文: wolf-bites-tweets 和 wolf-chews-tweets 开发小记

    项目地址: https://github.com/ohmykreee/wolf-bites-tweets

    为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:

    1. 想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)
    2. JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。
    继续阅读
    \ No newline at end of file diff --git a/tags/learning/index.xml b/tags/learning/index.xml new file mode 100644 index 00000000..6f8acb50 --- /dev/null +++ b/tags/learning/index.xml @@ -0,0 +1,23 @@ +Learning on Kreee's Bloghttps://blog.ohmykreee.top/tags/learning/Recent content in Learning on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p>关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p>wolf-bites-tweets 2.0.0 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/Wed, 27 Oct 2021 22:59:38 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-2.0.0/<h2 id="万恶之源">万恶之源</h2> +<p>接上文: <a href="https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/">wolf-bites-tweets 和 wolf-chews-tweets 开发小记</a></p> +<p>项目地址: <a href="https://github.com/ohmykreee/wolf-bites-tweets">https://github.com/ohmykreee/wolf-bites-tweets</a></p> +<p>为啥在已经有 wolf-bites-tweets v1 的情况下,还要重写并开发 v2.0.0 呢?原因有俩:</p> +<ol> +<li>想要节省下 build docker image 花掉的十几秒,以及那种直接运行的安全感。(?)</li> +<li>JavaScript 初上手,想要体验一下用 Node.js 开发后端的流程。</li> +</ol>wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>使用 GitHub Action 自动渲染和发布网页https://blog.ohmykreee.top/article/github-action-auto-pub-site/Mon, 07 Jun 2021 10:21:29 +0800https://blog.ohmykreee.top/article/github-action-auto-pub-site/<h2 id="why">Why?</h2> +<p>根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。<br> +然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 <code>gh-pages</code> 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 <code>gh-pages</code> 分支上。<br> +所以秉承着人类科技进步的本质是<del>懒</del>这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。<br> +So, let&rsquo;s begin!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/tags/learning/page/1/index.html b/tags/learning/page/1/index.html new file mode 100644 index 00000000..815dceb6 --- /dev/null +++ b/tags/learning/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/learning/ + \ No newline at end of file diff --git a/tags/learning/page/2/index.html b/tags/learning/page/2/index.html new file mode 100644 index 00000000..13f3add4 --- /dev/null +++ b/tags/learning/page/2/index.html @@ -0,0 +1,32 @@ +Learning | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    使用 GitHub Action 自动渲染和发布网页

    2021-06-07 +Learning +Kreee

    Why?

    根据 GitHub Pages 的政策,一个 GitHub 账号只能拥有一个个人主页和多个项目主页。我的个人主页名额给了服务器的 Landing Page,所以这个博客只能以项目主页的名义发布了。
    然鹅有一个问题是,不同于个人主页,项目主页的网页是要托管在 gh-pages 分支的,所以如果完全手动的话需要我自己在本地渲染好网页后,手动 push 到 gh-pages 分支上。
    所以秉承着人类科技进步的本质是这一原则,顺便学学 GitHub Action 做到网页渲染和发布一条龙吧。
    So, let’s begin!

    继续阅读

    Docker 学习小记

    2021-03-01 +Learning +Kreee

    本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
    其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
    以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
    但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
    Now, let’s begin!

    继续阅读
    \ No newline at end of file diff --git a/tags/life/index.html b/tags/life/index.html new file mode 100644 index 00000000..956f3c55 --- /dev/null +++ b/tags/life/index.html @@ -0,0 +1,19 @@ +Life | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/life/index.xml b/tags/life/index.xml new file mode 100644 index 00000000..75ac30c6 --- /dev/null +++ b/tags/life/index.xml @@ -0,0 +1 @@ +Life on Kreee's Bloghttps://blog.ohmykreee.top/tags/life/Recent content in Life on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 16:58:19 +0800<link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item></channel></rss> \ No newline at end of file diff --git a/tags/life/page/1/index.html b/tags/life/page/1/index.html new file mode 100644 index 00000000..cbf0ed98 --- /dev/null +++ b/tags/life/page/1/index.html @@ -0,0 +1,2 @@ +<!doctype html><html lang=zh-cn><head><title>https://blog.ohmykreee.top/tags/life/ + \ No newline at end of file diff --git a/tags/music/index.html b/tags/music/index.html new file mode 100644 index 00000000..49727954 --- /dev/null +++ b/tags/music/index.html @@ -0,0 +1,19 @@ +Music | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/music/index.xml b/tags/music/index.xml new file mode 100644 index 00000000..67b7e383 --- /dev/null +++ b/tags/music/index.xml @@ -0,0 +1 @@ +Music on Kreee's Bloghttps://blog.ohmykreee.top/tags/music/Recent content in Music on Kreee's BlogHugo -- gohugo.iozh-cnSun, 06 Jun 2021 16:58:19 +0800<link>https://blog.ohmykreee.top/status/fav-music/</link><pubDate>Sun, 06 Jun 2021 16:58:19 +0800</pubDate><guid>https://blog.ohmykreee.top/status/fav-music/</guid><description>最近的单曲循环:</description></item></channel></rss> \ No newline at end of file diff --git a/tags/music/page/1/index.html b/tags/music/page/1/index.html new file mode 100644 index 00000000..6c363748 --- /dev/null +++ b/tags/music/page/1/index.html @@ -0,0 +1,2 @@ +<!doctype html><html lang=zh-cn><head><title>https://blog.ohmykreee.top/tags/music/ + \ No newline at end of file diff --git a/tags/next.js/index.html b/tags/next.js/index.html new file mode 100644 index 00000000..ac7606a3 --- /dev/null +++ b/tags/next.js/index.html @@ -0,0 +1,24 @@ +Next.js | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/next.js/index.xml b/tags/next.js/index.xml new file mode 100644 index 00000000..51445f6e --- /dev/null +++ b/tags/next.js/index.xml @@ -0,0 +1,2 @@ +Next.js on Kreee's Bloghttps://blog.ohmykreee.top/tags/next.js/Recent content in Next.js on Kreee's BlogHugo -- gohugo.iozh-cnThu, 18 Nov 2021 16:17:41 +0800关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p> \ No newline at end of file diff --git a/tags/next.js/page/1/index.html b/tags/next.js/page/1/index.html new file mode 100644 index 00000000..0dfdd8dc --- /dev/null +++ b/tags/next.js/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/next.js/ + \ No newline at end of file diff --git a/tags/python/index.html b/tags/python/index.html new file mode 100644 index 00000000..b9de3a85 --- /dev/null +++ b/tags/python/index.html @@ -0,0 +1,32 @@ +Python | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/python/index.xml b/tags/python/index.xml new file mode 100644 index 00000000..e3d7d103 --- /dev/null +++ b/tags/python/index.xml @@ -0,0 +1,3 @@ +Python on Kreee's Bloghttps://blog.ohmykreee.top/tags/python/Recent content in Python on Kreee's BlogHugo -- gohugo.iozh-cnTue, 19 Oct 2021 12:29:53 +0800wolf-bites-tweets 和 wolf-chews-tweets 开发小记https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/Tue, 19 Oct 2021 12:29:53 +0800https://blog.ohmykreee.top/article/notes-of-developing-wbt-and-wct/<p><del>又为:论如何嫖秃 GitHub 服务器</del></p>模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p> \ No newline at end of file diff --git a/tags/python/page/1/index.html b/tags/python/page/1/index.html new file mode 100644 index 00000000..7f6d35b9 --- /dev/null +++ b/tags/python/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/python/ + \ No newline at end of file diff --git a/tags/react/index.html b/tags/react/index.html new file mode 100644 index 00000000..6202a268 --- /dev/null +++ b/tags/react/index.html @@ -0,0 +1,24 @@ +React | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/react/index.xml b/tags/react/index.xml new file mode 100644 index 00000000..c1f6fe8b --- /dev/null +++ b/tags/react/index.xml @@ -0,0 +1,2 @@ +React on Kreee's Bloghttps://blog.ohmykreee.top/tags/react/Recent content in React on Kreee's BlogHugo -- gohugo.iozh-cnThu, 18 Nov 2021 16:17:41 +0800关于部署 Next.js 静态网页到 GitHub Pages 有关注意事项https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/Thu, 18 Nov 2021 16:17:41 +0800https://blog.ohmykreee.top/article/deploy-nextjs-static-page-to-github-pages/<p>个人主页 <a href="https://www.ohmykreee.top">www.ohmykreee.top</a> <del>涅槃重生啦</del> ,快去围观吧!</p> +<p>(怎么这文案一股营销号的味道)</p> \ No newline at end of file diff --git a/tags/react/page/1/index.html b/tags/react/page/1/index.html new file mode 100644 index 00000000..1f024efb --- /dev/null +++ b/tags/react/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/react/ + \ No newline at end of file diff --git a/tags/selfhosted/index.html b/tags/selfhosted/index.html new file mode 100644 index 00000000..45f7db84 --- /dev/null +++ b/tags/selfhosted/index.html @@ -0,0 +1,41 @@ +Selfhosted | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!

    Docker 学习小记

    2021-03-01 +Learning +Kreee

    本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。
    其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。
    以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)
    但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。
    Now, let’s begin!

    继续阅读
    \ No newline at end of file diff --git a/tags/selfhosted/index.xml b/tags/selfhosted/index.xml new file mode 100644 index 00000000..4b929e58 --- /dev/null +++ b/tags/selfhosted/index.xml @@ -0,0 +1,10 @@ +Selfhosted on Kreee's Bloghttps://blog.ohmykreee.top/tags/selfhosted/Recent content in Selfhosted on Kreee's BlogHugo -- gohugo.iozh-cnSat, 24 Dec 2022 18:39:00 +0800PVE、OPNsense、Ubuntu Server设置小记https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/Sat, 24 Dec 2022 18:39:00 +0800https://blog.ohmykreee.top/article/setup-pve-with-opnsense-ubuntu-notes/<p><strong>注意!</strong> 这篇文章仅仅是作为自己边鼓捣边摸索出来的产物,并非为一篇教程,并不能保证所有的内容全部正确,如有错误也欢迎指出。</p>将后端服务器系统迁移至 Ubuntu serverhttps://blog.ohmykreee.top/article/migrate-to-ubuntu-server/Fri, 16 Jul 2021 14:31:14 +0800https://blog.ohmykreee.top/article/migrate-to-ubuntu-server/<h2 id="what-happend">What happend?</h2> +<p>本来用 CentOS 7 用得开开心心的,结果了解到 Redhat 公司要整治一下我们这群白嫖怪(感觉被强行喂了一口💩)。<br> +So, 为了服务器的可持续发展(其实是放假闲得无聊),顺便重装一下机器的系统,以及更新一下远古的备忘指南,Let&rsquo;s begin!</p>在 Hugo 里内嵌音乐播放器(APlayer)https://blog.ohmykreee.top/article/music-player-in-hugo-page/Mon, 07 Jun 2021 11:10:33 +0800https://blog.ohmykreee.top/article/music-player-in-hugo-page/<p>就是置顶状态的那个音乐播放器。<br> +想要吗?只需要短短三步哦!</p>自用备忘录表https://blog.ohmykreee.top/article/self-use-cheatsheet/Sun, 06 Jun 2021 19:53:42 +0800https://blog.ohmykreee.top/article/self-use-cheatsheet/<p>一个自用的备忘录表,记录一下要用但是又容易忘记的命令。<br> +不断更新中&hellip;</p>Docker 学习小记https://blog.ohmykreee.top/article/docker-notes/Mon, 01 Mar 2021 15:44:08 +0800https://blog.ohmykreee.top/article/docker-notes/<p>本来一开始不打算使用 Docker 来配置服务:虽然的确 Docker 能省下配置环境的麻烦,但是总觉得哪里不舒服(误)。<br> +其实是因为服务器不是长时间运行的,会时不时关机/重启,还要重新到 Docker 里启动。<br> +以及据说有安全隐患(其实其他软件配置不当也会有安全隐患233)<br> +但是现在是真的闲的无聊 + 还是有很多软件是基于 Docker 的(还是只提供了 Docker 的安装教程,吐了),故打算核心服务直接部署在服务器里,整一些不重要的东西放在 Docker 里。<br> +Now, let&rsquo;s begin!</p>Notes for Setting Up Back-end Serverhttps://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/Wed, 13 Jan 2021 22:58:38 +0800https://blog.ohmykreee.top/article/notes-for-setting-up-backend-server/<h2 id="install-centos">Install CentOS</h2> +<p>OS: CentOS 7 Minimal</p> \ No newline at end of file diff --git a/tags/selfhosted/page/1/index.html b/tags/selfhosted/page/1/index.html new file mode 100644 index 00000000..d467dd4b --- /dev/null +++ b/tags/selfhosted/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/selfhosted/ + \ No newline at end of file diff --git a/tags/study/index.html b/tags/study/index.html new file mode 100644 index 00000000..d28536c9 --- /dev/null +++ b/tags/study/index.html @@ -0,0 +1,25 @@ +Study | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/study/index.xml b/tags/study/index.xml new file mode 100644 index 00000000..e755a271 --- /dev/null +++ b/tags/study/index.xml @@ -0,0 +1,3 @@ +Study on Kreee's Bloghttps://blog.ohmykreee.top/tags/study/Recent content in Study on Kreee's BlogHugo -- gohugo.iozh-cnSat, 26 Jun 2021 10:40:42 +0800模拟键盘输入https://blog.ohmykreee.top/code/sim-keyboard-stroke/Sat, 26 Jun 2021 10:40:42 +0800https://blog.ohmykreee.top/code/sim-keyboard-stroke/<p>懂的都懂这是干啥用的。</p>Python 期末编程题题库https://blog.ohmykreee.top/article/python-final-exam-questions/Fri, 04 Jun 2021 14:24:37 +0800https://blog.ohmykreee.top/article/python-final-exam-questions/<p>(据说)Python 期末考的编程题会从这里面抽。<br> +有些没有答案的题目是临时写的,如果写的很烂欢迎反馈。<br> +愿人间没有挂科人。</p> \ No newline at end of file diff --git a/tags/study/page/1/index.html b/tags/study/page/1/index.html new file mode 100644 index 00000000..a26c9b1b --- /dev/null +++ b/tags/study/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/study/ + \ No newline at end of file diff --git a/tags/termux/index.html b/tags/termux/index.html new file mode 100644 index 00000000..935f4608 --- /dev/null +++ b/tags/termux/index.html @@ -0,0 +1,23 @@ +Termux | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/termux/index.xml b/tags/termux/index.xml new file mode 100644 index 00000000..693a8f1a --- /dev/null +++ b/tags/termux/index.xml @@ -0,0 +1,2 @@ +Termux on Kreee's Bloghttps://blog.ohmykreee.top/tags/termux/Recent content in Termux on Kreee's BlogHugo -- gohugo.iozh-cnSun, 05 Dec 2021 09:48:10 +0800使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p> \ No newline at end of file diff --git a/tags/termux/page/1/index.html b/tags/termux/page/1/index.html new file mode 100644 index 00000000..a13a2579 --- /dev/null +++ b/tags/termux/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/termux/ + \ No newline at end of file diff --git a/tags/vscode/index.html b/tags/vscode/index.html new file mode 100644 index 00000000..1670492c --- /dev/null +++ b/tags/vscode/index.html @@ -0,0 +1,23 @@ +VSCode | Kreee's Blog +

    Kreee's Blog

    Code with love ❤ and paws 🐾!
    \ No newline at end of file diff --git a/tags/vscode/index.xml b/tags/vscode/index.xml new file mode 100644 index 00000000..f32a66c6 --- /dev/null +++ b/tags/vscode/index.xml @@ -0,0 +1,2 @@ +VSCode on Kreee's Bloghttps://blog.ohmykreee.top/tags/vscode/Recent content in VSCode on Kreee's BlogHugo -- gohugo.iozh-cnSun, 05 Dec 2021 09:48:10 +0800使用 Android Pad 进行(前端)开发https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/Sun, 05 Dec 2021 09:48:10 +0800https://blog.ohmykreee.top/article/frontend-dev-with-android-pad/<p>四舍五入安卓系统是 Linux,四舍五入可以在安卓系统上直接进行开发。</p> +<p><del>四舍五入又水了一篇</del></p> \ No newline at end of file diff --git a/tags/vscode/page/1/index.html b/tags/vscode/page/1/index.html new file mode 100644 index 00000000..d61bde74 --- /dev/null +++ b/tags/vscode/page/1/index.html @@ -0,0 +1,2 @@ +https://blog.ohmykreee.top/tags/vscode/ + \ No newline at end of file diff --git a/theme-exclude-highlight.js b/theme-exclude-highlight.js new file mode 100644 index 00000000..c3e3c4e9 --- /dev/null +++ b/theme-exclude-highlight.js @@ -0,0 +1,2 @@ +/*! For license information please see theme-exclude-highlight.js.LICENSE.txt */ +(()=>{var e,t={3664:(e,t,n)=>{var a,s,r,i=n(9755);"undefined"!=typeof window?r=window:"undefined"!=typeof self&&(r=self),r.ALGOLIA_MIGRATION_LAYER=function e(t,n,a){function s(i,o){if(!n[i]){if(!t[i]){if(r)return r(i,!0);var d=new Error("Cannot find module '"+i+"'");throw d.code="MODULE_NOT_FOUND",d}var u=n[i]={exports:{}};t[i][0].call(u.exports,(function(e){var n=t[i][1][e];return s(n||e)}),u,u.exports,e,t,n,a)}return n[i].exports}for(var r=void 0,i=0;iwindow.ALGOLIA_SUPPORTS_DOCWRITE = true<\/script>"),!0===window.ALGOLIA_SUPPORTS_DOCWRITE?(document.write('