diff --git a/2022/08/20/basic-use-of-hexo/index.html b/2022/08/20/basic-use-of-hexo/index.html new file mode 100644 index 000000000..44e201d6d --- /dev/null +++ b/2022/08/20/basic-use-of-hexo/index.html @@ -0,0 +1,283 @@ +Hexo基本使用方法 | Stray Birds + + + + + + + + + + + + + +

Hexo基本使用方法

+

发布文章常用指令

1
2
3
4
5
6
hexo new "xxx" # 发布文章
hexo g # 生成页面
hexo d # 部署发布
hexo s # 本地预览 http://localhost:4000/
hexo clean # 清除缓存
hexo new page xxx # 新增标签页
+

文章Front-matter常用配置

1
2
3
4
5
6
7
8
9
title: xxx
date: xxx (创建文档时默认生成)
tags:
- xxx (默认有多个)
categories:
- xxx (一级分类)
- xxx (二级分类)
description: xxx
cover: http://img.cwxhmk.top/cover/hexo.png
+

插入图片

.gif图片也是支持的哦~

+
+ +

第一种:使用markdown语法

+
1
![文字](/img/图片名.jpg) 
+

第二种:适用于图片较大的情况,可等比例缩小

+
1
<img src="/img/图片名.jpg" alt="图片说明" width="50%" height="50%" /> 
+

插入视频

1
<iframe src="视频链接" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"  width="800px" height="470px"> </iframe>
+

插入公式

1
2
3
输入$a$ #行内公式
$$aabb$$ #独立公式并居中
$$a+b=c \tag{1.1}$$ #公式编号
+

效果展示

输入$a$
$$aabb$$
$$a+b=c \tag{1.1}$$

+

文章链接

1
2
3
4
5
{% post_link 'basic-use-of-hexo' %} #链接到本文/站内其他文章
{% post_link 'tag-plugin' %}
[跳转到插入图片](#插入图片) #链接本文锚点
<a href="{% post_path 'tag-plugin' %}#label">标签外挂</a> #链接站外文章锚点
[又拍云](https://www.upyun.com/) #站外链接
+

预览

Hexo基本使用方法 +Post not found: tag-plugin +

跳转到插入图片
标签外挂-label
又拍云

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/08/20/basic-use-of-hexo/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/08/21/jupyter-notebook-contents/index.html b/2022/08/21/jupyter-notebook-contents/index.html new file mode 100644 index 000000000..de764425c --- /dev/null +++ b/2022/08/21/jupyter-notebook-contents/index.html @@ -0,0 +1,293 @@ +Jupyter Notebook中添加目录 | Stray Birds + + + + + + + + + + + + + + +

Jupyter Notebook中添加目录

安装步骤

    +
  1. 安装nbextensions

    +
    +

    若之前安装过nbextensions遇到问题,需要先执行remove 语句

    +
    +
    1
    2
    3
    4
    5
    # conda remove jupyter_nbextensions_configurator 
    conda install -c conda-forge jupyter_nbextensions_configurator
    conda install -c conda-forge jupyter_contrib_nbextensions
    jupyter contrib nbextension install --user
    jupyter nbextensions_configurator enable --user
    +

    上述过程均完成后,打开jupyter notebook就会发现界面多了Nbextensions选项卡
    Nbextensions

    +
  2. +
  3. 勾选Table of Contents(2)复选框
    toc2

    +
  4. +
  5. 新建或打开已有的ipynb文件,点击新增的目录按钮即可显示目录 😁
    catalogue

    +
  6. +
+

问题记录

    +
  1. jupyter notebook nbextension常用扩展模块不显示
    按照安装步骤重新安装,先remove,再install
  2. +
  3. jupyter notebook报错:Bad file descriptor(C:\ci\zeromq_1602704446950\work\src\epoll.cpp:100)
    1
    2
    pip uninstall pyzmq
    pip install pyzmq==19.0.2
  4. +
  5. 启动Jupyter,cmd窗口出现很多行类似于下述的代码
    1
    Config option `template_path` not recognized by `LenvsLatexExporter`
  6. +
+
    +
  • 原因是nbconvert6.0.0版本以上的某些参数的名称发生了更改,与原先版本不兼容,需要将版本降低到5.6.1
    1
    pip install nbconvert==5.6.1 -i https://pypi.mirrors.ustc.edu.cn/simple
  • +
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/08/21/jupyter-notebook-contents/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/08/30/solidworks-featureworks/index.html b/2022/08/30/solidworks-featureworks/index.html new file mode 100644 index 000000000..813b35922 --- /dev/null +++ b/2022/08/30/solidworks-featureworks/index.html @@ -0,0 +1,280 @@ +Solidworks 自动识别特征 | Stray Birds + + + + + + + + + + + + + +

Solidworks 自动识别特征

最近需要编辑一个.stp的文件,下意识的反应是应该和.stl文件差不多,属于不可编辑的那种文件格式。从师姐那里得知inventor可以编辑.stp文件,但平时已经习惯了用solidworks,不想再学新的建模软件了,这时碰巧在b站看到了solidworks可以自动识别.stp文件的特征!激动!😎

+
+ +
    +
  1. 导入.stp文件
    essay
  2. +
  3. 断开链接(确认)
  4. +
+ +
    +
  1. 插入-FeatureWorks-识别特征(点确认,点√) +
  2. +
  3. 耐心等待! +
  4. +
  5. 识别成功啦,愉快的开始编辑吧!👍
    essay
  6. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/08/30/solidworks-featureworks/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/09/01/anaconda-new-env/index.html b/2022/09/01/anaconda-new-env/index.html new file mode 100644 index 000000000..35f88e34d --- /dev/null +++ b/2022/09/01/anaconda-new-env/index.html @@ -0,0 +1,269 @@ +在Anaconda中创建新环境 | Stray Birds + + + + + + + + + + + + + + +

在Anaconda中创建新环境

conda常用命令

1
2
conda info --envs # 查看anaconda中所有环境
conda list # 查看当前环境下有哪些包
+

添加新环境

1
2
3
4
5
6
conda create -n xxx # 创建新的环境,不指定python版本;xxx为环境名
conda create -n xxx python=3.8 # 可指定python版本
conda activate xxx # 激活xxx环境
conda deactivate # 退出xxx环境,返回base
conda uninstall -n xxx --all # 删除环境
conda install ipykernel # 添加进jupyter notebook环境 vscode中可以识别就可以
+

忽略warning信息

1
2
import warnings
warnings.filterwarnings("ignore")
+

将新环境添加进Jupyter Notebook

1
2
3
4
jupyter kernelspec list # 查看安装了哪些虚拟环境kernel
pip install --user ipykernel # 安装ipykernel
python -m ipykernel install --user --name=xxx # 将环境加入jupyter
jupyter kernelspec uninstall xxx # 删除指定的kernel
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/01/anaconda-new-env/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/09/04/hexo-tag-plugin/index.html b/2022/09/04/hexo-tag-plugin/index.html new file mode 100644 index 000000000..e96833894 --- /dev/null +++ b/2022/09/04/hexo-tag-plugin/index.html @@ -0,0 +1,477 @@ +Hexo标签外挂 | Stray Birds + + + + + + + + + + + + + + +

Hexo标签外挂

Note(Bootstrap Callout)

用法1 语法

1
2
3
{% note [class] [no-icon] [style] %}
Any content (support inline tags too.io).
{% endnote %}
+ + + + + + + + + + + + + + + + + + + +
参数解释
class【可选】标识,不同的标识有不同的配色(default / primary / success / info / warning / danger)
no-icon【可选】不显示 icon
style【可选】可以覆盖配置中的 style(simple/modern/flat/disabled)
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{% note simple %}
默认 提示块标志
{% endnote %}

{% note default simple %}
default 提示块标志
{% endnote %}

{% note primary simple %}
primary 提示块标志
{% endnote %}

{% note success simple %}
success 提示块标志
{% endnote %}

{% note info simple %}
info 提示块标志
{% endnote %}

{% note warning simple %}
warning 提示块标志
{% endnote %}

{% note danger simple %}
danger 提示块标志
{% endnote %}
+ +

默认 提示块标签

+
+ +

default 提示块标签

+
+ +

primary 提示块标签

+
+ +

success 提示块标签

+
+ +

info 提示块标签

+
+ +

warning 提示块标签

+
+ +

danger 提示块标签

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{% note modern %}
默认 提示块标签
{% endnote %}

{% note default modern %}
default 提示块标签
{% endnote %}

{% note primary modern %}
primary 提示块标签
{% endnote %}

{% note success modern %}
success 提示块标签
{% endnote %}

{% note info modern %}
info 提示块标签
{% endnote %}

{% note warning modern %}
warning 提示块标签
{% endnote %}

{% note danger modern %}
danger 提示块标签
{% endnote %}

+ +

默认 提示块标签

+
+ +

default 提示块标签

+
+ +

primary 提示块标签

+
+ +

success 提示块标签

+
+ +

info 提示块标签

+
+ +

warning 提示块标签

+
+ +

danger 提示块标签

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{% note flat %}
默认 提示块标签
{% endnote %}

{% note default flat %}
default 提示块标签
{% endnote %}

{% note primary flat %}
primary 提示块标签
{% endnote %}

{% note success flat %}
success 提示块标签
{% endnote %}

{% note info flat %}
info 提示块标签
{% endnote %}

{% note warning flat %}
warning 提示块标签
{% endnote %}

{% note danger flat %}
danger 提示块标签
{% endnote %}
+ +

默认 提示块标签

+
+ +

default 提示块标签

+
+ +

primary 提示块标签

+
+ +

success 提示块标签

+
+ +

info 提示块标签

+
+ +

warning 提示块标签

+
+ +

danger 提示块标签

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{% note disabled %}
默认 提示块标签
{% endnote %}

{% note default disabled %}
default 提示块标签
{% endnote %}

{% note primary disabled %}
primary 提示块标签
{% endnote %}

{% note success disabled %}
success 提示块标签
{% endnote %}

{% note info disabled %}
info 提示块标签
{% endnote %}

{% note warning disabled %}
warning 提示块标籤
{% endnote %}

{% note danger disabled %}
danger 提示块标签
{% endnote %}
+ +

默认 提示块标签

+
+ +

default 提示块标签

+
+ +

primary 提示块标签

+
+ +

success 提示块标签

+
+ +

info 提示块标签

+
+ +

warning 提示块标签

+
+ +

danger 提示块标签

+
+

用法2 语法

1
2
3
{% note [color] [no-icon] [style] %}
Any content (support inline tags too.io).
{% endnote %}
+ + + + + + + + + + + + + + + + + + + +
参数解释
color【可选】颜色(default / blue / pink / red / purple / orange / green)
icon【可选】可配置自定义 icon(只支持 fontawesome 图标, 也可以配置 no-icon )
style【可选】可以覆盖配置中的 style(simple/modern/flat/disabled)
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% note no-icon %}
测试1
{% endnote %}
{% note blue no-icon %}
测试2
{% endnote %}
{% note pink no-icon %}
测试3
{% endnote %}
{% note red no-icon %}
测试4
{% endnote %}
{% note orange no-icon %}
测试5
{% endnote %}
{% note purple no-icon %}
测试6
{% endnote %}
{% note green no-icon %}
测试7
{% endnote %}

测试1

+
+

测试2

+
+

测试3

+
+

测试4

+
+

测试5

+
+

测试6

+
+

测试7

+
+

tabs分栏

语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{% tabs Unique name, [index] %}
<!-- tab [Tab caption] [@icon] -->
Any content (support inline tags too).
<!-- endtab -->
{% endtabs %}

Unique name : Unique name of tabs block tag without comma.
Will be used in #id's as prefix for each tab with their index numbers.
If there are whitespaces in name, for generate #id all whitespaces will replaced by dashes.
Only for current url of post/page must be unique!
[index] : Index number of active tab.
If not specified, first tab (1) will be selected.
If index is -1, no tab will be selected. It's will be something like spoiler.
Optional parameter.
[Tab caption] : Caption of current tab.
If not caption specified, unique name with tab index suffix will be used as caption of tab.
If not caption specified, but specified icon, caption will empty.
Optional parameter.
[@icon] : FontAwesome icon name (full-name, look like 'fas fa-font')
Can be specified with or without space; e.g. 'Tab caption @icon' similar to 'Tab caption@icon'.
Optional parameter.
+

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{% tabs test1, 2 %}
<!-- tab Tab1 -->
**tab名**
<!-- endtab -->

<!-- tab @fas fa-bell -->
**仅tab图标**

因为tabs标签头设置了默认展示栏位2,所以优先展示这一栏
<!-- endtab -->

<!-- tab Tab3@fas fa-snowflake -->
**tab名+图标**
<!-- endtab -->
{% endtabs %}
+

预览

tab名
啦啦啦~

仅tab图标

+

因为tabs标签头设置了默认展示栏位2,所以优先展示这一栏

tab名+图标

+

label

语法

+ + + + + + + + + + + + + + +
参数解释
text文字
color【可选】背景颜色,默认为 default default/blue/pink/red/purple/orange/green
+

代码及预览

1
2
舜发于{% label 畎亩之中 %},傅说举于版筑之中,胶鬲举于鱼盐之中,管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先{% label 苦其心志 pink %},{% label 劳其筋骨 green %},饿其体肤,空乏其身行拂乱其所为,所以{% label 动心忍性 orange %},曾益其所不能。
人恒过,然后能改;困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡。然后知{% label 生于忧患 red %}而{% label 死于安乐 purple %}也。

舜发于畎亩之中 ,傅说举于版筑之中,胶鬲举于鱼盐之中,管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先苦其心志劳其筋骨 ,饿其体肤,空乏其身行拂乱其所为,所以动心忍性 ,曾益其所不能。人恒过,然后能改;困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡。然后知生于忧患死于安乐 也。

+

tag-hide

1
2
3
4
5
6
7
8
9
10
11
{% hideInline content,display,bg,color %} # inline
{% hideBlock display,bg,color %} # block
content
{% endhideBlock %}
{% hideToggle display,bg,color %} # toggle
content
{% endhideToggle %}
# content: 文本内容
# display: 按钮显示的文字(可选)
# bg: 按钮的背景颜色(可选)
# color: 按钮文字的颜色(可选)
1
2
1+1=?{% hideInline 2,查看答案,#FF7242,#fff %}
谁最可爱?{% hideInline 当然是你啦~}
+

1+1=?2
谁最可爱?当然是你啦~

1
2
3
4
考考你,《七步诗》的作者是
{% hideBlock 查看答案 %}
曹植
{% endhideBlock %}
+

考考你,《七步诗》的作者是

+

曹植

+
1
2
3
4
5
6
7
8
{% hideToggle 和HMK在一起的幸福时刻 %}
1. 牵手、拥抱、kiss~
2. 国庆假期突然出现在我家楼下,还骗我下楼取快递
3. 从身后拿出一朵玫瑰花送给我
4. 一起在西安城墙骑双人车
5. 一起吃李想大虾!!!
6. 带我回家
{% endhideToggle %}
+
和HMK在一起的幸福时刻
    +
  1. 牵手、拥抱、kiss~
  2. +
  3. 国庆假期突然出现在我家楼下,还骗我下楼取快递
  4. +
  5. 从身后拿出一朵玫瑰花送给我
  6. +
  7. 一起在西安城墙骑双人车
  8. +
  9. 一起吃李想大虾!!!
  10. +
  11. 带我回家
  12. +
+
+

Gallery相册

语法

1
2
3
{% gallery %}
markdown 图片格式
{% endgallery %}
+

代码示例

1
2
3
4
5
6
7
8
9
{% gallery %}
![](https://img.cwxhmk.top/gallary/1.jpg)
![](https://img.cwxhmk.top/gallary/2.jpg)
![](https://img.cwxhmk.top/gallary/3.jpg)
![](https://img.cwxhmk.top/gallary/4.jpg)
![](https://img.cwxhmk.top/gallary/6.jpg)
![](https://img.cwxhmk.top/gallary/5.jpg)
![](https://img.cwxhmk.top/gallary/7.jpg)
{% endgallery %}
+

预览

+

timeline

1
2
3
4
5
{% timeline 2018,orange %}
<!-- timeline 07-21 -->
我和康康在一起~
<!-- endtimeline -->
{% endtimeline %}

2018

+

07-21

+

我和康康在一起~

+
+

flink

1
2
3
4
5
6
7
8
9
10
11
12
13
{% flink %}
- class_name: 友情链接
class_desc: 那些人,那些事
link_list:
- name: JerryC
link: https://jerryc.me/
avatar: https://jerryc.me/img/avatar.png
descr: 今日事,今日毕
- name: Hexo
link: https://hexo.io/zh-tw/
avatar: https://d33wubrfki0l68.cloudfront.net/6657ba50e702d84afb32fe846bed54fba1a77add/827ae/logo.svg
descr: 快速、简单且强大的网誌框架
{% endflink %}
+

hexo-pdf

语法

1
{% pdf https://img.cwxhmk.top/pdf/mice_brain_atlas_v4.pdf %}
+

参考资料

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/04/hexo-tag-plugin/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/09/04/keyboard-shortcuts/index.html b/2022/09/04/keyboard-shortcuts/index.html new file mode 100644 index 000000000..e245c6828 --- /dev/null +++ b/2022/09/04/keyboard-shortcuts/index.html @@ -0,0 +1,265 @@ +Windows常用快捷键汇总 | Stray Birds + + + + + + + + + + + + + +

Windows常用快捷键汇总

1
2
3
4
5
6
7
8
9
Ctrl+S 保存
Ctrl+C 复制
Ctrl+V 粘贴
Ctrl+F5 刷新缓存 # 代码上传到github后页面没有变化时,可以试着刷新浏览器缓存
Win+: 表情符号 😊
Win+Shift+S 截图
Ctrl+Shift+N 新建文件夹
Ctrl+Shift+Esc 打开任务管理器
Ctrl+Shift+S 在浏览器内捕获区域
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/04/keyboard-shortcuts/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/09/04/solidworks-register-problem/index.html b/2022/09/04/solidworks-register-problem/index.html new file mode 100644 index 000000000..acda0a11f --- /dev/null +++ b/2022/09/04/solidworks-register-problem/index.html @@ -0,0 +1,279 @@ +无法获得下列许可SOLIDWORKS Standard | Stray Birds + + + + + + + + + + + + + +

无法获得下列许可SOLIDWORKS Standard

前几天突然打不开solidworks,说无法获得许可,无法链接到服务器···(见下图)百度了一番终于找到了解决方案。

+ +

打开任务管理器,在服务里找到SolidWorks Flexnet Server,开启服务,如下图所示(注意:该方法并非一劳永逸,下次再遇到时,同样的操作即可)

+
+ +

开启服务

+
+

每次打开solidworks都要去任务管理器中开启服务,太麻烦了,今天终于找到解决方法了!

+

打开任务管理器,选择服务,任意选中一个服务然后右键,选择打开服务,找到SolidWorks Flexnet Server,右键属性,在常规中将启动类型改为自动,在恢复中将失败后设为重新启动服务,在此时间之后重置失败计数0天,在此时间之后重新启动服务0分钟。SolidWorks Licensing Service的启动类型也设为自动。

+
+

经测试,SolidWorks可以正常运行,而不需要手动开启服务了。

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/04/solidworks-register-problem/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/09/05/install-hddm/index.html b/2022/09/05/install-hddm/index.html new file mode 100644 index 000000000..f3b85e0a2 --- /dev/null +++ b/2022/09/05/install-hddm/index.html @@ -0,0 +1,288 @@ +HDDM的安装方法 | Stray Birds + + + + + + + + + + + + + +

HDDM的安装方法

准备工作

Python Extension Packages 下载所需的Python包和相关依赖。

+
    +
  1. 注意Python版本和操作系统位宽(一般是64位)
  2. +
  3. 安装顺序为numpy-pymc-kabuki-hddm,务必按该顺序安装。
  4. +
  5. kabuki包可通过pip install git+git://github.com:hddm-devs/kabuki.git安装,若失败请看常见问题
  6. +
+
+

安装步骤

1
2
3
4
5
6
7
8
conda create -n hddm python=3.8 # 在anaconda中新建环境
conda activate hddm # 激活环境
pip install --user ipykernel # 安装ipykernel
python -m ipykernel install --user --name=xxx # 将环境加入jupyter
pip install numpy-1.22.4+mkl-cp38-cp38-win_amd64.whl #安装HDDM依赖的3个Python包
pip install pymc-2.3.8-cp38-cp38-win_amd64.whl
pip install kabuki-0.6.5.tar.gz
pip install HDDM-0.8.0-cp38-cp38-win_amd64.whl
+

Python包安装成功后,重新打开prompt(cmd)命令窗口

+
+

测试安装是否成功

    +
  1. 若可以成功打印HDDM版本号,则安装成功
  2. +
  3. 使用过程中,不要在hddm前导入matplotlib等包,即先import hddm,在import其他包
  4. +
+
+
1
2
import hddm
print(hddm.__version__)
+

测试HDDM

+

常见问题

pip install git+https:XXX 安装失败

    +
  1. 先通过github下载好原文件(这时候文件夹里往往有一个setup.py文件,但是有些时候并不能简单的python setup.py
  2. +
  3. 在下载的文件夹下执行 :python setup.py sdist
  4. +
  5. 打开dist文件夹便可以看到一个打包好的需要安装的项目xxx.tar.gz
  6. +
  7. pip install xxx.tar.gz ,到此安装完成
  8. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/05/install-hddm/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/09/06/upyun/index.html b/2022/09/06/upyun/index.html new file mode 100644 index 000000000..f2d5947f7 --- /dev/null +++ b/2022/09/06/upyun/index.html @@ -0,0 +1,301 @@ +使用又拍云提供CDN加速服务 | Stray Birds + + + + + + + + + + + + + + + +

使用又拍云提供CDN加速服务

加入又拍云联盟

加入又拍云联盟,免费获取每月10GB存储空间+15GB流量!!!

+
+

注册步骤如下图所示:
步骤

+
页脚添加又拍云徽标
    +
  1. blog根目录安装插件
    1
    npm install hexo-butterfly-footer-beautify --save
  2. +
  3. 在主题配置文件_config.butterfly.yml中添加
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    # footer_beautify
    # 页脚计时器:[Native JS Timer](https://akilar.top/posts/b941af/)
    # 页脚徽标:[Add Github Badge](https://akilar.top/posts/e87ad7f8/)
    footer_beautify:
    enable:
    timer: false # 计时器开关
    bdage: true # 徽标开关
    priority: 5 #过滤器优先权
    enable_page: all # 应用页面
    exclude: #屏蔽页面
    # - /posts/
    # - /about/
    layout: # 挂载容器类型
    type: id
    name: footer-wrap
    index: 0
    # 计时器部分配置项
    runtime_js: https://npm.elemecdn.com/hexo-butterfly-footer-beautify@1.0.0/lib/runtime.js
    runtime_css: https://npm.elemecdn.com/hexo-butterfly-footer-beautify@1.0.0/lib/runtime.css
    # 徽标部分配置项
    swiperpara: 3 #若非0,则开启轮播功能,每行徽标个数
    bdageitem:
    - link: https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral
    shields: https://img.shields.io/badge/CDN-%E5%8F%88%E6%8B%8D%E4%BA%91-00b6ff?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAABS2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+nhxg7wAABs1JREFUSInllv2PVFcZxz/n3LfZmdmd3ZndZWGhhV0qYLaFEgzQpog12tZYbVRCSa00mLap6Q+aNERp5QcVlRhi0GjaGElromI08aU1tMRXWmspRaEVbIDtdimwy77M7uy83Xvn3nP84c7b7oD/QE8yyT13znO/z/f7nOcF3m9L1B4OnNYYEoSG165kGZkukLLjdEmXiew4yum7+4qK31u2rduLFXOgEEoQCrQs9RjepaW2f35Nu/9QqRh4Fi4jrkHCMmhTitlCBcOIoP768CoAzGt5owFLQBKfad/Yflau+Mo4qY0IE8qAUbXUgKT9ctFZVJAzqzcivLN+/JGY0H6HKD0riKGvw7gFWAFtUmMTyFPF5C+Gded2LBmBaB2BAigRyeMJ0jGPgxtiyX+MtW18/ZL1DLEMK/TER9eb+Z2GQGU1CK0b8gKy9uCYYJmQcUCgUm+U0qeGw/R2pIwAdbPvAiE0aAGux0MDc7eJAJ57V7+GZYAQjLDo8yd0z6lAqQ5bBbh+iF8JWxmP5XwSJrhCyz9NJU7mdHwwknOBWEKAAq0EuIrPrKp8d3lb+M/HT/qvlsN2pKNRSoDUXAxSN+eKlWMPD7jrFi3pZc4NeHUh4+zcNMW5q/z47dLhi4X4IHYt2hFDBBFDpUmYJXoNb+y23tzPHlgRfu2F8bZ9s4W2zdgSpap2OopbzsysPUHX85YIcdU1YnxLX5pT0+59w+X4NqwmpgIIgUCxNF4+vsaY2bsknjtq+yYTnsGhMx33H8127SFp03KTBBAT/H3U+qTIZe9ambFfagHOl0OOjJs/wjCZdwtCARI2d899Z0iP7Rkv2J0ngu49xUCvu1R2+sJS6g4MAyF11deasY5+CjBs3jE6f3KrMXlDC/Cfr0xuuegtWYIpmjwXUA7YcbP69tb2ypPfO5naPyJ7d4fKioLUDihdVxZEpI4ApGiEyoKLM8aydyx5J/CXeTE+m5PbkFZV4qpBoPlAJnh7R7rw5G8vm9+/4PfvDg0rSiMdgYraeQ0xGVZu78o9tSUx9ViK0pUGc0CbTNtdu1oYG7Geu+vFAaLbqz0+3B1sf2WKnhcvJ79MvCn21JiKiGIAt6amn9scK+4brpiskOHMKRU/jCSS2xG8ddVbVcOrM54KrBvqoERyO4YqLTaKb76ct7+JtufHfuEyYKIkeoKKpN12ySs1QF28qkJmrL8FuBwqv7HTEELC4b/Fks/EjPgcDq05TeO8EJrhSten35KLDjpmhfd8/QBNYY6clp0twC1LAmGQLJdyCF08gub/MtYCECZni+JBTyYwrKS7ML2UbrxplEwpHeoJHkk9IPO/z3QluKen/GC/MXuM8PrIQkc3+sY298hAwsIQbSvnAWuwpSq3AGesyhhh08EwZKBdHi+EDjEkyxLBm9dtNYjqXx5DTnHvsCeXFCoi1fh6VPEsEYy3ACf1zN9qlRE0whAcdzM/GCk5Hz+W1dv+U0jubFy+aqdpFsCD9en8r4ba9fDLU6mfI8wo7Zqc65Ccru3q6dQtC79EVb6AUc1lQzJakP2jOvUSZrqKUgu0QMvqNgBkyOpk7ndfXKruP+11Pf5uwdgqHYWqHwIIGTTLh88tBN7a3/3i+VF/ZtyzujAFut57a0d0A1sDpdzoUkfMdCTNs4Pm3MG1nfL1Fy7bjxwtxn6IXfOzauNDZ6w8u67Pf/7IQuDB3hSfCMtPHDoX/hTDaJKxXgzR1ca/PjnzxOL47IGgXOYG2+U9f/Gyw1Op31yYsz6LKcEEpZryyPe5d1B+dWnf4rrwdeATo+P0yfBQr53cOVHp2oIjWpo/LgwlZp/etdo78MeJ9DeO5cUmM+fflNcdy9E2ONGkoWvZIQSUFGt63ZNb+hPPzPr1S9KUTlYndizDl1Zan+qOlXNUqobVD2gPMubcyP4PlR57Ix979MhI+9fLRsfH8qJ7OYYNhkZo1dRfNATQ3ebmdq2073KFQTmgFfjG7jjprjgrMsncPb2FDXEKkwRV8BCEGbD7g2LNmdnYwLPn257Gro6kNMaixlQlwJckVXbyvszsBseJTU+VqA4JC4DdisavwNUy2Ia4sCk5OdRvzLxCBXAVj64NdvTGtbf337ETaBvMa3V9EQ2BFbgpkf/XnbHpIUuHF2YrYMqGgPNi3OxJIZQgjYmNidIdYwHfyjpZ3ZGtHN6fXXbOVfE0MebncHXMAUiL4uRHlpQP3pJW+04OC3KhST+tw8k152oJeEpQNGxWx0tP+WGeK0Xbcb3SWCYpTS80ul0lECi0EF6n8LNJOzjThvuHobj/603dTnFcORQDQcf1y937bP0Pc6b8FW3Czt0AAAAASUVORK5CYII=she
    message: 本网站由又拍云提供CDN加速/云存储服务
    swiper_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css
    swiper_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js
    swiperbdage_init_js: https://npm.elemecdn.com/hexo-butterfly-footer-beautify/lib/swiperbdage_init.min.js
  4. +
  5. 效果预览可见本博客页脚处
  6. +
+
+

填写申请表后,等待审核(会有工作人员打电话询问网站的用途,如实回答即可),审核较快,成功加入后即可获得67元代金券。拿到代金券就可以开心地去创建CDN服务啦!😎

+
+ + +

创建CDN服务

创建服务

+

创建服务后,点击配置,绑定域名。

+
+

添加并解析域名

绑定域名

+

以阿里云域名服务商为例,解析CNAME,复制的内容填入“记录值”。

+
+ + +

申请SSL证书

点击链接申请免费的SSL证书,哪里免费点哪里~审核成功后,回到CDN控制台,点击HTTPS配置。

+
+

第一步
第二步

+

配置HTTPS

不配置HTTPS的话,网站和存储在又拍云的图片都会无法访问。配置好后耐心等待一段时间,可以通过ping来测试是否已经成功创建CDN加速。

+
+

HTTPS

+

测试服务

未加速时,ping网站网址时指向github.io;加速后,指向又拍云的ip。出现像下图类似的结果,就说明成功啦~

+
+

测试

+

参考链接

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/06/upyun/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/09/15/zjuer-questions/index.html b/2022/09/15/zjuer-questions/index.html new file mode 100644 index 000000000..9db58e73f --- /dev/null +++ b/2022/09/15/zjuer-questions/index.html @@ -0,0 +1,285 @@ +初来浙里,我曾经的那些疑惑 | Stray Birds + + + + + + + + + + + + + +

初来浙里,我曾经的那些疑惑

1.暑假可以搬进学校宿舍吗?

其实是可以申请的,不过我们组没有科研助理,很多流程和手续都不太清楚,所以暑假期间我还是老老实实住在老师给租的房子里了。
医学院提前来校学生申请入驻浙大审批流程(更新)

+
+
2.怎么知道班内同学和辅导员?

临近开学的时候,医学中心拉了个博士班的群,稀里糊涂就和同学们在一个群里了。至于辅导员的话,最开始是辅导员在钉钉上提醒我去做核酸,我才知道辅导员是谁的,后面也主要是辅导员在群里和我们下发通知。

+
+
3.工资怎么发放?

工资由两部分组成,学校发一部分(比例大),导师发一部分(比例小),良渚实验室会有¥1000路费补贴。

+
+
4.紫金港校区(申花路)是哪个门?

东2门~

+
+
5.开学后可以办校园卡吗?

可以的,新生入学那天,电信和移动都会在外面搭小帐篷,两者的套餐类似,每个月花费¥29,流量超多,通话时长超多,每个月还可以从给定app(爱奇艺、优酷、哔哩哔哩等)中任选一个充会员,真香!

+
+
6.宿舍有空调、吹风机和洗衣机吗?

宿舍有空调,需要自行租赁(¥450一年);一楼有公共吹风机,宿舍内使用吹风机也不会出现跳闸断电的情况;一楼有公共洗衣机,宿舍内也可以申请安装洗衣机。

+
+
7.体检是在什么时候?

入学后第二天就可以体检了,需要提前预约。体检的整个过程也很快,十几分钟就可以测完。😭我最后悔的一件事情就是,先抽了血,又去测其他项目,结果中途没止住血,当天又提了重物,导致胳膊上很严重的淤血···

+
+
8.怎么选课?

研究生迎新网站有选课的安排通知,按时间点来就可以。不过要注意,第一阶段是初选阶段,选课不分先后;初选结束后是初选确认阶段,可以得知自己有没有选上课,选上的课显示“正在修读”,没选上的课是“未选”;下一个阶段是补(退)选阶段,这个时候就是拼网速和手速了,课程有容量的话一般可以选上,不然就只能候补了;选课结果公布以后,课程才算最终确定哦~

+
+
9.怎么找到上课的地点?

来到宿舍会领到一张学校的手绘地图(我太爱了),趁着刚开学比较清闲,多在学校逛一逛、走一走,对照着地图认一认建筑物,上课的时候就不怕找不到路啦~😎上课地点主要是东教学楼、西教学楼和研究生楼,实验课的话可能会安排在医学院。

+
+
10.学校食堂怎么样?

学校的食堂超级多,有银泉餐厅、东区食堂、澄月餐厅、玉湖餐厅、麦香餐厅、留食餐厅···我比较喜欢东区食堂,菜品好吃不贵,种类齐全!😁

+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/15/zjuer-questions/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/09/20/hexo-move/index.html b/2022/09/20/hexo-move/index.html new file mode 100644 index 000000000..a8b74c13b --- /dev/null +++ b/2022/09/20/hexo-move/index.html @@ -0,0 +1,277 @@ +Hexo迁移至新电脑 | Stray Birds + + + + + + + + + + + + + +

Hexo迁移至新电脑

    +
  1. 下载GitHub Desktop并登陆GitHub
  2. +
  3. 将博客所在GitHub仓库clone至本地
  4. +
  5. 下载并安装Git
  6. +
  7. 下载并安装Node.js稳定版
  8. +
  9. 在Github/blog文件目录下安装hexo及相关插件

    需要以管理员权限进入终端,不然运行下面的命令会报错哦~🫣

    +
    +
    1
    2
    3
    npm install hexo-cli -g
    npm install
    npm install hexo-deployer-git --save
  10. +
  11. 测试

    测试能否通过github desktop正常推送博客!推送成功就说明迁移成功✅啦~

    +
    +
    1
    2
    hexo s # 测试本地预览
    hexo new "test" # 测试发布新文章
  12. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/20/hexo-move/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/09/21/solidworks-model-summary/index.html b/2022/09/21/solidworks-model-summary/index.html new file mode 100644 index 000000000..4016b2e46 --- /dev/null +++ b/2022/09/21/solidworks-model-summary/index.html @@ -0,0 +1,309 @@ +模型加工方法汇总 | Stray Birds + + + + + + + + + + + + + + +

模型加工方法汇总

3D打印

+
    +
  1. 文件格式:STL
  2. +
  3. 加工尺寸:厚度和孔径最低0.5mm
  4. +
  5. 加工工艺:逐层打印
  6. +
  7. 注意⚠️
      +
    • .sldprt文件转为.stl文件之后,一般需要通过magics软件扫描并修复问题
    • +
    • 一般只需向加工方提供.stl文件
    • +
    • 3D打印出的螺纹误差较大
    • +
    • 孔的尺寸过小会堵住,一般需要1mm以上
    • +
    +
  8. +
  9. 加工方: 未来工场
  10. +
+
+ +

铝合金加工

+
    +
  1. 文件格式:STEP
  2. +
  3. 加工精度:±0.1mm或±0.05mm
  4. +
  5. 加工工艺:轧制、挤压、拉伸和锻造等
  6. +
  7. 注意⚠️
      +
    • 最好提前向加工方说明零件用途及加工精度,以免出现较大误差导致返工
    • +
    • 需向加工方提供.step文件和工程图纸
    • +
    • 铝合金加工精度较高,不可随意修改尺寸
    • +
    • 最终目的:加工出来的零件能用!🥲
    • +
    +
  8. +
  9. 加工方: inper(加工慢但质量高)或速加网(加工教快但略粗糙)
  10. +
+
+ +

有机玻璃(亚克力板)加工

+
    +
  1. 文件格式:pdf
  2. +
  3. 加工工艺:切割(误差大概±1mm)
  4. +
  5. 注意⚠️
      +
    • 一般只需向加工方提供工程图纸
    • +
    +
  6. +
  7. 加工方: 淘宝克洛蒙旗舰店
  8. +
+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/09/21/solidworks-model-summary/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/11/12/upload-doc2github/index.html b/2022/11/12/upload-doc2github/index.html new file mode 100644 index 000000000..b003a82d4 --- /dev/null +++ b/2022/11/12/upload-doc2github/index.html @@ -0,0 +1,275 @@ +本地文件上传到Github | Stray Birds + + + + + + + + + + + + + +

本地文件上传到Github

前提:已安装Github Desktop

+
+ +
    +
  1. 通过Github Desktop新建仓库(Create new repository),在本地会新建一个与仓库同名的文件夹
  2. +
  3. 将带上传的文件代码放入新建的本地文件夹
  4. +
  5. 通过Github Desktop上传到Github远程仓库
  6. +
+

PS:也可以直接在Github创建仓库,然后克隆仓库,后续步骤同上2-3~

+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/11/12/upload-doc2github/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/12/27/English-class/index.html b/2022/12/27/English-class/index.html new file mode 100644 index 000000000..5d890fd63 --- /dev/null +++ b/2022/12/27/English-class/index.html @@ -0,0 +1,271 @@ +英语结课感想 | Stray Birds + + + + + + + + + + + + + +

英语结课感想

今天研究生英语结课了,明天把第五组的推文发出来,我助教的工作就完全结束了,竟然有些舍不得。虽然选课时因为六级成绩过期导致无法免修英语,心里有些不甘,但对英语本身我是不排斥的,我喜欢通过英语这个媒介加强与老师和同学们的交流。一直以来口语都是我的心病,我很想得到别人的认可,却又始终不敢开口讲英语,于是My spoken English is poor这句话就常常挂在嘴边,时间久了真就觉得自己口语不行。

+

在这八周的英语课上,无论是线上还是线下,课堂互动总是少不了的。最开始上课时小组讨论时不好意思开口讲英语,老师问问题也不敢大声回答,我多少有些不习惯这种形式的英语课堂,我习惯在传统课堂上当一个认真听课的好学生,在需要英语大量进口和出口 的课堂上我不确定能否表现好。后来我才意识到,最初的想法太天真了,回答个问题有啥的?难的在后头!上台配音、一起唱歌、根据话题极限写稿,英语课堂永远花样形式多变,不知不觉中和小组同学的关系就近了,也更能融入课堂氛围了。

+

我平时不是一点英语都不看的那种,TED演讲、美剧、电影都会看,只不过会看字幕,英语输入的量也不是很大。还记得老师第一次课问我们看过多少个TED演讲,超过50个的举手🙋‍,我当时一直在脑子里数看过的演讲个数,我知道我看过不少,但脑子里没有确切的数字,也就没敢举手。说实话我自认为我的英语发音还可以,所以课堂上或者随堂作业有稿子的时候,我都很放松,感觉处于自己的舒适区中,甚至狂妄地认为这个课对我的英语提升不会有太大帮助。

+

但是我想错了,老师拥有一套完整的方法论。从引入how to speak English in public这一主题,到passionpronunciation、轻重缓急之区分度、sentencestructure of a paragraphacting,循序渐进,最终带领我们呈现一个完整的英语演讲,我总能学到新的东西。每周一晚上大家一起往群里发随堂作业时,我偶尔会心血来潮把每个人的都点开看一遍,总有比我讲的好的同学,每次都会有新的体验和收获。

+

虽然我最后考核时的表现并不完美,一开始有点紧张卡词,表情可能也没有很自然,肢体语言不知道是否清楚恰当,不管怎样,我还是尽我所能顺利完成了考试,给冬学期的英语课程画上了完整的句号。

+

老师说,Hope you'll keep climbing。我相信,英语会在未来的路上一直陪伴着我!

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/12/27/English-class/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2022/12/28/my-2022/index.html b/2022/12/28/my-2022/index.html new file mode 100644 index 000000000..489d30dd2 --- /dev/null +++ b/2022/12/28/my-2022/index.html @@ -0,0 +1,372 @@ +2022年度总结 | Stray Birds + + + + + + + + + + + + + +

2022年度总结

2022我是怎么度过的

1月

    +
  • 抓拍了几张小侄女在我家玩的照片,打印出来以后她超级喜欢
  • +
  • 和爸爸、弟弟还有奶奶一起去了月季公园,玩了呐喊喷泉,还发现了一群鸽子🕊
  • +
  • 爸爸给我买了草莓🍓糖葫芦,嘻嘻嘻
  • +
  • 和小彤彤吃了海底捞,看了电影🎞️《李茂扮太子》(当时是在是没什么电影可看了)
  • +
  • 楼下有小朋友打雪仗,年轻真好
  • +
  • 买了手机支架,正好在奶奶包馄饨时录了个视频,就是手机美颜有点重了
  • +
+

2月

    +
  • 全家出动去月季公园看花灯,逞能玩射箭🏹结果弓都拉不开,箭直接掉出来了,丢人
  • +
  • 和爸爸还有弟弟一起放风筝🪁,我不理解:难道跑不快就放不起来风筝吗?
  • +
  • 和周敏还有王茹冰一起吃了火锅,收到了她们送的生日礼物🎁
  • +
  • 和雨曦一起拼好了积木,摁零件摁地手疼
  • +
  • 一家人在赶海人为我过了21周岁的生日,嘻嘻嘻
  • +
  • 情人节前一天爸爸去给妈妈买项链,顺便给我买了一条手链!手上戴着四叶草🍀,天天都是幸运girl!
  • +
  • 和小彤彤一起吃了串串,看了电影🎞️《这个杀手不太冷静》
  • +
  • 收到了康康送的耳机,不过不太习惯全入耳式的耳机
  • +
  • 在忙毕业设计里小鼠体态识别的实现!
  • +
+

3月

    +
  • 妇女节前一天收到了康康送的一大捧花,玫瑰的颜色好温柔🥰
  • +
  • 百合花开了,味道太浓郁,只能放在阳台散散味道了
  • +
  • 神奇的物物交换:西红柿、草莓、牛油果🥑
  • +
+

4月

    +
  • 给大一的同学做经验分享,结束后收到了冯导给我准备的礼物!📕
  • +
  • 毕业实习时数据库被黑客删了,网络安全很重要哇!
  • +
  • 在宿舍门口拍到了红嘴蓝鹊,我愿称之为目前见过的最美的鸟~
  • +
+

5月

    +
  • 学校的古树上挂满了心愿卡,我总喜欢饭后逛着看一看大家的愿望
  • +
  • 筹备并拍摄毕业证,用班费给每个人买了一束玫瑰花🌹
  • +
  • 和裴焱一起做了美甲💅,我们选的都是兔子,哈哈哈
  • +
  • 拍到了粉紫色的天空!
  • +
+

6月

    +
  • 毕业答辩,是校优嘿嘿~
  • +
  • 小李约我在西区跳蚤市场见面,送了我一个贝壳,嘿嘿
  • +
  • 全校组织各个学院拍毕业照,那天阳光很刺眼,照片里很多人眼睛都没睁开
  • +
  • 交完毕设材料,第二天我就去西安找康康啦!实现了一起在城墙上骑车的愿望!我竟然还进了创新港!
  • +
  • 大四下,国华因为疫情没能回学校,我们约好了在西安见面,去了海洋馆,还一起看了电影🎞️《坏蛋联盟》
  • +
  • 拿到驾照啦,不过至今还没碰过车🚗
  • +
  • 知道我快去杭州了,舅舅请我们吃了一顿大餐!
  • +
  • 月底,爸爸妈妈担心我一个人,硬是要陪我一起去杭州,路线:聊城-济南-济南西-杭州东。那时候我还不懂换乘,只记得我们到杭州以后地贴坐过站了,出了地铁又找不到良渚实验室的位置,天很闷热,汗水把眼睛都弄湿了,最后在手机电量耗尽时终于找舍友拿到了钥匙🔑
  • +
  • 爸爸妈妈跟团去乌镇和西湖旅游,他们给我买了好多特产,回聊城前带我吃了顿好吃的,不过那家店比较坑···
  • +
+

7月

    +
  • 我有自己的工作牌了,也收到了浙江大学的录取通知书~
  • +
  • 在肥叔充了100块钱,喜欢吃店里的锅贴
  • +
  • 开始学习3D建模,陆陆续续完成了一些小任务,找到了一点点成就感
  • +
  • 月底请了五天假,和康康回家见家长啦!幸福幸福幸福!一起遛弯,一起淋雨,一起等蛋糕,一起给玩偶涂颜色,一起吃超好吃的烤肉,一起踩点去看电影🎞️《独行月球》···
  • +
+

8月

    +
  • 七夕收到了爸爸给的红包还有康康送的项链~
  • +
  • 去北京参加暑期培训,CNeuro 2022,被一群大佬虐了十天,呜呜呜
  • +
  • 小李趁周末来找我玩,一起吃了火锅,还送了我一捧橘色泡泡!
  • +
  • 知道医院健身房位置之后,经常早起去打卡2公里~
  • +
+

9月

    +
  • 搬进学校宿舍啦,是双人间,舍友人也很nice~
  • +
  • 临近中秋节,收到了来自食堂和学校的月饼投喂!
  • +
  • 收到了小彤彤送的《云彩收集者手册》,没想到同门师姐也是一位云彩爱好者,嘿嘿~
  • +
  • 参加了新生典礼和开学典礼,小夜灯汇成一片蓝海也太震撼了!要做灿若星辰的浙大人!
  • +
  • 心血来潮去了西湖,这应该是我今年最肆意洒脱的一次,啃烧饼、看西湖、逛苏堤、看老年人舞蹈团表演,人与人之间的🔗好温暖!
  • +
  • 和佳宁学姐还有孟子杰一起吃了烧烤,啥时候我也把我家康康带上呐?
  • +
  • 看了校史大戏《求是魂》,当时不知道还要抢票就直接去了,被社团工作人员偷偷放进去了
  • +
+

10月

    +
  • 国庆去西安找康康了,打卡永兴坊!一起冒着雨在生意火爆的铁锅炖门口等餐、一起吃了超级赞的自助、一起看了电影🎞️《万里归途》···
  • +
  • 发现了学校的向日葵🌻,一位老师热心地帮我拍了好多张站在向日葵花海中的照片!
  • +
  • 跨专业听课好难,哭了😭
  • +
  • 在操场跑完两公里,紧接着点了一份鸭血粉丝汤,罪恶!
  • +
  • 看何婷师姐切小鼠脑片,不知道以后我会不会做生物实验呢?
  • +
  • 学校的桂花开了,校园里香香的,阳光照下来时,小小的花亮亮的
  • +
  • 收到了康康送的丑萌的“羊了个羊”蛋糕,不过超级好吃!
  • +
+

11月

    +
  • 魔鬼考试周,为什么浙大的一学期只有两个月,┭┮﹏┭┮
  • +
  • 打卡西溪国家湿地公园,小孩子比较多,没逛太久就回去了
  • +
  • 给爸爸订了一个兔子🐇蛋糕,太可爱了,哈哈哈,不过以后还是顺着大人的心意多来点实在的水果吧!
  • +
  • 下课后幸运地看到了完整的日落🌇,各个阶段都绝美!
  • +
  • 排练校歌,嗓子经不起折腾,唱一会就会哑,谁懂?!
  • +
  • 当英语助教了,虽然只是一个1学分的小课,但还是想尽力和英语有多一点的联系
  • +
  • 强迫妈妈听我用平板弹生日快乐歌,哈哈哈
  • +
  • 听了陈嘉映和孙周兴两位老师关于“哲学与大学”的讲座,结束后堪称大型粉丝见面会
  • +
+

12月

    +
  • 紫金港因疫情封校一周,每顿饭送到门口也太幸福了!
  • +
  • 杭州下雪了🌨,不过我们还在封控,只能站在阳台看雪。舍友是南方人,确实很兴奋~
  • +
  • 行程卡下线了,不查核酸了,新冠改名了···魔幻的2022!
  • +
  • 师兄博士答辩完请我们吃饭!每道菜都很好吃!
  • +
  • 我回家了,我阳🐏了,我阳康了。嗓子疼真要命,还好我们家经常熬冰糖梨水~
  • +
+

2022年到处拍拍拍

天空

+

美食

+

臭美

+

和朋友

+

和康康

+

小确幸

+

关于2022,我想说

记得年初时我买了一个手账本,附带的卡片上说我今年的主题词是“繁花”,我心想,2022一定会是极好的一年,事实证明的确如此。回顾这一年,上半年是告别,下半年是新生。大学毕业于我而言,一半是逃离,一半是不舍。无论如何,我在太原理工大学的生活画上了句号。我的所谓毕业旅行很短,也没有鼓足勇气和康康去拍写真,在家也没有待很久,就匆匆收拾行囊赶赴了下一站——杭州。新学校很美,学校很包容、很智能、很自由,我在学习之余增加了许多生活中的新奇体验,变得更加独立和勇敢。不过谈到科研,说实话我还没有完全适应跨专业的生活,我花了很长时间适应新身份——神经生物学专业的学生,熟悉新的领域,摸索如何将计算机领域的知识用在生物方面,初学硬件知识···但我现在还是很难平衡好课程和实验室任务,面对许多任务会丧失行动力,对自己的定位和认知还有些模糊,不过也逐渐习惯了和老板的相处之道。小陈同学,要愈挫愈勇才行,你的福气在后头!

+

你好,2023

主题:告别拖延
目标:10部电影➕10本书➕定期复盘

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/12/28/my-2022/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2022/12/31/last-day-of-2022/index.html b/2022/12/31/last-day-of-2022/index.html new file mode 100644 index 000000000..cf03a39f8 --- /dev/null +++ b/2022/12/31/last-day-of-2022/index.html @@ -0,0 +1,268 @@ +2022年的最后一天 | Stray Birds + + + + + + + + + + + + +

2022年的最后一天

今天早上赖床了,八点多才起床,早上依旧是喝玉米糊。妈妈今天倒班,白天一直在家。上午我磨蹭到九点才挪动到书桌旁边,开始背大型仪器的问答题,背了大概一小时左右,妈妈说一会陪她逛超市。我第一反应是拒绝的,因为今天安排的复习任务比较多,但妈妈第二次提出这个要求的时候我就同意了,毕竟妈妈很少有空逛超市。我午睡本来打算睡半小时的,结果愣是睡了一个半小时,午睡时长确实是一个大问题,怎么才能控制一下呢?每次醒来都发现下午也快过去了时,真的要命!下午把突触那一节的回放◀看了一遍,老师有划重点,视频大概两个小时左右,所以听起来并不费力。

+

晚上看到清一色复盘2022的推文,复习的心❤️一下子乱了,总想再看看人民日报制作的年度温暖视频,再看会搞笑的脱口秀,可是复习的重任和一周一度的周报和组会在心头压着,我突然emo😈起来,逮住男朋友就开始找事。磨蹭到晚上九点才开始继续复习,看了一部分神经环路的视频,然后开始看学习记忆的视频(这个老师有明确说考题)。复习着复习着,就到晚上十一点了,拖延真的是无形中对我们的消耗。很多时候我们一些令人费解的行为,比如一直刷视频、想寻求刺激、觉得身体疲惫等等,可能只是在拖延时间,借此逃避高压的现实。但实际上拖延是在为现实增负,大脑🧠习惯沉溺在舒适区,这就注定成长和突破是要付出一些代价的。

+

最近我每天都用Forest 软件记录时间,主要是学习、工作和写博客三大块。我每天都忙活到十一点多,但一看一天的专注时长才三小时左右,不禁感叹时间都去哪儿了?我是不是也在假装很努力,实际上浪费了很多时间呢?前几天写2022年年度复盘时,我给2023年定的主题词是“告别拖延”,我希望这次不仅是说一说,而是真正落实到每一天的生活中,落实到每一个任务中。明年的课程会少很多,要尽快转入科研主线,多做一些为自己增值的事情,少一些无理取闹和胡思乱想。多读书,多写作,多思考,多实践,多锻炼。希望新的一年我可以交到好朋友 ,培养一门兴趣爱好,情绪也更加稳定。无论所处环境如何,要始终热爱生活,踏实做事,真诚待人,逐渐变成自己喜欢的样子。

+

最后借用总书记新年贺词中的一句话结尾,路虽远,行则将至;事虽难,做则必成。祝愿大家身体健康、新年快乐、皆得所愿!

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2022/12/31/last-day-of-2022/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/01/the-first-day-of-2023/index.html b/2023/01/01/the-first-day-of-2023/index.html new file mode 100644 index 000000000..c9e4546b9 --- /dev/null +++ b/2023/01/01/the-first-day-of-2023/index.html @@ -0,0 +1,269 @@ +2023年的第一天 | Stray Birds + + + + + + + + + + + + + +

2023年的第一天

前几天就计划好今天去东昌湖玩,只不过从下午改到了上午。其实往年元旦我都是在学校过的,三天的假期很少有机会回家。今年沾了疫情的光,去年十二月底就回家了,新的一年第一天,一家人就要整整齐齐出去玩!爸爸把车停到摩天轮里面的停车场了,我们就顺便在摩天轮附件逛着玩了一会。之前总是远远的看过摩天轮🎡,这是第一次看到正门,近距离看摩天轮时发现摩天轮转地好慢!没想到旁边还有一个小型的动物园,有好多匹白色的矮马🐎和各种颜色的孔雀🦚,有的小马的毛发还编了辫子,超级可爱🤩

+

一路向鼓楼走去,东昌湖结冰了,冰面上零星散落着砖块、摔炮盒和烟花桶,想必先前有很多人想来测试一下冰面的厚度吧,向远处望去,隐约看到一只水鸭踉跄地在冰面上走来走去,画面有些滑稽。本以为今天鼓楼这边会很热闹,没想到却是没多少人,路两侧布满了红色的摊位,出摊的却很少。大冷天的,冰糖葫芦的生意当属第一,比如我们就给商家贡献了五串糖葫芦🍡的交易。路边上有两个大爷在卖气球🎈,是短视频里很流行的花朵🌼笑脸气球,我想:要是康康带我来这里玩,肯定会给我买气球的!

+

今天又是喜欢给爷爷奶奶拍照的小陈同学( •̀ ω •́ )~抓紧复习去啦!!!🐇

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/01/the-first-day-of-2023/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/02/dynamic-mind/index.html b/2023/01/02/dynamic-mind/index.html new file mode 100644 index 000000000..db904757b --- /dev/null +++ b/2023/01/02/dynamic-mind/index.html @@ -0,0 +1,269 @@ +动态思维 | Stray Birds + + + + + + + + + + + + + +

动态思维

导师在某次组会上说,我手头的多个任务并不是互相孤立的,有的任务两两之间存在联系 ,比如arduino和Bpod两者配合实现动物行为的触发和记录,学懂了一方,会对另一方起到促进作用。自此以后,我变得有意识地关注事物之间的联系。我时常会在攻克某个小障碍之后豁然开朗,我不仅明白了事物背后的原理,而且看待其他问题时有了新的视角和思路。

+

说实话,我本身存在很强的定式思维,比如我拿到一个任务,如果周围人都说这个任务很难,而我恰巧在这方面也不是很自信,那我很可能就先入为主地认为自己无法很好地完成这个任务,在执行过程中就可能变得畏手畏脚。或者,我会从触发思绪的一个事件点(有可能只是一句话、一个通知、一张图片等)发散思考,悲观地认为很长一段时间甚至一辈子都会是这样。这种思考方式在我很小的时候就出现了,我小时候一直是短头发,我很羡慕别的女孩子头发长长的,扎起来又精神又好看,但我头发一长就会被妈妈带去理发店,我常常躺在床上想,结婚时短发穿婚纱会不会不好看?我会不会一辈子都是短头发呢?但事实是,我从初三就开始留长发了,在我自己有意愿且有能力自己扎头发以后,妈妈并没有阻拦过我留长发。回看过去,很多时候我们忽视了事物发展的动态性,有时只有站在较长的时间尺度上才能看见变化本身

+

这几天复习时,把老师讲课的视频回放又看了一遍。其实我上课时有认真听老师讲课,但有的老师讲课时间长,有的老师讲课语速快,有的内容我比较生疏,总之第一遍听下来,我几乎捕获不到老师讲课的框架和重点。渐渐地,这些课程回放在我眼中变成一个个凶狠的怪兽,我在临近期末考试时才不得不选择重新听课。神奇的是,第二次听课时,我发现这些课程之间很多内容是互通的,几乎每个老师都会介绍动作电位、突触以及膜片钳技术,有三位老师都讲到了长时程增强,有两位老师都讲到了量子释放,谷氨酸和GABA受体也是在各个老师口中常出现的词,一个一个回放看下来,似乎曾经在我眼里困难重重的神经生物学知识,变得条理清晰起来。各个老师的讲解互相补充和联系,知识点逐渐串联成了知识面。

+

我所说的动态思维 ,也可以说是成长型思维、主观能动性,或者用发展的眼光看问题,在我看来都是一个意思,就是要认识到我们所处的世界的在发展的,事物之间是相互联系而不是孤立的或一成不变的。我们总觉得自己的想法是正确的、有预见性的,但这往往很有迷惑性,我们往往容易忽视事物之间的联系,也很难用静止的思维去评判动态发展的事物。事物在变化,随着对事物的熟悉程度或思考深度增加,我们对事物的认识同样会发生变化。所以不要害怕困难,主动权掌握在我们手里,我们可以用积极的行动改变认知,进而影响任务的走向。

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/02/dynamic-mind/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/03/press-stop-button/index.html b/2023/01/03/press-stop-button/index.html new file mode 100644 index 000000000..60f6a2343 --- /dev/null +++ b/2023/01/03/press-stop-button/index.html @@ -0,0 +1,280 @@ +及时按下暂停键⏸ | Stray Birds + + + + + + + + + + + + + +

及时按下暂停键⏸

牛顿第一定律:任何物体都要保持匀速直线运动或静止状态,直到外力迫使它改变运动状态为止。

+
+ + +

我经常会想,要是生活有replay button该多好,要是我从大一就好好练习编程能力,是不是也有机会参加计算机的竞赛?要是我考完四六级以后听英语老师的话一鼓作气把英语的证书都考下来,或者没有就此把英语扔到一旁,我现在英语的听说读写是不是都超好?要是我坚持把收藏的网课看完,现在是不是已经成为跨界高手了?要是我把时间管理的好习惯坚持到今天,是不是面对多任务就游刃有余了?这种想法其实没有太大意义,时间不会重来,即使让我重新来过,我能否坚定地做出难而正确的选择呢?

+

相较于replay button,我认为pause button更常用且可操作性更高。原本拿起手机📱是想看一下群里的通知,却不知不觉看起了推送和短视频;明知道有很紧急的事情要做,却因为别人的一句批评而深陷消极情绪;明明知道任务A更重要,却仍选择将时间花在一个个无关紧要的事情上;本来只想网购一个本子,却不自主地挑起了衣服···这样的场景数不胜数,很多时候我们处于这种失控状态。这时我们需要做的是果断按下暂停键,防止负面情绪伤人伤己。

+

我们的大脑中有两个小人,小人A喜欢轻轻松松,小人B喜欢自我约束。我们的大脑乐于处于愉快且低能耗的状态,因此大多数情况下是小人A说了算,但这往往会让我们变得贪玩和懒散。当我们想做出改变时,小人A和小人B会在脑内开始打架,往往还是小人A获胜。就像我们在追剧时,想着看完这一集就去学习或者就去睡觉,但一集结束后,我们还未来得及打败那个想继续看下去的小人,下一级就自动播放了,这时我们往往会想,刚刚的剧情好精彩,不如就再看一集吧。

+

那小人B怎样才能打败小人A呢?以我个人经验而言,可以有两种方法。第一种,内心的小人在斗争时,再努力挣扎一下,强迫自己去做另一件可以带来正向影响的事情,在事件的切换中找回对生活的掌控感。就比如我今天下午复习的节奏很乱,经常被别人打断,但我又不能对家人发脾气,晚饭后没复习好的失落感配上饭桌上叽叽喳喳的说话声,我突然陷入一种极强的消极情绪,对什么事情都失去了兴趣,但我强迫自己把刚刚看的视频回放的重点总结出来,但此时心情还是不好,于是我又去洗了个澡(即使我心情不好什么都不想做,但我知道洗澡极大概率会让我的心情变好,于是我就去做了),洗完澡果然心情就恢复正常了,我又可以重新投入学习中了。第二种,借助外界刺激,这种往往是不可控的,而且是可遇不可求的。比如玩手机的时候老板发来消息问任务怎么样了,逛街时看到群消息确定了考试日期等,这种刺激往往会马上给小人B注入能量,从而促使我们立刻放下手头的玩乐活动,转而投入学习或者工作。

+

多审视自身状态,面对行为上的自我放逐,及时按下暂停键。

+
昨天晚上睡觉时的一点思考
    +
  1. 要想和比自己地位或能力高的人有效对话,首先要在认知领域上有相交,不要习惯做门外汉。
  2. +
  3. 不要着急看到结果,把功夫花在关键事情上,改变自然就会发生。
  4. +
+
+ +
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/03/press-stop-button/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/05/end-of-winter-semester/index.html b/2023/01/05/end-of-winter-semester/index.html new file mode 100644 index 000000000..8558a268d --- /dev/null +++ b/2023/01/05/end-of-winter-semester/index.html @@ -0,0 +1,268 @@ +冬学期结束感想 | Stray Birds + + + + + + + + + + + + + +

冬学期结束感想

今天下午四点零五结束了冬学期的最后一门考试!考前的时间充实且紧张,可真到开考倒计时变为0时,一切紧张和焦虑就都被抛在身后,关注的只是考题和脑子里的知识。牵绊着我们的一件件事情结束时,会带给我一种很奇妙的感觉,我想是这件事情承载的关注与一切戛然而止造成的落差导致的。我会突然觉得似乎也没什么,再不愿面对的事情总归是过去了。该背的知识点再拗口也背下来了,再难理解的知识也照样听进去了,逼自己一把,没什么是不可能的。

+

下午系统自动收卷的那一刻,我感到非常释然,我终于可以回到没有考试任务的生活节奏中来了。每天全部的时间都可以自己安排,这下总不能说没什么做任务了,如果没有考试复习压力,我依旧没有推进任务,那问题就出在我身上了。虽然这段时间我在备考的过程中每天时间利用率都比较高,但我不知道没有了考试这个有紧迫时限且不得不去认真准备的事情之后,我能否把有效的时间用在科研任务上。

+

我很期待未来一段时间的实践,我想证明我可以。👍

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/05/end-of-winter-semester/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/06/draw-money/index.html b/2023/01/06/draw-money/index.html new file mode 100644 index 000000000..360902924 --- /dev/null +++ b/2023/01/06/draw-money/index.html @@ -0,0 +1,277 @@ +取钱小记 | Stray Birds + + + + + + + + + + + + + +

取钱小记

过年前陪爷爷奶奶去银行取钱,是我们之间的一个小默契。奶奶说,这钱是一部分是过年给小孩子们发压岁钱用的,剩下的留着用作年后日常花销。我们拿上银行卡和存折,走上十多分钟就可以到银行,顺利地话在自助取款机上就可以完成取钱任务。但偶尔也会有一些突发情况,需要存折、身份证但忘记带,或者不记得银行卡密码了···

+

第一次取钱

+

往年我都是放寒假回家,今年情况特殊,是临时变更学习场所,回家以后还要准备线上考试。在复习周的某天上午,爷爷奶奶提出想让我带他们去取钱,我想着当天剩下的复习任务不是很重了,便答应了。爷爷需要在中国银行取¥5000,奶奶需要在中国邮政储蓄银行取这一年的养老金。

+

我们家离银行很近,各大银行都在一条街上,相互离得也不远。我们先走到中国邮政,就想着先把奶奶卡里的钱取出来。结果我在自助取款机看卡的余额只有两块钱。银行的工作人员说可能是卡没有激活,需要存折才行。但奶奶出门没想那么多,只带了两张银行卡和两张身份证。爷爷心急,把奶奶说了一通,让奶奶回家取存折。奶奶本想和我们一起去中国银行取钱,但爷爷说她来回要很久,现在回家可以节省些时间,奶奶才迈着不太轻快的步伐回家了。

+

我和爷爷去中国银行取钱就比较顺利了,自助取款机上没有钱了,我们在大厅里的取款机上取的钱,有工作人员的热心服务,取钱任务很快就完成了。我和爷爷回到中国邮政门口,时不时张望着路口处有没有奶奶的身影,奶奶走路慢,年纪大了又不敢骑自行车,我们等了很久,才看到我们期待的身影。不过坏消息是,存折上查出来的余额依旧是两块钱。奶奶有些着急,念叨着:那我的老年金去哪里了?后来爷爷提出看看社保卡上有没有钱,我就拿着社保卡去自助取款机上试了一下,没想到养老金真在这个卡上!爷爷奶奶悬着的心终于放下了,取钱顺利完成!

+

之前从来没有用这张社保卡取过钱,谁能想到钱在这里呢?🥲

+

第二次取钱

+

第一次取钱结束后,我在饭桌上郑重声明,在我考试结束前谁都别来打扰我。于是,家里人真的让我清净了两天。上次从奶奶的社保卡里取了钱,爷爷一直想去看看他的社保卡里有没有钱,但我在忙考试就没敢提这个事情。昨天下午四点多考完试,爷爷奶奶还又找我确认了一遍:考完试这下你没什么事了吧?🤣

+

今天早上爷爷想让我带他查一下他的社保卡里有没有钱,我们拿着社保卡和身份证就出发了,想着应该很快就能回来。我在自助取款机上试了一下,密码竟然还是默认的卡号后六位数字,有了上次的经验,我知道是卡没激活。我们去找工作人员问了一下,激活需要本人到场,需要本人的身份证,但由于爷爷不会写字,我代签的话需要提供身份证。我想着既然来了就帮爷爷把这个事情办好,我让他在大厅坐着等我回去取身份证,爷爷还提醒我骑自行车来,比较快。

+

我也不知道来回花了多久,总之戴着口罩有点喘,进了大厅有点出汗。我看了柜台窗口上叫的业务号,我们当时领的号已经过去了,我就重新排了个业务号,前面有6个人。大部分都是老年人取钱的业务,所以没等多久就到我们了。工作人员一听说我要代签,很是诧异,对我爷爷说:大爷,我看你年纪也不大,自己的名字写不了吗?爷爷无奈地摇了摇头。我领了代签,一顿签字以后,爷爷一顿按手印。又是拍合照,又是录密码,又是点确认,前前后后花了半小时左右。

+

我当时回头望了下沙发上坐着的一群老年人,他们大部分都在看我们激活银行卡,我不知道他们是觉得我们太慢了,还是在羡慕爷爷有孙女陪着来,我自己更倾向于后者。(❁´◡`❁)社保卡激活以后,我们麻烦工作人员查了下余额,没想到里面有两万多,透过口罩我都能感觉到爷爷的开心。爷爷没有取钱,查完余额我们就回家啦~

+

记得以前爷爷奶奶都是拜托爸爸帮他们取钱,不知道什么时候他们开始愿意让我带他们一起去取钱。和爷爷奶奶在一起时,我觉得自己是大孩子了,我可以在这个信息时代为他们抵挡一些风浪,我也很想被爷爷奶奶依靠!👵👧👴

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/06/draw-money/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/08/a-happy-weekend/index.html b/2023/01/08/a-happy-weekend/index.html new file mode 100644 index 000000000..51bd8573b --- /dev/null +++ b/2023/01/08/a-happy-weekend/index.html @@ -0,0 +1,275 @@ +愉快的周末 | Stray Birds + + + + + + + + + + + + + +

愉快的周末

前几天和小彤彤说好周末出去逛街,十点在百货大楼见面。我今天虽然出门比之前稍晚一会,但等公交并没有花很久,赶在约定的时间点前一分钟到达了目的地,然后又等了她十分钟左右。我早上只喝了玉米糊,她是根本没吃饭。我们在尚街逛到十一点左右,就去金鼎吃重庆火锅啦!店里有免费的甜品,番茄和牛油的鸳鸯锅锅底也很有卖相和食欲,我们点了双人套餐,又加了一份金针菇,后面写了好评,店家又送了两个炸蛋,太幸福了!!!套餐里食物种类不少,肉类也很新鲜,服务人员会及时加汤,我们两个都吃的饱饱的!吃完火锅有点渴,我们去了茶百道买奶茶,我点的店里的新品,喝起来有点像茶和奶酪的结合体。我们坐在店里休息的时候,有一对年纪很小的双胞胎一直看着我们笑,好可爱!休息好后我们一起去了商场,小彤彤帮我选了牛仔裤和毛衣,牛仔裤很有弹性,毛衣也是试了三件以后我最满意的一件,收获满满~

+

虽然我一年中大部分时间都不在聊城,但每次回家后都会想和好朋友见一面,一起吃好吃的,一起在热闹的地方逛一逛,一起聊聊天~(●’◡’●)我相信健康的友谊会让彼此受益!

+ +
今日小结
    +
  1. 今天大部分时间是在听小彤彤讲她的事情,有在小小践行《人性的弱点》中作者总结的与人交往的原则
  2. +
  3. 给爷爷奶奶买的收音机到了,他们看起来很喜欢,很快就学会如何操作了!
  4. +
  5. 给弟弟买了草莓蛋糕杯,他一口气吃完了,我猜测应该是好吃的
  6. +
+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/08/a-happy-weekend/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/01/10/matlab-skills/index.html b/2023/01/10/matlab-skills/index.html new file mode 100644 index 000000000..0d08eb0b1 --- /dev/null +++ b/2023/01/10/matlab-skills/index.html @@ -0,0 +1,273 @@ +Matlab常用命令 | Stray Birds + + + + + + + + + + + + + +

Matlab常用命令

    +
  1. 矩阵拼接
    1
    2
    cat(2,A,B) % 相当于[A,B]
    cat(1,A,B) % 相当于[A;B]
  2. +
  3. 去除重复元素
    1
    2
    3
    unique(A,'sorted') % 去除重复元素,且升序排列('sorted'一般省略)
    unique(A,'stable') % 去除重复元素,不排序
    unique(A,'rows'); % 去除重复的行
  4. +
  5. 查找元素下标
    1
    2
    3
    4
    5
    find(X):返回一个包含元素索引的向量
    find(X,n):返回 X 中元素的前n个索引
    find(X,n,Direction):根据Direction在X中找到n个索引,其中Direction-'first''last'
    [row,col] = find():返回数组中元素的行列下标
    [row,col,V] = find():返回包含非零元素的向量V
  6. +
  7. 查看矩阵中是否有某个元素
    1
    ismember(1,A) % 若包含则返回值为1,否则为0
  8. +
  9. 打开matlab出现警告“名称不存在或不是目录”
    1
    edit pathdef % 把对应的路径删掉即可
  10. +
  11. 保存变量
    1
    save('abc.mat','m','n') % 将变量m和 保存到abc.mat文件
  12. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/01/10/matlab-skills/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/06/26/spider/index.html b/2023/06/26/spider/index.html new file mode 100644 index 000000000..3bd3eabbe --- /dev/null +++ b/2023/06/26/spider/index.html @@ -0,0 +1,273 @@ +爬取网站数据 | Stray Birds + + + + + + + + + + + + + +

爬取网站数据

爬虫基本步骤

1
2
3
4
5
6
7
8
9
10
11
import requests
url = 'https://www.google.com/' #以爬取谷歌页面为例
headers = {
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537 36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58"
}
proxies={
'http':'http://127.0.0.1:10808' #依据本地代理端口填写地址
}
r = requests.get(url=url, headers=headers, proxies=proxies)
print(r.status_code) #200
print(r.text)
+

经验(●’◡’●)

    +
  1. 静态页面一般可以直接通过get请求获得网页数据
  2. +
  3. 需要js动态渲染的页面获取数据会稍微复杂一点,可以先查看返回的xhr或json文件是否有想要的数据(预览),或者ctrl+F搜索关键词
  4. +
  5. 通过“发起程序”可以查看文件的请求程序发起链
  6. +
  7. 爬虫的关键是抓包!找到我们感兴趣的数据!
  8. +
+

应用案例1:爬取网站课件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import json
import os

url = "https://classroom.zju.edu.cn/pptnote/v1/schedule/search-ppt?course_id=49219&sub_id=848702&per_page=100"
headers = {
"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43"
}

page_num = 2
date = '20230615'
save_dir = 'D:/Desktop/ppt_img/' + date + '/'

for i in range(page_num):
params = {'page':i+1}
r = requests.get(url=url, headers=headers, params=params)
# print(r.status_code)
text = r.text
text_dict = json.loads(text)
ppt_list = text_dict['list']
print(len(ppt_list))
folder = os.path.exists(save_dir + str(i))
if not folder:
os.makedirs(save_dir + str(i))

for j in range(len(ppt_list)):
content = json.loads(ppt_list[j]['content'])
img_url = content['pptimgurl']
r = requests.get(img_url,headers=headers)
save_path = save_dir + str(i) + '/' + str(i) + '_' + str(j) + '.jpg'
with open(save_path, 'wb') as f:#把图片数据写入本地,wb表示二进制储存
f.write(r.content)
+

应用案例2:爬取Allen小鼠脑图谱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests
import json
import os

url = "https://atlas.brain-map.org/atlasviewer/atlases/602630314/576985993.json"

headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58"
}

r = requests.get(url=url, headers=headers)
dict = json.loads(r.text)
num = len(dict['msg'][0]['section_images'])
img_dict = dict['msg'][0]['section_images']
# print(img_dict[130]['path'])
add_1 = "https://atlas.brain-map.org/cgi-bin/imageservice?path="
add_2 = "&mime=1&zoom=3&width=1140&height=800"

save_dir = "D:/Desktop/allen_img/"

for i in range(num):
path = img_dict[i]['path']
img_url = add_1 + path[:-4] + '_rendered.aff' + add_2
r = requests.get(img_url, headers=headers)
save_path = save_dir + str(i+1) + '.jpg'
with open(save_path, 'wb') as f:
f.write(r.content)
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/06/26/spider/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/06/26/style-transfer/index.html b/2023/06/26/style-transfer/index.html new file mode 100644 index 000000000..902cc0506 --- /dev/null +++ b/2023/06/26/style-transfer/index.html @@ -0,0 +1,281 @@ +图像风格迁移 | Stray Birds + + + + + + + + + + + + + + + +

图像风格迁移

数据集准备

按照该链接下载coco数据集的指定类,作为训练数据集。YOLO-Coco-Dataset-Custom-Classes-Extractor

+

开源模型介绍

风格迁移模型参照该github开源项目。onnx_small_style

+
    +
  • images/目录下包含输入图片文件夹、输出图片文件夹及风格图片文件夹
  • +
  • model/目录下有按特定风格图片及尺寸训练好的模型,可以直接使用
  • +
  • 风格迁移在线demo1:风格迁移网站
  • +
  • 风格迁移在线demo2:风格迁移网站
  • +
+

项目内容介绍

+

模型训练及测试

1
2
3
4
# 使用训练好的模型
python neural_style/neural_style.py eval --content-image images/content-images/birds.jpeg --model model/rain_princess.model --output-image images/output-images/birds_rain.jpg --cuda 0 # cpu
# 训练自己的模型
python neural_style/neural_style.py train --dataset dataset --style-image images/style-images/girl.jpg --save-model-dir model --epochs 2 --cuda 1 # gpu
+

注意事项

    +
  1. 训练过程中报内存不足时,考虑风格图片的尺寸是否过大,或者减小batchsize
  2. +
  3. 如果使用自己的笔记本训练数据,最好不要使用完整的coco数据集,可以只选取某些类别的图像数据
  4. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/06/26/style-transfer/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/02/making-choices/index.html b/2023/07/02/making-choices/index.html new file mode 100644 index 000000000..fef509e46 --- /dev/null +++ b/2023/07/02/making-choices/index.html @@ -0,0 +1,286 @@ +做选择 | Stray Birds + + + + + + + + + + + + + +

做选择

我不得不承认,除了友情上的一些小挫折,我的大学生活真的是太顺利了,似乎没有太用力就一步一步走到了保研升学这个岔路口。曾经我并没有觉得这样有什么问题,直到我读博一年以后,我愈发觉得做出明智的选择是多么重要,而大学时的我是多么稚嫩和无知。

+
+

那些年少无知做出的选择

    +
  1. 关于学习:身边的老师、同学都说成绩很重要,学校的保研政策也只有加权排名这一项,我在大学的工作重心就只放在的课程学习上,准确的说是应试上。缺少了知识体系的构建和课程内容的实践,课程设计和实践项目代码也没有很好的归档,导致毕业以后沉淀的内容很少。
  2. +
  3. 关于比赛:其实我一直对自己的能力没有太多自信,大家对计算机专业的第一印象就是编程能力强,可我却没参加过程序设计竞赛,除了学校开设的课程以外,我没有花额外的时间提升自己的编程水平。现在在课题组内做一些具体的任务,我可以很明显的感觉到解决问题没有一个完整的思路,写代码也离不开CSDN(呜呜呜),太丢人了!
  4. +
  5. 关于自学:大学的时候,尤其是大三、大四的时候,我有大把的空余时间,明明知道项目很重要,机器学习和人工智能很火,但却始终没有学起来,网课反复观看前几集。我现在的数据分析大量需要机器学习的算法,导师天天提神经网络,可我脑子里却没有一个成型的概念。
  6. +
  7. 关于文档:我大学里学习专业课程,每次考完试笔记和学习资料就扔一边了,从来没有试着整理成电子文档保存下来,或者和其他课程建立联系。课程设计完成以后代码就丢一边了,没有系统的保管代码。现在做项目需要用到以前的专业知识,我都差不多要重新学,知识储备干净地像一张白纸。
  8. +
  9. 关于跨专业:我之前对专业没有什么概念,什么专业好,什么专业天坑,我都没怎么了解过。关于跨专业到神经生物学,我当时只是觉得我不是很喜欢用别人写好的模型做项目,我想有自己的东西,做研究也挺好的,这个专业挺需要计算机的,于是我就跨专业了。但我当时至少应该了解一下这个专业是干什么的,就业前景如何,也可以试着听几节神经生物学相关的课,看看自己是否对这个专业真的感兴趣。这样我也不会来到新的课题组之后不知道自己可以干什么,不知道自己对什么研究方向感兴趣,苦苦摸索。
  10. +
  11. 关于选导师:保研那段时间,除了上科大是我主动联系的导师以外,我入营的其他学校都是老师主动联系的我。我当时很天真,我认为应该答应第一个联系我的老师,毕竟是这个老师先联系我的,却忽视了选导师最重要的是适合自己。如果时光机让我回到一年前,我会对当时的我说:了解一下这个老师的研究方向、课题组规模和人员配置、工资情况、有无科研助理、出勤要求、课题组氛围、课题组内部对导师的评价,不要不好意思问,不要轻易做决定,在提交系统之前,你有选择导师的主动权。
  12. +
  13. 关于直博:当时脑院只招直博生,于是我稀里糊涂直博了。我知道直博只需要五年就可以拿到博士学位,但我不知道导师会上来就拿博士生的标准要求一个本科毕业的学生,不知道博士延毕的比例这么高,不知道博士读不完会一无所有。如果可以重来,我希望自己先读一个硕士,既可以从本科慢慢过渡提升自己的能力,也可以探索自己是否有意愿读博。既然走上了这条路,就好好地走下去吧!
  14. +
+

建议

    +
  1. 无论是做计划还是做选择,给自己至少三个选项,从中选最优的那一个
  2. +
  3. 现在过得难一点是好事,未来或许会轻松一点
  4. +
  5. 我们的记忆是有限的,学到的知识要及时整理,不要觉得麻烦,这些都是宝贵的财富
  6. +
  7. 在决定做出改变之前,先进行原型设计,以最小的成本体验要做出的改变(有点类似于创业过程中的MVP)
  8. +
  9. 不要害怕向别人寻求帮助和建议,事前暴露自己的无知也比掉坑里再呼救要好得多
  10. +
  11. 时刻保持清醒
  12. +
  13. 学习要有连续性,不要每个东西都只学个皮毛
  14. +
  15. 成事之根本:行动起来
  16. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/02/making-choices/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/02/mice-brain-atlas/index.html b/2023/07/02/mice-brain-atlas/index.html new file mode 100644 index 000000000..258e1b3a3 --- /dev/null +++ b/2023/07/02/mice-brain-atlas/index.html @@ -0,0 +1,273 @@ +小鼠脑图谱第四版 | Stray Birds + + + + + + + + + + + + + +

小鼠脑图谱第四版

+ +
+ +
+ + + +
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/02/mice-brain-atlas/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/07/03/imagej-plugin/index.html b/2023/07/03/imagej-plugin/index.html new file mode 100644 index 000000000..ed69f9b9e --- /dev/null +++ b/2023/07/03/imagej-plugin/index.html @@ -0,0 +1,300 @@ +BIRDS插件代码学习【01】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【01】

BIRDS简介

BIRDS(Bi-channel Image Registration and Deep-learning Segmentation for efficient, versatile mapping of mouse brain)是ImageJ的一个插件,由费鹏老师实验室开发,主要用于小鼠脑片配准和细胞计数。BIRDS改进了脑片与图谱的配准算法,并借助Imaris实现了全脑的三维可视化。

+BIRDS界面 + +

BIRDS主要包括downsample、coarse、precise、visual和setSeg五个部分,分别用于图像预处理、图片配准、可视化检查和手动校正以及脑区分割预测。

+

我关注的主要是前三部分,核心是脑片和图谱的配准,具体流程如下图。

+

BIRDS脑片配准流程

+

Java GUI 组件

JPanel 面板

1
JPanel northPanel = new JPanel();
+

JLabel 标签

1
JLabel urlLabel = new JLabel("url:");
+

JTextField 单行文本框

1
JTextField urlText = new JTextField(20);
+

JOptionPane

1
JOptionPane.showMessageDialog(null,"Pay attention to the cache url!","warning",JOptionPane.WARNING_MESSAGE);
+

JTabbedPane

1
2
3
4
5
6
JTabbedPane centerPanel;
JPanel mypanel = new JPanel();
Button mybutton = new Button("import");
mypanel.add(mybutton);
centerPanel.addTab("rawImg", new ImageIcon(tabImage), mypanel);
centerPanel.setSelectedIndex(0);
+

JButton 按钮

1
JButton urlButton = new JButton("choose");
+

JTextArea 多行文本框

1
JTextArea logText = new JTextArea("Welcome!");
+

JFrame 窗

1
2
3
4
5
6
7
8
frame = new JFrame("BIRDS01");
frame.add(southJsp, BorderLayout.SOUTH);
frame.add(centerPanel, BorderLayout.CENTER);
frame.add(northPanel, BorderLayout.NORTH);
frame.setSize(500, 600);
frame.setVisible(true);
//frame.setLocation(600, 300);
frame.setLocationRelativeTo(null);
+ +

组件触发事件

1
2
3
4
5
6
7
8
9
10
11
urlButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("o((>ω< ))o");
}
});
centerPanel.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e){
System.out.println("目前选中的是面板" + centerPanel.getSelectedIndex());
}
})
+

获取ImageJ图片

1
2
3
4
5
import ij.ImageJ;
import ij.IJ;

new ImageJ(); //打开ImageJ
brainImg = IJ.getImage(); //获取导入ImageJ的图片
+

今日总结

不知道是不是因为把显示器搬到实验室的原因,今天工作非常有动力,面对BIRDS源码中超级多的包和类,一点都没有害怕,就奔着一个很小的目标去了:我要搞清楚这个插件是怎么获取到我导入ImageJ中的图片的。今天主要就是学习了BirdsPlugin.java这个文件的代码,对应的是BIRDS插件的GUI,组件布局和触发事件等都在这个文件里面。虽然还不太熟悉java中图像处理的一些方法,但今天学会了看API(要是有具体的使用示例就更好了),也是一个进步!

+

下一步还是要明确目标:学习脑片与图谱配准的算法!!!BirdsPlugin.java中case2要仔细读一下,我一切换到precise板块,极短的时间内就会弹出配准后的脑片序列,而且也不像提前存好的图片,这个tab触发的逻辑要仔细读一下。不过脑片与图谱配准的核心算法应该是在coarse那部分,明天认真读一下!!!

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/03/imagej-plugin/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/04/imagej-plugin-2/index.html b/2023/07/04/imagej-plugin-2/index.html new file mode 100644 index 000000000..3400caf97 --- /dev/null +++ b/2023/07/04/imagej-plugin-2/index.html @@ -0,0 +1,288 @@ +BIRDS插件代码学习【02】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【02】

ImageJ常用方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建新的图像窗口
ImagePlus lineImage = NewImage.createByteImage(null, 500, 300, 10, NewImage.FILL_WHITE);
ImageStack lineImageStack = PreciseRegistration.lineImage.getImageStack();
PreciseRegistration.lineImage.setStack(lineImageStack);

// 展示图像
lineImage.show();

// 查看stack的某一张
// getProcessor:Returns an ImageProcessor for the specified slice, where 1<=n<=nslices.
ImageProcessor imageProcessor = annotationImageStack.getProcessor(120);
ImagePlus myImg = new ImagePlus("ip2", imageProcessor);
myImg.show();

// 保存图像
new FileSaver(PreciseRegistration.lineImage).saveAsTiff(GlobalValue.URL+"/registration/precise/line.tif");
+

线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
创建一个 CountDownLatch 对象时,需要指定一个初始计数值,该计数值表示需要等待的线程数量。
每当一个线程完成了其任务,它调用 CountDownLatch 的 countDown() 方法,计数器的值就会减一。
当计数器的值变成 0 时,等待的线程就会被唤醒,继续执行它们的任务。
*/
import java.util.concurrent.CountDownLatch;

public class Test03 {
public static void main(String[] args) throws InterruptedException {

CountDownLatch count = new CountDownLatch(5);//在线程执行完之前,会阻塞主程序的执行

for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" "+(num+1));
count.countDown();
}).start();
}
try {
count.await();
} catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Runtime.getRuntime().availableProcessors()); // 返回可用的计算资源
System.out.println(Thread.currentThread().getName()+" 执行完毕···");
}
}
/**
输出结果:
Thread-0 1
Thread-4 5
Thread-3 4
Thread-2 3
Thread-1 2
16
main 执行完毕···
*/
+

使用多线程处理图像

+

脑片配准 fuseImage

1
2
3
RGBStackMerge rgbStackMerge = new RGBStackMerge();
fuseImageStack = rgbStackMerge.mergeStacks(lenX, lenY, lenZ, downSampleImageStack, lineImageStack, null, true);
PreciseRegistration.getPreciseregistration().fuseImage.setStack(fuseImageStack);
+ +

脑区识别

鼠标悬停即可识别脑区

+

今日总结

昨天看了一整天代码,今天再看这些java和ImageJ的方法就没有那么生疏了,今天还掌握了一个java新技能:多线程!(本科四年一直听说但从未使用过的谜之知识)。昨天研究了半天的ImageProcessor,今天发现BIRDS里很多地方也用到了,不过主要是对stack的处理。昨天发现界面中切换到precise面板时,会弹出配准后的脑片,即使不手动校正,效果已经能达到我的预期了,所以今天就从这个地方入手,希望能找到脑片配准的核心代码。

+

BIRDS中主要涉及了annotationImage、lineImage、fuseImage和downsampleImage这四组图片,脑片配准的效果就是通过合并downsampleImage和lineImage得到的。起初我主要在看脑区的轮廓线是如何得到的,似乎是遍历像素,特定位置赋为白色,但我最开始不懂为什么annotationImage会实现这种效果。后面我发现脑区识别也是获取鼠标位置以后根据像素灰度值与脑区进行匹配(提前存在一个excel文件里面),这些功能的实现都不算复杂,最关键的点就是如何给不同的脑区赋不同的颜色(虽然我还没有找到这部分代码,但大胆猜测是将脑图谱直接灰度化,不过怎么脑区和对应的灰度值是怎么得到的我还没想清楚)。

+

本以为图像预处理部分不是很重要,但今天的代码看下来,downsample部分是必须要看的,里面就包括我比较关心的annotationImage.tif,coarse部分也会得到一个类似的图像文件,只不过是和脑片配准之后的。明天可以重点看预处理这部分代码,慢慢来。

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/04/imagej-plugin-2/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/05/eclipse-icons/index.html b/2023/07/05/eclipse-icons/index.html new file mode 100644 index 000000000..6254d8723 --- /dev/null +++ b/2023/07/05/eclipse-icons/index.html @@ -0,0 +1,283 @@ +Java基础知识 | Stray Birds + + + + + + + + + + + + + +

Java基础知识

Eclipse中图标含义

+ +
+ +
+ + + +

Java 修饰符

访问修饰符
非访问修饰符

+

Java 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
// 示例
public static int max(int num1, int num2){
int result;
if (num1 > num2){
result = num1;
}else{
result = num2;
}
return result;
}
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/05/eclipse-icons/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/05/imagej-plugin-3/index.html b/2023/07/05/imagej-plugin-3/index.html new file mode 100644 index 000000000..708fdb70f --- /dev/null +++ b/2023/07/05/imagej-plugin-3/index.html @@ -0,0 +1,287 @@ +BIRDS插件代码学习【03】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【03】

图像预处理过程

图像介绍

DownSample.java文件中主要涉及了以下图像:

+
    +
  • ourBrainImage:导入ImageJ的原始图像
  • +
  • Atlas132labelImage:Allen小鼠脑图谱(冠状面)570×400×660
  • +
  • tempInvertOrgImage:Allen小鼠脑平均模板反转
  • +
  • tempOrgImage:Allen小鼠脑平均模板
  • +
  • annotationImage:注释图谱
    其中Atlas132labelImage、annotationImage、tempOrgImage和tempInvertOrgImage是直接存入cache的。Atlas132labelImage仅仅是用于展示脑图谱,并没有做过多的处理。tempOrgImage和annotationImage均由Allen Brain提供(CCFv3)。
  • +
+

获取CCFv3小鼠全脑平均模板和注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import nrrd # pip install pynrrd
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

AVGT, metaAVGT = nrrd.read('average_template_25.nrrd'); # 25 voxel
ANO, metaANO = nrrd.read('CCFv3_annotation_25.nrrd');

AVGT.shape # (528, 320, 456)
# 存储average template
for i in range(526):
slice = AVGT[i+1,:,:].astype(float)
slice /= np.max(slice)
im = Image.fromarray(np.uint8(plt.cm.gray(slice)*255))
im.save('avgt/avgt_coronal_%d.png'%(i+1))
# 存储annotation
for i in range(526):
slice = ANO[i+1,:,:].astype(float)
slice /= 2000
im = Image.fromarray(np.uint8(plt.cm.gray(slice)*255))
im.save('anno/ano_coronal_%d.png'%(i+1))
+

今日总结

我之前并没有留意BIRDS插件一开始载入缓存文件夹中的内容,本以为就是把github下载下来的压缩包解压,但今天仔细看了一下代码,才发现中间调用了AddtionalFile.java,用于生成orgInvertImage.tif,该代码又使用了InverTool.java,看来细节还是蛮多的。

+

我花了很长时间找annotationImage的原始出处,最终发现最有可能的来源是CCFv3,但下载后是nrrd格式,用ImageJ打开是矢状面。我在github、Allen社区以及文章提供的数据中下载到的模板和注释,打开后都是矢状面。晚上回到宿舍以后我还是不甘心,总觉得作者不应该没有提供冠状面的模板,我从nrrd这个文件格式入手,意外看到了一篇博客下面的评论,ImageJ里面可以查看stacks的正交视角!!!我试了一下,果然可以看到冠状面!

+

接下来的问题就是怎么把全脑冠状面存储为tif格式,昨天没想到好的解决办法,今天早上试了一下Allen提供的API,写了个循环获取冠状面(按顺序命名),然后用ImageJ读取Image sequence并存储为tif格式。(我没有找到BIRDS里面用的voxel是20µm的模板,但感觉问题不大~)

+

┭┮﹏┭┮ 今天早上喜提周六文献汇报,看论文去了!

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/05/imagej-plugin-3/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/06/imagej-plugin-4/index.html b/2023/07/06/imagej-plugin-4/index.html new file mode 100644 index 000000000..1d7b99e89 --- /dev/null +++ b/2023/07/06/imagej-plugin-4/index.html @@ -0,0 +1,274 @@ +BIRDS插件代码学习【04】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【04】

体素 voxel

体素是三维空间的像素。体素网格是用固定大小的立方块作为最小单元来表示三维物体的一种数据结构。

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* 该程序实现鼠标事实获取stack当前图像(slice)的体素值(16unit 颜色值)
* 备注:通过该体素值可以进一步匹配到对应的脑区(该程序不包含此部分)
* 代码主要参考了BIRDS配准源码
* @author 文欣
* @version 1.0
*/
package I.plugin;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import ij.IJ;
import ij.ImageJ;
import ij.ImagePlus;
import ij.ImageStack;

public class Test04 implements MouseListener,MouseMotionListener{
private Test04() {}
public static ImagePlus brainImg;
public static void main(String[] args) {
new ImageJ();

brainImg = IJ.openImage("D:/Desktop/annotationOrgImage.tif");
brainImg.show();

System.out.println(brainImg.getTitle());
System.out.println(brainImg.getStackSize());
new Test04().addMouseListener();
}
public void addMouseListener() {

brainImg.getCanvas().addMouseListener(this);
brainImg.getCanvas().addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e) {
ImageStack brainStack = brainImg.getImageStack();
int currentSlice = brainImg.getCurrentSlice();
Point tempPoint = brainImg.getCanvas().getCursorLoc();
int val = (int)(brainStack.getVoxel(tempPoint.x, tempPoint.y, currentSlice-1));//16位像素值
System.out.println(val); //打印
}

@Override
public void mouseDragged(MouseEvent e) {}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}

@Override
public void mouseExited(MouseEvent e) {}

}
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/06/imagej-plugin-4/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/08/imagej-plugin-5/index.html b/2023/07/08/imagej-plugin-5/index.html new file mode 100644 index 000000000..9febd6955 --- /dev/null +++ b/2023/07/08/imagej-plugin-5/index.html @@ -0,0 +1,309 @@ +BIRDS插件代码学习【05】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【05】

Java 调用命令行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Test05 {
public static void main(String[] args) {
String cmd = "calc";
try {
Process ps = Runtime.getRuntime().exec(cmd);//打开计算器
// ps.getInputStream() 获取进程的输出流
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
}catch(Exception e) {
e.printStackTrace();
}
}
}
+

elastix 使用

    +
  1. 下载 elastix-5.1.0-win64,解压后得到elastix.exetransformix.exe
  2. +
  3. 下载 elastix 用户手册 + +
    + +
    + + +
  4. +
  5. 命令行调用elastix.exetransformix.exe得到配准后的脑片
    1
    2
    3
    4
    5
    6
    elastix.exe --help
    elastix -f input/downSampleImage.tif -m input/tempImage.tif -out output -p input/Parameters_BSpline.txt

    transformix.exe --help
    transformix -in input/annotationImage.tif -out result -tp output/TransformParameters.0.txt
    # 参数文件中可以设置输出格式,默认为mhd,此处修改为tif
  6. +
+

ImageJ 合并通道

    +
  1. 将待合并的两张图像载入ImageJ
  2. +
  3. Image→Color→Merge Channels
  4. +
  5. 脑片保留红色通道,脑区轮廓保留绿色通道(注意不要勾选create composite,以免保存时仅有最上层的通道)
    合并通道
  6. +
  7. 保存为tif文件合并后的图像
  8. +
+

二维脑片配准关键步骤

    +
  1. 定位与脑片最匹配的图谱(相似度最高)
  2. +
  3. 获取Allen全脑平均模板tempImage和对应的注释文件annotationImage
  4. +
  5. 通过elastix.exetransformix.exe对脑片配准(模板→脑片 注释→脑片)
  6. +
  7. 根据注释文件获取脑区轮廓lineImage
  8. +
  9. 轮廓与脑片合并得到fuseImage
  10. +
  11. 根据annotationImage的像素值匹配脑区
  12. +
  13. 脑区细胞计数
    二维脑片配准流程图
  14. +
+

今日总结

到目前为止感觉BIRDS的配准是通过elastix实现的,需要看一下elastix的论文,然后试一下elastix进行脑片配准的效果。

+

不管老板对我的要求是怎样的,我对自己的要求就是把一个小项目做完再做下一个小项目,不能三心二意。我的课题要根据我自己的兴趣来,广泛涉猎给自己找一条出路,我现在没有能力回绝老板的各种要求就是因为我没有能够给出其他方案,要行动起来。

+

每天拿出1~2个小时跟着吴思老师实验室出的书《神经计算建模实战——基于brainpy》实操一下,总要下点功夫入门计算神经科学吧!可能需要补一下微积分的知识😎

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/08/imagej-plugin-5/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/09/v2rayu-mac/index.html b/2023/07/09/v2rayu-mac/index.html new file mode 100644 index 000000000..e4b75ec9c --- /dev/null +++ b/2023/07/09/v2rayu-mac/index.html @@ -0,0 +1,273 @@ +解决mac电脑更新后V2rayU无法启动 | Stray Birds + + + + + + + + + + + + + +

解决mac电脑更新后V2rayU无法启动

电脑更新完以后,突然一直弹出警告让我卸载V2rayU,┭┮﹏┭┮,这可是我的宝贝软件,怎么能卸载呢???在网上搜索了半天,终于找到解决方案了!

+
+
1
2
3
4
5
6
7
# 1. 命令行输入
sudo codesign --force --deep --sign - /Applications/V2rayU.app
# 2. 右键单击软件→显示简介→勾选☑️覆盖恶意软件保护
# 3. 打开软件
# 4. 命令行输入
sudo codesign --force --deep --sign - ~/.V2rayU/V2rayUTool
sudo codesign --force --deep --sign - ~/.V2rayU/v2ray-core/v2ray
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/09/v2rayu-mac/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/10/brainpy-1/index.html b/2023/07/10/brainpy-1/index.html new file mode 100644 index 000000000..ce3308de0 --- /dev/null +++ b/2023/07/10/brainpy-1/index.html @@ -0,0 +1,272 @@ +BrainPy学习笔记【01】 | Stray Birds + + + + + + + + + + + + + + +

BrainPy学习笔记【01】

安装教程(Windows环境)

1
2
3
4
5
6
7
8
9
10
11
12
conda env list
conda create --name bdp python=3.9 -y
conda activate bdp

python -m pip install git+https://git.openi.org.cn/OpenI/BrainPy
conda install numpy
pip install "jax[cpu]" -f https://whls.blob.core.windows.net/unstable/index.html
python -m pip install brainpylib # 报错 需要安装matplotlib
conda install matplotlib
python -m pip install brainpylib

conda install ipykernel
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/10/brainpy-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/10/imagej-plugin-6/index.html b/2023/07/10/imagej-plugin-6/index.html new file mode 100644 index 000000000..841446b75 --- /dev/null +++ b/2023/07/10/imagej-plugin-6/index.html @@ -0,0 +1,289 @@ +BIRDS插件代码学习【06】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【06】

今日计划

    +
  • 准备和刘越老师讨论的PPT,主要整理计算建模的思路以及难点
  • +
  • 提取单张脑片的脑区轮廓
  • +
  • BrainPy环境搭建
  • +
  • 整理计算神经科学领域比较有名的实验室和科学家
  • +
+

提取脑区轮廓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package I.plugin;

import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.plugin.RGBStackMerge;
import ij.process.ImageProcessor;

public class Test06 {

public ImageProcessor getLineImg(ImageProcessor ip, ImageProcessor op) {
int lenX = ip.getWidth();
int lenY = ip.getHeight();
for(int i = 0; i < lenX; i ++) { //按列
int begin = 0; //初始像素值为黑色
for(int j = 0; j < lenY; j ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
for(int j = 0; j < lenY; j ++) {
int begin = 0; //初始像素值为黑色
for(int i = 0; i < lenX; i ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
return op;
}

public static void main(String[] args) {
ImagePlus brainImage = new ImagePlus("D:/Desktop/downSampleImage0160.tif");
ImageStack brainStack = brainImage.getStack();

ImagePlus annoImage = new ImagePlus("D:/Desktop/anno_output/result0160.tif");
ImageProcessor ap = annoImage.getProcessor();
int width = ap.getWidth();
int height = ap.getHeight();

ImagePlus lineImage = NewImage.createByteImage("lineImage", width, height, 0, NewImage.FILL_BLACK);
ImageStack lineStack = lineImage.getStack();
ImageProcessor lp = lineImage.getProcessor();

ImageProcessor op = new Test06().getLineImg(ap, lp);

lineImage.setProcessor(op);
lineImage.show();

ImagePlus fuseImage = NewImage.createByteImage("fuseImage", width, height, 0, NewImage.FILL_BLACK);

ImageStack fuseStack = RGBStackMerge.mergeStacks(brainStack, lineStack, null, true);

fuseImage.setStack(fuseStack);
fuseImage.show();
// 保存图片
new FileSaver(fuseImage).saveAsTiff("D:/Desktop/fuseImage.tif");
}
}
+

细胞计数

没想到BIRDS里细胞计数是通过调用Imaris的方法实现的,看来还是要学一下这个软件的用法🥲运行Imaris前记得先运行license server.bat~
.tif → .ims可以通过ImarisFileConverter.exe实现,Imaris默认安装在C盘。
没有找到很方便的API,看代码似乎是要现在Imaris里面操作完成之后,Java再获取对应的数据,这好像和我想要达到的效果不一样。
👻不想动脑子,怎么办!!!

+
+

流程测试

⭐脑片与标准脑模板的尺寸要大致相同,为了不过度损失脑片分辨率,此处对标准脑模板进行上采样
elastix.exe配准的参数使用para-Standard_bspline.txtpara-Standard_affine.txtpara-Standard_rigid.txt(去掉了对图片维度的限制)效果比较好
👻不知道为什么提取的脑区轮廓有很明显的锯齿,难道是因为我把注释图片分辨率调高了?不过问题不大~
👻由于原始脑片本身边缘有破损,因此与轮廓边缘处会出现明显的变形

+
+
    +
  1. 将标准脑模板和注释图片的分辨率提高至与脑片匹配的程度(尽量不损失原始脑片的图像分辨率)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from PIL import Image

    Image.MAX_IMAGE_PIXELS = None
    raw = Image.open(r"D:/Desktop/elastix-5.1.0-win64/input/result1.tif")
    img = Image.open(r"D:/Desktop/elastix-5.1.0-win64/out_anno/annotationImage0270.tif")
    # img = Image.open(r"D:/Desktop/elastix-5.1.0-win64/out_temp/tempImage0270.tif")

    target_width = raw.size[0]
    scale = round(target_width/img.size[0],1)
    width = int(img.size[0]*scale)
    height = int(img.size[1]*scale)

    out = img.resize((width, height))
    type = img.format
    out.save('D:/Desktop/elastix-5.1.0-win64/out_anno/annotationImage0270-1.tif',type)
    # out.save('D:/Desktop/elastix-5.1.0-win64/out_temp/tempImage0270-1.tif',type)
  2. +
  3. 脑片与图谱配准
    1
    2
    3
    elastix -f input/result1.tif -m out_temp/tempImage0270-1.tif -out output -p input/para-Standard_rigid.txt -p input/para-Standard_affine.txt -p input/para-Standard_bspline_2.txt

    transformix -in out_anno/annotationImage0270-1.tif -out result -tp output/TransformParameters.2.txt
  4. +
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/10/imagej-plugin-6/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/11/set-proxy/index.html b/2023/07/11/set-proxy/index.html new file mode 100644 index 000000000..9f51443a0 --- /dev/null +++ b/2023/07/11/set-proxy/index.html @@ -0,0 +1,272 @@ +windows设置代理及取消代理 | Stray Birds + + + + + + + + + + + + + +

windows设置代理及取消代理

本来想用coursera-dl下载coursera上面的网课,结果一直报错,想找找下载视频的插件,也没找到好用的,最终还是回归伟大的哔哩哔哩!😽

+
+

设置代理

1
2
3
4
5
6
# 翻墙后设置代理
set http_proxy=http://127.0.0.1(代理的IP地址):1080(代理的端口号)
set https_proxy=http://127.0.0.1(代理的IP地址):1080(代理的端口号)
# 不翻墙的话需要取消代理,否则打开一些页面会很慢
set http_proxy=
set https_proxy=
+

油猴插件

点击网站右上角(篡改猴)图标→获取新脚本→搜索用户脚本→安装

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/11/set-proxy/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/12/RNN-1/index.html b/2023/07/12/RNN-1/index.html new file mode 100644 index 000000000..236500212 --- /dev/null +++ b/2023/07/12/RNN-1/index.html @@ -0,0 +1,330 @@ +RNN学习笔记【01】 | Stray Birds + + + + + + + + + + + + + +

RNN学习笔记【01】

第一次找到和我要做的课题那么接近的教程,人工翻译一遍不过分吧!😎
本文对应的代码在这里!😽[Open in colab]😽

+
+

任务优化的循环神经网络建模

引言

这里,我们基于人工神经网络的方法构建循环神经网络。学习人工神经网络或深度学习,不仅是当今机器学习的主导框架,对计算神经科学而言也是一个有用的工具。

+

深度学习本身可能并不符合生物现实。然而,深度学习最终的结果可能是有用的大脑模型(不保证,但是可能)。由于人工神经网络的复杂性,它们可以模拟复杂的行为和神经活动。

+

从优化的角度来说,人工神经网络建模可以提供规范性解释,即为什么一个网络可以以某种方式完成某个任务,因为我们可以设计目标函数,类似于生物进化的视角。

+

任务介绍

2AFC

+

双向强迫选择任务PerceptualDecisionMaking,被试需要整合两个刺激来决定哪一个刺激的平均水平更高。
在刺激阶段会呈现一个有噪声的刺激。刺激的强度(coherence)在每个试次中是随机抽样的。因为刺激中存在噪声,智能体需要随时间整合刺激信息。
参数介绍:
dt:Timestep duration. (def: 100 (ms) int)
rewards

+
    +
  • R_ABORTED: given when breaking fixation. (def: -0.1 float)
  • +
  • R_CORRECT:given when correct. (def: +1. float)
  • +
  • R_FAIL:given when incorrect. (def: 0. float)
  • +
+

timing:Description and duration of periods forming a trial.
stim_scale:Controls the difficulty of the experiment. (def: 1., float)
cohs:list of float, coherence levels controlling the difficulty of the task
sigma:float, input noise level
dim_ring:int, dimension of ring input and output

+
+

环境配置

    +
  • NeuroGym是一个精选的神经科学任务集合,具有统一的接口。其目标是促进关于神经科学任务的神经网络模型的训练。
    NeuroGym
  • +
  • Google Colab是一个基于云端的免费Jupyter笔记本环境,为用户提供了方便、免费的编码环境,并具备强大的计算资源和协作功能,适用于数据科学家、研究人员和机器学习工程师等进行代码开发、实验和协作。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # install neurogym (for training environments)
    ! git clone https://github.com/gyyang/neurogym.git
    %cd neurogym
    ! pip install -e .

    # import packages
    import time # for measuring time
    import numpy as np # for numerical computation
    from matplotlib import cm # for plotting figures
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    from matplotlib.colors import ListedColormap, LinearSegmentedColormap
    from matplotlib.lines import Line2D
    from IPython import display # for controlling colab

    import gym # for neurogym
    import neurogym as ngym # for training environments
    import torch # for training neural nets
    import torch.nn.functional as F

    from sklearn.decomposition import PCA # for principal component analysis
    from scipy.special import softmax
    mpl.rcParams.update(mpl.rcParamsDefault)
  • +
+

模型概览

RNN模型概览

+

$x(t)$:输入变量

+

$r(t)$:循环变量

+

$o(t)$:输出

+

$W_x$:输入权重【可训练】

+

$W_r, b_r$:循环权重 & 偏置

+

$W_o, b_o$:输出权重 & 偏置

+

$\alpha=\frac{\bigtriangleup t}{\tau }$

+
+

此外,在人工神经网络建模中,我们可以使用各种各样的激活函数,比如ReLUsigmoidsoftplus函数。

+激活函数 + +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Parameter definition
# Hyperparameters
hpar = dict(
# Task parameters
dt = 20, # simulation time step [ms]
stim_len = 1000, # stimulus input duration [ms]
stim_noise = 0.3, # stimulus input noise [unitless]
seq_len = 60, # trial duration in time steps
# Network parameters
n_neurons = 64, # number of recurrent neurons
network_noise = 0.1, # noise to network [unitless]
tau = 100, # network time constant [ms]
activation_fun = 'relu', # activation function(sigmoid, relu, softplus)
# Network parameters:training
batch_size = 16, # size of batch
n_iteration = 1000, # number of epochs
learning_rate = 0.01, # training learning rate
optimizer = 'Adam', # optimizer(Adam, RMSprop, SGD)
loss = 'CrossEntropy' # loss function(CrossEntropy, L1, L2)
)
+

batch:指每次迭代中用于训练模型的样本数量。批大小的选择会影响训练的效果和速度。较大的批大小可以提高训练的效率,因为可以同时处理更多的样本,但会消耗更多的内存。较小的批大小可以提供更多的随机性和模型收敛的稳定性,但可能会导致训练时间增加。
iteration:指完成整个训练数据集的一次遍历。迭代的数量取决于训练数据集的大小和训练过程的要求。通常,较大的数据集需要更多的迭代来使模型收敛,而较小的数据集可能需要较少的迭代。

+
+

训练 RNN 执行任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# make neurogym environment
task_name = 'PerceptualDecisionMaking-v0'
kwargs = {'dt': hpar['dt'],
'timing': {'stimulus': hpar['stim_len']},
'sigma': hpar['stim_noise']}
env = gym.make(task_name, **kwargs)

# make supervised dataset
dataset = ngym.Dataset(env, batch_size=hpar['batch_size'], seq_len=hpar['seq_len'])

# generate one batch of data when called
inputs, target = dataset()
print('Input to network has shape(SeqLen,Batch,Dim)=', inputs.shape)
print('Target to network has shape(SeqLen,Batch)=', target.shape)
# 输出
# Input to network has shape(SeqLen,Batch,Dim)= (60, 16, 3)
# Target to network has shape(SeqLen,Batch)= (60, 16)
+

gym.make(task_name, **kwargs):是OpenAI Gym库中用于创建一个与特定任务相关的环境对象。task_name表示要创建的任务的名称,例如CartPole-v1,每个名称对应一个特定的任务环境。**kwargs是一个可选的关键字参数,用于传递额外的配置选项给环境。
在Python中,**用于将一个字典(dictionary)解包为关键字参数传递给函数。字典的关键字需与函数的参数名称匹配,参数顺序可以改变。

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Task structure
i_trial = np.random.choice(hpar['batch_size']) # 随机从一个batch内选择一个trial
end = sum([v for _,v in env.timing.items()])/1000 # 单位换为s
times = np.arange(end, step=env.dt/1000)
rules = end - env.timing['decision']/1000, end

f, ax = plt.subplots(1, 2, figsize=(16,5))
ax[0].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[0].plot(times, inputs[:,i_trial,1], 'blue', label='Evidence for right motion')
ax[0].plot(times, inputs[:,i_trial,2], 'red', label='Evidence for left motion')
ax[0].plot(times, inputs[:,i_trial,0], 'green', label='Fixation rule')
ax[0].set_ylabel('input')
ax[0].set_ylim([-0.1,1.1])
ax[0].legend(loc='upper left')
ax[0].set_xlabel('time(s)')
ax[0].set_title(f'Input to RNN(trial number={i_trial})')

ax[1].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[1].hlines(y=1, xmin=times[0], xmax=times[-1], color='gray', linestyle="dashed")
ax[1].hlines(y=2, xmin=times[0], xmax=times[-1], color='gray', linestyle="dashed")
ax[1].text(0, 0.08, 'Fixation')
ax[1].text(0, 0.9, 'Right Decision')
ax[1].text(0, 1.9, 'Left Decision')
ax[1].plot(times, target[:,i_trial], 'k')
ax[1].set_ylabel('desired output')
ax[1].set_ylim([-0.1,2.1])
ax[1].set_xlabel('time(s)')
ax[1].set_title(f'Desired output from RNN(trial number={i_trial})')
plt.show()
+

示例trial的输入和输出

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Model definition
class RNN(torch.nn.Module):
def __init__(self, input_size, output_size, **hpar):
super().__init__()
self.input_size = input_size
self.output_size = output_size
self.hidden_size = hpar['n_neurons']
self.noise = hpar['network_noise']
self.tau = hpar['tau']
self.alpha = hpar['dt']/self.tau
self.input2rec = torch.nn.Linear(self.input_size, self.hidden_size, bias=False)
self.rec2rec = torch.nn.Linear(self.hidden_size, self.hidden_size)
self.rec2output = torch.nn.Linear(self.hidden_size, self.output_size)
self.normal = torch.distributions.normal.Normal(0,1)
self.set_activation_fun(**hpar)

def set_activation_fun(self, **hpar):
if hpar['activation_fun'] == 'sigmoid':
self.activation = torch.sigmoid
elif hpar['activation_fun'] == 'relu':
self.activation = torch.relu
elif hpar['activation_fun'] == 'softplus':
self.activation = F.softplus
else:
raise NotImplementedError('Activation functions should be either ReLU, Sigmoid, or Softplus')

def init_hidden(self, input_shape):
batch_size = input_shape[1]
return torch.zeros(batch_size, self.hidden_size)

def recurrence(self, input, hidden):
noise = self.noise * self.normal.sample(hidden.shape)
h_new = self.activation(self.input2rec(input) + self.rec2rec(hidden))
h_new = hidden * (1-self.alpha) + h_new * self.alpha
h_new += noise * (2*self.alpha) ** 0.5
return h_new

def forward(self, input, hidden=None):
if hidden is None:
hidden = self.init_hidden(input.shape).to(input.device)
rnn_output = []
steps = range(input.size(0))
for i in steps:
hidden = self.recurrence(input[i], hidden)
rnn_output.append(hidden)

rnn_output = torch.stack(rnn_output, dim=0)
output = self.rec2output(rnn_output)

return output, rnn_output

input_size = env.observation_space.shape[0]
print(input_size) #
output_size = env.action_space.n
net = RNN(input_size, output_size, **hpar)
print(net)
for name, param in net.named_parameters():
if param.requires_grad:
print('\t', name, "," , param.data.shape)
# 输出
# RNN(
# (input2rec): Linear(in_features=3, out_features=64, bias=False)
# (rec2rec): Linear(in_features=64, out_features=64, bias=True)
# (rec2output): Linear(in_features=64, out_features=3, bias=True)
# )
# input2rec.weight , torch.Size([64, 3])
# rec2rec.weight , torch.Size([64, 64])
# rec2rec.bias , torch.Size([64])
# rec2output.weight , torch.Size([3, 64])
# rec2output.bias , torch.Size([3])
+

__init__:在Python中,__init__是一个特殊的方法(也称为构造方法),用于在创建类的实例时进行初始化操作。__init__方法在创建类的实例时自动调用,并用于设置对象的初始状态。它接受类的实例作为第一个参数(通常被命名为self),以便可以访问和操作该实例的属性和方法。除了self参数外,__init__方法可以接受其他参数,这些参数可以用来初始化对象的属性。
super().__init__():调用父类的构造方法,确保父类的初始化操作得以执行。
Activation function:ReLU、Sigmoid、Softplus
Optimizer:Adam、RMSprop、SGD
loss function:CrossEntropy、L1、L2

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# train model
learning_rate = 0.01
optimizer = 'Adam'
loss_function = 'CrossEntropy'

hpar['learning_rate'] = learning_rate
hpar['optimizer'] = optimizer
hpar['loss_function'] = loss_function

def train_model(net, dataset, **hpar):
# define an optimizer
learning_rate = hpar['learning_rate']
if hpar['optimizer'] == 'Adam':
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)
elif hpar['optimizer'] == 'RMSprop':
optimizer = torch.optim.RMSprop(net.parameters(), lr=learning_rate)
elif hpar['optimizer'] == 'SGD':
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)
else:
raise NotImplementedError('Optimizer should be either Adam, RMSprop, or SGD')
# define a loss function
if hpar['loss'] == 'CrossEntropy':
criterion = torch.nn.CrossEntropyLoss()
elif hpar['loss'] == 'L1':
criterion = torch.nn.L1loss()
elif hpar['loss'] == 'L2':
criterion = torch.nn.MSELoss()
else:
raise NotImplementedError('Loss function should be either CrossEntropy, l1, or L2')

start_time = time.time()
losses = []
accs = []

# Plot
fig = plt.figure(figsize=[18,6])
plt.tight_layout()
ax0 = fig.add_subplot(121)
ax0.set_xlim([0,hpar['n_iteration']])
plt.ylim([0,0.5])
ax0.set_xlabel('Number of iteration')
ax0.set_ylabel('Loss')
ax0.set_title('RNN model training curve')
ax1 = fig.add_subplot(121, sharex=ax0, frameon=False)
ax1.yaxis.tick_right()
ax1.yaxis.set_label_position('right')
ax1.set_ylabel('Accuracy(%)')
ax1.set_ylim([0,100])
ax1.yaxis.label.set_color('r')
ax0.spines['right'].set_color('r')
ax1.tick_params(axis='y', colors='r')
ax2 = fig.add_subplot(122)
ax2.set_title('RNN model recurrent weight $W_r$')

# Loop
for i in range(hpar['n_iteration']):
inputs, labels = dataset() # 一个batch的数据
inputs = torch.from_numpy(inputs).type(torch.float)
labels = torch.from_numpy(labels.flatten()).type(torch.long)

optimizer.zero_grad() # clear the gradient buffers
output, _ = net(inputs) # run the network
output = output.view(-1, output_size)

if hpar['loss'] == 'CrossEntropy':
loss = criterion(output, labels)
else:
loss = criterion(output, F.one_hot(labels).type(torch.float))
loss.backward() # backpropagation
optimizer.step() # gradient descent

# compute the running loss every 100 steps
losses.append(loss.item())
# 将输出张量转换为 NumPy 数组,然后选择最后 hpar['batch_size'] 行,并找到选定数组中每个样本的预测类别的索引。最终,pred 是一个包含每个样本预测类别索引的数组。
pred = np.argmax(output.detach().numpy()[(-hpar['batch_size']):,:],axis=-1)
true = labels.detach().numpy()[(-hpar['batch_size']):]
accs.append((pred==true).mean()*100)

if i % 100 == 99:
accs_ma = accs.copy()
accs_ma[10:] = np.convolve(accs_ma, np.ones(10)/10, mode='valid')

ax0.plot(losses, color='k', linewidth=2)
ax1.plot(accs_ma, color='r', linewidth=1)

recurrent_weight = net.get_parameter('rec2rec.weight').detach().numpy()
im = ax2.imshow(recurrent_weight, clim=[-0.6,0.6], cmap='RdBu_r')
ax2.set_xlabel('Presynaptic neuron index')
ax2.set_ylabel('Postsynaptic neuron index')
cb = plt.colorbar(im, ax=ax2)

display.clear_output(wait=True)
display.display(plt.gcf())
if i != hpar['n_iteration'] -1:
cb.remove()
if i == hpar['n_iteration'] -1:
display.clear_output(wait=True)
print(f'Final training loss={np.round(np.mean(losses[(-100):]),2)}')
print(f'Final training accuracy(%)={np.round(np.mean(accs[(-100):]),2)}')
return net
net = RNN(input_size, output_size, **hpar)
net = train_model(net, dataset, **hpar)
+

训练误差及准确率

+

分析训练好的 RNN 模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Analysis
def run_model(net, env, num_trial=200):
env.reset(no_step=True)
input_dict = {}
activity_dict = {}
trial_infos = {}
for i in range(num_trial):
trial_info = env.new_trial()
ob, gt = env.ob, env.gt # observation and ground-truth
inputs = torch.from_numpy(ob[:, np.newaxis, :]).type(torch.float)

action_pred, rnn_activity = net(inputs)
action_pred = action_pred.detach().numpy()[:, 0, :]
choice = np.argmax(action_pred[-1, :])
correct = choice==gt[-1]

_input = inputs[:, 0, :].detach().numpy()
rnn_activity = rnn_activity[:, 0, :].detach().numpy()
input_dict[i] = _input
activity_dict[i] = rnn_activity
trial_infos[i] = trial_info
trial_infos[i].update({
'correct': correct,
'pred': action_pred,
'target': dataset.env.gt
})
return input_dict, activity_dict, trial_infos

run_inputs, activity_dict, trial_infos = run_model(net, dataset.env)
test_acc = np.round(np.mean([val['correct'] for val in trial_infos.values()])*100, 2)
print(f'Testing accuracy(%)={test_acc}')
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# randomly choose an example trial
i_trial = np.random.choice(200)
coh = trial_infos[i_trial]['coh']
print(f'coherence={coh}')
# dict_items([('fixation', 100), ('stimulus', 1000), ('delay', 0), ('decision', 100)])
end = sum([v for _,v in env.timing.items()])/1000
times = np.arange(end, step=env.dt/1000) # 0~(end-1)
rules = end - env.timing['decision']/1000, end

f, ax = plt.subplots(1, 2, figsize=(16,5))
ax[0].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[0].plot(times, run_inputs[i_trial][:,1], 'blue', label='Evidence for right motion')
ax[0].plot(times, run_inputs[i_trial][:,2], 'red', label='Evidence for left motion')
ax[0].plot(times, run_inputs[i_trial][:,0], 'green', label='Fixation rule')
ax[0].legend(loc='upper left')
ax[0].set_xlabel('time(s)')
ax[0].set_ylabel('input')
ax[0].set_title(f'Input to RNN(trial number={i_trial} coherence={coh})')

im = ax[1].imshow(softmax(trial_infos[i_trial]['pred'],axis=-1).T, extent=[times[0],end,-0.5,2.5], aspect='auto', origin='lower')
ax[1].text(0.05,0.1,'Fixation', color='r')
ax[1].text(0.05,1,'Right decision', color='r')
ax[1].text(0.05,2,'Left decision', color='r')
ax[1].plot(times, trial_infos[i_trial]['target'], 'k', linewidth=5, label='ground truth')
ax[1].set_xlabel('time(s)')
ax[1].set_ylabel('RNN output')
ax[1].set_yticks([0,1,2])
ax[1].set_title(f'RNN output(trial number={i_trial} coherence={coh})')
ax[1].legend()

cb = plt.colorbar(im, ax=ax[1])
cb.ax.set_title('Predicted probabolity')
plt.tight_layout()
plt.show()
+

示例试次输出结果展示

+

RNN模型测试准确率达到90%以上时,PCA分析不同运动一致比例条件下RNN群体活动轨迹比较容易分开。如果模型的准确率不高,则轨迹比较集中。🦁也就是说,模型是否训练好要设定一个performance threshold~

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# PCA(2 principal components)
activity = np.concatenate(list(activity_dict[i] for i in range(200)), axis=0)
pca = PCA(n_components=3)
pca.fit(activity)
activity_pc = pca.transform(activity)

blues = cm.get_cmap('Blues', len(env.cohs)+1)
reds = cm.get_cmap('Reds', len(env.cohs)+1)

figure = plt.figure(figsize=([7,7]))
for i in range(100):
activity_pc = pca.transform(activity_dict[i])
trial = trial_infos[i]
color_c = blues if trial['ground_truth'] == 0 else reds
color = color_c(np.where(env.cohs == trial['coh'])[0][0])
plt.plot(activity_pc[:,0], activity_pc[:,1], 'o-', color=color)

plt.plot(activity_pc[0,0], activity_pc[0,1], '^', color='black', markersize=10)

handles, labels = plt.gca().get_legend_handles_labels()
dot = Line2D([], [], marker='^', label='Starting point', color='black', linestyle='None', markersize=10)
lines = []
for i_coh, v_coh in reversed(list(enumerate(env.cohs))): # index value
line_r = Line2D([], [], label=f'L motion trial, c={v_coh}', color=reds(i_coh))
lines.append(line_r)
for i_coh, v_coh in enumerate(env.cohs):
line_b = Line2D([], [], label=f'R motion trial, c={v_coh}', color=blues(i_coh))
lines.append(line_b)
handles.extend([dot]+lines)
plt.legend(title='Legend', bbox_to_anchor=(1.4,1.0), handles=handles, frameon=False)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('State space based on principal component analysis')
plt.show()
+图片说明 + +
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# PCA(3 principal components)
from mpl_toolkits.mplot3d import Axes3D
activity = np.concatenate(list(activity_dict[i] for i in range(200)), axis=0)
pca = PCA(n_components=3)
pca.fit(activity)
activity_pc = pca.transform(activity)

blues = cm.get_cmap('Blues', len(env.cohs)+1)
reds = cm.get_cmap('Reds', len(env.cohs)+1)

fig = plt.figure(figsize=([7,7]))
ax = fig.add_subplot(111, projection='3d')
for i in range(100):
activity_pc = pca.transform(activity_dict[i])
trial = trial_infos[i]
color_c = blues if trial['ground_truth'] == 0 else reds
color = color_c(np.where(env.cohs == trial['coh'])[0][0])
ax.plot(activity_pc[:,0], activity_pc[:,1], activity_pc[:,2], 'o-', color=color)

ax.plot(activity_pc[0,0], activity_pc[0,1], activity_pc[0,2],'^', color='black', markersize=10)

handles, labels = plt.gca().get_legend_handles_labels()
dot = Line2D([], [], marker='^', label='Starting point', color='black', linestyle='None', markersize=10)
lines = []
for i_coh, v_coh in reversed(list(enumerate(env.cohs))): # index value
line_r = Line2D([], [], label=f'L motion trial, c={v_coh}', color=reds(i_coh))
lines.append(line_r)
for i_coh, v_coh in enumerate(env.cohs):
line_b = Line2D([], [], label=f'R motion trial, c={v_coh}', color=blues(i_coh))
lines.append(line_b)
handles.extend([dot]+lines)
ax.set_xlabel('PC 1')
ax.set_ylabel('PC 2')
ax.set_zlabel('PC 3')
ax.set_title('State space based on principal component analysis')
plt.legend(title='Legend', bbox_to_anchor=(1.6,0.9), handles=handles, frameon=False)
plt.show()
+

PCA(三个主成分)

+

补充知识

**kwargs

1
2
3
4
5
6
7
8
9
10
11
kwargs = {'arg1': 10, 'arg3': True, 'arg2': 'hello'}

def example_function(arg1, arg2, arg3):
print(arg1)
print(arg2)
print(arg3)

example_function(**kwargs)
# 10
# hello
# True
+

字典

在Python中,字典是一种可变的数据结构,用于存储键-值对的集合。字典可以使用{}来创建,也可以通过dict()函数创建。
update方法可以接受一个字典对象或包含键值对的可迭代对象作为参数,并将其中的键值对添加到调用update方法的字典中。

+
1
2
3
4
5
6
7
8
9
10
11
12
my_dict = {'key1': 'value1', 'key2': 'value2'}
my_dict = dict(
key1 = value1,
key2 = value2,
)

my_dict = {'key1': 'value1', 'key2': 'value2'}
new_dict = {'key3': 'value3', 'key4': 'value4'}

my_dict.update(new_dict)
print(my_dict)
# 输出:{'key1': 'value1', 'key2': 'value2', 'key3': 'value3', 'key4': 'value4'}
+

time.time()

1
2
3
4
5
6
7
import time

start_time = time.time()
for i in range(10):
print(i)
end_time = time.time() # 可用于计算程序运行的时间
print(f'程序用时:{end_time-start_time}s')
+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/12/RNN-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/13/neuronal-dynamics-1/index.html b/2023/07/13/neuronal-dynamics-1/index.html new file mode 100644 index 000000000..c70ff9779 --- /dev/null +++ b/2023/07/13/neuronal-dynamics-1/index.html @@ -0,0 +1,292 @@ +《神经动力学》学习笔记【01】 | Stray Birds + + + + + + + + + + + + + +

《神经动力学》学习笔记【01】

课程地址:[进入哔哩哔哩观看 资源1] [进入哔哩哔哩观看 资源2] [进入youtube观看]
课件汇总:[PPT下载]
参考教材:Neuronal Dynamics: From Single Neurons to Networks and Models of Cognition
[下载地址]
提取码: rk96

+
+

神经动力学:从单个神经元到网络和认知模型

当我们做决策时,我们的大脑中发生了什么?是什么触发了神经元发送信号?神经编码是什么?

+

这本面向高年级本科生和初级研究生的教科书,为计算和理论神经科学提供了全面而最新的的介绍。它涵盖了经典的主题,包括Hodgkin-Huxley方程和Hopfield模型,以及该领域在现代的发展,如广义线性模型和决策理论。概念通过清晰的逐步解释引入,适合仅有基础微分方程和概率知识的读者,并辅以丰富的图表和详细的实例说明。

+

章末总结和随堂练习使本书非常适合课堂教学或者自学。作者也指出了文献和大量的参考数目,对于有兴趣进一步研究的读者来说将非常有价值。

+

目录

+ +
+ +
+ + + +

前言

这本面向高年级本科生和初级研究生的教科书系统地介绍了关于神经建模、神经动力学、神经编码以及神经网络领域。它可以作为计算和理论神经科学的入门课程的教材,也可以作为研究生级别更加专注于神经动力学和神经建模的课程的主要教材。对于想学习不同神经元模型和神经活动描述之间关系的研究人员和学生来说,本书也是一个有用的资源。

+

所有的数学概念都以一步一步的方式进行介绍。所有的章节都有丰富的图表和实例。每一章都以简短的总结和一系列数学练习结尾。在作者的网页上提供了用于数值模拟的python源代码,以阐述章节的主要观点和模型。

+

本书分为4部分,共20章。Part I对计算神经科学及其数学工具的基础知识进行了概括性介绍。它涵盖了经典的内容,比如Hodgkin-Huxley模型、离子通道和树突等,以及二维微分方程系统的相平面分析。本书特别关注在Hodgkin-Huxley模型和Morris-Lecar模型等简化的二维神经元模型中触发动作电位的阈值问题。

+

Part II着重介绍单个神经元动力学的简化模型。它涵盖了带有适应性和不带适应性的非线性积分-放电模型integrate-and-fire model,尤其是二次和指数的积分-放电模型,以及Izhikevich模型和自适应指数积分-发放模型。还讨论了神经动力学中噪声的问题,并呈现了两种经典的噪声描述。首先,通过随机尖峰到达引起的随机性:这个方法导致电压微分方程中的噪声项,可以用朗之万方程表示。其次,神经元内在的随机性导致在亚阈区域时跨越触发阈值的“逃逸”:这个方法引出了广义线性模型的框架,该模型会在神经编码和解码的应用中系统地介绍和讨论。强调第二部分中神经元模型和生物数据之间的关系,并介绍了系统的参数优化算法。

+

Part III将第二部分得出的简化模型用于构建网络。以群体活动方程,也称为群体发放率,描述神经网络动力学的集体特性。确定了可以使用标准发放速率模型描述群体活动的条件。

+

Part IV将动力学与认知联系起来。使用群体活动方程分析计算和认知神经科学中著名的范式,比如在决策或记忆检索过程中的神经活动。在第四部分,我们也概述了与突触可塑性相关的学习理论。本书以极有吸引力的神经动力学原理帮助帕金森病人的应用结尾。

+

本书的一小部分内容基于《Spiking Neuron Models》,该书于2002年首次出版,并在此后多次重印。与此同时,这个领域在发生变化,我们认为简单更新《Spiking Neuron Models》的第二版不足以肯定到目前所出现的发展。

+

从更一般的角度来看,我们设计一本从一开始就作为教科书而不是专题著作的书将非常有用。因此,本书更突出与实验数据的联系,有更多解释性文字,并且最重要的是,提供了一系列在多年的课堂教学中已经经过测试的练习题。

+

我们希望这本书对学生和研究人员都能有所帮助。

+

给读者的建议

每一章以一个具体的问题开始,并在第一节给出直观的答案。随着章节的进行,内容变得更加高级,呈现方式也更加技术化。在第一次阅读本书时,可以先只阅读每一章的第一节或前两节,然后快速浏览后续节。

+

更具体的建议取决于读者的背景。比如,建议初次接触计算神经科学领域的读者在开始第二部分和第四部分之前,建议花足够的时间学习第一部分的经典材料。专业的读者可以完全跳过第一部分,直接开始阅读第二部分。

+

在第三部分,主要思想在第12章和第15章进行了阐述,这些章节为第四部分的速率模型打下了基础。第三部分更具技术性的章节在第一次阅读时可以跳过,但有必要对当下计算神经科学领域的最新发展有一个深入的理解。

+

第四部分涉及神经动力学到认知问题的应用,可以按任意的顺序阅读。

+

*标记的小节在数学上更高级,第一次阅读本书时可以忽略。

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/13/neuronal-dynamics-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/14/imagej-plugin-7/index.html b/2023/07/14/imagej-plugin-7/index.html new file mode 100644 index 000000000..ad1b7a1f4 --- /dev/null +++ b/2023/07/14/imagej-plugin-7/index.html @@ -0,0 +1,287 @@ +BIRDS插件代码学习【07】 | Stray Birds + + + + + + + + + + + + + + + +

BIRDS插件代码学习【07】

图像降采样

原始脑片分辨率过高,与Allen平均脑模板的分辨率相差过大,为得到更好的配准效果,需要将原始脑片的分辨率降低。
😎我原本是在ImageJ软件上操作的,没想到用代码实现也并不复杂!

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package I.plugin;

import ij.ImagePlus;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.process.ImageProcessor;

public class Test07 {
public static void main(String[] args) {
ImagePlus brainImage = new ImagePlus("D:/Desktop/elastix-5.1.0-win64/input/result1.tif");
ImageProcessor bp = brainImage.getProcessor();
int width = bp.getWidth();
int height = bp.getHeight();
brainImage.show();

double scale = 0.1;
int newWidth = (int)(width*scale);
int newHeight = (int)(height*scale);
ImagePlus resizedImage = NewImage.createByteImage("resizedImage", newWidth, newHeight, 0, NewImage.FILL_BLACK);
ImageProcessor rp = resizedImage.getProcessor();

rp = bp.resize(newWidth, newHeight, false);
resizedImage.setProcessor(rp);
resizedImage.show();

new FileSaver(resizedImage).saveAsTiff("D:/Desktop/elastix-5.1.0-win64/input/resized-result1.tif");
}
}
+

脑区识别

代码效果:鼠标移动到图片的哪个位置,就在Eclipse控制台输出对应的脑区,超出全脑范围则输出null。

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package I.plugin;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.plugin.RGBStackMerge;
import ij.process.ImageProcessor;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;

public class Test06 implements MouseListener, MouseMotionListener {

public static ImagePlus fuseImage = null;
public static ImagePlus brainImage = null;
public static ImagePlus annoImage = null;
public Map<Integer,String> grayMap = new HashMap<>();

// 提取脑区轮廓
public ImageProcessor getLineImg(ImageProcessor ip, ImageProcessor op) {
int lenX = ip.getWidth();
int lenY = ip.getHeight();
for(int i = 0; i < lenX; i ++) { //按列
int begin = 0; //初始像素值为黑色
for(int j = 0; j < lenY; j ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
for(int j = 0; j < lenY; j ++) {
int begin = 0; //初始像素值为黑色
for(int i = 0; i < lenX; i ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
return op;
}
// 监听鼠标 将excel中的灰度值-脑区读取到HashMap中
public void addMouseListener() throws Exception, IOException {
File file = new File("D:/Desktop/rgb_name.xls");
Workbook wb = Workbook.getWorkbook(file);
Sheet sheet = wb.getSheet("test1");
for(int i = 0; i < sheet.getRows(); i ++) {
Cell[] cell = sheet.getRow(i);
grayMap.put(Integer.valueOf(cell[0].getContents()),cell[1].getContents());
}
// System.out.println(grayMap);
wb.close();

fuseImage.show();
fuseImage.getCanvas().addMouseListener(this);
fuseImage.getCanvas().addMouseMotionListener(this);
}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}

@Override
public void mouseExited(MouseEvent e) {}

@Override
public void mouseDragged(MouseEvent e) {}

@Override
public void mouseMoved(MouseEvent e) {
// 监听鼠标的移动
int currentSlice = fuseImage.getCurrentSlice();
Point point = fuseImage.getCanvas().getCursorLoc();
int val = (int)annoImage.getImageStack().getVoxel(point.x, point.y, currentSlice-1);

System.out.println(grayMap.get(val));
}
// 主程序
public static void main(String[] args) throws IOException, Exception {
brainImage = new ImagePlus("D:\\Desktop\\elastix-5.1.0-win64\\input\\result1-1.tif");
ImageStack brainStack = brainImage.getStack();

annoImage = new ImagePlus("D:\\Desktop\\elastix-5.1.0-win64\\result\\result.tif");
ImageProcessor ap = annoImage.getProcessor();
int width = ap.getWidth();
int height = ap.getHeight();

ImagePlus lineImage = NewImage.createByteImage("lineImage", width, height, 0, NewImage.FILL_BLACK);
ImageStack lineStack = lineImage.getStack();
ImageProcessor lp = lineImage.getProcessor();

ImageProcessor op = new Test06().getLineImg(ap, lp);

lineImage.setProcessor(op);
lineImage.show();

fuseImage = NewImage.createByteImage("fuseImage", width, height, 0, NewImage.FILL_BLACK);

ImageStack fuseStack = RGBStackMerge.mergeStacks(brainStack, lineStack, null, true);
fuseImage.setStack(fuseStack);
new FileSaver(fuseImage).saveAsTiff("D:/Desktop/fuseImage-1.tif");

new Test06().addMouseListener();
}
}
+

操作演示

操作演示

+

注意事项

    +
  1. Eclipse中导入jxl.jar包,具体方法可参考博客,需要注意jxl.jar包只能处理.xls文件
  2. +
  3. 脑片降低分辨率后统计出的各个脑区的细胞数目,需要与人工计数的结果进行对比,如果差别不大,则后续采用降低分辨率的脑片进行配准。
  4. +
  5. 配准后的图像使用Imaris软件计数,具体操作步骤见文章Imairs细胞计数教程
  6. +
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/14/imagej-plugin-7/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/14/imaris-cell-counting/index.html b/2023/07/14/imaris-cell-counting/index.html new file mode 100644 index 000000000..c54a22ee1 --- /dev/null +++ b/2023/07/14/imaris-cell-counting/index.html @@ -0,0 +1,279 @@ +Imairs细胞计数教程 | Stray Birds + + + + + + + + + + + + + +

Imairs细胞计数教程

操作步骤

    +
  1. fuseImage导入Imaris
  2. +
  3. Ctrl+D打开通道面板
  4. +
  5. 点击Slice测量细胞的直径(取个平均值即可)
  6. +
  7. 点击Add new Spots(图标为一团黄色的小球) → 点击▶️ → 选择source channel(此处为红色) → 填写直径(此处为1.5µm)→ 点击▶️ → 根据实际情况调整阈值 → 点击绿色箭头 → 点击折线图即可看到整张脑片的细胞计数情况
  8. +
  9. 点击Add new Surfaces(图标为蓝色的椭球) → 点击Skip automatic creation, edit manually → 界面右侧改为Select → 左下角Draw → 沿着要统计的脑区轮廓绘制闭合曲线 → 点击Create Surface → 点击Edit(图标为一支铅笔✏)选择Mask Selection → 保持勾选Duplicate channel before applying mask → 点击OK之后可以在右侧通道处看到新增的通道(Channel 4) → 取消左侧界面Surfaces的勾选,右侧通道仅保留刚刚复制的通道,其余通道取消勾选 → 接下来对该区域进行细胞计数
  10. +
  11. 点击Add new Spots(图标为一团黄色的小球) → 点击▶️ → 选择source channel(此处注意改为Channel 4) → 填写直径(此处为1.5µm)→ 点击▶️ → 根据实际情况调整阈值 → 点击绿色箭头 → 点击折线图即可看到特定脑区的细胞计数情况
  12. +
+

操作演示

+ +

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/14/imaris-cell-counting/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/16/imagej-plugin-8/index.html b/2023/07/16/imagej-plugin-8/index.html new file mode 100644 index 000000000..8ea34ab83 --- /dev/null +++ b/2023/07/16/imagej-plugin-8/index.html @@ -0,0 +1,276 @@ +二维脑片配准插件开发 | Stray Birds + + + + + + + + + + + + + +

二维脑片配准插件开发

+ +
+
+ + +
+
+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/16/imagej-plugin-8/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/16/life-review/index.html b/2023/07/16/life-review/index.html new file mode 100644 index 000000000..7e7c2fe6f --- /dev/null +++ b/2023/07/16/life-review/index.html @@ -0,0 +1,271 @@ +认识你自己 | Stray Birds + + + + + + + + + + + + +

认识你自己

不知道是从什么时候开始,我变了。刚入学那会我多么希望可以有个朋友和我一起上课、吃饭、坐校车啊,那种一个人走在路上突然冒出来的孤独感,我已经很久没有感受到了。我的内心愈发平静,我的喜好愈发明确,我似乎看见了一个更清晰的自我。

+

说实话,我对自己之前的学习习惯不是很满意,知识不成体系,记笔记零零散散,记忆随着时间的推移渐渐消退,我却好像什么也没留下,总有一种学了但没学扎实的感觉。这个习惯被我带到了新学校,每天八点半来到实验室,一整天的时间点开了各种网页,检索了各种知识,看过了但不清楚自己是否记住了,下次遇到问题又是同样的搜索路径。我分析数据、写应用程序,却总觉得这种东拼西凑的知识来得不踏实。

+

大约是两周前我开始尝试写博客记录每天的学习内容,不是在一天结束的时候写,而是从早上来到工位开始,每日计划、优质博客、学习进展、方法教程等,什么都可以写,总之就是每天结束时要有所收获。和之前全是随笔的博客相比,工作日写下的博客可以说是干货满满。如果我是做一个小项目或是翻译教材,会在博客标题中标上序号,这个小细节在无形之中转化为我坚持的动力。

+

我原本就喜欢写博客,但一般把写博客安排在周末,但周末有时又有别的事情,所以总是断断续续的写。现在把自己喜欢的事情融入到每天的学习中,我的情绪变得更稳定,做事更有底气,效率也更高了。最近这几天不到九点回到宿舍,竟觉得待在宿舍好无聊,明明再有两个小时就要睡觉了,可我却觉得非常难熬,刷短视频没意思,对电视剧、电影或者综艺节目没有任何兴趣,有时躺在床上还会怀念白天的工作时光,真怪。

+

之前我总想着早早下班,周末坚决不来实验室,但现在我觉得我想在实验室多学一会,周末在宿舍也没事干不如来实验室,我知道我不是在做给老板看,也不是在为他学,我是为我自己的成长和进步付出时间和精力。

+

最近还有一个神奇的变化,我现在晚上十一点基本上倒头就睡,早上六点会自然醒,虽然我现在还是会再睡到闹钟响起,但我还是为这个小小的变化感到惊喜。今天早上买了几本字帖,打算以后六点醒来洗漱完练会字,这是我能想到的相对不打扰舍友又能充分利用清晨时间的一种方式,我想变得更好。

+

我很享受现在的生活,自我与工作近乎达到平衡状态,我没有因为忙碌的工作丢掉自我,而是将主动权掌握在自己手中,努力借助更优质的平台实现能力跃迁。

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/16/life-review/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/07/17/neurogym/index.html b/2023/07/17/neurogym/index.html new file mode 100644 index 000000000..65eb1a3ff --- /dev/null +++ b/2023/07/17/neurogym/index.html @@ -0,0 +1,318 @@ +neurogym学习笔记【01】 | Stray Birds + + + + + + + + + + + + +

neurogym学习笔记【01】

NeuroGym是一个经过仔细挑选的神经科学任务集合,具有公共接口。其目标是促进在神经科学任务上神经网络模型的训练。

+

NeuroGym是一个工具包,可以让您在许多已建立的神经科学任务技术上训练任何神经网络模型,如标准的监督学习或强化学习。

+

该教程用于理解Neurogym的任务结构,程序运行环境为Google Colab。本文翻译自Neurogym官方文档,对应的代码 [Open in Colab]

+

neurogym是基于gym开发的,很多参数的设置用起来不是很顺手,不清楚源代码怎么写的,有些代码不太好理解。但本质上就是继承了gym的一些方法,生成行为任务的数据。后面可能不会直接用neurogym,而是仿写并实现课题组内已有的范式。

+
+

安装

1
2
3
4
! pip install gym
! git clone https://github.com/gyyang/neurogym.git
%cd neurogym
! pip install -e .
+

OpenAI gym 任务

Neurogym任务遵循基本的OpenAI gym任务形式。每个任务定义为一个Python类,继承自gym.Env类。

+

在这一节中,我们描述一个OpenAI gym任务的基本结构。

+

__init__方法中,必须定义两个属性,self.observation_spaceself.action_space,它们描述了观测(网络输入)和动作(网络输出)的空间类型。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import warnings
warnings.filterwarnings("ignore")

import numpy as np
import gym

class MyEnv(gym.Env):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(low=0., high=1., shape=(2,))
self.action_space = gym.spaces.Discrete(3)
def step(self, action):
ob = self.observation_space.sample()
reward = 1.
done = False
info = {}
return ob, reward, done, info
def reset(self):
ob = self.observation_space.sample()
return ob
env = MyEnv()
print('sample random observation value')
print(env.observation_space.sample())
print('sample random action value')
print(env.action_space.sample())
# 输出:
# sample random observation value
# [0.23197113 0.8055692 ]
# sample random action value
# 0
+

另一个需要定义的关键方法是step方法,用于接收智能体的动作后更新环境、输出观测和奖励。

+

step方法将action作为输入,并输出智能体的下一个观测observation,智能体获得的标量奖励reward,用于描述环境是否需要重置的布尔值done,以及包含任何额外信息的字典info

+

如果环境通过内部状态描述,reset方法需要重置这些内部状态。该方法返回一个初始观测observation

+

下面我们定义一个简单的任务,智能体沿着一维直线采取动作。奖励由智能体在直线上的位置决定。

+
1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt

def get_reward(x):
return np.sin(x) * np.exp(-np.abs(x)/3)

xs = np.linspace(-10, 10, 100)
plt.plot(xs, get_reward(xs))
plt.xlabel('State value(observation)')
plt.ylabel('Reward')
+

运行结果
智能体可以与环节迭代地互动,红色星星表示智能体的初始状态。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class MyEnv(gym.Env):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(-10,10,(1,))
self.action_space = gym.spaces.Discrete(3) # 0,1,2
self.state = 0.
def step(self,action):
self.state += (action - 1.) * 0.1 # action 0 1 2 对应状态 -0.1 0 0.1
self.state = np.clip(self.state, -10, 10) # 限制取值范围
ob = self.state
reward = get_reward(self.state)
done = False
info = {}
return ob, reward, done, info
def reset(self):
# 重新初始化状态
self.state = self.observation_space.sample()
return self.state
env = MyEnv()
ob = env.reset()
ob_log = list()
reward_log = list()
for i in range(1000):
action = env.action_space.sample()
ob, reward, done, info = env.step(action)
ob_log.append(ob)
reward_log.append(reward)
plt.plot(ob_log, reward_log)
plt.xlabel('State value(observation)')
plt.ylabel('Reward')
+

运行结果

+

基于试次(trial)的Neurogym任务

许多神经科学和认知科学的任务有试次结构。neurogym.TrialEnv为常见的基于试次任务提供了类。它与gym.Env的主要不同在于_new_trial()方法,该方法可以生成新试次的摘要信息,并且可选择地,生成观测和真实值输出。除此之外,用户提供了_step()方法而不是step()方法。

+

_new_trial()方法接收任意键-值参数**kwargs,输出一个包含该试次相关信息的字典trial。这个字典在_step中可以作为self.trial访问。

+

这里我们定义一个简单的任务,智能体在每个试次需要基于它的观测做出一个二元决策。每个试次只有一个时间步。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import neurogym as ngym
from neurogym import TrialEnv

class MyTrialEnv(TrialEnv):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(-1., 1., (1,))
self.action_space = gym.spaces.Discrete(2) # 0 1
self.next_ob = np.random.uniform(-1, 1, size=(1,)) # 用于生成[-1,1)范围内均分分布的随机数
def _new_trial(self): # 实现父类TrialEnv中的_new_trial和_step方法
ob = self.next_ob
self.next_ob = np.random.uniform(-1, 1, size=(1,))
trial = dict()
trial['ground_truth'] = (ob > 0) * 1.0
return trial
def _step(self, action):
ob = self.next_ob
reward = (action == self.trial['ground_truth']) * 1.0

done = False
info = {'new_trial': True}
return ob, reward, done, info

env = MyTrialEnv()
ob = env.reset()
print('Trial', 0)
print('Observation', ob)

for i in range(5):
action = env.action_space.sample()
print('Action', action)
ob, reward, done, info = env.step(action)
print('Reward', reward)
print('Trial', i+1)
print('Observation', ob)
Trial 0
# 输出:
# Observation [0.37521716]
# Action 1
# Reward [1.]
# Trial 1
# Observation [0.88569181]
# Action 1
# Reward [1.] ···
+ +

TrialEnv类定义了两个抽象方法:_new_trial()_step()。这两个方法没有具体的实现,只有方法的声明和文档字符串。这样做的目的是强制任何继承TrialEnv的子类必须实现这两个方法,以便成为一个完整的环境。

+

环境reset时会调用new_trial()方法,step之后也会调用new_trial()方法,只不过这些是在父类中实现的,我们创建环境时只需要把_new_trial()方法实现即可。

+

具体可见neurogym目录下的core.py文件。

+

在基于试次的任务中包含时间,阶段和观测

许多神经科学和认知科学任务遵循额外的时间结构,这些结构被包含进neurogym.TrialEnv。这些任务通常

+
    +
  1. 描述为实际时间而不是离散时间步。例如,任务可以持续3s
  2. +
  3. 每个试次包含许多时间阶段,比如刺激阶段和响应阶段。
  4. +
+

为了包含这些特征,neurogym任务通常支持设置每一步的时间长度dt(单位为ms),以及每个时间阶段的时间长度timing

+

例如,考虑下面的二元决策任务,有500ms的刺激阶段,跟着500ms的决策阶段。可以通过self._new_trial()中的self.add_period()在每个试次中添加阶段。在_step()中,你可以通过self.in_period(period_name)检查任务当前所处的阶段。

+

关于这段代码,我真的向多说几句:官方文档给的这段示例代码有点问题,按它原本的写法,stimulus阶段不应该获得奖励,但是奖励却为1。我调试了很久,总觉得observation、action和reward之间错位了,但看代码又找不出具体问题。今天上午终于发现了,在env.reset()时stimulus阶段就开始了,等进入循环时时间步已经走了一步了,但是此时仍用初始的观测执行env.step(action),就会造成reward不匹配。所以采取的修改方式是删掉循环外存储的ob,直接从第二个时间步开始,这样就不会错位了。

+
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import numpy as np
import neurogym as ngym
import gym
from neurogym import TrialEnv
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'DejaVu Sans'


class MyDecisionEnv(TrialEnv):
def __init__(self, dt=100, timing=None):
super().__init__(dt=dt)
self.timing = {'stimulus':500, 'decision':500}
if timing:
self.timing.update(timing)
self.observation_space = gym.spaces.Box(-1., 1., (1,))
self.action_space = gym.spaces.Discrete(2)
def _new_trial(self):
periods = ['stimulus', 'decision']
self.add_period(periods)

stimulus = np.random.uniform(-1, 1, (1,))
trial = dict()
trial['stimulus'] = stimulus
trial['ground_truth'] = (stimulus > 0) * 1.0
trial['new_trial'] = True
return trial

def _step(self, action):
if self.in_period('stimulus'):
ob = np.array([self.trial['stimulus']])
reward = 0.
else:
ob = np.array([0.])
reward = (action==self.trial['ground_truth'])*1.0

done = False
info = {'new_trial': False}
return ob, reward, done, info

log = {'ob':[], 'action':[], 'reward':[]}
env = MyDecisionEnv(dt=100)
ob = env.reset()

# log['ob'].append(ob)
for i in range(20):
action = env.action_space.sample()
log['action'].append(action)
ob, reward, done, info = env.step(action)
log['reward'].append(reward)
log['ob'].append(ob)

log['ob'] = log['ob'][:-1]
f, axes = plt.subplots(3, 1, sharex=True)
for ax, key in zip(axes, ['ob', 'action', 'reward']):
ax.plot(log[key], 'o-')
ax.set_ylabel(key)
+

运行结果

+

在每个试次的开始设置观测和真实值

在许多任务中,每个试次的观测和真实值是提前确定的,可以在self._new_trial()中设置。生成的观测和真实值可以用作监督学习的输入和目标。

+

观测和真实值可以在self._new_trial()中通过self.add_ob()self.set_groundtruth()方法设置。用户可以用它们的名字指明观测的阶段和位置。比如,self.add_ob(1, period='stimulus', where='fixation')

+

允许用户通过self.obself.gt访问整个试次的观测和真实值,并通过self.ob_nowself.gt_now访问它们的值。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import numpy as np
import neurogym as ngym
import gym
from neurogym import TrialEnv
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'DejaVu Sans'

class MyDecisionEnv(TrialEnv):
def __init__(self, dt=100, timing=None):
# 初始化,关键是设置观测空间和动作空间
super().__init__(dt=dt)
self.timing = {'stimulus':500, 'decision':500}
if timing:
self.timing.update(timing)

name = {'fixation': 0, 'stimulus': 1}
self.observation_space = ngym.spaces.Box(low=-1, high=1, shape=(2,), name=name) # 可以给每个维度命名
name = {'fixation':0, 'choice':[1,2]}
self.action_space = ngym.spaces.Discrete(3, name=name)
def _new_trial(self):
# 返回试次相关信息:阶段,刺激,真实值等
periods = ['stimulus', 'decision']
self.add_period(periods)
stimulus = np.random.uniform(-1, 1, (1,))
self.add_ob(1, period="stimulus", where="fixation")
self.add_ob(stimulus, period="stimulus", where="stimulus")
# where对应的是维度名
ground_truth = int(stimulus > 0)
self.set_groundtruth(ground_truth, period="decision", where="choice")

trial = dict()
trial['stimulus'] = stimulus
trial['ground_truth'] = ground_truth

return trial

def _step(self, action):
# 执行动作,返回观测,奖励等信息
reward = (action==self.gt_now) * 1.0
done = False # 环境是否需要重置
info = {'new_trial': False}
return self.ob_now, reward, done, info
env = MyDecisionEnv()
_ = env.reset()

trial = env.new_trial()
ob, gt = env.ob, env.gt

print(trial)
print(ob)
print(gt)
fig = ngym.utils.plot_env(env, num_trials=2)
+

补充知识

    +
  1. self: 在Python中,当定义一个类方法时,第一个参数通常被称为self,它代表类的实例对象,允许在类的方法中访问对象的属性和其他方法。
  2. +
  3. super().init(): 在面向对象编程中,当创建一个子类时,通常需要继承父类的属性和方法,可以使用super().__init__()来调用父类的构造方法,确保父类的初始化代码得以执行。当super().__init__()不带参数时,它会调用父类的构造方法,并将子类的实例作为第一个参数传递给父类的构造方法。
  4. +
  5. 继承: 在面向对象编程中,继承是一种重要的概念,它允许你创建一个新的类(子类),从一个现有的类(父类)继承属性和方法。子类可以访问父类的属性和方法,并且还可以添加自己的属性和方法。如class Child(Parent): 这样的语法表示子类 Child 继承了父类 Parent。
  6. +
  7. 时间步(time step): 在计算机科学和数学中,时间步长通常用于描述在离散时间模型中的时间间隔。理解时间步长的关键是认识到许多模型和系统在仿真或模拟时需要将时间划分成离散的部分,而时间步长就是这个离散化的单位。在每个时间步长内,系统的状态会被更新,从而使得系统在连续时间范围内的变化可以通过离散时间步长来近似。
  8. +
  9. 抽象方法: 抽象方法是指在父类中声明但没有具体实现的方法,它只有方法名、参数列表和文档字符串,没有具体的代码实现。子类继承这个父类时,必须实现这些抽象方法,否则子类也会被视为抽象类,无法实例化。
  10. +
+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/17/neurogym/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/21/basal-ganglia/index.html b/2023/07/21/basal-ganglia/index.html new file mode 100644 index 000000000..8a332db6c --- /dev/null +++ b/2023/07/21/basal-ganglia/index.html @@ -0,0 +1,271 @@ +基底神经节环路 | Stray Birds + + + + + + + + + + + + +

基底神经节环路

术语解释:
Cortex 大脑皮层
STR(striatum) 纹状体
STN(subthalamic nucleus)丘脑底核
GPe(globus pallidus )苍白球外侧
GPi(globus pallidus in)苍白球内侧
Subthalamic nucleaus 丘脑底核
Thalamus 丘脑
SNr(substantia nigra pars reticulata)黑质网状部

+
+

红色和灰色的箭头分别表示兴奋性和抑制性的连接
直接通路促进运动
间接通路抑制运动
直接通路和间接通路

+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/21/basal-ganglia/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/07/21/imagej-plugin-9/index.html b/2023/07/21/imagej-plugin-9/index.html new file mode 100644 index 000000000..6f075c5b8 --- /dev/null +++ b/2023/07/21/imagej-plugin-9/index.html @@ -0,0 +1,292 @@ +ImageJ插件开发 | Stray Birds + + + + + + + + + + + + + + + +

ImageJ插件开发

开发流程

    +
  1. 安装Java8 JDK (Windows x86 64-bit) ​https://docs.azul.com/core/zulu-openjdk/install/windows
  2. +
  3. 安装Eclipse IDE for Java Developers ​https://www.eclipse.org/downloads/
  4. +
  5. 在github下载示例插件并修改 ​GitHub - imagej/example-imagej2-command: Simple Maven project for an ImageJ2 command
  6. +
+
    +
  • 修改pom.xml:重点修改groupId、artifactId、version、name、的内容
  • +
  • Eclipse-Import-Maven-Existing Maven Projects
  • +
  • 重命名:项目名、包名、java文件中类名和菜单路径
  • +
+
    +
  1. Run as Java application 确保程序可以正常运行
  2. +
  3. Run as Maven build 控制台输出BUILD SUCCESS 则表示程序成功打包为jar包(保存在target目录下)
  4. +
  5. 将jar包粘贴至Fiji的plugin目录,运行软件测试插件效果
  6. +
+

问题记录

    +
  1. 如果pom.xml中报错,则尝试修改,并等待右下角更新完成
  2. +
  3. 打包好的插件在ImageJ中无法正常运行,报错java.lang.ClassCastException: com.chen.brain.pluginMain cannot be cast to org.scijava.plugin.SciJavaPlugin
    报错原因:pluginMain类没有实现org.scijava.command.Command接口,而这是必须的,才能将其识别为有效的SciJava插件。@Plugin注解用于指定该类应注册为一个命令插件,但由于它没有实现所需的接口,因此会导致ClassCastException异常。
    解决方案:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import org.scijava.command.Command;
    import org.scijava.plugin.Plugin;

    @Plugin(type = Command.class, menuPath = "Plugins>brainRegistration")
    public class pluginMain implements Command {

    // 省略其他部分

    @Override
    public void run() {
    // 在这里实现插件的逻辑
    }

    public static void main(String[] args) {
    new pluginMain().location();
    }
    }
  4. +
  5. 在Eclipse中初次导入项目时,要等待build(可能需要等待几分钟)
  6. +
  7. 最好在官方提供的模板基础上写自己的代码,而不是用自己新建的maven项目
  8. +
+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/07/21/imagej-plugin-9/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/23/mac-vmware-fusion/index.html b/2023/12/23/mac-vmware-fusion/index.html new file mode 100644 index 000000000..b6b3e4bbe --- /dev/null +++ b/2023/12/23/mac-vmware-fusion/index.html @@ -0,0 +1,278 @@ +在Mac电脑上安装VMware Fusion | Stray Birds + + + + + + + + + + + +

在Mac电脑上安装VMware Fusion

大学毕业以后买了一台新的联想电脑,当时还因为终于可以用GPU而兴奋了很久,后来去北京出差背着电脑来回走了很久,不插着电源很快就会没电。从北京回来我就斥巨资买了一台苹果电脑,续航能力没得说,平时用的大部分软件也都是有mac版的。因为工位空间有限,我就把苹果电脑放在了工位,联想电脑留在了宿舍,平时偶尔会远程控制一下宿舍的电脑,但有时会很卡,操作也不太方便。

+

之前有想过安装mac双系统,但又怕对电脑不好,就一直将就着使用了。最近有一些软件只能在windows系统上运行,狠了狠心,在mac上安了个虚拟机(VMware Fusion 13),可以比较方便地使用windows系统。(存储空间一下子少了很多,┻┳|・ω・|)

+

VMware Fusion有个人免费版,但我实在是注册不上这个网站,曲线救国选择下载Fusion 13 Pro,然后输入网上找到的序列号(5N400-4AH82-M88Q3-0LC0P-0TRL0 ),就可以正常使用了。

+

注意事项

    +
  1. 可以直接通过Microsoft安装win11
  2. +
  3. 新建虚拟磁盘
  4. +
  5. 记住密码并存储在mac钥匙串中
  6. +
  7. 安装VMware Tools之后全屏可以铺满且有原始mac电脑的分辨率(以管理员身份运行windows powershell→输入Set-ExecutionPolicy RemoteSigned→A→菜单栏选择虚拟机→安装VMware Tools)
  8. +
  9. 我安装的时候没有遇到网上教程所说的网络问题
  10. +
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/23/mac-vmware-fusion/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/23/vscode-ipynb-error/index.html b/2023/12/23/vscode-ipynb-error/index.html new file mode 100644 index 000000000..784360194 --- /dev/null +++ b/2023/12/23/vscode-ipynb-error/index.html @@ -0,0 +1,276 @@ +VSCode无法正常打开.ipynb文件 | Stray Birds + + + + + + + + + + + + + + +

VSCode无法正常打开.ipynb文件

上午原本想写程序,打开VSCode之后发现不能打开.ipynb文件了,报错信息如下:

+

Error loading webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

+

The editor could not be opened due to an unexpected error: Could not initialize webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

+
+

在网上查了一些解决方法,尝试过删除vscode缓存(~/Library/Application Support/Code/)、重新安装插件和重启VSCode,但都不起作用。经过不懈努力,终于在stack overflow上找到了适合我的解决方案,删除Service Worker文件夹之后重启VSCode,.ipynb文件就可以正常显示了!

+

There is another possible reason for OSX, that the files in the following paths are restricted by user permissions.

+

MAC: ~/Library/Application Support/Code/Service Worker

+

You can directly delete folders with restricted permissions.

+

After restarting VScode, he will generate it again.

+
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/23/vscode-ipynb-error/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/12/25/arduino-button-led-demo/index.html b/2023/12/25/arduino-button-led-demo/index.html new file mode 100644 index 000000000..1bc809088 --- /dev/null +++ b/2023/12/25/arduino-button-led-demo/index.html @@ -0,0 +1,279 @@ +【arduino探索】按键控制LED灯 | Stray Birds + + + + + + + + + + + + + +

【arduino探索】按键控制LED灯

Arudino Uno R3开发板简介

Arudino Uno R3开发板引脚说明

+

电路图

目标:使用四角按键开关控制LED灯,当按钮按下时灯亮,松开时灯灭。

+

实现思路:将引脚2改为input mode,反映按键的状态。引脚12为output mode,控制led灯的亮灭。当按键按下时,引脚2为高电平,此时led灯亮;当按钮松开时,引脚2为低电平,此时led灯灭。(对应仿真图连线)

+

如果引脚2的状态为input pullup mode(如果外部组件未启用,上拉电阻将输入端口处的电压拉到高电平),当按键按下时,引脚2为低电平,此时led灯亮;当按钮松开时,引脚2为高电平,此时led灯灭。(对应实物连线)

+

注意事项:四角按键同侧不相连,相连不同侧。

+
+ +

仿真
实物

+

Arduino程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int buttonPin = 2;
int ledPin = 12;

void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}

void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(buttonPin) == LOW){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}

+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/25/arduino-button-led-demo/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/26/arcontrol-boom-game/index.html b/2023/12/26/arcontrol-boom-game/index.html new file mode 100644 index 000000000..33cd362b2 --- /dev/null +++ b/2023/12/26/arcontrol-boom-game/index.html @@ -0,0 +1,286 @@ +【arduino探索】使用ArControl编写“炸弹💣游戏” | Stray Birds + + + + + + + + + + + + + + +

【arduino探索】使用ArControl编写“炸弹💣游戏”

游戏规则:
简易版:游戏有一个5秒倒计时炸弹,时间到了就会爆炸,马里奥玩家就会死亡。如果玩家可以在这5s内按下停止开关,炸弹不会爆炸,玩家马里奥任务成功。

+

实验材料:
Arduino UNO R3 * 1
面包板 * 1
发光二极管 * 1(模拟炸弹)
按钮 * 1(模拟开关)

+
+

Arduino引脚映射

ArControl对Arduino UNO开发板做了端口映射,定义好了6个输入端口和8个输出端口,示意图如下。IN和OUT都是相对于Arduino开发板来说的。在这个小游戏中,我们使用pinA0IN1接收按钮的状态,pin2OUT1控制LED灯的状态。

+

Arduino引脚映射

+

Arduino测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//测试按钮控制led灯是否正常
int ledPin = 2;

void setup() {
pinMode(A0, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {
if (digitalRead(A0) == HIGH){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}
+

Arduino实物连接图

关于接线我还闹了个笑话,我在ArControl上进行测试,发现按下按钮之后,IN1端口会持续很久的高电平,而且不按按钮时也会有通道闪烁的情况。我在arduino IDE中测试按钮控制LED灯的情况,发现了类似的问题,当我不按按钮时,LED灯也是亮的,按下按钮之后,LED灯只是变得更亮了。我检查线路并没发现什么问题,去请教师兄,才发现我接线时按钮旁边的下拉电阻没接上!!!😅按我那样的接法,电阻纯属摆设,跟按钮的电路半毛钱关系都没有。重新接好电阻之后,再测试就正常了。(^-^)V

+
+

实物连接图

+

ArControl使用流程

ArControl的软件部分主要包括两个应用程序,其中ArControl Designer用于编写行为范式的protocol,ArControl Recorder用于监控端口的运行状态并采集实验数据。

+

ArControl Designer

ArControl Designer借鉴了状态机的原理,把行为实验流程等效分解为一系列时序上相互衔接的子任务(State),可以根据实验逻辑在状态之间进行跳转。

+

每一个State可以对6种功能进行配置,包括改变任务变量(do-var)、控制输出通道(do-pin)、 检测任务变量(when-var)、检测实验计数(when-count)、检测等待时间 (when-time)以及检测输入端口(when-pin)。其中每个功能的详细配置是在子窗体中进行的。

+

在这个小游戏中,逻辑比较简单,可以分为倒计时、炸弹爆炸和炸弹不爆炸三个状态,分别记为S1S2S3。如果在没有在5s内按下停止开关,则跳转到S2;如果在5s内按下停止开关,则跳转到S3。编写完实验流程之后,保存。

+

ArControl Designer
如果想查看实验流程图,也可以点击File→Export pdf,这个功能真的很方便检查实验逻辑!
流程图

+

ArControl Recorder

选择Arduino开发板对应的端口,载入实验流程并烧录进开发板。点击Start按钮即可运行,点击Stop按钮即可手动终止程序,也可以等程序运行完自动结束。中间的板块可以实时观察输入/输出端口的电平变化,如果为绿色,则表示当前端口是高电平。下图分别为炸弹💣爆炸💥和成功按下停止开关时的端口状态。

+

Boom
No boom

+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/26/arcontrol-boom-game/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/26/arduino-pump/index.html b/2023/12/26/arduino-pump/index.html new file mode 100644 index 000000000..33e69ee60 --- /dev/null +++ b/2023/12/26/arduino-pump/index.html @@ -0,0 +1,271 @@ +【arduino探索】控制蠕动泵出水 | Stray Birds + + + + + + + + + + + + + +

【arduino探索】控制蠕动泵出水

前几天在淘宝上买的蠕动泵终于到货了,早上拆开快递一脸懵,摆在我面前两个难题:第一,我该怎么给这个蠕动泵供电呢?虽然顶部标有正负极,但我还是不知道该怎么办;第二,蠕动泵自带了管子,比较短,我怎么换成我们实验室自己的硅胶管呢?

+

对于第一个问题,我请教了师弟。拿剪刀将杜邦线剪去一头,然后用剥线钳暴露电线,将电线穿过蠕动泵顶部的孔,折叠后焊锡,另一个孔也同样操作即可。接好线后我在arduino板上测试了一下,一端接入5V电压,另一端接地,测试发现可以正常工作!

+

对于第二个问题,我的第一反应是把自带的管抽出来,换成我们实验室自己的硅胶管。但我抽出来才发现,泵头的孔太小,硅胶管穿不进去。后来尝试把管口剪尖,终于穿进去了,结果泵头的一个小组件崩飞了,┭┮﹏┭┮。后来师弟和师姐意外发现快递里面的转接头(我早就看到了,但不知道是干啥用的),告诉我说这个可以直接接到自带的管上,然后另一端连自己的硅胶管,我才恍然大悟!

+图片说明 + +

虽然小零件崩飞了,但我还是完整地测试了一下蠕动泵的功能(用led blink的程序测试的),一端接pin12,一端接地,arduino写入程序后蠕动泵可以实现间隔1s给水。静待我买的新蠕动泵!
蠕动泵实物连线

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/26/arduino-pump/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/12/27/architectures-of-neuronal-circuits/index.html b/2023/12/27/architectures-of-neuronal-circuits/index.html new file mode 100644 index 000000000..8d3ec67cb --- /dev/null +++ b/2023/12/27/architectures-of-neuronal-circuits/index.html @@ -0,0 +1,263 @@ +【综述】神经环路的架构 | Stray Birds + + + + + + + + + + + +

【综述】神经环路的架构

文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/27/architectures-of-neuronal-circuits/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2023/12/27/neural-encoding-and-decoding/index.html b/2023/12/27/neural-encoding-and-decoding/index.html new file mode 100644 index 000000000..ade2f6db0 --- /dev/null +++ b/2023/12/27/neural-encoding-and-decoding/index.html @@ -0,0 +1,308 @@ +神经编码和神经解码 | Stray Birds + + + + + + + + + + + + + + +

神经编码和神经解码

神经系统的编码方式

信息是怎样在大脑🧠中编码的?几个世纪以来,这个问题一直吸引着医学生、科学家和哲学家。然而,每当有人提出如何在大脑中处理和表征信息的建议时,这些建议往往被证明是简单化和理想主义的。下面简单介绍一下信息可能怎样存储在神经活动中的理论和概念。

+

频率编码 Rate/Frequency coding

频率编码被大多数的研究者视为主要的信息编码方式。如皮肤上的温度感受器就是通过频率编码将温度信息从输入系统转为神经活动的,低温刺激时,皮肤中的温度敏感性外周神经元的放电比较缓慢,随着温度的升高,神经元的发放率升高。在听觉系统中也存在频率编码,神经元的发放率与声音频率直接相关,但高于1kHz这个阈值会采用不同的编码方式。
需要注意的是,传递温度信息的神经元的活动与传递触觉或痛觉信息的神经元的活动没有什么不同,频率编码和动作电位是相似的。感觉被识别为触觉或痛觉是由信息来自的感觉输入系统类型决定的。

+

时间编码 Temporal coding

在我们考虑必须从神经响应中精确测量神经元的放电时间以提取额大部分的信息时,时间编码的概念就产生了。这种精确性决定了神经编码的时间分辨率。大量的研究发现这种时间分辨率在毫秒级别,提示精确的放电时间是神经编码中的一个重要因素。当发现精确的放电时间或高频发放波动携带信息时,神经编码通常被确认为时间编码。
下图为猴子MT脑区的一个神经元在三个不同视觉刺激下的响应模式,最上方面板的发放模式通常被认为是频率编码,最下方面板的发放模式反映时间编码。
时间编码

+

多路复用编码 Multiplexed coding

群体编码 Population coding

稀疏编码 Sparse coding

拓扑结构编码 Topological coding

相位编码 Phase coding

序列编码 Sequence coding


+

编码模型与解码模型

向量x表示众多神经元的活动 ,如:神经元峰电位Spikes、局部场电位LFP、颅内脑电信号iEEG和脑电图EEG等。
向量y表示感兴趣的行为、认知等状态 ,如:运动意图、记忆状态、情感和各种疾病状态等。

+

编码模型encoder():描述感兴趣的行为、认知等状态y如何表征于神经元的活动x
$$x = encoder(y)$$

+

$$f(stimulus)\to neural\ activity$$

+

解码模型decoder():描述如何从神经元的活动x中估计感兴趣的行为、认知等状态y
$$y = decoder(x)$$

+

$$f(neural\ activity)\to stimulus$$

+
+

神经编码

广义线性模型 GLM

可以使用广义线性模型根据提示、刺激、奖励、惩罚等行为和任务变量预测神经元的活动,进而评估行为和任务变量(如)对神经元活动的贡献。

+

神经解码

neural content:在特定脑区有哪些信息?在什么时间?
neural coding:神经活动的什么特征包含信息?
神经解码背后的思想是通过神经活动尝试预测刺激本身或动物的行为。本质上,如果我们可以从许多脑区做记录,并辨别出不同部分的内容, 我们可以追踪大脑的信息流并试图解开使我们能执行特定任务的算法。
群体解码示意图

+

例如,我们向猴子展示一张猕猴桃🥝的照片,同时我们记录某个脑区神经元的活动。神经解码就是我们把神经活动模式“喂进”机器学习算法,我们称之为模式分类器。这个算法学习建立特定刺激和特定神经活动模式的关联。然后用另外的照片重复这个过程,获得另一组神经活动模式,喂进分类器,然后分类器学习这个关联。一旦分类器学到这个关联,我们可以使用或测试这个分类器,用于预测呈现的刺激,与实际呈现的刺激相比,即可判断分类器预测是否正确。

+

交叉验证

在进行交叉验证时,通常是将数据集划分为训练集和测试集,然后在训练集上进行交叉验证来评估模型性能和选择最佳超参数,最后使用选定的最佳模型配置在测试集上进行最终的性能评估。

+

交叉验证

+

最大相关系数分类器 Maximum Correlation Coefficient Classifier

Maximum Correlation Coefficient (MCC) Classifier(最大相关系数分类器)是一种用于模式识别和分类任务的统计学方法,其核心思想是寻找能最大化特征与类别之间相关性的投影方向。计算测试向量与不同刺激下神经元群体活动的原型向量的相关性,相关性最高的即为分类器的预测结果。解码可以视为评估下游神经元可获得的信息,分类器要学习的是神经元的突触权重,待分类的神经元活动模式为突触前活动。
在同一时间窗下训练和测试数据,如果是在baseline阶段,即刺激呈现之前,不同刺激的baseline阶段活动应差别不大,所以解码准确率大概维持在chance level(1/刺激的类别数)。
数据组织方式
原型

+

梯度提升树解码器 Gradient Boosted Trees Decoder

支持向量机 Support Vector Machine

支持向量机是一种监督式学习算法,通常用于分类和回归分析。其目标是在特征空间中找到一个最优的超平面,能够有效地将不同类别的数据分开。SVM的主要思想是找到能够最大化类别间间隔(Margin)的超平面,即找到一个决策边界,使得两个不同类别的数据点到这个边界的距离尽可能远。而支持向量则是离这个决策边界最近的那些数据点。

+

基本数据分析

计算神经元的发放速率 Firing rate

神经元的概率性发放:即使是相同刺激下的不同试次,同一神经元不是确定性地发放,而是按照一定概率分布发放。
神经元的发放概率Pr(t至t+∆t):某个特定时间段内发放的概率;
神经元的发放速率r(t):某个特定时间点发放的概率密度
$$Pr(t至t+\Delta t)=r(t)\Delta t$$

+

补充知识:连续型随机变量X落在区间(x1,x2]上的概率P{x1<X≤x2}等于区间(x1,x2]上曲线y=f(x)之下的曲边梯形的面积。介于曲线y=f(x)与x轴之间的面积等于1。

+

概率密度

+

当∆x充分小时,有
$$P \{x<X\le x+\Delta x \} \approx f(x)\Delta x$$

+
+ +

对于具有相同试次结构的trial-by-trial的实验,一般认为试次之间是同质的。在有多次同等条件试验的情况下,假定有N个试次,选定一个足够小的时间窗∆t(如50ms),计算t至t+∆t范围内所有试次中神经元发放的次数n,则发放速率
$$r(t) ≈ \frac{n}{N\Delta t}$$

+

单位为spikes/s或Hz。

+

对于单个试次条件下,假定刺激是缓慢变化的,沿着时间进行平均,可以通过较长时间窗T内的平均发放次数估计发放速率,时间窗T内的发放次数记为n,则
$$r = \frac{n}{T}$$

+

作图

栅格图(Raster plot)可以直观地展示神经元的发放事件,一行代表神经元在一次试验中的发放,每个点代表一次放电。刺激前后反应直方图(Peri-Stimulus Time Histogram PSTH)用于展示特定刺激事件发生前后在各个时间点神经元的发放速率。

+
    +
  1. 将N个试次按照感兴趣的刺激事件发生的时间对齐,如灯亮/蜂鸣器响等
  2. +
  3. 选择合适的时间窗∆t,将时间分为长度为∆t的小段
  4. +
  5. 每个小段内,统计所有试次中该神经元的总发放次数n
  6. +
  7. 用n/N∆t(单位为spikes/s或Hz)作为每个小段内的发放速率的估计
  8. +
  9. 绘制发放速率沿着时间变化的直方图
  10. +
+

光栅图和PSTH

+

参考内容

    +
  • 《Information processing by neuronal populations》
  • +
  • 浙江大学现代神经生物学课程
  • +
  • 《From molecules to networks: an introduction to cellular and molecular neuroscience》
  • +
  • 《Theoretical neuroscience: computational and mathematical modeling of neural systems》
  • +
  • 梯度提升树(Gradient Boosted Trees):模型理解
  • +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/27/neural-encoding-and-decoding/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/28/neurons-exc-or-inh/index.html b/2023/12/28/neurons-exc-or-inh/index.html new file mode 100644 index 000000000..bf6901546 --- /dev/null +++ b/2023/12/28/neurons-exc-or-inh/index.html @@ -0,0 +1,278 @@ +神经元类型和活动状态判断标准 | Stray Birds + + + + + + + + + + + + + +

神经元类型和活动状态判断标准

神经元发放率标准化方法

Z-score是用来衡量数据点与其所在数据集平均值之间偏差程度的一种统计量。它通常将数据点减去均值,再除以标准差,将数据标准化到一个标准正态分布上。点击查看标准正态分布表
$$Zscore=\frac{x-\bar{x}}{\sigma}$$

+

标准正态分布
68-95-99.7法则:
约有 68% 的数据点落在均值左右一个标准差的范围内。
约有 95% 的数据点落在均值左右两个标准差的范围内。
约有 99.7% 的数据点落在均值左右三个标准差的范围内。

+

相关概念

标准差

$$\sigma =\sqrt{\frac{\sum_{1}^{n}(x_i-\bar x)^2 }{n}}$$

+

标准差是方差的平方根,用于描述一组数据的离散程度或变异程度。标准差衡量数据集中各个数据值与其平均值之间的偏离程度。标准差消除了平方的影响,数值更接近于原始数据的数量级,更易于直观理解和比较。

+

标准误

$$SEM=\frac{\sigma}{\sqrt{n}}$$

+

标准误差是一种用于衡量样本平均值估计的变异程度或不确定性的统计量。它表示样本平均值估计与总体平均值之间的偏差,标准误差的值越小,代表样本均值估计越接近总体均值,或者说样本均值的可靠性越高。

+

兴奋or抑制

参考文献1
We first examined whether a neuron was excited or inhibited by light stimulation by asking whether its firing rate during the first 500 ms after light onset was higher or lower, respectively, than its firing rate in the 500 ms immediately before light onset. This was examined separately for each light intensity (Wilcoxon signed-rank test, p < 0.05, corrected for multiple comparisons). In order to quantify the strength of inhibition we calculated the normalized firing rate by dividing the mean firing in the first 500 ms after laser onset by the mean baseline firing in the 500 ms before laser onset.

+

Babl S S, Rummell B P, Sigurdsson T. The spatial extent of optogenetic silencing in transgenic mice expressing channelrhodopsin in inhibitory interneurons[J]. Cell reports, 2019, 29(5): 1381-1395. e4.

+
+

参考文献2
Food-cue, lever-press, and dish-entry responses were calculated as Z-scores normalized to 20 pre-cue bins of 300 ms. Neurons showing a Z-score >2.58 (P < 0.01) during the first two bins following the onset of the food cue, lever press, or dish entry were classified as excitatory responses, whereas neurons showing a Z-score < −1.96 (P < 0.05) during the same first two bins were classified as inhibitory responses.

+

Engelke D S, Zhang X O, O’Malley J J, et al. A hypothalamic-thalamostriatal circuit that controls approach-avoidance conflict in rats[J]. Nature communications, 2021, 12(1): 2517.

+
+

神经元类型

The spike width, defined as the time from the valley to the return to baseline after the peak, and the ratio between peak and valley amplitudes.

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/28/neurons-exc-or-inh/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/29/arduino-touch-pump/index.html b/2023/12/29/arduino-touch-pump/index.html new file mode 100644 index 000000000..b07e9ef62 --- /dev/null +++ b/2023/12/29/arduino-touch-pump/index.html @@ -0,0 +1,303 @@ +【arduino探索】搭建触摸给水装置 | Stray Birds + + + + + + + + + + + + + +

【arduino探索】搭建触摸给水装置

实验材料准备

    +
  • 电容触摸传感器*1

    +触摸传感器 +
  • +
  • 蠕动泵*1

    +
  • +
  • 可孚一次性无菌加药器 50ml(粗针管)

    +
  • +
  • 杜邦线公对公

    +
  • +
  • Arduino Uno R3*1

    +
  • +
  • 粗针头*2

    +
  • +
  • 绝缘胶带

    +
  • +
+
+

电容触摸传感器和蠕动泵需要焊接杜邦线,用剪刀减去杜邦线一端的公头,用剥线钳暴露铜丝,短暂加热焊锡覆盖暴露的铜丝。

+
+

配件功能测试

首先测试给水装置核心配件的功能是否正常。

+

电容触摸传感器

电容触摸传感器上标有VCC、GND和DAT引脚,VCC是电源引脚,用于给传感器供电;GND是接地引脚;DAT是数据引脚,用于传输触摸信号。经过Arduino程序测试,发现电容触摸传感器默认为高电平,触摸时为低电平。

+
1
2
3
4
5
6
7
8
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
}
+

用绝缘胶带缠绕触摸传感器引脚的杜邦线(起到保护和固定的作用),将粗针头固定到传感器较平整的一面,该装置即可作为小鼠的舔水口,小鼠通过针头舔水时,针头另一端会按压触摸传感器,因此可以根据触摸传感器电平的变化检测舔水事件。

+

蠕动泵

上次买的蠕动泵有一个小配件被我弄坏了,这次测试新买的蠕动泵,通过转接头连接硅胶管,进水口放入粗针管内。给蠕动泵提供5V的电压,经测试,可以正常工作,出水口正常出水。
由于要控制训练过程中每个试次的给水量,因此对蠕动泵的出水量进行测试。经询问师弟,可以采用给水0.1s,间隔0.1s,并重复40次的方式测量,测量前称纸巾的重量,测量后再对纸巾称重,即可计算出每次给水的体积。连续两天测量蠕动泵的出水量,如果保持不变,即认为可正常工作。
$$m=\rho V$$

+

$$\rho_{水} =1g/cm^3 $$

+

$$1cm^3=1000\mu L$$

+
    +
  • 12.29 测试结果:40次 给水0.1s 间隔0.1s 称重:0.05g
  • +
+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
delay(1000);
int i = 0;
for(i = 1; i <= 40; i ++){ // 测出水量
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
delay(100); // ms
}
}

void loop() {
Serial.println(digitalRead(A0));
}
+

实验装置

触摸给水装置实物连线

+

触摸给水

接下来测试触摸传感器控制蠕动泵给水的功能,经测试,功能正常。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
if (digitalRead(A0) == LOW){ // 测试触摸给水
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
}
}
+

经验

    +
  1. 小鼠训练过程中每天摄入水量为1ml~1.2ml
  2. +
  3. 测试时针管内的气泡一定要排干净,且传感器的放置方式与实际任务期间保持一致
  4. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/29/arduino-touch-pump/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/29/eeg-emg-analysis/index.html b/2023/12/29/eeg-emg-analysis/index.html new file mode 100644 index 000000000..dd1d401d8 --- /dev/null +++ b/2023/12/29/eeg-emg-analysis/index.html @@ -0,0 +1,278 @@ +脑电数据分析 | Stray Birds + + + + + + + + + + + + + + +

脑电数据分析

睡眠分期

小鼠的睡眠周期主要包括清醒、非快速眼动和快速眼动三个阶段,有时也会考虑微觉醒状态,即发生在NREM阶段的短暂(小于10s)觉醒状态。

+
    +
  • WAKE:desynchronized EEG and high EMG activity
  • +
  • NREM:synchronized EEG with high-amplitude, low-frequency (1–4 Hz) activity and low EMG activity
  • +
  • REM:high EEG power at theta frequencies (6–9 Hz) and low EMG activity
  • +
+

睡眠阶段示意图

+

脑电频段

脑电波通常被分为以下几个频段,每个频段对应不同发脑功能活动。需要注意这些频段的划分并非绝对,不同的研究可能会对频段的划分略有不同。
脑电波

+

时域分析

频域分析

时频分析

快速傅里叶变换

小波变换

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/29/eeg-emg-analysis/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/29/experience-2023/index.html b/2023/12/29/experience-2023/index.html new file mode 100644 index 000000000..4d6825582 --- /dev/null +++ b/2023/12/29/experience-2023/index.html @@ -0,0 +1,420 @@ +2023年度总结 | Stray Birds + + + + + + + + + + + + + +

2023年度总结

小确幸

科研

和去年的我相比,我最大的感触就是我开始去做一些事情了,我能渐渐抛开过去的成绩,正视自己存在的不足,耐心去学习、去积累。从一开始辅助课题组同事做数据分析,到后来争取到合作课题,再到现在慢慢有了自己的课题,很多事情在一开始我并不能看清未来的走向,但我还是选择坚定的走下去,我相信只有这样才能把路走远走宽。

+

我原本以为这五年我都不会碰生物实验,我相信或许我跨专业就不该碰生物实验,但我常常内心动摇,一方面是对我已有的能力能否支撑我顺利毕业信心不足,另一方面是希望可以自己做实验收集数据,不想一直依附于其他人。

+

我经常感觉很多事情困难,其实是因为它们一直停留在我的想象中,从未付诸实践。今年下半年我的做事态度转变很大,我开始敢于提出自己的数据分析思路,开始尝试稍微复杂一些的算法,开始学做生物实验,开始自己焊接线路搭建行为装置。我才发现我有能力做到这么多事情,我可以用数据分析结果影响课题的走向,我可以一个人完成小鼠脑立体定位手术,我可以搭建好硬件电路!

+

希望新的一年我可以进一步提升专业技能,努力做一个有价值的、值得信赖的人,也希望科研方面可以有新的突破,加油加油!我的2024一定很哇塞!🥳

+

电影🎬

    +
  • 航海王:红发歌姬
  • +
  • 满江红
  • +
  • 人生路不熟
  • +
  • 变形金刚:超能勇士崛起
  • +
  • 消失的她
  • +
  • 八角笼中
  • +
  • 长安三万里
  • +
  • 流浪地球2
  • +
  • 孤注一掷
  • +
  • 无价之宝
  • +
  • 刀尖
  • +
  • 指环王
  • +
  • 三大队
  • +
+

旅行

    +
  • 聊城
  • +
+ +
    +
  • 杭州
  • +
    • +
    • 浙大紫金港
    • +
    +
  • +
+ + +
    +
    • +
    • 动物园和植物园
    • +
    +
  • +
+ + +
    +
    • +
    • 湘湖
    • +
    +
  • +
+ + +
    +
    • +
    • 西湖
    • +
    +
  • +
+ + +
    +
    • +
    • 灵隐寺
    • +
    +
  • +
+ +
    +
    • +
    • 浙江升非物质文化遗产馆
    • +
    +
  • +
+ +
    +
    • +
    • 塘栖古镇
    • +
    +
  • +
+ +
    +
    • +
    • 闲逛
    • +
    +
  • +
+ +
    +
  • 北京
  • +
+ +
    +
  • 南京
  • +
+ +
    +
  • 绍兴
  • +
+ +
    +
  • 邢台
  • +
+ +
    +
  • 西安
  • +
+ +

鸟🐦

+

喜事

    +
  • 我的小侄子出生啦~
  • +
  • 实验室三位同门都在今年结婚了,喜糖不断!🍬
  • +
  • 康康要来杭州工作啦!
  • +
+

小技能

    +
  • 催眠课上学到了一个小魔术🥰
  • +
  • 做饭!
  • +
+ + +

讲座

+

经验

    +
  1. 生活不是一成不变的,路是越走越宽的
  2. +
  3. 不要一味地获取资源,对已有资源的消化和吸收更重要
  4. +
  5. 在做重大决定之前要给自己想好后路,不要心血来潮
  6. +
  7. 想学的东西很多不要怕,每次学多少也不用太过死板,重要的是持续去学习
  8. +
  9. 从论文中摘录的观点或数据图,要注明文献出处,以免后续找不到哪一篇文献
  10. +
  11. 代码要规范命名,写好注释及文档说明,及时同步到github
  12. +
  13. 做事情要有逻辑,数据分析要紧紧围绕科研问题
  14. +
  15. 我们并不仅仅是被动处于一个环境之中,我们也可以通过努力去影响和改变周围的环境
  16. +
  17. 做事要善始善终,别人交代的事情要及时反馈
  18. +
  19. 笔记中注明当天时间,便于复盘
  20. +
  21. 对自己的能力有合理的评估,既要量力而行,又要适当突破舒适圈
  22. +
  23. 要相信每次讨论都是有价值的,及时记录
  24. +
  25. 文件多平台同步会极大提高工作效率
  26. +
  27. 学到的知识及时整理,尽量可以用自己的话写出来,有机会的话还可以讲给别人,这样对知识的理解更深刻
  28. +
  29. 要警惕一直做别人安排的事情,要有自己的思想,对自己做的事情有清晰的认知和规划,明确任务的优先级
  30. +
  31. 事情并不会总按预期进行,要考虑全面,接受有可能发生的不好的结果
  32. +
  33. 实践是最快速的学习方式
  34. +
  35. 成绩不等于个人能力,要想证明自己就要拿出成果
  36. +
  37. 过去偷懒绕开的困难也许在不久的将来又会变成拦路石,总是要面对的
  38. +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/29/experience-2023/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2023/12/29/matlab-app-designer-1/index.html b/2023/12/29/matlab-app-designer-1/index.html new file mode 100644 index 000000000..93c5d093c --- /dev/null +++ b/2023/12/29/matlab-app-designer-1/index.html @@ -0,0 +1,263 @@ +【MATLAB App Designer使用教程】可拖拽的线 | Stray Birds + + + + + + + + + + + +

【MATLAB App Designer使用教程】可拖拽的线

文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2023/12/29/matlab-app-designer-1/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2024/01/01/html-show-current-time/index.html b/2024/01/01/html-show-current-time/index.html new file mode 100644 index 000000000..05e5e70fd --- /dev/null +++ b/2024/01/01/html-show-current-time/index.html @@ -0,0 +1,281 @@ +在网页中实时显示当前时间 | Stray Birds + + + + + + + + + + + + + + +

在网页中实时显示当前时间

早上吃完早饭去浙大图书馆主馆逛了一圈,终于见识到了传说中的自习区域墨水屏幕,确实很高级,如果这个座位被人预约了,屏幕上会显示预约人的姓名和预约时间!之前的基础图书馆里面很少有计算机相关的书籍,没想到新开的主馆里弥补了这个缺憾。

+

我上午看了一本arduino编程相关的书籍,对蓝牙和wifi模块很感兴趣,书中对这两个模块的使用只是举了一个很简单的例子,连接的都是arduino开发板的串口收发口,可以实现手机与arduino串口监视器的通信。

+

书中最后举了一个智能温室大棚的例子,我一直不太理解怎么实现手机远程控制arduino端的传感器。中午请教了一下康康,梳理了一下大致流程:arduino板连接wifi模块,接入校园网,向服务器发送传感器数据,可以存入txt文件或数据库中,手机或网页端通过服务器获取到传感器的数据,可以每隔1s请求一次数据。

+

上位机:指可以直接发送操作指令的计算机或单片机,一般提供用户操作交互界面并向用户展示反馈数据。

+

下位机:指直接与机器相连接的计算机或单片机,一般用于接收和反馈上位机的指令,并且根据指令控制机器执行动作以及从机器传感器读取数据

+

上位机给下位机发送控制命令,下位机收到此命令并执行相应的动作。
上位机给下位机发送状态获取命令,下位机收到此命令后调用传感器测量,然后转为数字信息反馈给上位机。
下位机主动发送状态信息或报警信息给上位机。

+
+

我一直困惑间隔1s请求一次数据,是否会在网页上看到数据刷新时的闪烁,为了解决这个困惑,康康建议我写个简单的网页测试一下,每个1s获取一下当前的时间。经实践测试,人眼并不会看到数据刷新时的闪烁。

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

</head>
<body>
<div id="time-now">

</div>
<script>
setInterval(function (){
$('#time-now').text(new Date())
}, 1000)
</script>
</body>
</html>
+

参考文章

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/01/html-show-current-time/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2024/01/02/electrode-holder/index.html b/2024/01/02/electrode-holder/index.html new file mode 100644 index 000000000..f058399f1 --- /dev/null +++ b/2024/01/02/electrode-holder/index.html @@ -0,0 +1,290 @@ +记录电极支架制作步骤 | Stray Birds + + + + + + + + + + + + + +

记录电极支架制作步骤

利用转动螺杆驱动螺母移动的机械推进原理,利用3D打印的滑片、支架、螺杆和螺母等材料,组装成可推进式多通道电极驱动装置。通过转动螺杆,可以使固定于其上的电极同步推进。当电极记录位点附近的神经元失活后,还可以推进记录电极到更深部的脑组织,从而在实验中观察到更多的神经元活动。

+
+

步骤

    +
  1. 用钳子剪下一段排母,包含10个排针
  2. +
  3. 将电路板卡到排母中间,用焊锡焊接(注意焊接手法,需要多练习)
  4. +
  5. 剪两段银丝作地线(不需要剪太长,一小段即可),焊接在电路板两侧的孔里
  6. +
  7. 用电钻(选用合适的钻头,一般选最细的)打磨滑片和底座的孔,尽量保持垂直
  8. +
  9. 准备三个点胶针,两粗一细,截断处打磨平整,可以借助昆虫针疏通针管
  10. +
  11. 螺杆穿过滑片中间的孔,拧上两颗螺母,一颗紧靠滑片底部(也不要拧太紧),并涂AB胶固定,用钳子剪去多余的螺杆,留大概7mm的长度
  12. +
  13. 将滑片放入底座,根据孔的距离判断左右,左侧用粗点胶针固定,右侧用粗点胶针套细点胶针
  14. +
  15. 放置好后用AB胶固定下面两层,及滑片下方与细点胶针的连接处,胶干后可以尝试拧一下螺丝,看是否可以正常滑动,以及细点胶针是否可以正常向下走
  16. +
  17. 使用AB胶将底座固定在电路板上(可能需要打磨电路板上的两个孔),注意保持底座和电路板平行
  18. +
+

注意事项

    +
  • 涂AB胶固定时一定要小心,搞清楚哪里是需要移动的,哪里是需要固定住的,螺母下端固定,涂胶时避免粘住螺母与滑片上端
  • +
  • 以后做电极时戴上口罩,焊锡和AB胶味道太大了
  • +
  • 将细针管、螺杆🔩和粗针管的孔径分别修改为0.7mm、1.1mm和0.9mm,针管孔径距两侧均为0.8mm,支架背部柱子直径改为1.65mm
  • +
  • AB胶完全干要一定的时间,耐心等待,或第二天再测试电极支架
  • +
  • 螺杆的长度预留大概7mm,不能超出电极支架底部
  • +
  • 焊接时,先用电烙铁同时加热针脚和焊盘,将焊锡靠近电烙铁的焊头,焊锡粘在焊盘上后,快速抽走焊锡
  • +
  • 剪排母时,钳子对准第10列和第11列中间靠右的位置,多剪下来一列没关系,至少要保证前10排排针是完好的
  • +
+

参考文章

    +
  • 多通道在体记录技术——小鼠可推进式微电极阵列帽制作与植入手术
  • +
+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/02/electrode-holder/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2024/01/04/install-origin/index.html b/2024/01/04/install-origin/index.html new file mode 100644 index 000000000..d52e789d0 --- /dev/null +++ b/2024/01/04/install-origin/index.html @@ -0,0 +1,269 @@ +下载教育版origin | Stray Birds + + + + + + + + + + + + + +

下载教育版origin

之前在联想电脑上安装过origin,今天想在mac的虚拟机上也安一个origin,结果发现我不记得怎么下载了,也不记得之前是从哪里找到的正版安装途径,今天在搜索过程中竟然连官网都找错了,索性记录一下安装过程。

+

进入origin官网,点击顶部的Try Origin for Free,选择I have NEVER used OriginStudent,点击继续,即可看到如下的界面。

+

选择Learning Edition,填写姓名、学校、邮箱等信息。填写完提交后去教育邮箱中验证,即可收到软件的下载链接、序列号和密钥。

+

用同一个教育邮箱申请账号的话,得到的密钥是同一个,如果已经激活过origin软件,就不能在别的电脑上安装origin时使用了。┭┮﹏┭┮

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/04/install-origin/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2024/01/05/dlPFC-bayesian-inference/index.html b/2024/01/05/dlPFC-bayesian-inference/index.html new file mode 100644 index 000000000..762fb7e2b --- /dev/null +++ b/2024/01/05/dlPFC-bayesian-inference/index.html @@ -0,0 +1,268 @@ +【文献学习】前额叶皮层在反转学习中预测状态转换 | Stray Birds + + + + + + + + + + + + + + +

【文献学习】前额叶皮层在反转学习中预测状态转换

作者:Bartolo R, Averbeck B B.
标题:Prefrontal cortex predicts state switches during reversal learning
期刊:Neuron, 2020

+
+

具体内容

研究目的/科学问题

研究背景

研究结果

研究结论

想法记录

可以跟进的参考文献

可以借鉴的内容

其它

文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/05/dlPFC-bayesian-inference/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2024/01/05/github-desktop/index.html b/2024/01/05/github-desktop/index.html new file mode 100644 index 000000000..2ad004048 --- /dev/null +++ b/2024/01/05/github-desktop/index.html @@ -0,0 +1,283 @@ +Github Desktop同步代码 | Stray Birds + + + + + + + + + + + + + +

Github Desktop同步代码

Github Desktop主要有三个添加仓库的选项:

+
    +
  1. Clone a Repository
  2. +
  3. Create a new Repository
  4. +
  5. Add Existing/Local Repository
  6. +
+

如果想把github远程仓库的代码克隆到本地,选择Clone a Repository,即可把远程仓库下载到指定的本地路径。

+

如果想创建新的仓库,选择Create a new Repository

+

如果想把本地文件夹作为新的仓库上传到github,选择Add Local Repository

+

如果本地改动了仓库中的代码,点击Commit to main,然后Push origin,即将新的代码推送到github上。Fetching origin是把github上的代码拉到本地。

+
    +
  • 不要轻易同意删除本地仓库!!!警惕带local的选项!如果不小心删除了,尝试去回收站找回。
  • +
  • 大部分情况下,创建仓库时选择Keep this code private
  • +
  • 不要一次性上传很多文件,也不要反复push代码,撤销push操作可能会误删本地代码!
  • +
  • 同步重要数据时提前把数据复制到别的地方,做好备份,给自己留个后路!
  • +
+
+ +
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/05/github-desktop/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
公告
我们度过的每个平凡的日常,也许就是连续发生的奇迹。
\ No newline at end of file diff --git a/2024/01/09/arduino-tft/index.html b/2024/01/09/arduino-tft/index.html new file mode 100644 index 000000000..454173b06 --- /dev/null +++ b/2024/01/09/arduino-tft/index.html @@ -0,0 +1,275 @@ +【arduino探索】点亮ST7789 1.3寸TFT屏幕 | Stray Birds + + + + + + + + + + + + + +

【arduino探索】点亮ST7789 1.3寸TFT屏幕

Adafruit-GFX-Library

该类库为所有彩色屏幕的基础类库,安装方式:在Arduino的项目-加载库-库管理器中搜索Adafruit GFX Library,选择最新版本进行安装。Github下载地址
Arduino中的第三方库的存放地址可以在首选项-项目文件夹位置处查看,该路径下的libraries文件夹下即为第三方库的存放地址。

+

Arduino-ST7789-Library

该类库为ST7789的专用驱动库。Github下载地址
运行画直线的程序,用时约32.6s,太慢了,每次黑屏都要等半天!

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <Adafruit_GFX.h>    // Core graphics library by Adafruit
#include <Arduino_ST7789.h> // Hardware-specific library for ST7789 (with or without CS pin)
#include <SPI.h>

#define TFT_DC 8
#define TFT_RST 7 //9
#define TFT_CS 9 //10 // only for displays with CS pin
#define TFT_MOSI 11 // for hardware SPI data pin (all of available pins)
#define TFT_SCLK 13 // for hardware SPI sclk pin (all of available pins)

#define w 240
#define h 240


Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_CS); //for display with CS pin

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}


void setup(){
Serial.begin(9600);
tft.init(w, h);
}

void loop(){
uint32_t start = micros_start();

tft.fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;
tft.setCursor(0, 20);
tft.setTextSize(3);
tft.setTextColor(RED);
tft.println("Cost Time:");

tft.setCursor(0, 50);
tft.setTextSize(4);
tft.setTextColor(RED);
tft.println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}
+

Arduino_GFX

安装方式:在Arduino的项目-加载库-库管理器中搜索GFX Library For Arduino,选择最新版本进行安装。Github下载地址
运行画直线的程序,用时约5.7s,速度超级快!在测试Arduino_GFX的时候还发生了一个小插曲,我连线明明是正确的,但屏幕没有任何反应,排了很久的bug,最后发现是我的arduino开发板有问题,果然太便宜了容易出问题,以后还是用正版的arduino开发板吧!

+
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <Arduino_GFX_Library.h>
int32_t w, h;

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus *bus = create_default_Arduino_DataBus();

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
Arduino_GFX *gfx = new Arduino_ST7789(bus, DF_GFX_RST, 0 /* rotation */, true /* IPS */);

#endif /* !defined(DISPLAY_DEV_KIT) */

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}

void setup(){
Serial.begin(9600);
gfx->begin();
w = gfx->width();
h = gfx->height();

#ifdef DF_GFX_BL
pinMode(DF_GFX_BL, OUTPUT);
digitalWrite(DF_GFX_BL, HIGH);
#endif
}

void loop(){
uint32_t start = micros_start();

gfx->fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;

gfx->setCursor(0, 20);
gfx->setTextSize(3);
gfx->setTextColor(RED);
gfx->println(F("Cost Time:"));

gfx->setCursor(0, 50);
gfx->setTextSize(4);
gfx->setTextColor(RED);
gfx->println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}
+

参考内容

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/09/arduino-tft/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/2024/01/09/stereotexic-localization-of-brain/index.html b/2024/01/09/stereotexic-localization-of-brain/index.html new file mode 100644 index 000000000..beb163240 --- /dev/null +++ b/2024/01/09/stereotexic-localization-of-brain/index.html @@ -0,0 +1,341 @@ +小鼠脑立体定位手术 | Stray Birds + + + + + + + + + + + + + +

小鼠脑立体定位手术

脑立体定位手术

在神经科学的研究方法中,为了使各种处理手段(给药、毁损、病毒注射等)或信号采集(微电极、探针)到达目的脑区的相应位置,需要使用脑立体定位技术。通过向目标脑区注射红墨水,练习脑立体定位手术,注射完后需要灌流取脑,然后固定、沉糖、切片看位点,最终成像。

+

查找目标核团坐标

根据研究目的和小鼠种类不同,选择合适的闹立体定位图谱,动物的体重应该尽量与图谱一致,具体信息可在Introduction部分找到,如C57BL/J6成年小鼠,体重26~30g。
在脑图谱List of structures中查找眶额叶皮层的缩写:

+
    +
  • DLO dorsolateral orbital cortex
  • +
  • LO lateral orbital cortex
  • +
  • MO medial orbital cortex
  • +
  • VO ventral orbital cortex
  • +
+

按照缩写在Index of Abbreviations定位到目标核团所在的页码:

+
    +
  • LO lateral orbital cortex 0, 4-15, 17, 112-120
  • +
+

+

经目标核团中心点画水平线和垂直线,即可读出核团的颅骨下深度坐标和中线旁开左右坐标,右下角的Bregma值是核团的前后坐标(正值代表前囟前,负值代表前囟后)。

+

最终确认位点:(+2.6mm, ±1.3mm, -1.6mm)

+

实验操作流程

    +
  1. 准备手术器具并喷酒精消毒
  2. +
  3. 小鼠称重,腹腔注射水合氯醛(用量:体重*0.01)
  4. +
  5. 酒精擦拭后,用刀片剃除小鼠头部毛发
  6. +
  7. 通过适配器门齿夹和耳杆固定头部(检查是否固定成功:鼻对正中,头部不动,提尾不掉,目测大脑放置水平)
  8. +
  9. 涂上红霉素眼膏,避免强光损失小鼠眼睛
  10. +
  11. 剪开小鼠头部皮肤
  12. +
  13. 双氧水腐蚀脑膜,去除颅骨表面结缔组织,暴露前后囟
  14. +
  15. 定位(以bregma点为原点)要先保证小鼠头部X轴方向左右齐平(左右深度相同即可),Y轴方向前后齐平(误差在0.03mm内)
  16. +
  17. 钻孔 颅骨钻在钻孔点轻磨颅骨,将颅骨打薄,最后用针头挑破(避免损失脑组织)
  18. +
  19. 生理盐水打湿棉球,放在钻孔处保持湿润,防止伤口干燥
  20. +
  21. 埋电极/光纤/打病毒,停针10~15min
  22. +
  23. 涂牙科水泥(两次)
  24. +
+

注意事项

    +
  • 注射位点的坐标一定要记牢,前后和左右的坐标是以前囟为原点,深度是以钻孔后的脑表面为原点
  • +
  • 固定小鼠两侧的位置类似于人的太阳穴,按压会让小鼠的眼球凸起
  • +
  • 气相泵用完之后记得关
  • +
  • 拉针仪参数是预设号的,打开开关就能使用,下面固定针管的那部分记得推上去玻璃针管很容易断,
  • +
  • 注射病毒切勿来回拔插,尽量一次到位,注射后要停针10~15分钟,一方面等待病毒扩散,一方面防止病毒随着针拔出而漏出核团
  • +
+

心脏灌流取脑

+

实验材料

动物:成年健康小鼠。
试剂:2%戊巴比妥钠麻醉剂,灌注盐溶液PBS(可用生理盐水代替),中性缓冲多聚甲醛固定液PFA。
用具:注射器(15 ml),带软导管的头皮针,手术剪,眼科剪,平镊,止血钳,手术刀片,小烧杯,15 ml离心管,标签,标记笔,生物垃圾桶。
设备:通风橱,电子称,冰箱。

+

后续步骤

    +
  1. 将鼠脑放入4%PFA溶液,4℃冰箱中固定一夜
  2. +
  3. 将固定结束的鼠脑转入30%蔗糖溶液,放入4℃冰箱等待沉底(2天左右)
  4. +
+

注意事项

    +
  • 小鼠灌流完空鼠笼中的饲料及时清理,倒入医疗废物垃圾桶,清水清洗后喷酒精消毒
  • +
  • 夹住剑突,沿着左右肋骨剪开,暴露心脏和肝脏针管不要扎太深
  • +
  • 最后要把针管中的液体都排出,充满空气(速度开到最大150,灌流时70~80)
  • +
  • 废液倒入脚下的废液桶中,因为液体有毒,所以最好拿到通风橱中进行(用小桶,小桶满了倒入大桶)
  • +
  • 器材使用完清洗归位
  • +
  • 取脑时不要着急,操作不要太过粗暴,尽量保持脑的完整性
  • +
+

冰冻切片

实验材料准备

将沉糖的鼠脑取出,倒掉蔗糖溶液,用吸水纸擦干鼠脑表面的水分,用剪刀修剪脑干部分,保证鼠脑底部水平。剪一块方形锡纸制作长方体模具,模具底部铺一层包埋剂,用镊子将鼠脑腹侧向下平放入模具中,使大脑中缝平行于模具长边,加入包埋剂至完全没过鼠脑(高于脑组织2~3mm),用记号笔标记哪边是鼠脑前侧,然后放-80℃冰箱快速冷冻。
去5楼使用冰冻切片机时,记得带上6孔板、脑图谱和酒精喷壶。

+

冰冻切片机

    +
  1. 开机后首先设置参数,温度设置为-20℃,粗调和微调均设为40μm
  2. +
  3. 安装刀片
  4. +
  5. 在样品托上加入一层包埋剂,将鼠脑放在样品托上(前侧朝上),放入速冻区快速冷冻,等待OCT包埋剂凝固后,将样品托固定在样品头上
  6. +
  7. 修整样品(粗调)
  8. +
  9. 放下防卷板并调整位置,收集脑片至6孔板中的PBS溶液中
  10. +
  11. 收集完后清理冰冻切片机和样品托,并用酒精擦拭
  12. +
  13. 将脑片放入4℃冰箱保存
  14. +
+

问题记录

    +
  • 切片时防卷板有点卡顿不顺畅
  • +
+

贴片染色成像

    +
  1. 将脑片用细毛笔捞取到干净的PBS溶液中洗片
  2. +
  3. 将脑片均匀的贴到盖玻片中央,一张载玻片可以贴4~8片
  4. +
  5. 贴完后用擦镜纸擦干载玻片边缘和底部的液体,等待晾干
  6. +
  7. 在载玻片中央加入80μl的DAPI(尽量避免出现气泡),然后盖上盖玻片
  8. +
  9. 如果立即成像,则无需封片;否则用指甲油封住盖玻片和载玻片的边缘
  10. +
+

参考教程

+
文章作者: 文欣
文章链接: http://chen.cwxhmk.top/2024/01/09/stereotexic-localization-of-brain/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Stray Birds

评论
\ No newline at end of file diff --git a/404.html b/404.html new file mode 100644 index 000000000..76f7167f6 --- /dev/null +++ b/404.html @@ -0,0 +1,172 @@ +页面没有找到 | Stray Birds + + + + + + + + +
Page not found

404

Page Not Found
\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..eb0fca331 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +chen.cwxhmk.top \ No newline at end of file diff --git a/about/index.html b/about/index.html new file mode 100644 index 000000000..280408c4c --- /dev/null +++ b/about/index.html @@ -0,0 +1,284 @@ +关于我 | Stray Birds + + + + + + + + + + + + +

基本介绍

浙江大学脑科学与脑医学学院直博生

+

研究方向:脑电数据分析;强化学习与动物行为建模;RNN

+

联系方式

QQ:1172950805【加好友请备注:博客】

+

邮箱📮:1172950805@qq.com

+

自我评价

我是一个慢性子的人,喜欢慢慢走路,慢慢骑车,慢慢和人熟络。

+

我有一个幸福的家庭,和爱我、懂我的男朋友。

+

我爱大哭,也爱大笑。

+

我不太喜欢热闹,也不太擅长社交,一个人的时候反而更舒服,思维更活跃。

+

我擅于捕获生活中细小的美好与感动,常常感觉自己被幸福包围。

+

我喜欢蓝天、白云、花与飞鸟。

+

我向往心灵上的自由,喜欢按自己的想法工作和生活,珍视每一个微小的进步。

+

我的生活充满了选择,变与不变、机遇与挑战并存。

+

我想在有限的生命里尝试更多的可能,不被定义,勇敢做自己。

+

评论
\ No newline at end of file diff --git a/archives/2022/08/index.html b/archives/2022/08/index.html new file mode 100644 index 000000000..a326e50bb --- /dev/null +++ b/archives/2022/08/index.html @@ -0,0 +1,179 @@ +八月 2022 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2022/09/index.html b/archives/2022/09/index.html new file mode 100644 index 000000000..340f64d5e --- /dev/null +++ b/archives/2022/09/index.html @@ -0,0 +1,179 @@ +九月 2022 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2022/11/index.html b/archives/2022/11/index.html new file mode 100644 index 000000000..340a44ce0 --- /dev/null +++ b/archives/2022/11/index.html @@ -0,0 +1,179 @@ +十一月 2022 | Stray Birds + + + + + + + + +
文章总览 - 1
2022
本地文件上传到Github
本地文件上传到Github
\ No newline at end of file diff --git a/archives/2022/12/index.html b/archives/2022/12/index.html new file mode 100644 index 000000000..09c927d3b --- /dev/null +++ b/archives/2022/12/index.html @@ -0,0 +1,179 @@ +十二月 2022 | Stray Birds + + + + + + + + +
文章总览 - 3
2022
2022年的最后一天
2022年的最后一天
2022年度总结
2022年度总结
英语结课感想
英语结课感想
\ No newline at end of file diff --git a/archives/2022/index.html b/archives/2022/index.html new file mode 100644 index 000000000..2bfdc1d88 --- /dev/null +++ b/archives/2022/index.html @@ -0,0 +1,179 @@ +2022 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2022/page/2/index.html b/archives/2022/page/2/index.html new file mode 100644 index 000000000..fb13334bb --- /dev/null +++ b/archives/2022/page/2/index.html @@ -0,0 +1,179 @@ +2022 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/01/index.html b/archives/2023/01/index.html new file mode 100644 index 000000000..c0c8175b5 --- /dev/null +++ b/archives/2023/01/index.html @@ -0,0 +1,179 @@ +一月 2023 | Stray Birds + + + + + + + + +
文章总览 - 7
2023
Matlab常用命令
Matlab常用命令
愉快的周末
愉快的周末
取钱小记
取钱小记
冬学期结束感想
冬学期结束感想
及时按下暂停键⏸
及时按下暂停键⏸
动态思维
动态思维
2023年的第一天
2023年的第一天
\ No newline at end of file diff --git a/archives/2023/06/index.html b/archives/2023/06/index.html new file mode 100644 index 000000000..a62d71561 --- /dev/null +++ b/archives/2023/06/index.html @@ -0,0 +1,179 @@ +六月 2023 | Stray Birds + + + + + + + + +
文章总览 - 2
2023
图像风格迁移
图像风格迁移
爬取网站数据
爬取网站数据
\ No newline at end of file diff --git a/archives/2023/07/index.html b/archives/2023/07/index.html new file mode 100644 index 000000000..a65a54f04 --- /dev/null +++ b/archives/2023/07/index.html @@ -0,0 +1,179 @@ +七月 2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/07/page/2/index.html b/archives/2023/07/page/2/index.html new file mode 100644 index 000000000..94ad94fdd --- /dev/null +++ b/archives/2023/07/page/2/index.html @@ -0,0 +1,179 @@ +七月 2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/07/page/3/index.html b/archives/2023/07/page/3/index.html new file mode 100644 index 000000000..ef5cf8f77 --- /dev/null +++ b/archives/2023/07/page/3/index.html @@ -0,0 +1,179 @@ +七月 2023 | Stray Birds + + + + + + + + +
文章总览 - 21
2023
做选择
做选择
\ No newline at end of file diff --git a/archives/2023/12/index.html b/archives/2023/12/index.html new file mode 100644 index 000000000..e32ae9c15 --- /dev/null +++ b/archives/2023/12/index.html @@ -0,0 +1,179 @@ +十二月 2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/12/page/2/index.html b/archives/2023/12/page/2/index.html new file mode 100644 index 000000000..186cf1c33 --- /dev/null +++ b/archives/2023/12/page/2/index.html @@ -0,0 +1,179 @@ +十二月 2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/index.html b/archives/2023/index.html new file mode 100644 index 000000000..ed865b8ab --- /dev/null +++ b/archives/2023/index.html @@ -0,0 +1,179 @@ +2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/page/2/index.html b/archives/2023/page/2/index.html new file mode 100644 index 000000000..90422229f --- /dev/null +++ b/archives/2023/page/2/index.html @@ -0,0 +1,179 @@ +2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/page/3/index.html b/archives/2023/page/3/index.html new file mode 100644 index 000000000..9e420aa88 --- /dev/null +++ b/archives/2023/page/3/index.html @@ -0,0 +1,179 @@ +2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/page/4/index.html b/archives/2023/page/4/index.html new file mode 100644 index 000000000..53e7c316c --- /dev/null +++ b/archives/2023/page/4/index.html @@ -0,0 +1,179 @@ +2023 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2023/page/5/index.html b/archives/2023/page/5/index.html new file mode 100644 index 000000000..e4933259a --- /dev/null +++ b/archives/2023/page/5/index.html @@ -0,0 +1,179 @@ +2023 | Stray Birds + + + + + + + + +
文章总览 - 42
2023
动态思维
动态思维
2023年的第一天
2023年的第一天
\ No newline at end of file diff --git a/archives/2024/01/index.html b/archives/2024/01/index.html new file mode 100644 index 000000000..435326734 --- /dev/null +++ b/archives/2024/01/index.html @@ -0,0 +1,179 @@ +一月 2024 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/2024/index.html b/archives/2024/index.html new file mode 100644 index 000000000..169480d74 --- /dev/null +++ b/archives/2024/index.html @@ -0,0 +1,179 @@ +2024 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/index.html b/archives/index.html new file mode 100644 index 000000000..02cc44d7e --- /dev/null +++ b/archives/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/page/2/index.html b/archives/page/2/index.html new file mode 100644 index 000000000..348f9b2bf --- /dev/null +++ b/archives/page/2/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/page/3/index.html b/archives/page/3/index.html new file mode 100644 index 000000000..a6f465dae --- /dev/null +++ b/archives/page/3/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/page/4/index.html b/archives/page/4/index.html new file mode 100644 index 000000000..6a9030e61 --- /dev/null +++ b/archives/page/4/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/page/5/index.html b/archives/page/5/index.html new file mode 100644 index 000000000..2724bc6b3 --- /dev/null +++ b/archives/page/5/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
文章总览 - 65
2023
图像风格迁移
图像风格迁移
爬取网站数据
爬取网站数据
Matlab常用命令
Matlab常用命令
愉快的周末
愉快的周末
取钱小记
取钱小记
冬学期结束感想
冬学期结束感想
及时按下暂停键⏸
及时按下暂停键⏸
动态思维
动态思维
2023年的第一天
2023年的第一天
2022
2022年的最后一天
2022年的最后一天
\ No newline at end of file diff --git a/archives/page/6/index.html b/archives/page/6/index.html new file mode 100644 index 000000000..71224225a --- /dev/null +++ b/archives/page/6/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/archives/page/7/index.html b/archives/page/7/index.html new file mode 100644 index 000000000..b9035c8d4 --- /dev/null +++ b/archives/page/7/index.html @@ -0,0 +1,179 @@ +归档 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/atom.xml b/atom.xml new file mode 100644 index 000000000..9dd3a9c37 --- /dev/null +++ b/atom.xml @@ -0,0 +1,450 @@ + + + Stray Birds + + + + + + 2024-01-10T10:16:48.350Z + http://chen.cwxhmk.top/ + + + 文欣 + + + + Hexo + + + 小鼠脑立体定位手术 + + http://chen.cwxhmk.top/2024/01/09/stereotexic-localization-of-brain/ + 2024-01-09T11:10:09.000Z + 2024-01-10T10:16:48.350Z + + 脑立体定位手术

在神经科学的研究方法中,为了使各种处理手段(给药、毁损、病毒注射等)或信号采集(微电极、探针)到达目的脑区的相应位置,需要使用脑立体定位技术。通过向目标脑区注射红墨水,练习脑立体定位手术,注射完后需要灌流取脑,然后固定、沉糖、切片看位点,最终成像。

查找目标核团坐标

根据研究目的和小鼠种类不同,选择合适的闹立体定位图谱,动物的体重应该尽量与图谱一致,具体信息可在Introduction部分找到,如C57BL/J6成年小鼠,体重26~30g。
在脑图谱List of structures中查找眶额叶皮层的缩写:

  • DLO dorsolateral orbital cortex
  • LO lateral orbital cortex
  • MO medial orbital cortex
  • VO ventral orbital cortex

按照缩写在Index of Abbreviations定位到目标核团所在的页码:

  • LO lateral orbital cortex 0, 4-15, 17, 112-120

经目标核团中心点画水平线和垂直线,即可读出核团的颅骨下深度坐标和中线旁开左右坐标,右下角的Bregma值是核团的前后坐标(正值代表前囟前,负值代表前囟后)。

最终确认位点:(+2.6mm, ±1.3mm, -1.6mm)

实验操作流程

  1. 准备手术器具并喷酒精消毒
  2. 小鼠称重,腹腔注射水合氯醛(用量:体重*0.01)
  3. 酒精擦拭后,用刀片剃除小鼠头部毛发
  4. 通过适配器门齿夹和耳杆固定头部(检查是否固定成功:鼻对正中,头部不动,提尾不掉,目测大脑放置水平)
  5. 涂上红霉素眼膏,避免强光损失小鼠眼睛
  6. 剪开小鼠头部皮肤
  7. 双氧水腐蚀脑膜,去除颅骨表面结缔组织,暴露前后囟
  8. 定位(以bregma点为原点)要先保证小鼠头部X轴方向左右齐平(左右深度相同即可),Y轴方向前后齐平(误差在0.03mm内)
  9. 钻孔 颅骨钻在钻孔点轻磨颅骨,将颅骨打薄,最后用针头挑破(避免损失脑组织)
  10. 生理盐水打湿棉球,放在钻孔处保持湿润,防止伤口干燥
  11. 埋电极/光纤/打病毒,停针10~15min
  12. 涂牙科水泥(两次)

注意事项

  • 注射位点的坐标一定要记牢,前后和左右的坐标是以前囟为原点,深度是以钻孔后的脑表面为原点
  • 固定小鼠两侧的位置类似于人的太阳穴,按压会让小鼠的眼球凸起
  • 气相泵用完之后记得关
  • 拉针仪参数是预设号的,打开开关就能使用,下面固定针管的那部分记得推上去玻璃针管很容易断,
  • 注射病毒切勿来回拔插,尽量一次到位,注射后要停针10~15分钟,一方面等待病毒扩散,一方面防止病毒随着针拔出而漏出核团

心脏灌流取脑

实验材料

动物:成年健康小鼠。
试剂:2%戊巴比妥钠麻醉剂,灌注盐溶液PBS(可用生理盐水代替),中性缓冲多聚甲醛固定液PFA。
用具:注射器(15 ml),带软导管的头皮针,手术剪,眼科剪,平镊,止血钳,手术刀片,小烧杯,15 ml离心管,标签,标记笔,生物垃圾桶。
设备:通风橱,电子称,冰箱。

后续步骤

  1. 将鼠脑放入4%PFA溶液,4℃冰箱中固定一夜
  2. 将固定结束的鼠脑转入30%蔗糖溶液,放入4℃冰箱等待沉底(2天左右)

注意事项

  • 小鼠灌流完空鼠笼中的饲料及时清理,倒入医疗废物垃圾桶,清水清洗后喷酒精消毒
  • 夹住剑突,沿着左右肋骨剪开,暴露心脏和肝脏针管不要扎太深
  • 最后要把针管中的液体都排出,充满空气(速度开到最大150,灌流时70~80)
  • 废液倒入脚下的废液桶中,因为液体有毒,所以最好拿到通风橱中进行(用小桶,小桶满了倒入大桶)
  • 器材使用完清洗归位
  • 取脑时不要着急,操作不要太过粗暴,尽量保持脑的完整性

冰冻切片

实验材料准备

将沉糖的鼠脑取出,倒掉蔗糖溶液,用吸水纸擦干鼠脑表面的水分,用剪刀修剪脑干部分,保证鼠脑底部水平。剪一块方形锡纸制作长方体模具,模具底部铺一层包埋剂,用镊子将鼠脑腹侧向下平放入模具中,使大脑中缝平行于模具长边,加入包埋剂至完全没过鼠脑(高于脑组织2~3mm),用记号笔标记哪边是鼠脑前侧,然后放-80℃冰箱快速冷冻。
去5楼使用冰冻切片机时,记得带上6孔板、脑图谱和酒精喷壶。

冰冻切片机

  1. 开机后首先设置参数,温度设置为-20℃,粗调和微调均设为40μm
  2. 安装刀片
  3. 在样品托上加入一层包埋剂,将鼠脑放在样品托上(前侧朝上),放入速冻区快速冷冻,等待OCT包埋剂凝固后,将样品托固定在样品头上
  4. 修整样品(粗调)
  5. 放下防卷板并调整位置,收集脑片至6孔板中的PBS溶液中
  6. 收集完后清理冰冻切片机和样品托,并用酒精擦拭
  7. 将脑片放入4℃冰箱保存

问题记录

  • 切片时防卷板有点卡顿不顺畅

贴片染色成像

  1. 将脑片用细毛笔捞取到干净的PBS溶液中洗片
  2. 将脑片均匀的贴到盖玻片中央,一张载玻片可以贴4~8片
  3. 贴完后用擦镜纸擦干载玻片边缘和底部的液体,等待晾干
  4. 在载玻片中央加入80μl的DAPI(尽量避免出现气泡),然后盖上盖玻片
  5. 如果立即成像,则无需封片;否则用指甲油封住盖玻片和载玻片的边缘

参考教程

]]>
+ + + 记录小鼠脑立体定位的实验步骤 + + + + + + + + +
+ + + 【arduino探索】点亮ST7789 1.3寸TFT屏幕 + + http://chen.cwxhmk.top/2024/01/09/arduino-tft/ + 2024-01-09T05:07:15.000Z + 2024-01-10T10:16:48.350Z + + Adafruit-GFX-Library

该类库为所有彩色屏幕的基础类库,安装方式:在Arduino的项目-加载库-库管理器中搜索Adafruit GFX Library,选择最新版本进行安装。Github下载地址
Arduino中的第三方库的存放地址可以在首选项-项目文件夹位置处查看,该路径下的libraries文件夹下即为第三方库的存放地址。

Arduino-ST7789-Library

该类库为ST7789的专用驱动库。Github下载地址
运行画直线的程序,用时约32.6s,太慢了,每次黑屏都要等半天!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <Adafruit_GFX.h>    // Core graphics library by Adafruit
#include <Arduino_ST7789.h> // Hardware-specific library for ST7789 (with or without CS pin)
#include <SPI.h>

#define TFT_DC 8
#define TFT_RST 7 //9
#define TFT_CS 9 //10 // only for displays with CS pin
#define TFT_MOSI 11 // for hardware SPI data pin (all of available pins)
#define TFT_SCLK 13 // for hardware SPI sclk pin (all of available pins)

#define w 240
#define h 240


Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_CS); //for display with CS pin

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}


void setup(){
Serial.begin(9600);
tft.init(w, h);
}

void loop(){
uint32_t start = micros_start();

tft.fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;
tft.setCursor(0, 20);
tft.setTextSize(3);
tft.setTextColor(RED);
tft.println("Cost Time:");

tft.setCursor(0, 50);
tft.setTextSize(4);
tft.setTextColor(RED);
tft.println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}

Arduino_GFX

安装方式:在Arduino的项目-加载库-库管理器中搜索GFX Library For Arduino,选择最新版本进行安装。Github下载地址
运行画直线的程序,用时约5.7s,速度超级快!在测试Arduino_GFX的时候还发生了一个小插曲,我连线明明是正确的,但屏幕没有任何反应,排了很久的bug,最后发现是我的arduino开发板有问题,果然太便宜了容易出问题,以后还是用正版的arduino开发板吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <Arduino_GFX_Library.h>
int32_t w, h;

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus *bus = create_default_Arduino_DataBus();

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
Arduino_GFX *gfx = new Arduino_ST7789(bus, DF_GFX_RST, 0 /* rotation */, true /* IPS */);

#endif /* !defined(DISPLAY_DEV_KIT) */

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}

void setup(){
Serial.begin(9600);
gfx->begin();
w = gfx->width();
h = gfx->height();

#ifdef DF_GFX_BL
pinMode(DF_GFX_BL, OUTPUT);
digitalWrite(DF_GFX_BL, HIGH);
#endif
}

void loop(){
uint32_t start = micros_start();

gfx->fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;

gfx->setCursor(0, 20);
gfx->setTextSize(3);
gfx->setTextColor(RED);
gfx->println(F("Cost Time:"));

gfx->setCursor(0, 50);
gfx->setTextSize(4);
gfx->setTextColor(RED);
gfx->println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}

参考内容

]]>
+ + + 记录使用arduino点亮TFT屏幕的过程。 + + + + + + + + +
+ + + 【文献学习】前额叶皮层在反转学习中预测状态转换 + + http://chen.cwxhmk.top/2024/01/05/dlPFC-bayesian-inference/ + 2024-01-05T06:43:12.000Z + 2024-01-10T10:16:48.350Z + +

作者:Bartolo R, Averbeck B B.
标题:Prefrontal cortex predicts state switches during reversal learning
期刊:Neuron, 2020

具体内容

研究目的/科学问题

研究背景

研究结果

研究结论

想法记录

可以跟进的参考文献

可以借鉴的内容

其它

]]>
+ + + + + <div class="note info flat"><p>作者:Bartolo R, Averbeck B B.<br>标题:Prefrontal cortex predicts state switches during reversal learning<br>期刊:Ne + + + + + + + + + + + +
+ + + Github Desktop同步代码 + + http://chen.cwxhmk.top/2024/01/05/github-desktop/ + 2024-01-05T02:46:45.000Z + 2024-01-10T10:16:48.350Z + + Github Desktop主要有三个添加仓库的选项:

  1. Clone a Repository
  2. Create a new Repository
  3. Add Existing/Local Repository

如果想把github远程仓库的代码克隆到本地,选择Clone a Repository,即可把远程仓库下载到指定的本地路径。

如果想创建新的仓库,选择Create a new Repository

如果想把本地文件夹作为新的仓库上传到github,选择Add Local Repository

如果本地改动了仓库中的代码,点击Commit to main,然后Push origin,即将新的代码推送到github上。Fetching origin是把github上的代码拉到本地。

  • 不要轻易同意删除本地仓库!!!警惕带local的选项!如果不小心删除了,尝试去回收站找回。
  • 大部分情况下,创建仓库时选择Keep this code private
  • 不要一次性上传很多文件,也不要反复push代码,撤销push操作可能会误删本地代码!
  • 同步重要数据时提前把数据复制到别的地方,做好备份,给自己留个后路!
]]>
+ + + 上午同步代码到github,不小心把本地仓库删除了,那一瞬间我仿佛把所有的伤心事都想了一遍,还好在回收站找回了,必须记录一下github desktop的操作方法。 + + + + + + + + +
+ + + 下载教育版origin + + http://chen.cwxhmk.top/2024/01/04/install-origin/ + 2024-01-04T08:44:28.000Z + 2024-01-10T10:16:48.350Z + + 之前在联想电脑上安装过origin,今天想在mac的虚拟机上也安一个origin,结果发现我不记得怎么下载了,也不记得之前是从哪里找到的正版安装途径,今天在搜索过程中竟然连官网都找错了,索性记录一下安装过程。

进入origin官网,点击顶部的Try Origin for Free,选择I have NEVER used OriginStudent,点击继续,即可看到如下的界面。

选择Learning Edition,填写姓名、学校、邮箱等信息。填写完提交后去教育邮箱中验证,即可收到软件的下载链接、序列号和密钥。

用同一个教育邮箱申请账号的话,得到的密钥是同一个,如果已经激活过origin软件,就不能在别的电脑上安装origin时使用了。┭┮﹏┭┮

]]>
+ + + 记录下载和安装origin的过程 + + + + + + + + +
+ + + 记录电极支架制作步骤 + + http://chen.cwxhmk.top/2024/01/02/electrode-holder/ + 2024-01-02T10:03:02.000Z + 2024-01-10T10:16:48.350Z + +

利用转动螺杆驱动螺母移动的机械推进原理,利用3D打印的滑片、支架、螺杆和螺母等材料,组装成可推进式多通道电极驱动装置。通过转动螺杆,可以使固定于其上的电极同步推进。当电极记录位点附近的神经元失活后,还可以推进记录电极到更深部的脑组织,从而在实验中观察到更多的神经元活动。

步骤

  1. 用钳子剪下一段排母,包含10个排针
  2. 将电路板卡到排母中间,用焊锡焊接(注意焊接手法,需要多练习)
  3. 剪两段银丝作地线(不需要剪太长,一小段即可),焊接在电路板两侧的孔里
  4. 用电钻(选用合适的钻头,一般选最细的)打磨滑片和底座的孔,尽量保持垂直
  5. 准备三个点胶针,两粗一细,截断处打磨平整,可以借助昆虫针疏通针管
  6. 螺杆穿过滑片中间的孔,拧上两颗螺母,一颗紧靠滑片底部(也不要拧太紧),并涂AB胶固定,用钳子剪去多余的螺杆,留大概7mm的长度
  7. 将滑片放入底座,根据孔的距离判断左右,左侧用粗点胶针固定,右侧用粗点胶针套细点胶针
  8. 放置好后用AB胶固定下面两层,及滑片下方与细点胶针的连接处,胶干后可以尝试拧一下螺丝,看是否可以正常滑动,以及细点胶针是否可以正常向下走
  9. 使用AB胶将底座固定在电路板上(可能需要打磨电路板上的两个孔),注意保持底座和电路板平行

注意事项

  • 涂AB胶固定时一定要小心,搞清楚哪里是需要移动的,哪里是需要固定住的,螺母下端固定,涂胶时避免粘住螺母与滑片上端
  • 以后做电极时戴上口罩,焊锡和AB胶味道太大了
  • 将细针管、螺杆🔩和粗针管的孔径分别修改为0.7mm、1.1mm和0.9mm,针管孔径距两侧均为0.8mm,支架背部柱子直径改为1.65mm
  • AB胶完全干要一定的时间,耐心等待,或第二天再测试电极支架
  • 螺杆的长度预留大概7mm,不能超出电极支架底部
  • 焊接时,先用电烙铁同时加热针脚和焊盘,将焊锡靠近电烙铁的焊头,焊锡粘在焊盘上后,快速抽走焊锡
  • 剪排母时,钳子对准第10列和第11列中间靠右的位置,多剪下来一列没关系,至少要保证前10排排针是完好的

参考文章

  • 多通道在体记录技术——小鼠可推进式微电极阵列帽制作与植入手术
]]>
+ + + 记录制作电极支架的步骤。 + + + + + + + + +
+ + + 在网页中实时显示当前时间 + + http://chen.cwxhmk.top/2024/01/01/html-show-current-time/ + 2024-01-01T08:51:25.000Z + 2024-01-10T10:16:48.350Z + + 早上吃完早饭去浙大图书馆主馆逛了一圈,终于见识到了传说中的自习区域墨水屏幕,确实很高级,如果这个座位被人预约了,屏幕上会显示预约人的姓名和预约时间!之前的基础图书馆里面很少有计算机相关的书籍,没想到新开的主馆里弥补了这个缺憾。

我上午看了一本arduino编程相关的书籍,对蓝牙和wifi模块很感兴趣,书中对这两个模块的使用只是举了一个很简单的例子,连接的都是arduino开发板的串口收发口,可以实现手机与arduino串口监视器的通信。

书中最后举了一个智能温室大棚的例子,我一直不太理解怎么实现手机远程控制arduino端的传感器。中午请教了一下康康,梳理了一下大致流程:arduino板连接wifi模块,接入校园网,向服务器发送传感器数据,可以存入txt文件或数据库中,手机或网页端通过服务器获取到传感器的数据,可以每隔1s请求一次数据。

上位机:指可以直接发送操作指令的计算机或单片机,一般提供用户操作交互界面并向用户展示反馈数据。

下位机:指直接与机器相连接的计算机或单片机,一般用于接收和反馈上位机的指令,并且根据指令控制机器执行动作以及从机器传感器读取数据

上位机给下位机发送控制命令,下位机收到此命令并执行相应的动作。
上位机给下位机发送状态获取命令,下位机收到此命令后调用传感器测量,然后转为数字信息反馈给上位机。
下位机主动发送状态信息或报警信息给上位机。

我一直困惑间隔1s请求一次数据,是否会在网页上看到数据刷新时的闪烁,为了解决这个困惑,康康建议我写个简单的网页测试一下,每个1s获取一下当前的时间。经实践测试,人眼并不会看到数据刷新时的闪烁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

</head>
<body>
<div id="time-now">

</div>
<script>
setInterval(function (){
$('#time-now').text(new Date())
}, 1000)
</script>
</body>
</html>

参考文章

]]>
+ + + 随手记录和康康一起交流学习的过程。 + + + + + + + + + + +
+ + + 2023年度总结 + + http://chen.cwxhmk.top/2023/12/29/experience-2023/ + 2023-12-29T10:06:54.000Z + 2024-01-10T10:16:48.350Z + + 小确幸

科研

和去年的我相比,我最大的感触就是我开始去做一些事情了,我能渐渐抛开过去的成绩,正视自己存在的不足,耐心去学习、去积累。从一开始辅助课题组同事做数据分析,到后来争取到合作课题,再到现在慢慢有了自己的课题,很多事情在一开始我并不能看清未来的走向,但我还是选择坚定的走下去,我相信只有这样才能把路走远走宽。

我原本以为这五年我都不会碰生物实验,我相信或许我跨专业就不该碰生物实验,但我常常内心动摇,一方面是对我已有的能力能否支撑我顺利毕业信心不足,另一方面是希望可以自己做实验收集数据,不想一直依附于其他人。

我经常感觉很多事情困难,其实是因为它们一直停留在我的想象中,从未付诸实践。今年下半年我的做事态度转变很大,我开始敢于提出自己的数据分析思路,开始尝试稍微复杂一些的算法,开始学做生物实验,开始自己焊接线路搭建行为装置。我才发现我有能力做到这么多事情,我可以用数据分析结果影响课题的走向,我可以一个人完成小鼠脑立体定位手术,我可以搭建好硬件电路!

希望新的一年我可以进一步提升专业技能,努力做一个有价值的、值得信赖的人,也希望科研方面可以有新的突破,加油加油!我的2024一定很哇塞!🥳

电影🎬

  • 航海王:红发歌姬
  • 满江红
  • 人生路不熟
  • 变形金刚:超能勇士崛起
  • 消失的她
  • 八角笼中
  • 长安三万里
  • 流浪地球2
  • 孤注一掷
  • 无价之宝
  • 刀尖
  • 指环王
  • 三大队

旅行

  • 聊城
  • 杭州
    • 浙大紫金港
    • 动物园和植物园
    • 湘湖
    • 西湖
    • 灵隐寺
    • 浙江升非物质文化遗产馆
    • 塘栖古镇
    • 闲逛
  • 北京
  • 南京
  • 绍兴
  • 邢台
  • 西安

鸟🐦

喜事

  • 我的小侄子出生啦~
  • 实验室三位同门都在今年结婚了,喜糖不断!🍬
  • 康康要来杭州工作啦!

小技能

  • 催眠课上学到了一个小魔术🥰
  • 做饭!

讲座

经验

  1. 生活不是一成不变的,路是越走越宽的
  2. 不要一味地获取资源,对已有资源的消化和吸收更重要
  3. 在做重大决定之前要给自己想好后路,不要心血来潮
  4. 想学的东西很多不要怕,每次学多少也不用太过死板,重要的是持续去学习
  5. 从论文中摘录的观点或数据图,要注明文献出处,以免后续找不到哪一篇文献
  6. 代码要规范命名,写好注释及文档说明,及时同步到github
  7. 做事情要有逻辑,数据分析要紧紧围绕科研问题
  8. 我们并不仅仅是被动处于一个环境之中,我们也可以通过努力去影响和改变周围的环境
  9. 做事要善始善终,别人交代的事情要及时反馈
  10. 笔记中注明当天时间,便于复盘
  11. 对自己的能力有合理的评估,既要量力而行,又要适当突破舒适圈
  12. 要相信每次讨论都是有价值的,及时记录
  13. 文件多平台同步会极大提高工作效率
  14. 学到的知识及时整理,尽量可以用自己的话写出来,有机会的话还可以讲给别人,这样对知识的理解更深刻
  15. 要警惕一直做别人安排的事情,要有自己的思想,对自己做的事情有清晰的认知和规划,明确任务的优先级
  16. 事情并不会总按预期进行,要考虑全面,接受有可能发生的不好的结果
  17. 实践是最快速的学习方式
  18. 成绩不等于个人能力,要想证明自己就要拿出成果
  19. 过去偷懒绕开的困难也许在不久的将来又会变成拦路石,总是要面对的
]]>
+ + + 回顾我的2023 + + + + + + + + +
+ + + 【MATLAB App Designer使用教程】可拖拽的线 + + http://chen.cwxhmk.top/2023/12/29/matlab-app-designer-1/ + 2023-12-29T08:19:50.000Z + 2024-01-10T10:16:48.350Z + + + + + + + + + + + + + 脑电数据分析 + + http://chen.cwxhmk.top/2023/12/29/eeg-emg-analysis/ + 2023-12-29T06:54:38.000Z + 2024-01-10T10:16:48.350Z + + 睡眠分期

小鼠的睡眠周期主要包括清醒、非快速眼动和快速眼动三个阶段,有时也会考虑微觉醒状态,即发生在NREM阶段的短暂(小于10s)觉醒状态。

  • WAKE:desynchronized EEG and high EMG activity
  • NREM:synchronized EEG with high-amplitude, low-frequency (1–4 Hz) activity and low EMG activity
  • REM:high EEG power at theta frequencies (6–9 Hz) and low EMG activity

睡眠阶段示意图

脑电频段

脑电波通常被分为以下几个频段,每个频段对应不同发脑功能活动。需要注意这些频段的划分并非绝对,不同的研究可能会对频段的划分略有不同。
脑电波

时域分析

频域分析

时频分析

快速傅里叶变换

小波变换

参考文章

]]>
+ + + 总结常用的脑电数据分析算法。 + + + + + + + + + + +
+ + + 【arduino探索】搭建触摸给水装置 + + http://chen.cwxhmk.top/2023/12/29/arduino-touch-pump/ + 2023-12-29T05:10:40.000Z + 2024-01-10T10:16:48.350Z + + 实验材料准备
  • 电容触摸传感器*1

    触摸传感器
  • 蠕动泵*1

  • 可孚一次性无菌加药器 50ml(粗针管)

  • 杜邦线公对公

  • Arduino Uno R3*1

  • 粗针头*2

  • 绝缘胶带

电容触摸传感器和蠕动泵需要焊接杜邦线,用剪刀减去杜邦线一端的公头,用剥线钳暴露铜丝,短暂加热焊锡覆盖暴露的铜丝。

配件功能测试

首先测试给水装置核心配件的功能是否正常。

电容触摸传感器

电容触摸传感器上标有VCC、GND和DAT引脚,VCC是电源引脚,用于给传感器供电;GND是接地引脚;DAT是数据引脚,用于传输触摸信号。经过Arduino程序测试,发现电容触摸传感器默认为高电平,触摸时为低电平。

1
2
3
4
5
6
7
8
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
}

用绝缘胶带缠绕触摸传感器引脚的杜邦线(起到保护和固定的作用),将粗针头固定到传感器较平整的一面,该装置即可作为小鼠的舔水口,小鼠通过针头舔水时,针头另一端会按压触摸传感器,因此可以根据触摸传感器电平的变化检测舔水事件。

蠕动泵

上次买的蠕动泵有一个小配件被我弄坏了,这次测试新买的蠕动泵,通过转接头连接硅胶管,进水口放入粗针管内。给蠕动泵提供5V的电压,经测试,可以正常工作,出水口正常出水。
由于要控制训练过程中每个试次的给水量,因此对蠕动泵的出水量进行测试。经询问师弟,可以采用给水0.1s,间隔0.1s,并重复40次的方式测量,测量前称纸巾的重量,测量后再对纸巾称重,即可计算出每次给水的体积。连续两天测量蠕动泵的出水量,如果保持不变,即认为可正常工作。
$$m=\rho V$$

$$\rho_{水} =1g/cm^3 $$

$$1cm^3=1000\mu L$$

  • 12.29 测试结果:40次 给水0.1s 间隔0.1s 称重:0.05g
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
delay(1000);
int i = 0;
for(i = 1; i <= 40; i ++){ // 测出水量
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
delay(100); // ms
}
}

void loop() {
Serial.println(digitalRead(A0));
}

实验装置

触摸给水装置实物连线

触摸给水

接下来测试触摸传感器控制蠕动泵给水的功能,经测试,功能正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
if (digitalRead(A0) == LOW){ // 测试触摸给水
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
}
}

经验

  1. 小鼠训练过程中每天摄入水量为1ml~1.2ml
  2. 测试时针管内的气泡一定要排干净,且传感器的放置方式与实际任务期间保持一致
]]>
+ + + 训练小鼠做任务很重要的一环是正向强化,通过给水奖励强化小鼠的正确行为。 + + + + + + + + +
+ + + 神经元类型和活动状态判断标准 + + http://chen.cwxhmk.top/2023/12/28/neurons-exc-or-inh/ + 2023-12-28T06:25:07.000Z + 2024-01-10T10:16:48.350Z + + 神经元发放率标准化方法

Z-score是用来衡量数据点与其所在数据集平均值之间偏差程度的一种统计量。它通常将数据点减去均值,再除以标准差,将数据标准化到一个标准正态分布上。点击查看标准正态分布表
$$Zscore=\frac{x-\bar{x}}{\sigma}$$

标准正态分布
68-95-99.7法则:
约有 68% 的数据点落在均值左右一个标准差的范围内。
约有 95% 的数据点落在均值左右两个标准差的范围内。
约有 99.7% 的数据点落在均值左右三个标准差的范围内。

相关概念

标准差

$$\sigma =\sqrt{\frac{\sum_{1}^{n}(x_i-\bar x)^2 }{n}}$$

标准差是方差的平方根,用于描述一组数据的离散程度或变异程度。标准差衡量数据集中各个数据值与其平均值之间的偏离程度。标准差消除了平方的影响,数值更接近于原始数据的数量级,更易于直观理解和比较。

标准误

$$SEM=\frac{\sigma}{\sqrt{n}}$$

标准误差是一种用于衡量样本平均值估计的变异程度或不确定性的统计量。它表示样本平均值估计与总体平均值之间的偏差,标准误差的值越小,代表样本均值估计越接近总体均值,或者说样本均值的可靠性越高。

兴奋or抑制

参考文献1
We first examined whether a neuron was excited or inhibited by light stimulation by asking whether its firing rate during the first 500 ms after light onset was higher or lower, respectively, than its firing rate in the 500 ms immediately before light onset. This was examined separately for each light intensity (Wilcoxon signed-rank test, p < 0.05, corrected for multiple comparisons). In order to quantify the strength of inhibition we calculated the normalized firing rate by dividing the mean firing in the first 500 ms after laser onset by the mean baseline firing in the 500 ms before laser onset.

Babl S S, Rummell B P, Sigurdsson T. The spatial extent of optogenetic silencing in transgenic mice expressing channelrhodopsin in inhibitory interneurons[J]. Cell reports, 2019, 29(5): 1381-1395. e4.

参考文献2
Food-cue, lever-press, and dish-entry responses were calculated as Z-scores normalized to 20 pre-cue bins of 300 ms. Neurons showing a Z-score >2.58 (P < 0.01) during the first two bins following the onset of the food cue, lever press, or dish entry were classified as excitatory responses, whereas neurons showing a Z-score < −1.96 (P < 0.05) during the same first two bins were classified as inhibitory responses.

Engelke D S, Zhang X O, O’Malley J J, et al. A hypothalamic-thalamostriatal circuit that controls approach-avoidance conflict in rats[J]. Nature communications, 2021, 12(1): 2517.

神经元类型

The spike width, defined as the time from the valley to the return to baseline after the peak, and the ratio between peak and valley amplitudes.

]]>
+ + + 调研判断神经元被兴奋还是被抑制的标准以及粗略判断神经元类型的标准。 + + + + + + + + +
+ + + 【综述】神经环路的架构 + + http://chen.cwxhmk.top/2023/12/27/architectures-of-neuronal-circuits/ + 2023-12-27T06:02:54.000Z + 2024-01-10T10:16:48.350Z + + + + + + + + + + + + + 神经编码和神经解码 + + http://chen.cwxhmk.top/2023/12/27/neural-encoding-and-decoding/ + 2023-12-27T05:59:28.000Z + 2024-01-10T10:16:48.350Z + + 神经系统的编码方式

信息是怎样在大脑🧠中编码的?几个世纪以来,这个问题一直吸引着医学生、科学家和哲学家。然而,每当有人提出如何在大脑中处理和表征信息的建议时,这些建议往往被证明是简单化和理想主义的。下面简单介绍一下信息可能怎样存储在神经活动中的理论和概念。

频率编码 Rate/Frequency coding

频率编码被大多数的研究者视为主要的信息编码方式。如皮肤上的温度感受器就是通过频率编码将温度信息从输入系统转为神经活动的,低温刺激时,皮肤中的温度敏感性外周神经元的放电比较缓慢,随着温度的升高,神经元的发放率升高。在听觉系统中也存在频率编码,神经元的发放率与声音频率直接相关,但高于1kHz这个阈值会采用不同的编码方式。
需要注意的是,传递温度信息的神经元的活动与传递触觉或痛觉信息的神经元的活动没有什么不同,频率编码和动作电位是相似的。感觉被识别为触觉或痛觉是由信息来自的感觉输入系统类型决定的。

时间编码 Temporal coding

在我们考虑必须从神经响应中精确测量神经元的放电时间以提取额大部分的信息时,时间编码的概念就产生了。这种精确性决定了神经编码的时间分辨率。大量的研究发现这种时间分辨率在毫秒级别,提示精确的放电时间是神经编码中的一个重要因素。当发现精确的放电时间或高频发放波动携带信息时,神经编码通常被确认为时间编码。
下图为猴子MT脑区的一个神经元在三个不同视觉刺激下的响应模式,最上方面板的发放模式通常被认为是频率编码,最下方面板的发放模式反映时间编码。
时间编码

多路复用编码 Multiplexed coding

群体编码 Population coding

稀疏编码 Sparse coding

拓扑结构编码 Topological coding

相位编码 Phase coding

序列编码 Sequence coding


编码模型与解码模型

向量x表示众多神经元的活动 ,如:神经元峰电位Spikes、局部场电位LFP、颅内脑电信号iEEG和脑电图EEG等。
向量y表示感兴趣的行为、认知等状态 ,如:运动意图、记忆状态、情感和各种疾病状态等。

编码模型encoder():描述感兴趣的行为、认知等状态y如何表征于神经元的活动x
$$x = encoder(y)$$

$$f(stimulus)\to neural\ activity$$

解码模型decoder():描述如何从神经元的活动x中估计感兴趣的行为、认知等状态y
$$y = decoder(x)$$

$$f(neural\ activity)\to stimulus$$

神经编码

广义线性模型 GLM

可以使用广义线性模型根据提示、刺激、奖励、惩罚等行为和任务变量预测神经元的活动,进而评估行为和任务变量(如)对神经元活动的贡献。

神经解码

neural content:在特定脑区有哪些信息?在什么时间?
neural coding:神经活动的什么特征包含信息?
神经解码背后的思想是通过神经活动尝试预测刺激本身或动物的行为。本质上,如果我们可以从许多脑区做记录,并辨别出不同部分的内容, 我们可以追踪大脑的信息流并试图解开使我们能执行特定任务的算法。
群体解码示意图

例如,我们向猴子展示一张猕猴桃🥝的照片,同时我们记录某个脑区神经元的活动。神经解码就是我们把神经活动模式“喂进”机器学习算法,我们称之为模式分类器。这个算法学习建立特定刺激和特定神经活动模式的关联。然后用另外的照片重复这个过程,获得另一组神经活动模式,喂进分类器,然后分类器学习这个关联。一旦分类器学到这个关联,我们可以使用或测试这个分类器,用于预测呈现的刺激,与实际呈现的刺激相比,即可判断分类器预测是否正确。

交叉验证

在进行交叉验证时,通常是将数据集划分为训练集和测试集,然后在训练集上进行交叉验证来评估模型性能和选择最佳超参数,最后使用选定的最佳模型配置在测试集上进行最终的性能评估。

交叉验证

最大相关系数分类器 Maximum Correlation Coefficient Classifier

Maximum Correlation Coefficient (MCC) Classifier(最大相关系数分类器)是一种用于模式识别和分类任务的统计学方法,其核心思想是寻找能最大化特征与类别之间相关性的投影方向。计算测试向量与不同刺激下神经元群体活动的原型向量的相关性,相关性最高的即为分类器的预测结果。解码可以视为评估下游神经元可获得的信息,分类器要学习的是神经元的突触权重,待分类的神经元活动模式为突触前活动。
在同一时间窗下训练和测试数据,如果是在baseline阶段,即刺激呈现之前,不同刺激的baseline阶段活动应差别不大,所以解码准确率大概维持在chance level(1/刺激的类别数)。
数据组织方式
原型

梯度提升树解码器 Gradient Boosted Trees Decoder

支持向量机 Support Vector Machine

支持向量机是一种监督式学习算法,通常用于分类和回归分析。其目标是在特征空间中找到一个最优的超平面,能够有效地将不同类别的数据分开。SVM的主要思想是找到能够最大化类别间间隔(Margin)的超平面,即找到一个决策边界,使得两个不同类别的数据点到这个边界的距离尽可能远。而支持向量则是离这个决策边界最近的那些数据点。

基本数据分析

计算神经元的发放速率 Firing rate

神经元的概率性发放:即使是相同刺激下的不同试次,同一神经元不是确定性地发放,而是按照一定概率分布发放。
神经元的发放概率Pr(t至t+∆t):某个特定时间段内发放的概率;
神经元的发放速率r(t):某个特定时间点发放的概率密度
$$Pr(t至t+\Delta t)=r(t)\Delta t$$

补充知识:连续型随机变量X落在区间(x1,x2]上的概率P{x1<X≤x2}等于区间(x1,x2]上曲线y=f(x)之下的曲边梯形的面积。介于曲线y=f(x)与x轴之间的面积等于1。

概率密度

当∆x充分小时,有
$$P \{x<X\le x+\Delta x \} \approx f(x)\Delta x$$

对于具有相同试次结构的trial-by-trial的实验,一般认为试次之间是同质的。在有多次同等条件试验的情况下,假定有N个试次,选定一个足够小的时间窗∆t(如50ms),计算t至t+∆t范围内所有试次中神经元发放的次数n,则发放速率
$$r(t) ≈ \frac{n}{N\Delta t}$$

单位为spikes/s或Hz。

对于单个试次条件下,假定刺激是缓慢变化的,沿着时间进行平均,可以通过较长时间窗T内的平均发放次数估计发放速率,时间窗T内的发放次数记为n,则
$$r = \frac{n}{T}$$

作图

栅格图(Raster plot)可以直观地展示神经元的发放事件,一行代表神经元在一次试验中的发放,每个点代表一次放电。刺激前后反应直方图(Peri-Stimulus Time Histogram PSTH)用于展示特定刺激事件发生前后在各个时间点神经元的发放速率。

  1. 将N个试次按照感兴趣的刺激事件发生的时间对齐,如灯亮/蜂鸣器响等
  2. 选择合适的时间窗∆t,将时间分为长度为∆t的小段
  3. 每个小段内,统计所有试次中该神经元的总发放次数n
  4. 用n/N∆t(单位为spikes/s或Hz)作为每个小段内的发放速率的估计
  5. 绘制发放速率沿着时间变化的直方图

光栅图和PSTH

参考内容

  • 《Information processing by neuronal populations》
  • 浙江大学现代神经生物学课程
  • 《From molecules to networks: an introduction to cellular and molecular neuroscience》
  • 《Theoretical neuroscience: computational and mathematical modeling of neural systems》
  • 梯度提升树(Gradient Boosted Trees):模型理解
]]>
+ + + 介绍神经编码和神经解码相关基础知识。 + + + + + + + + + + +
+ + + 【arduino探索】使用ArControl编写“炸弹💣游戏” + + http://chen.cwxhmk.top/2023/12/26/arcontrol-boom-game/ + 2023-12-26T05:38:56.000Z + 2024-01-10T10:16:48.350Z + +

游戏规则:
简易版:游戏有一个5秒倒计时炸弹,时间到了就会爆炸,马里奥玩家就会死亡。如果玩家可以在这5s内按下停止开关,炸弹不会爆炸,玩家马里奥任务成功。

实验材料:
Arduino UNO R3 * 1
面包板 * 1
发光二极管 * 1(模拟炸弹)
按钮 * 1(模拟开关)

Arduino引脚映射

ArControl对Arduino UNO开发板做了端口映射,定义好了6个输入端口和8个输出端口,示意图如下。IN和OUT都是相对于Arduino开发板来说的。在这个小游戏中,我们使用pinA0IN1接收按钮的状态,pin2OUT1控制LED灯的状态。

Arduino引脚映射

Arduino测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//测试按钮控制led灯是否正常
int ledPin = 2;

void setup() {
pinMode(A0, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {
if (digitalRead(A0) == HIGH){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}

Arduino实物连接图

关于接线我还闹了个笑话,我在ArControl上进行测试,发现按下按钮之后,IN1端口会持续很久的高电平,而且不按按钮时也会有通道闪烁的情况。我在arduino IDE中测试按钮控制LED灯的情况,发现了类似的问题,当我不按按钮时,LED灯也是亮的,按下按钮之后,LED灯只是变得更亮了。我检查线路并没发现什么问题,去请教师兄,才发现我接线时按钮旁边的下拉电阻没接上!!!😅按我那样的接法,电阻纯属摆设,跟按钮的电路半毛钱关系都没有。重新接好电阻之后,再测试就正常了。(^-^)V

实物连接图

ArControl使用流程

ArControl的软件部分主要包括两个应用程序,其中ArControl Designer用于编写行为范式的protocol,ArControl Recorder用于监控端口的运行状态并采集实验数据。

ArControl Designer

ArControl Designer借鉴了状态机的原理,把行为实验流程等效分解为一系列时序上相互衔接的子任务(State),可以根据实验逻辑在状态之间进行跳转。

每一个State可以对6种功能进行配置,包括改变任务变量(do-var)、控制输出通道(do-pin)、 检测任务变量(when-var)、检测实验计数(when-count)、检测等待时间 (when-time)以及检测输入端口(when-pin)。其中每个功能的详细配置是在子窗体中进行的。

在这个小游戏中,逻辑比较简单,可以分为倒计时、炸弹爆炸和炸弹不爆炸三个状态,分别记为S1S2S3。如果在没有在5s内按下停止开关,则跳转到S2;如果在5s内按下停止开关,则跳转到S3。编写完实验流程之后,保存。

ArControl Designer
如果想查看实验流程图,也可以点击File→Export pdf,这个功能真的很方便检查实验逻辑!
流程图

ArControl Recorder

选择Arduino开发板对应的端口,载入实验流程并烧录进开发板。点击Start按钮即可运行,点击Stop按钮即可手动终止程序,也可以等程序运行完自动结束。中间的板块可以实时观察输入/输出端口的电平变化,如果为绿色,则表示当前端口是高电平。下图分别为炸弹💣爆炸💥和成功按下停止开关时的端口状态。

Boom
No boom

参考内容

]]>
+ + + 使用实验室已毕业师兄开发的ArControl编写“炸弹游戏” + + + + + + + + + + +
+ + + 【arduino探索】控制蠕动泵出水 + + http://chen.cwxhmk.top/2023/12/26/arduino-pump/ + 2023-12-26T02:38:53.000Z + 2024-01-10T10:16:48.350Z + + 前几天在淘宝上买的蠕动泵终于到货了,早上拆开快递一脸懵,摆在我面前两个难题:第一,我该怎么给这个蠕动泵供电呢?虽然顶部标有正负极,但我还是不知道该怎么办;第二,蠕动泵自带了管子,比较短,我怎么换成我们实验室自己的硅胶管呢?

对于第一个问题,我请教了师弟。拿剪刀将杜邦线剪去一头,然后用剥线钳暴露电线,将电线穿过蠕动泵顶部的孔,折叠后焊锡,另一个孔也同样操作即可。接好线后我在arduino板上测试了一下,一端接入5V电压,另一端接地,测试发现可以正常工作!

对于第二个问题,我的第一反应是把自带的管抽出来,换成我们实验室自己的硅胶管。但我抽出来才发现,泵头的孔太小,硅胶管穿不进去。后来尝试把管口剪尖,终于穿进去了,结果泵头的一个小组件崩飞了,┭┮﹏┭┮。后来师弟和师姐意外发现快递里面的转接头(我早就看到了,但不知道是干啥用的),告诉我说这个可以直接接到自带的管上,然后另一端连自己的硅胶管,我才恍然大悟!

图片说明

虽然小零件崩飞了,但我还是完整地测试了一下蠕动泵的功能(用led blink的程序测试的),一端接pin12,一端接地,arduino写入程序后蠕动泵可以实现间隔1s给水。静待我买的新蠕动泵!
蠕动泵实物连线

]]>
+ + + 使用arduino uno r3开发板控制蠕动泵出水 + + + + + + + + +
+ + + 【arduino探索】按键控制LED灯 + + http://chen.cwxhmk.top/2023/12/25/arduino-button-led-demo/ + 2023-12-25T07:55:45.000Z + 2024-01-10T10:16:48.350Z + + Arudino Uno R3开发板简介

Arudino Uno R3开发板引脚说明

电路图

目标:使用四角按键开关控制LED灯,当按钮按下时灯亮,松开时灯灭。

实现思路:将引脚2改为input mode,反映按键的状态。引脚12为output mode,控制led灯的亮灭。当按键按下时,引脚2为高电平,此时led灯亮;当按钮松开时,引脚2为低电平,此时led灯灭。(对应仿真图连线)

如果引脚2的状态为input pullup mode(如果外部组件未启用,上拉电阻将输入端口处的电压拉到高电平),当按键按下时,引脚2为低电平,此时led灯亮;当按钮松开时,引脚2为高电平,此时led灯灭。(对应实物连线)

注意事项:四角按键同侧不相连,相连不同侧。

仿真
实物

Arduino程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int buttonPin = 2;
int ledPin = 12;

void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}

void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(buttonPin) == LOW){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}

参考文章

]]>
+ + + 使用arduino uno r3开发板实现按键控制LED灯 + + + + + + + + +
+ + + 在Mac电脑上安装VMware Fusion + + http://chen.cwxhmk.top/2023/12/23/mac-vmware-fusion/ + 2023-12-23T03:52:52.000Z + 2024-01-10T10:16:48.350Z + + 大学毕业以后买了一台新的联想电脑,当时还因为终于可以用GPU而兴奋了很久,后来去北京出差背着电脑来回走了很久,不插着电源很快就会没电。从北京回来我就斥巨资买了一台苹果电脑,续航能力没得说,平时用的大部分软件也都是有mac版的。因为工位空间有限,我就把苹果电脑放在了工位,联想电脑留在了宿舍,平时偶尔会远程控制一下宿舍的电脑,但有时会很卡,操作也不太方便。

之前有想过安装mac双系统,但又怕对电脑不好,就一直将就着使用了。最近有一些软件只能在windows系统上运行,狠了狠心,在mac上安了个虚拟机(VMware Fusion 13),可以比较方便地使用windows系统。(存储空间一下子少了很多,┻┳|・ω・|)

VMware Fusion有个人免费版,但我实在是注册不上这个网站,曲线救国选择下载Fusion 13 Pro,然后输入网上找到的序列号(5N400-4AH82-M88Q3-0LC0P-0TRL0 ),就可以正常使用了。

注意事项

  1. 可以直接通过Microsoft安装win11
  2. 新建虚拟磁盘
  3. 记住密码并存储在mac钥匙串中
  4. 安装VMware Tools之后全屏可以铺满且有原始mac电脑的分辨率(以管理员身份运行windows powershell→输入Set-ExecutionPolicy RemoteSigned→A→菜单栏选择虚拟机→安装VMware Tools)
  5. 我安装的时候没有遇到网上教程所说的网络问题

参考文章

]]>
+ + + mac电脑的尽头是windows? + + + + + + + + +
+ + + VSCode无法正常打开.ipynb文件 + + http://chen.cwxhmk.top/2023/12/23/vscode-ipynb-error/ + 2023-12-23T02:38:03.000Z + 2024-01-10T10:16:48.354Z + + 上午原本想写程序,打开VSCode之后发现不能打开.ipynb文件了,报错信息如下:

Error loading webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

The editor could not be opened due to an unexpected error: Could not initialize webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

在网上查了一些解决方法,尝试过删除vscode缓存(~/Library/Application Support/Code/)、重新安装插件和重启VSCode,但都不起作用。经过不懈努力,终于在stack overflow上找到了适合我的解决方案,删除Service Worker文件夹之后重启VSCode,.ipynb文件就可以正常显示了!

There is another possible reason for OSX, that the files in the following paths are restricted by user permissions.

MAC: ~/Library/Application Support/Code/Service Worker

You can directly delete folders with restricted permissions.

After restarting VScode, he will generate it again.

]]>
+ + + 记录VSCode无法正常显示.ipynb文件的问题。 + + + + + + + + + + +
+ + + ImageJ插件开发 + + http://chen.cwxhmk.top/2023/07/21/imagej-plugin-9/ + 2023-07-21T12:33:25.000Z + 2024-01-10T10:16:48.350Z + + 开发流程
  1. 安装Java8 JDK (Windows x86 64-bit) ​https://docs.azul.com/core/zulu-openjdk/install/windows
  2. 安装Eclipse IDE for Java Developers ​https://www.eclipse.org/downloads/
  3. 在github下载示例插件并修改 ​GitHub - imagej/example-imagej2-command: Simple Maven project for an ImageJ2 command
  • 修改pom.xml:重点修改groupId、artifactId、version、name、的内容
  • Eclipse-Import-Maven-Existing Maven Projects
  • 重命名:项目名、包名、java文件中类名和菜单路径
  1. Run as Java application 确保程序可以正常运行
  2. Run as Maven build 控制台输出BUILD SUCCESS 则表示程序成功打包为jar包(保存在target目录下)
  3. 将jar包粘贴至Fiji的plugin目录,运行软件测试插件效果

问题记录

  1. 如果pom.xml中报错,则尝试修改,并等待右下角更新完成
  2. 打包好的插件在ImageJ中无法正常运行,报错java.lang.ClassCastException: com.chen.brain.pluginMain cannot be cast to org.scijava.plugin.SciJavaPlugin
    报错原因:pluginMain类没有实现org.scijava.command.Command接口,而这是必须的,才能将其识别为有效的SciJava插件。@Plugin注解用于指定该类应注册为一个命令插件,但由于它没有实现所需的接口,因此会导致ClassCastException异常。
    解决方案:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import org.scijava.command.Command;
    import org.scijava.plugin.Plugin;

    @Plugin(type = Command.class, menuPath = "Plugins>brainRegistration")
    public class pluginMain implements Command {

    // 省略其他部分

    @Override
    public void run() {
    // 在这里实现插件的逻辑
    }

    public static void main(String[] args) {
    new pluginMain().location();
    }
    }
  3. 在Eclipse中初次导入项目时,要等待build(可能需要等待几分钟)
  4. 最好在官方提供的模板基础上写自己的代码,而不是用自己新建的maven项目

参考内容

]]>
+ + + 之前明明走过开发插件的流程,没想到把自己写的代码打包的时候遇到各种问题,服了!!! + + + + + + + + + + + + +
+ +
diff --git a/categories/index.html b/categories/index.html new file mode 100644 index 000000000..8234c845d --- /dev/null +++ b/categories/index.html @@ -0,0 +1,269 @@ +分类 | Stray Birds + + + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" "b/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" new file mode 100644 index 000000000..eadaf5e56 --- /dev/null +++ "b/categories/\345\255\246\344\271\240\347\254\224\350\256\260/index.html" @@ -0,0 +1,179 @@ +分类: 学习笔记 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\346\226\271\346\263\225\346\225\231\347\250\213/index.html" "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/index.html" new file mode 100644 index 000000000..46e5f9514 --- /dev/null +++ "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/index.html" @@ -0,0 +1,179 @@ +分类: 方法教程 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/2/index.html" "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/2/index.html" new file mode 100644 index 000000000..c191a29d3 --- /dev/null +++ "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/2/index.html" @@ -0,0 +1,179 @@ +分类: 方法教程 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/3/index.html" "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/3/index.html" new file mode 100644 index 000000000..71b2dc48e --- /dev/null +++ "b/categories/\346\226\271\346\263\225\346\225\231\347\250\213/page/3/index.html" @@ -0,0 +1,179 @@ +分类: 方法教程 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\347\224\237\346\264\273\351\232\217\347\254\224/index.html" "b/categories/\347\224\237\346\264\273\351\232\217\347\254\224/index.html" new file mode 100644 index 000000000..e4d222747 --- /dev/null +++ "b/categories/\347\224\237\346\264\273\351\232\217\347\254\224/index.html" @@ -0,0 +1,179 @@ +分类: 生活随笔 | Stray Birds + + + + + + + + +
分类 - 生活随笔
2023
2023年度总结
2023年度总结
认识你自己
认识你自己
做选择
做选择
愉快的周末
愉快的周末
取钱小记
取钱小记
冬学期结束感想
冬学期结束感想
及时按下暂停键⏸
及时按下暂停键⏸
动态思维
动态思维
2023年的第一天
2023年的第一天
2022
2022年的最后一天
2022年的最后一天
\ No newline at end of file diff --git "a/categories/\347\224\237\346\264\273\351\232\217\347\254\224/page/2/index.html" "b/categories/\347\224\237\346\264\273\351\232\217\347\254\224/page/2/index.html" new file mode 100644 index 000000000..569b06b6d --- /dev/null +++ "b/categories/\347\224\237\346\264\273\351\232\217\347\254\224/page/2/index.html" @@ -0,0 +1,179 @@ +分类: 生活随笔 | Stray Birds + + + + + + + + +
分类 - 生活随笔
2022
2022年度总结
2022年度总结
英语结课感想
英语结课感想
初来浙里,我曾经的那些疑惑
初来浙里,我曾经的那些疑惑
\ No newline at end of file diff --git "a/categories/\347\224\237\347\211\251\345\256\236\351\252\214/index.html" "b/categories/\347\224\237\347\211\251\345\256\236\351\252\214/index.html" new file mode 100644 index 000000000..b6593f6d1 --- /dev/null +++ "b/categories/\347\224\237\347\211\251\345\256\236\351\252\214/index.html" @@ -0,0 +1,179 @@ +分类: 生物实验 | Stray Birds + + + + + + + + +
分类 - 生物实验
2024
小鼠脑立体定位手术
小鼠脑立体定位手术
\ No newline at end of file diff --git "a/categories/\347\241\254\344\273\266\345\274\200\345\217\221/index.html" "b/categories/\347\241\254\344\273\266\345\274\200\345\217\221/index.html" new file mode 100644 index 000000000..272fae722 --- /dev/null +++ "b/categories/\347\241\254\344\273\266\345\274\200\345\217\221/index.html" @@ -0,0 +1,179 @@ +分类: 硬件开发 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\350\257\276\351\242\230\347\247\257\347\264\257/index.html" "b/categories/\350\257\276\351\242\230\347\247\257\347\264\257/index.html" new file mode 100644 index 000000000..2f4ea1318 --- /dev/null +++ "b/categories/\350\257\276\351\242\230\347\247\257\347\264\257/index.html" @@ -0,0 +1,179 @@ +分类: 课题积累 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git "a/categories/\351\241\271\347\233\256\345\256\236\346\210\230/index.html" "b/categories/\351\241\271\347\233\256\345\256\236\346\210\230/index.html" new file mode 100644 index 000000000..5e4a41a88 --- /dev/null +++ "b/categories/\351\241\271\347\233\256\345\256\236\346\210\230/index.html" @@ -0,0 +1,179 @@ +分类: 项目实战 | Stray Birds + + + + + + + + +
\ No newline at end of file diff --git a/comments/index.html b/comments/index.html new file mode 100644 index 000000000..9f4f6055e --- /dev/null +++ b/comments/index.html @@ -0,0 +1,303 @@ +留言板 | Stray Birds + + + + + + + + + + +

来自文欣的留言:

很高兴在这里与你相遇!
有什么想问的?
有什么想分享的?
都可以告诉我哦 o(* ̄▽ ̄*)ブ
我的QQ:1172950805

文欣小助手竭诚为您服务!


评论
\ No newline at end of file diff --git a/css/background.css b/css/background.css new file mode 100644 index 000000000..19f292073 --- /dev/null +++ b/css/background.css @@ -0,0 +1,57 @@ +#web_bg { + background: -webkit-linear-gradient( + 0deg, + rgba(247, 149, 51, 0.1) 0, + rgba(243, 112, 85, 0.1) 15%, + rgba(239, 78, 123, 0.1) 30%, + rgba(161, 102, 171, 0.1) 44%, + rgba(80, 115, 184, 0.1) 58%, + rgba(16, 152, 173, 0.1) 72%, + rgba(7, 179, 155, 0.1) 86%, + rgba(109, 186, 130, 0.1) 100% + ); + background: -moz-linear-gradient( + 0deg, + rgba(247, 149, 51, 0.1) 0, + rgba(243, 112, 85, 0.1) 15%, + rgba(239, 78, 123, 0.1) 30%, + rgba(161, 102, 171, 0.1) 44%, + rgba(80, 115, 184, 0.1) 58%, + rgba(16, 152, 173, 0.1) 72%, + rgba(7, 179, 155, 0.1) 86%, + rgba(109, 186, 130, 0.1) 100% + ); + background: -o-linear-gradient( + 0deg, + rgba(247, 149, 51, 0.1) 0, + rgba(243, 112, 85, 0.1) 15%, + rgba(239, 78, 123, 0.1) 30%, + rgba(161, 102, 171, 0.1) 44%, + rgba(80, 115, 184, 0.1) 58%, + rgba(16, 152, 173, 0.1) 72%, + rgba(7, 179, 155, 0.1) 86%, + rgba(109, 186, 130, 0.1) 100% + ); + background: -ms-linear-gradient( + 0deg, + rgba(247, 149, 51, 0.1) 0, + rgba(243, 112, 85, 0.1) 15%, + rgba(239, 78, 123, 0.1) 30%, + rgba(161, 102, 171, 0.1) 44%, + rgba(80, 115, 184, 0.1) 58%, + rgba(16, 152, 173, 0.1) 72%, + rgba(7, 179, 155, 0.1) 86%, + rgba(109, 186, 130, 0.1) 100% + ); + background: linear-gradient( + 90deg, + rgba(247, 149, 51, 0.1) 0, + rgba(243, 112, 85, 0.1) 15%, + rgba(239, 78, 123, 0.1) 30%, + rgba(161, 102, 171, 0.1) 44%, + rgba(80, 115, 184, 0.1) 58%, + rgba(16, 152, 173, 0.1) 72%, + rgba(7, 179, 155, 0.1) 86%, + rgba(109, 186, 130, 0.1) 100% + ); +} diff --git a/css/hbe.style.css b/css/hbe.style.css new file mode 100644 index 000000000..060f1f83b --- /dev/null +++ b/css/hbe.style.css @@ -0,0 +1,749 @@ +.hbe, +.hbe:after, +.hbe:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +.hbe-container{ + margin: 0 auto; + overflow: hidden; +} +.hbe-content { + text-align: center; + font-size: 150%; + padding: 1em 0; +} + +.hbe-input { + position: relative; + z-index: 1; + display: inline-block; + margin: 1em; + width: 80%; + min-width: 200px; + vertical-align: top; +} + +.hbe-input-field { + line-height: normal; + font-size: 100%; + margin: 0; + position: relative; + display: block; + float: right; + padding: 0.8em; + width: 60%; + border: none; + border-radius: 0; + background: #f0f0f0; + color: #aaa; + font-weight: 400; + font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif; + -webkit-appearance: none; /* for box shadows to show on iOS */ +} + +.hbe-input-field:focus { + outline: none; +} + +.hbe-input-label { + display: inline-block; + float: right; + padding: 0 1em; + width: 40%; + color: #696969; + font-weight: bold; + font-size: 70.25%; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.hbe-input-label-content { + position: relative; + display: block; + padding: 1.6em 0; + width: 100%; +} + +.hbe-graphic { + position: absolute; + top: 0; + left: 0; + fill: none; +} + +/* hbe button in post page */ +.hbe-button { + width: 130px; + height: 40px; + background: linear-gradient(to bottom, #4eb5e5 0%,#389ed5 100%); /* W3C */ + border: none; + border-radius: 5px; + position: relative; + border-bottom: 4px solid #2b8bc6; + color: #fbfbfb; + font-weight: 600; + font-family: 'Open Sans', sans-serif; + text-shadow: 1px 1px 1px rgba(0,0,0,.4); + font-size: 15px; + text-align: left; + text-indent: 5px; + box-shadow: 0px 3px 0px 0px rgba(0,0,0,.2); + cursor: pointer; + + display: block; + margin: 0 auto; + margin-bottom: 20px; +} + +.hbe-button:active { + box-shadow: 0px 2px 0px 0px rgba(0,0,0,.2); + top: 1px; +} + +.hbe-button:after { + content: ""; + width: 0; + height: 0; + display: block; + border-top: 20px solid #187dbc; + border-bottom: 20px solid #187dbc; + border-left: 16px solid transparent; + border-right: 20px solid #187dbc; + position: absolute; + opacity: 0.6; + right: 0; + top: 0; + border-radius: 0 5px 5px 0; +} +/* hbe button in post page */ + +/* default theme {{{ */ +.hbe-input-default { + overflow: hidden; +} + +.hbe-input-field-default { + width: 100%; + background: transparent; + padding: 0.5em; + margin-bottom: 2em; + color: #f9f7f6; + z-index: 100; + opacity: 0; +} + +.hbe-input-label-default { + width: 100%; + position: absolute; + text-align: left; + padding: 0.5em 0; + pointer-events: none; + font-size: 1em; +} + +.hbe-input-label-default::before, +.hbe-input-label-default::after { + content: ''; + position: absolute; + width: 100%; + left: 0; +} + +.hbe-input-label-default::before { + height: 100%; + background: #666666; + top: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + -webkit-transition: -webkit-transform 0.2s; + transition: transform 0.2s; +} + +.hbe-input-label-default::after { + height: 2px; + background: #666666; + top: 100%; + -webkit-transition: opacity 0.2s; + transition: opacity 0.2s; +} + +.hbe-input-label-content-default { + padding: 0; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s, color 0.2s; + transition: transform 0.2s, color 0.2s; +} + +.hbe-input-field-default:focus, +.hbe-input--filled .hbe-input-field-default { + opacity: 1; + -webkit-transition: opacity 0s 0.2s; + transition: opacity 0s 0.2s; +} + +.hbe-input-label-default::before, +.hbe-input-label-default::after, +.hbe-input-label-content-default, +.hbe-input-field-default:focus, +.hbe-input--filled .hbe-input-field-default { + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-default:focus + .hbe-input-label-default::before, +.hbe-input--filled .hbe-input-label-default::before { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-default:focus + .hbe-input-label-default::after, +.hbe-input--filled .hbe-input-label-default::after { + opacity: 0; +} + +.hbe-input-field-default:focus + .hbe-input-label-default .hbe-input-label-content-default, +.hbe-input--filled .hbe-input-label-default .hbe-input-label-content-default { + color: #555555; + -webkit-transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); + transform: translate3d(0, 2.1em, 0) scale3d(0.65, 0.65, 1); +} +/* default theme }}} */ + +/* up theme {{{ */ +.hbe-input-up { + overflow: hidden; + padding-top: 2em; +} + +.hbe-input-field-up { + width: 100%; + background: transparent; + opacity: 0; + padding: 0.35em; + z-index: 100; + color: #837482; +} + +.hbe-input-label-up { + width: 100%; + bottom: 0; + position: absolute; + pointer-events: none; + text-align: left; + color: #8E9191; + padding: 0 0.5em; +} + +.hbe-input-label-up::before { + content: ''; + position: absolute; + width: 100%; + height: 4em; + top: 100%; + left: 0; + background: #fff; + border-top: 4px solid #9B9F9F; + -webkit-transform: translate3d(0, -3px, 0); + transform: translate3d(0, -3px, 0); + -webkit-transition: -webkit-transform 0.4s; + transition: transform 0.4s; + -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); + transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); +} + +.hbe-input-label-content-up { + padding: 0.5em 0; + -webkit-transform-origin: 0% 100%; + transform-origin: 0% 100%; + -webkit-transition: -webkit-transform 0.4s, color 0.4s; + transition: transform 0.4s, color 0.4s; + -webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); + transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1); +} + +.hbe-input-field-up:focus, +.input--filled .hbe-input-field-up { + cursor: text; + opacity: 1; + -webkit-transition: opacity 0s 0.4s; + transition: opacity 0s 0.4s; +} + +.hbe-input-field-up:focus + .hbe-input-label-up::before, +.input--filled .hbe-input-label-up::before { + -webkit-transition-delay: 0.05s; + transition-delay: 0.05s; + -webkit-transform: translate3d(0, -3.3em, 0); + transform: translate3d(0, -3.3em, 0); +} + +.hbe-input-field-up:focus + .hbe-input-label-up .hbe-input-label-content-up, +.input--filled .hbe-input-label-content-up { + color: #6B6E6E; + -webkit-transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); + transform: translate3d(0, -3.3em, 0) scale3d(0.81, 0.81, 1); +} +/* up theme }}} */ + +/* wave theme {{{ */ +.hbe-input-wave { + overflow: hidden; + padding-top: 1em; +} + +.hbe-input-field-wave { + padding: 0.5em 0em 0.25em; + width: 100%; + background: transparent; + color: #9da8b2; + font-size: 1.25em; +} + +.hbe-input-label-wave { + position: absolute; + top: 0.95em; + font-size: 0.85em; + left: 0; + display: block; + width: 100%; + text-align: left; + padding: 0em; + pointer-events: none; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s 0.15s, color 1s; + transition: transform 0.2s 0.15s, color 1s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.hbe-graphic-wave { + stroke: #92989e; + pointer-events: none; + -webkit-transition: -webkit-transform 0.7s, stroke 0.7s; + transition: transform 0.7s, stroke 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-wave:focus + .hbe-input-label-wave, +.input--filled .hbe-input-label-wave { + color: #333; + -webkit-transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1); + transform: translate3d(0, -1.25em, 0) scale3d(0.75, 0.75, 1); +} + +.hbe-input-field-wave:focus ~ .hbe-graphic-wave, +.input--filled .graphic-wave { + stroke: #333; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* wave theme }}} */ + +/* flip theme {{{ */ +.hbe-input-field-flip { + width: 100%; + background-color: #d0d1d0; + border: 2px solid transparent; + -webkit-transition: background-color 0.25s, border-color 0.25s; + transition: background-color 0.25s, border-color 0.25s; +} + +.hbe-input-label-flip { + width: 100%; + text-align: left; + position: absolute; + bottom: 100%; + pointer-events: none; + overflow: hidden; + padding: 0 1.25em; + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + -webkit-transition: -webkit-transform 0.25s; + transition: transform 0.25s ; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.hbe-input-label-content-flip { + color: #8B8C8B; + padding: 0.25em 0; + -webkit-transition: -webkit-transform 0.25s; + transition: transform 0.25s; + -webkit-transition-timing-function: ease-in-out; + transition-timing-function: ease-in-out; +} + +.hbe-input-label-content-flip::after { + content: attr(data-content); + position: absolute; + font-weight: 800; + bottom: 100%; + left: 0; + height: 100%; + width: 100%; + color: #666666; + padding: 0.25em 0; + letter-spacing: 1px; + font-size: 1em; +} + +.hbe-input-field-flip:focus + .hbe-input-label-flip, +.input--filled .hbe-input-label-flip { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-flip:focus + .hbe-input-label-flip .hbe-input-label-content-flip, +.input--filled .hbe-input-label-content-flip { + -webkit-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} + +.hbe-input-field-flip:focus + .hbe-input-field-flip, +.input--filled .hbe-input-field-flip { + background-color: transparent; + border-color: #666666; +} +/* flip theme }}} */ + +/* xray theme {{{ */ +.hbe-input-xray { + overflow: hidden; + padding-bottom: 2.5em; +} + +.hbe-input-field-xray { + padding: 0; + margin-top: 1.2em; + width: 100%; + background: transparent; + color: #84AF9B ; + font-size: 1.55em; +} + +.hbe-input-label-xray { + position: absolute; + top: 2em; + left: 0; + display: block; + width: 100%; + text-align: left; + padding: 0em; + letter-spacing: 1px; + color: #84AF9B ; + pointer-events: none; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.2s 0.1s, color 0.3s; + transition: transform 0.2s 0.1s, color 0.3s; + -webkit-transition-timing-function: ease-out; + transition-timing-function: ease-out; +} + +.hbe-graphic-xray { + stroke: #84AF9B ; + pointer-events: none; + stroke-width: 2px; + top: 1.25em; + bottom: 0px; + height: 3.275em; + -webkit-transition: -webkit-transform 0.7s, stroke 0.7s; + transition: transform 0.7s, stroke 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-xray:focus + .hbe-input-label-xray, +.input--filled .hbe-input-label-xray { + color: #84AF9B ; + -webkit-transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1); + transform: translate3d(0, 3.5em, 0) scale3d(0.85, 0.85, 1); +} + +.hbe-input-field-xray:focus ~ .hbe-graphic-xray, +.input--filled .graphic-xray { + stroke: #84AF9B ; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* xray theme }}} */ + +/* blink theme {{{ */ +.hbe-input-blink { + padding-top: 1em; +} + +.hbe-input-field-blink { + width: 100%; + padding: 0.8em 0.5em; + background: transparent; + border: 2px solid; + color: #8781bd; + -webkit-transition: border-color 0.25s; + transition: border-color 0.25s; +} + +.hbe-input-label-blink { + width: 100%; + position: absolute; + top: 0; + text-align: left; + overflow: hidden; + padding: 0; + pointer-events: none; + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); +} + +.hbe-input-label-content-blink { + padding: 0 1em; + font-weight: 400; + color: #b5b5b5; +} + +.hbe-input-label-content-blink::after { + content: attr(data-content); + position: absolute; + top: -200%; + left: 0; + color: #8781bd ; + font-weight: 800; +} + +.hbe-input-field-blink:focus, +.input--filled .hbe-input-field-blink { + border-color: #8781bd ; +} + +.hbe-input-field-blink:focus + .hbe-input-label-blink, +.input--filled .hbe-input-label-blink { + -webkit-animation: anim-blink-1 0.25s forwards; + animation: anim-blink-1 0.25s forwards; +} + +.hbe-input-field-blink:focus + .hbe-input-label-blink .hbe-input-label-content-blink, +.input--filled .hbe-input-label-content-blink { + -webkit-animation: anim-blink-2 0.25s forwards ease-in; + animation: anim-blink-2 0.25s forwards ease-in; +} + +@-webkit-keyframes anim-blink-1 { + 0%, 70% { + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + } + 71%, 100% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@-webkit-keyframes anim-blink-2 { + 0% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 70%, 71% { + -webkit-transform: translate3d(0, 125%, 0); + transform: translate3d(0, 125%, 0); + opacity: 0; + -webkit-animation-timing-function: ease-out; + } + 100% { + color: transparent; + -webkit-transform: translate3d(0, 200%, 0); + transform: translate3d(0, 200%, 0); + } +} + +@keyframes anim-blink-1 { + 0%, 70% { + -webkit-transform: translate3d(0, 3em, 0); + transform: translate3d(0, 3em, 0); + } + 71%, 100% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } +} + +@keyframes anim-blink-2 { + 0% { + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); + } + 70%, 71% { + -webkit-transform: translate3d(0, 125%, 0); + transform: translate3d(0, 125%, 0); + opacity: 0; + -webkit-animation-timing-function: ease-out; + } + 100% { + color: transparent; + -webkit-transform: translate3d(0, 200%, 0); + transform: translate3d(0, 200%, 0); + } +} +/* blink theme }}} */ + +/* surge theme {{{ */ +.hbe-input-surge { + overflow: hidden; + padding-bottom: 1em; +} + +.hbe-input-field-surge { + padding: 0.25em 0.5em; + margin-top: 1.25em; + width: 100%; + background: transparent; + color: #D0D0D0; + font-size: 1.55em; + opacity: 0; +} + +.hbe-input-label-surge { + width: 100%; + text-align: left; + position: absolute; + top: 1em; + pointer-events: none; + overflow: hidden; + padding: 0 0.25em; + -webkit-transform: translate3d(1em, 2.75em, 0); + transform: translate3d(1em, 2.75em, 0); + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; +} + +.hbe-input-label-content-surge { + color: #A4A5A6; + padding: 0.4em 0 0.25em; + -webkit-transition: -webkit-transform 0.3s; + transition: transform 0.3s; +} + +.hbe-input-label-content-surge::after { + content: attr(data-content); + position: absolute; + font-weight: 800; + top: 100%; + left: 0; + height: 100%; + width: 100%; + color: #2C3E50; + padding: 0.25em 0; + letter-spacing: 1px; + font-size: 0.85em; +} + +.hbe-graphic-surge { + fill: #2C3E50; + pointer-events: none; + top: 1em; + bottom: 0px; + height: 4.5em; + z-index: -1; + -webkit-transition: -webkit-transform 0.7s, fill 0.7s; + transition: transform 0.7s, fill 0.7s; + -webkit-transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); + transition-timing-function: cubic-bezier(0, 0.25, 0.5, 1); +} + +.hbe-input-field-surge:focus, +.input--filled .hbe-input-field-surge { + -webkit-transition: opacity 0s 0.35s; + transition: opacity 0s 0.35s; + opacity: 1; +} + +.hbe-input-field-surge:focus + .hbe-input-label-surge, +.input--filled .hbe-input-label-surge { + -webkit-transition-delay: 0.15s; + transition-delay: 0.15s; + -webkit-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} + +.hbe-input-field-surge:focus + .hbe-input-label-surge .hbe-input-label-content-surge, +.input--filled .hbe-input-label-content-surge { + -webkit-transition-delay: 0.15s; + transition-delay: 0.15s; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); +} + +.hbe-input-field-surge:focus ~ .hbe-graphic-surge, +.input--filled .graphic-surge { + fill: #2C3E50; + -webkit-transform: translate3d(-66.6%, 0, 0); + transform: translate3d(-66.6%, 0, 0); +} +/* surge theme }}} */ + +/* shrink theme {{{ */ +.hbe-input-field-shrink { + width: 100%; + background: transparent; + padding: 0.5em 0; + margin-bottom: 2em; + color: #2C3E50; +} + +.hbe-input-label-shrink { + width: 100%; + position: absolute; + text-align: left; + font-size: 1em; + padding: 10px 0 5px; + pointer-events: none; +} + +.hbe-input-label-shrink::after { + content: ''; + position: absolute; + width: 100%; + height: 7px; + background: #B7C3AC; + left: 0; + top: 100%; + -webkit-transform-origin: 50% 100%; + transform-origin: 50% 100%; + -webkit-transition: -webkit-transform 0.3s, background-color 0.3s; + transition: transform 0.3s, background-color 0.3s; +} + +.hbe-input-label-content-shrink { + padding: 0; + -webkit-transform-origin: 0 0; + transform-origin: 0 0; + -webkit-transition: -webkit-transform 0.3s, color 0.3s; + transition: transform 0.3s, color 0.3s; +} + +.hbe-input-field-shrink:focus + .hbe-input-label-shrink::after, +.input--filled .hbe-input-label-shrink::after { + background: #84AF9B; + -webkit-transform: scale3d(1, 0.25, 1); + transform: scale3d(1, 0.25, 1); +} + +.hbe-input-field-shrink:focus + .hbe-input-label-shrink .hbe-input-label-content-shrink, +.input--filled .hbe-input-label-shrink .hbe-input-label-content-shrink { + color: #84AF9B; + -webkit-transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1); + transform: translate3d(0, 2em, 0) scale3d(0.655, 0.655, 1); +} +/* shrink theme }}} */ diff --git a/css/index.css b/css/index.css new file mode 100644 index 000000000..5a53c6f8f --- /dev/null +++ b/css/index.css @@ -0,0 +1,5950 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html { + line-height: 1.15; + -webkit-text-size-adjust: 100% +} + +body { + margin: 0 +} + +main { + display: block +} + +h1 { + font-size: 2em; + margin: .67em 0 +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible +} + +pre { + font-family: monospace, monospace; + font-size: 1em +} + +a { + background-color: transparent +} + +abbr[title] { + border-bottom: none; + text-decoration: underline; + text-decoration: underline dotted +} + +b, +strong { + font-weight: bolder +} + +code, +kbd, +samp { + font-family: monospace, monospace; + font-size: 1em +} + +small { + font-size: 80% +} + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline +} + +sub { + bottom: -.25em +} + +sup { + top: -.5em +} + +img { + border-style: none +} + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + font-size: 100%; + line-height: 1.15; + margin: 0 +} + +button, +input { + overflow: visible +} + +button, +select { + text-transform: none +} + +[type=button], +[type=reset], +[type=submit], +button { + -webkit-appearance: button +} + +[type=button]::-moz-focus-inner, +[type=reset]::-moz-focus-inner, +[type=submit]::-moz-focus-inner, +button::-moz-focus-inner { + border-style: none; + padding: 0 +} + +[type=button]:-moz-focusring, +[type=reset]:-moz-focusring, +[type=submit]:-moz-focusring, +button:-moz-focusring { + outline: 1px dotted ButtonText +} + +fieldset { + padding: .35em .75em .625em +} + +legend { + box-sizing: border-box; + color: inherit; + display: table; + max-width: 100%; + padding: 0; + white-space: normal +} + +progress { + vertical-align: baseline +} + +textarea { + overflow: auto +} + +[type=checkbox], +[type=radio] { + box-sizing: border-box; + padding: 0 +} + +[type=number]::-webkit-inner-spin-button, +[type=number]::-webkit-outer-spin-button { + height: auto +} + +[type=search] { + -webkit-appearance: textfield; + outline-offset: -2px +} + +[type=search]::-webkit-search-decoration { + -webkit-appearance: none +} + +::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit +} + +details { + display: block +} + +summary { + display: list-item +} + +template { + display: none +} + +[hidden] { + display: none +} + + +.limit-one-line, +#article-container .flink .flink-item-name, +#article-container .flink .flink-item-desc, +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span, +.site-data > a .headline, +#pagination .prev_info, +#pagination .next_info, +#sidebar #sidebar-menus .menus_items .site-page { + overflow: hidden; + -o-text-overflow: ellipsis; + text-overflow: ellipsis; + white-space: nowrap; +} +.limit-more-line, +.error404 #error-wrap .error-content .error-info .error_subtitle, +.article-sort-item-title, +#recent-posts > .recent-post-item >.recent-post-info > .article-title, +#recent-posts > .recent-post-item >.recent-post-info > .content, +#aside-content .aside-list > .aside-list-item .content > .name, +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment, +#post-info .post-title, +.relatedPosts > .relatedPosts-list .content .title, +#article-container figure.gallery-group p, +#article-container figure.gallery-group .gallery-group-name { + display: -webkit-box; + overflow: hidden; + -webkit-box-orient: vertical; +} +.fontawesomeIcon, +hr:before, +#article-container.post-content h1:before, +#article-container.post-content h2:before, +#article-container.post-content h3:before, +#article-container.post-content h4:before, +#article-container.post-content h5:before, +#article-container.post-content h6:before, +#post .post-copyright:before, +#post .post-outdate-notice:before, +.note:not(.no-icon)::before { + display: inline-block; + font-weight: 600; + font-family: 'Font Awesome 6 Free'; + text-rendering: auto; + -webkit-font-smoothing: antialiased; +} +.cardHover, +.error404 #error-wrap .error-content, +.layout > div:first-child:not(.recent-posts), +#recent-posts > .recent-post-item, +#aside-content .card-widget, +.layout > .recent-posts .pagination > *:not(.space) { + border-radius: 8px; + background: var(--card-bg); + -webkit-box-shadow: var(--card-box-shadow); + box-shadow: var(--card-box-shadow); + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.cardHover:hover, +.error404 #error-wrap .error-content:hover, +.layout > div:first-child:not(.recent-posts):hover, +#recent-posts > .recent-post-item:hover, +#aside-content .card-widget:hover, +.layout > .recent-posts .pagination > *:not(.space):hover { + -webkit-box-shadow: var(--card-hover-box-shadow); + box-shadow: var(--card-hover-box-shadow); +} +.imgHover, +.error404 #error-wrap .error-content .error-img img, +.article-sort-item-img img, +#recent-posts > .recent-post-item .post_cover img.post_bg, +#aside-content .aside-list > .aside-list-item .thumbnail > img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.6s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.6s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.6s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.6s; + transition: filter 375ms ease-in 0.2s, transform 0.6s; + object-fit: cover; +} +.imgHover:hover, +.error404 #error-wrap .error-content .error-img img:hover, +.article-sort-item-img img:hover, +#recent-posts > .recent-post-item .post_cover img.post_bg:hover, +#aside-content .aside-list > .aside-list-item .thumbnail > img:hover { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover:hover img, +#pagination .prev-post:hover img, +#pagination .next-post:hover img, +.relatedPosts > .relatedPosts-list > div:hover img { + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +.postImgHover img, +#pagination .prev-post img, +#pagination .next-post img, +.relatedPosts > .relatedPosts-list > div img { + position: absolute; + width: 100%; + height: 100%; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transition: all 0.6s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.6s, filter 375ms ease-in 0.2s; + -o-transition: all 0.6s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.6s, filter 375ms ease-in 0.2s; + transition: all 0.6s, filter 375ms ease-in 0.2s; + object-fit: cover; +} +.list-beauty, +.category-lists ul { + list-style: none; +} +.list-beauty li, +.category-lists ul li { + position: relative; + padding: 0.12em 0.4em 0.12em 1.4em; +} +.list-beauty li:hover:before, +.category-lists ul li:hover:before { + border-color: var(--pseudo-hover); +} +.list-beauty li:before, +.category-lists ul li:before { + position: absolute; + top: 0.67em; + left: 0; + width: 0.43em; + height: 0.43em; + border: 0.215em solid #49b1f5; + border-radius: 0.43em; + background: transparent; + content: ''; + cursor: pointer; + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +#content-inner, +#footer { + -webkit-animation: bottom-top 1s; + -moz-animation: bottom-top 1s; + -o-animation: bottom-top 1s; + -ms-animation: bottom-top 1s; + animation: bottom-top 1s; +} +#page-header { + -webkit-animation: header-effect 1s; + -moz-animation: header-effect 1s; + -o-animation: header-effect 1s; + -ms-animation: header-effect 1s; + animation: header-effect 1s; +} +#site-title, +#site-subtitle { + -webkit-animation: titleScale 1s; + -moz-animation: titleScale 1s; + -o-animation: titleScale 1s; + -ms-animation: titleScale 1s; + animation: titleScale 1s; +} +#nav.show { + -webkit-animation: headerNoOpacity 1s; + -moz-animation: headerNoOpacity 1s; + -o-animation: headerNoOpacity 1s; + -ms-animation: headerNoOpacity 1s; + animation: headerNoOpacity 1s; +} +canvas:not(#ribbon-canvas), +#web_bg { + -webkit-animation: to_show 4s; + -moz-animation: to_show 4s; + -o-animation: to_show 4s; + -ms-animation: to_show 4s; + animation: to_show 4s; +} +#ribbon-canvas { + -webkit-animation: ribbon_to_show 4s; + -moz-animation: ribbon_to_show 4s; + -o-animation: ribbon_to_show 4s; + -ms-animation: ribbon_to_show 4s; + animation: ribbon_to_show 4s; +} +#sidebar-menus.open > :nth-child(1) { + -webkit-animation: sidebarItem 0.2s; + -moz-animation: sidebarItem 0.2s; + -o-animation: sidebarItem 0.2s; + -ms-animation: sidebarItem 0.2s; + animation: sidebarItem 0.2s; +} +#sidebar-menus.open > :nth-child(2) { + -webkit-animation: sidebarItem 0.4s; + -moz-animation: sidebarItem 0.4s; + -o-animation: sidebarItem 0.4s; + -ms-animation: sidebarItem 0.4s; + animation: sidebarItem 0.4s; +} +#sidebar-menus.open > :nth-child(3) { + -webkit-animation: sidebarItem 0.6s; + -moz-animation: sidebarItem 0.6s; + -o-animation: sidebarItem 0.6s; + -ms-animation: sidebarItem 0.6s; + animation: sidebarItem 0.6s; +} +#sidebar-menus.open > :nth-child(4) { + -webkit-animation: sidebarItem 0.8s; + -moz-animation: sidebarItem 0.8s; + -o-animation: sidebarItem 0.8s; + -ms-animation: sidebarItem 0.8s; + animation: sidebarItem 0.8s; +} +.scroll-down-effects { + -webkit-animation: scroll-down-effect 1.5s infinite; + -moz-animation: scroll-down-effect 1.5s infinite; + -o-animation: scroll-down-effect 1.5s infinite; + -ms-animation: scroll-down-effect 1.5s infinite; + animation: scroll-down-effect 1.5s infinite; +} +.reward-main { + -webkit-animation: donate_effcet 0.3s 0.1s ease both; + -moz-animation: donate_effcet 0.3s 0.1s ease both; + -o-animation: donate_effcet 0.3s 0.1s ease both; + -ms-animation: donate_effcet 0.3s 0.1s ease both; + animation: donate_effcet 0.3s 0.1s ease both; +} +@-moz-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-webkit-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-o-keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@keyframes scroll-down-effect { + 0% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } + 50% { + top: -16px; + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + top: 0; + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + } +} +@-moz-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes header-effect { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes headerNoOpacity { + 0% { + -webkit-transform: translateY(-50px); + -moz-transform: translateY(-50px); + -o-transform: translateY(-50px); + -ms-transform: translateY(-50px); + transform: translateY(-50px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes bottom-top { + 0% { + margin-top: 50px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + margin-top: 0; + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes titleScale { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes search_close { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-moz-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-webkit-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-o-keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@keyframes to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + } +} +@-moz-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-webkit-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-o-keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@keyframes to_hide { + 0% { + opacity: 1; + -ms-filter: none; + filter: none; + } + 100% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } +} +@-moz-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes ribbon_to_show { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-moz-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-o-keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes avatar_turn_around { + from { + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); + } + to { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes sub_menus { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(10px); + -moz-transform: translateY(10px); + -o-transform: translateY(10px); + -ms-transform: translateY(10px); + transform: translateY(10px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes donate_effcet { + 0% { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transform: translateY(-20px); + -moz-transform: translateY(-20px); + -o-transform: translateY(-20px); + -ms-transform: translateY(-20px); + transform: translateY(-20px); + } + 100% { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-moz-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-webkit-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@-o-keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +@keyframes sidebarItem { + 0% { + -webkit-transform: translateX(200px); + -moz-transform: translateX(200px); + -o-transform: translateX(200px); + -ms-transform: translateX(200px); + transform: translateX(200px); + } + 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } +} +:root { + --global-font-size: 14px; + --global-bg: #fff; + --font-color: #4c4948; + --hr-border: #a4d8fa; + --hr-before-color: #80c8f8; + --search-bg: #f6f8fa; + --search-input-color: #4c4948; + --search-result-title: #4c4948; + --preloader-bg: #37474f; + --preloader-color: #fff; + --tab-border-color: #f0f0f0; + --tab-botton-bg: #f0f0f0; + --tab-botton-color: #1f2d3d; + --tab-button-hover-bg: #dcdcdc; + --tab-button-active-bg: #fff; + --card-bg: #fff; + --sidebar-bg: #f6f8fa; + --btn-hover-color: #ff7242; + --btn-color: #fff; + --btn-bg: #49b1f5; + --text-bg-hover: rgba(73,177,245,0.7); + --light-grey: #eee; + --dark-grey: #cacaca; + --white: #fff; + --text-highlight-color: #1f2d3d; + --blockquote-color: #6a737d; + --blockquote-bg: rgba(73,177,245,0.1); + --reward-pop: #f5f5f5; + --toc-link-color: #666261; + --card-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.05); + --card-hover-box-shadow: 0 3px 8px 6px rgba(7,17,27,0.09); + --pseudo-hover: #ff7242; + --headline-presudo: #a0a0a0; + --scrollbar-color: #49b1f5; +} +body { + position: relative; + min-height: 100%; + background: var(--global-bg); + color: var(--font-color); + font-size: var(--global-font-size); + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Lato, Roboto, 'PingFang SC', 'Microsoft YaHei', sans-serif; + line-height: 2; + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +*::-webkit-scrollbar { + width: 8px; + height: 8px; +} +*::-webkit-scrollbar-thumb { + background: var(--scrollbar-color); +} +*::-webkit-scrollbar-track { + background-color: transparent; +} +* { + scrollbar-width: thin; + scrollbar-color: var(--scrollbar-color) transparent; +} +input::placeholder { + color: var(--font-color); +} +#web_bg { + position: fixed; + z-index: -999; + width: 100%; + height: 100%; + background: #efefef; + background-attachment: local; + background-position: center; + background-size: cover; + background-repeat: no-repeat; +} +h1, +h2, +h3, +h4, +h5, +h6 { + position: relative; + margin: 20px 0 14px; + color: var(--text-highlight-color); + font-weight: bold; +} +h1 code, +h2 code, +h3 code, +h4 code, +h5 code, +h6 code { + font-size: inherit !important; +} +* { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +hr { + position: relative; + margin: 40px auto; + border: 2px dashed var(--hr-border); + width: calc(100% - 4px); +} +hr:hover:before { + left: calc(95% - 20px); +} +hr:before { + position: absolute; + top: -10px; + left: 5%; + z-index: 1; + color: var(--hr-before-color); + content: '\f0c4'; + font-size: 20px; + line-height: 1; + -webkit-transition: all 1s ease-in-out; + -moz-transition: all 1s ease-in-out; + -o-transition: all 1s ease-in-out; + -ms-transition: all 1s ease-in-out; + transition: all 1s ease-in-out; +} +.table-wrap { + overflow-x: scroll; + margin: 0 0 20px; +} +table { + display: table; + width: 100%; + border-spacing: 0; + border-collapse: collapse; + empty-cells: show; +} +table thead { + background: rgba(153,169,191,0.1); +} +table th, +table td { + padding: 6px 12px; + border: 1px solid var(--light-grey); + vertical-align: middle; +} +*::selection { + background: #00c4b6; + color: #f7f7f7; +} +button { + padding: 0; + outline: 0; + border: none; + background: none; + cursor: pointer; + touch-action: manipulation; +} +a { + color: #99a9bf; + text-decoration: none; + word-wrap: break-word; + -webkit-transition: all 0.2s; + -moz-transition: all 0.2s; + -o-transition: all 0.2s; + -ms-transition: all 0.2s; + transition: all 0.2s; + overflow-wrap: break-word; +} +a:hover { + color: #49b1f5; +} +.is-center { + text-align: center; +} +.copy-true { + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; +} +.pull-left { + float: left; +} +.pull-right { + float: right; +} +img[src=''], +img:not([src]) { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.img-alt { + margin: -10px 0 10px; + color: #858585; +} +.img-alt:hover { + text-decoration: none !important; +} +blockquote { + margin: 0 0 20px; + padding: 12px 15px; + border-left: 3px solid #49b1f5; + background-color: var(--blockquote-bg); + color: var(--blockquote-color); +} +blockquote footer cite:before { + padding: 0 5px; + content: '—'; +} +blockquote > :last-child { + margin-bottom: 0 !important; +} +:root { + --hl-color: #90a4ae; + --hl-bg: #f6f8fa; + --hltools-bg: #e6ebf1; + --hltools-color: #90a4ae; + --hlnumber-bg: #f6f8fa; + --hlnumber-color: rgba(144,164,174,0.5); + --hlscrollbar-bg: #dce4eb; + --hlexpand-bg: linear-gradient(180deg, rgba(246,248,250,0.6), rgba(246,248,250,0.9)); +} +figure.highlight table { + scrollbar-color: var(--hlscrollbar-bg) transparent; +} +figure.highlight table::-webkit-scrollbar-thumb { + background: var(--hlscrollbar-bg); +} +figure.highlight pre .deletion { + color: #bf42bf; +} +figure.highlight pre .addition { + color: #105ede; +} +figure.highlight pre .meta { + color: #7c4dff; +} +figure.highlight pre .comment { + color: rgba(149,165,166,0.8); +} +figure.highlight pre .variable, +figure.highlight pre .attribute, +figure.highlight pre .regexp, +figure.highlight pre .ruby .constant, +figure.highlight pre .xml .tag .title, +figure.highlight pre .xml .pi, +figure.highlight pre .xml .doctype, +figure.highlight pre .html .doctype, +figure.highlight pre .css .id, +figure.highlight pre .tag .name, +figure.highlight pre .css .class, +figure.highlight pre .css .pseudo { + color: #e53935; +} +figure.highlight pre .tag { + color: #39adb5; +} +figure.highlight pre .number, +figure.highlight pre .preprocessor, +figure.highlight pre .literal, +figure.highlight pre .params, +figure.highlight pre .constant, +figure.highlight pre .command { + color: #f76d47; +} +figure.highlight pre .built_in { + color: #ffb62c; +} +figure.highlight pre .ruby .class .title, +figure.highlight pre .css .rules .attribute, +figure.highlight pre .string, +figure.highlight pre .value, +figure.highlight pre .inheritance, +figure.highlight pre .header, +figure.highlight pre .ruby .symbol, +figure.highlight pre .xml .cdata, +figure.highlight pre .special, +figure.highlight pre .number, +figure.highlight pre .formula { + color: #91b859; +} +figure.highlight pre .keyword, +figure.highlight pre .title, +figure.highlight pre .css .hexcolor { + color: #39adb5; +} +figure.highlight pre .function, +figure.highlight pre .python .decorator, +figure.highlight pre .python .title, +figure.highlight pre .ruby .function .title, +figure.highlight pre .ruby .title .keyword, +figure.highlight pre .perl .sub, +figure.highlight pre .javascript .title, +figure.highlight pre .coffeescript .title { + color: #6182b8; +} +figure.highlight pre .tag .attr, +figure.highlight pre .javascript .function { + color: #7c4dff; +} +#article-container figure.highlight .line.marked { + background-color: rgba(128,203,196,0.251); +} +#article-container figure.highlight table { + display: block; + overflow: auto; + border: none; +} +#article-container figure.highlight table td { + padding: 0; + border: none; +} +#article-container figure.highlight .gutter pre { + padding-right: 10px; + padding-left: 10px; + background-color: var(--hlnumber-bg); + color: var(--hlnumber-color); + text-align: right; +} +#article-container figure.highlight .code pre { + padding-right: 10px; + padding-left: 10px; + width: 100%; +} +#article-container pre, +#article-container figure.highlight { + overflow: auto; + margin: 0 0 20px; + padding: 0; + background: var(--hl-bg); + color: var(--hl-color); + line-height: 1.6; +} +#article-container pre, +#article-container code { + font-size: var(--global-font-size); + font-family: consolas, Menlo, 'PingFang SC', 'Microsoft YaHei', sans-serif !important; +} +#article-container code { + padding: 2px 4px; + background: rgba(27,31,35,0.05); + color: #f47466; +} +#article-container pre { + padding: 10px 20px; +} +#article-container pre code { + padding: 0; + background: none; + color: var(--hl-color); + text-shadow: none; +} +#article-container figure.highlight { + position: relative; +} +#article-container figure.highlight pre { + margin: 0; + padding: 8px 0; + border: none; +} +#article-container figure.highlight figcaption, +#article-container figure.highlight .caption { + padding: 6px 0 2px 14px; + font-size: var(--global-font-size); + line-height: 1em; +} +#article-container figure.highlight figcaption a, +#article-container figure.highlight .caption a { + float: right; + padding-right: 10px; + color: var(--hl-color); +} +#article-container figure.highlight figcaption a:hover, +#article-container figure.highlight .caption a:hover { + border-bottom-color: var(--hl-color); +} +#article-container .highlight-tools { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + min-height: 24px; + height: 2.15em; + background: var(--hltools-bg); + color: var(--hltools-color); + font-size: var(--global-font-size); +} +#article-container .highlight-tools.closed ~ * { + display: none; +} +#article-container .highlight-tools .expand { + position: absolute; + padding: 0.57em 0.7em; + cursor: pointer; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#article-container .highlight-tools .expand + .code-lang { + left: 1.7em; +} +#article-container .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(-90deg) !important; + -moz-transform: rotate(-90deg) !important; + -o-transform: rotate(-90deg) !important; + -ms-transform: rotate(-90deg) !important; + transform: rotate(-90deg) !important; +} +#article-container .highlight-tools .code-lang { + position: absolute; + left: 14px; + text-transform: uppercase; + font-weight: bold; + font-size: 1.15em; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .highlight-tools .copy-notice { + position: absolute; + right: 2.4em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.4s; + -moz-transition: opacity 0.4s; + -o-transition: opacity 0.4s; + -ms-transition: opacity 0.4s; + transition: opacity 0.4s; +} +#article-container .highlight-tools .copy-button { + position: absolute; + right: 14px; + cursor: pointer; + -webkit-transition: color 0.2s; + -moz-transition: color 0.2s; + -o-transition: color 0.2s; + -ms-transition: color 0.2s; + transition: color 0.2s; +} +#article-container .highlight-tools .copy-button:hover { + color: #49b1f5; +} +#article-container .gutter { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +#article-container .gist table { + width: auto; +} +#article-container .gist table td { + border: none; +} +#article-container figure.highlight { + margin: 0 0 24px; + border-radius: 7px; + -webkit-box-shadow: 0 5px 10px 0 rgba(144,164,174,0.4); + box-shadow: 0 5px 10px 0 rgba(144,164,174,0.4); + -webkit-transform: translateZ(0); +} +#article-container figure.highlight .highlight-tools:after { + position: absolute; + left: 14px; + width: 12px; + height: 12px; + border-radius: 50%; + background: #fc625d; + -webkit-box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + box-shadow: 20px 0 #fdbc40, 40px 0 #35cd4b; + content: ' '; +} +#article-container figure.highlight .highlight-tools .expand { + right: 0; +} +#article-container figure.highlight .highlight-tools .expand.closed { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: rotate(90deg) !important; + -moz-transform: rotate(90deg) !important; + -o-transform: rotate(90deg) !important; + -ms-transform: rotate(90deg) !important; + transform: rotate(90deg) !important; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-notice { + right: 3.45em; +} +#article-container figure.highlight .highlight-tools .expand ~ .copy-button { + right: 2.1em; +} +#article-container figure.highlight .highlight-tools .code-lang { + left: 75px; +} +#article-container .code-expand-btn { + position: absolute; + bottom: 0; + z-index: 10; + width: 100%; + background: var(--hlexpand-bg); + text-align: center; + font-size: var(--global-font-size); + cursor: pointer; +} +#article-container .code-expand-btn i { + padding: 6px 0; + color: var(--hlnumber-color); + -webkit-animation: code-expand-key 1.2s infinite; + -moz-animation: code-expand-key 1.2s infinite; + -o-animation: code-expand-key 1.2s infinite; + -ms-animation: code-expand-key 1.2s infinite; + animation: code-expand-key 1.2s infinite; +} +#article-container .code-expand-btn.expand-done > i { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +#article-container .code-expand-btn.expand-done + table, +#article-container .code-expand-btn.expand-done + pre { + margin-bottom: 1.8em; +} +#article-container .code-expand-btn:not(.expand-done) ~ table, +#article-container .code-expand-btn:not(.expand-done) ~ pre { + overflow: hidden; + height: 300px; +} +@-moz-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-webkit-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@-o-keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +@keyframes code-expand-key { + 0% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } + 50% { + opacity: 0.1; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=10)"; + filter: alpha(opacity=10); + } + 100% { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); + } +} +.error404 #error-wrap { + position: absolute; + top: 50%; + right: 0; + left: 0; + margin: 0 auto; + padding: 60px 20px 0; + max-width: 1000px; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +.error404 #error-wrap .error-content { + overflow: hidden; + margin: 0 20px; + height: 360px; +} +@media screen and (max-width: 768px) { + .error404 #error-wrap .error-content { + margin: 0; + height: 500px; + } +} +.error404 #error-wrap .error-content .error-img { + display: inline-block; + overflow: hidden; + width: 50%; + height: 100%; +} +@media screen and (max-width: 768px) { + .error404 #error-wrap .error-content .error-img { + width: 100%; + height: 45%; + } +} +.error404 #error-wrap .error-content .error-img img { + background-color: #49b1f5; +} +.error404 #error-wrap .error-content .error-info { + display: -webkit-inline-box; + display: -moz-inline-box; + display: -webkit-inline-flex; + display: -ms-inline-flexbox; + display: inline-box; + display: inline-flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + -webkit-box-pack: center; + -moz-box-pack: center; + -o-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + -ms-flex-line-pack: center; + -webkit-align-content: center; + align-content: center; + width: 50%; + height: 100%; + vertical-align: top; + text-align: center; +} +@media screen and (max-width: 768px) { + .error404 #error-wrap .error-content .error-info { + width: 100%; + height: 55%; + } +} +.error404 #error-wrap .error-content .error-info .error_title { + margin-top: -0.6em; + font-size: 9em; +} +@media screen and (max-width: 768px) { + .error404 #error-wrap .error-content .error-info .error_title { + font-size: 8em; + } +} +.error404 #error-wrap .error-content .error-info .error_subtitle { + margin-top: -3em; + word-break: break-word; + font-size: 1.6em; + -webkit-line-clamp: 2; +} +.error404 + #rightside { + display: none; +} +.article-sort { + margin-left: 10px; + padding-left: 20px; + border-left: 2px solid #aadafa; +} +.article-sort-title { + position: relative; + margin-left: 10px; + padding-bottom: 20px; + padding-left: 20px; + font-size: 1.72em; +} +.article-sort-title:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-title:before { + position: absolute; + top: calc(((100% - 36px) / 2)); + left: -9px; + z-index: 1; + width: 10px; + height: 10px; + border: 5px solid #49b1f5; + border-radius: 10px; + background: var(--card-bg); + content: ''; + line-height: 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-title:after { + position: absolute; + bottom: 0; + left: 0; + z-index: 0; + width: 2px; + height: 1.5em; + background: #aadafa; + content: ''; +} +.article-sort-item { + position: relative; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + margin: 0 0 20px 10px; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item:hover:before { + border-color: var(--pseudo-hover); +} +.article-sort-item:before { + position: absolute; + left: calc(-20px - 17px); + width: 6px; + height: 6px; + border: 3px solid #49b1f5; + border-radius: 6px; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +.article-sort-item.no-article-cover { + height: 80px; +} +.article-sort-item.no-article-cover .article-sort-item-info { + padding: 0; +} +.article-sort-item.year { + font-size: 1.43em; +} +.article-sort-item.year:hover:before { + border-color: #49b1f5; +} +.article-sort-item.year:before { + border-color: var(--pseudo-hover); +} +.article-sort-item-time { + color: #858585; + font-size: 95%; +} +.article-sort-item-time time { + padding-left: 6px; + cursor: default; +} +.article-sort-item-title { + color: var(--font-color); + font-size: 1.1em; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-line-clamp: 2; +} +.article-sort-item-title:hover { + color: #49b1f5; + -webkit-transform: translateX(10px); + -moz-transform: translateX(10px); + -o-transform: translateX(10px); + -ms-transform: translateX(10px); + transform: translateX(10px); +} +.article-sort-item-img { + overflow: hidden; + width: 80px; + height: 80px; +} +.article-sort-item-info { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding: 0 16px; +} +.category-lists .category-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .category-lists .category-title { + font-size: 2em; + } +} +.category-lists .category-list { + margin-bottom: 0; +} +.category-lists .category-list a { + color: var(--font-color); +} +.category-lists .category-list a:hover { + color: #49b1f5; +} +.category-lists .category-list .category-list-count { + margin-left: 8px; + color: #858585; +} +.category-lists .category-list .category-list-count:before { + content: '('; +} +.category-lists .category-list .category-list-count:after { + content: ')'; +} +.category-lists ul { + padding: 0 0 0 20px; +} +.category-lists ul ul { + padding-left: 4px; +} +.category-lists ul li { + position: relative; + margin: 6px 0; + padding: 0.12em 0.4em 0.12em 1.4em; +} +#body-wrap { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + min-height: 100vh; +} +.layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1 auto; + -ms-flex: 1 auto; + flex: 1 auto; + margin: 0 auto; + padding: 40px 15px; + max-width: 1200px; + width: 100%; +} +@media screen and (max-width: 900px) { + .layout { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + } +} +@media screen and (max-width: 768px) { + .layout { + padding: 20px 5px; + } +} +@media screen and (min-width: 2000px) { + .layout { + max-width: 1500px; + } +} +.layout > div:first-child:not(.recent-posts) { + -webkit-align-self: flex-start; + align-self: flex-start; + -ms-flex-item-align: start; + padding: 50px 40px; +} +@media screen and (max-width: 768px) { + .layout > div:first-child:not(.recent-posts) { + padding: 36px 14px; + } +} +.layout > div:first-child { + width: 74%; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +@media screen and (max-width: 900px) { + .layout > div:first-child { + width: 100% !important; + } +} +@media screen and (min-width: 900px) { + .layout > div:first-child { + -webkit-box-ordinal-group: 2; + -moz-box-ordinal-group: 2; + -o-box-ordinal-group: 2; + -ms-flex-order: 2; + -webkit-order: 2; + order: 2; + } +} +.layout.hide-aside { + max-width: 1000px; +} +@media screen and (min-width: 2000px) { + .layout.hide-aside { + max-width: 1300px; + } +} +.layout.hide-aside > div { + width: 100% !important; +} +.apple #page-header.full_page { + background-attachment: scroll !important; +} +.apple .recent-post-item, +.apple .avatar-img, +.apple .flink-item-icon { + -webkit-transform: translateZ(0); + -moz-transform: translateZ(0); + -o-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); +} +#article-container .flink { + margin-bottom: 20px; +} +#article-container .flink .flink-list { + overflow: auto; + padding: 10px 10px 0; + text-align: center; +} +#article-container .flink .flink-list > .flink-list-item { + position: relative; + float: left; + overflow: hidden; + margin: 15px 7px; + width: calc(100% / 3 - 15px); + height: 90px; + border-radius: 8px; + line-height: 17px; + -webkit-transform: translateZ(0); +} +@media screen and (max-width: 1024px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(50% - 15px) !important; + } +} +@media screen and (max-width: 600px) { + #article-container .flink .flink-list > .flink-list-item { + width: calc(100% - 15px) !important; + } +} +#article-container .flink .flink-list > .flink-list-item:hover .flink-item-icon { + margin-left: -10px; + width: 0; +} +#article-container .flink .flink-list > .flink-list-item:before { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + background: var(--text-bg-hover); + content: ''; + -webkit-transition: -webkit-transform 0.3s ease-out; + -moz-transition: -moz-transform 0.3s ease-out; + -o-transition: -o-transform 0.3s ease-out; + -ms-transition: -ms-transform 0.3s ease-out; + transition: transform 0.3s ease-out; + -webkit-transform: scale(0); + -moz-transform: scale(0); + -o-transform: scale(0); + -ms-transform: scale(0); + transform: scale(0); +} +#article-container .flink .flink-list > .flink-list-item:hover:before, +#article-container .flink .flink-list > .flink-list-item:focus:before, +#article-container .flink .flink-list > .flink-list-item:active:before { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); +} +#article-container .flink .flink-list > .flink-list-item a { + color: var(--font-color); + text-decoration: none; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon { + float: left; + overflow: hidden; + margin: 15px 10px; + width: 60px; + height: 60px; + border-radius: 35px; + -webkit-transition: width 0.3s ease-out; + -moz-transition: width 0.3s ease-out; + -o-transition: width 0.3s ease-out; + -ms-transition: width 0.3s ease-out; + transition: width 0.3s ease-out; +} +#article-container .flink .flink-list > .flink-list-item a .flink-item-icon img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +#article-container .flink .flink-list > .flink-list-item a .img-alt { + display: none; +} +#article-container .flink .flink-item-name { + padding: 16px 10px 0 0; + height: 40px; + font-weight: bold; + font-size: 1.43em; +} +#article-container .flink .flink-item-desc { + padding: 16px 10px 16px 0; + height: 50px; + font-size: 0.93em; +} +#article-container .flink .flink-name { + margin-bottom: 5px; + font-weight: bold; + font-size: 1.5em; +} +#recent-posts > .recent-post-item:not(:first-child) { + margin-top: 20px; +} +#recent-posts > .recent-post-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + overflow: hidden; + height: 18em; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item { + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; + height: auto; + } +} +#recent-posts > .recent-post-item:hover img.post_bg { + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +#recent-posts > .recent-post-item.ads-wrap { + display: block !important; + height: auto !important; +} +#recent-posts > .recent-post-item .post_cover { + overflow: hidden; + width: 44%; + height: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover { + width: 100%; + height: 230px; + } +} +#recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 1; + -moz-box-ordinal-group: 1; + -o-box-ordinal-group: 1; + -ms-flex-order: 1; + -webkit-order: 1; + order: 1; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item .post_cover.right { + -webkit-box-ordinal-group: 0; + -moz-box-ordinal-group: 0; + -o-box-ordinal-group: 0; + -ms-flex-order: 0; + -webkit-order: 0; + order: 0; + } +} +#recent-posts > .recent-post-item >.recent-post-info { + padding: 0 40px; + width: 57%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info { + padding: 20px 20px 30px; + width: 100%; + } +} +#recent-posts > .recent-post-item >.recent-post-info.no-cover { + width: 100%; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info.no-cover { + padding: 30px 20px; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title { + color: var(--text-highlight-color); + font-size: 1.72em; + line-height: 1.4; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; + -webkit-line-clamp: 2; +} +@media screen and (max-width: 768px) { + #recent-posts > .recent-post-item >.recent-post-info > .article-title { + font-size: 1.43em; + } +} +#recent-posts > .recent-post-item >.recent-post-info > .article-title:hover { + color: #49b1f5; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap { + margin: 6px 0; + color: #858585; + font-size: 90%; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap > .post-meta-date { + cursor: default; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .sticky { + color: #ff7242; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap i { + margin: 0 4px 0 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .fa-spinner { + margin: 0; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-label { + padding-right: 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-separator { + margin: 0 6px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap .article-meta-link { + margin: 0 4px; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a { + color: #858585; +} +#recent-posts > .recent-post-item >.recent-post-info > .article-meta-wrap a:hover { + color: #49b1f5; + text-decoration: underline; +} +#recent-posts > .recent-post-item >.recent-post-info > .content { + -webkit-line-clamp: 2; +} +.tag-cloud-list a { + display: inline-block; + padding: 0 8px; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.tag-cloud-list a:hover { + color: #49b1f5 !important; + -webkit-transform: scale(1.1); + -moz-transform: scale(1.1); + -o-transform: scale(1.1); + -ms-transform: scale(1.1); + transform: scale(1.1); +} +@media screen and (max-width: 768px) { + .tag-cloud-list a { + zoom: 0.85; + } +} +.tag-cloud-title { + font-size: 2.57em; +} +@media screen and (max-width: 768px) { + .tag-cloud-title { + font-size: 2em; + } +} +h1.page-title + .tag-cloud-list { + text-align: left; +} +#aside-content { + width: 26%; +} +@media screen and (min-width: 900px) { + #aside-content { + padding-right: 15px; + } +} +@media screen and (max-width: 900px) { + #aside-content { + width: 100%; + } +} +#aside-content > .card-widget:first-child { + margin-top: 0; +} +@media screen and (max-width: 900px) { + #aside-content > .card-widget:first-child { + margin-top: 20px; + } +} +#aside-content .card-widget { + position: relative; + overflow: hidden; + margin-top: 20px; + padding: 20px 24px; +} +#aside-content .card-info .author-info__name { + font-weight: 500; + font-size: 1.57em; +} +#aside-content .card-info .author-info__description { + margin-top: -0.42em; +} +#aside-content .card-info .card-info-data { + margin: 14px 0 4px; +} +#aside-content .card-info .card-info-social-icons { + margin: 6px 0 -6px; +} +#aside-content .card-info .card-info-social-icons .social-icon { + margin: 0 10px; + color: var(--font-color); + font-size: 1.4em; +} +#aside-content .card-info .card-info-social-icons i { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#aside-content .card-info .card-info-social-icons i:hover { + -webkit-transform: rotate(540deg); + -moz-transform: rotate(540deg); + -o-transform: rotate(540deg); + -ms-transform: rotate(540deg); + transform: rotate(540deg); +} +#aside-content .card-info #card-info-btn { + display: block; + margin-top: 14px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + line-height: 2.4; +} +#aside-content .card-info #card-info-btn:hover { + background-color: var(--btn-hover-color); +} +#aside-content .card-info #card-info-btn span { + padding-left: 10px; +} +#aside-content .item-headline { + padding-bottom: 6px; + font-size: 1.2em; +} +#aside-content .item-headline span { + margin-left: 6px; +} +@media screen and (min-width: 900px) { + #aside-content .sticky_layout { + position: sticky; + position: -webkit-sticky; + top: 20px; + -webkit-transition: top 0.3s; + -moz-transition: top 0.3s; + -o-transition: top 0.3s; + -ms-transition: top 0.3s; + transition: top 0.3s; + } +} +#aside-content .card-tag-cloud a { + display: inline-block; + padding: 0 4px; +} +#aside-content .card-tag-cloud a:hover { + color: #49b1f5 !important; +} +#aside-content .aside-list > span { + display: block; + margin-bottom: 10px; + text-align: center; +} +#aside-content .aside-list > .aside-list-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 6px 0; +} +#aside-content .aside-list > .aside-list-item:first-child { + padding-top: 0; +} +#aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed #f5f5f5; +} +#aside-content .aside-list > .aside-list-item:last-child { + padding-bottom: 0; +} +#aside-content .aside-list > .aside-list-item .thumbnail { + overflow: hidden; + width: 4.2em; + height: 4.2em; +} +#aside-content .aside-list > .aside-list-item .content { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-left: 10px; + word-break: break-all; +} +#aside-content .aside-list > .aside-list-item .content > .name { + -webkit-line-clamp: 1; +} +#aside-content .aside-list > .aside-list-item .content > time, +#aside-content .aside-list > .aside-list-item .content > .name { + display: block; + color: #858585; + font-size: 85%; +} +#aside-content .aside-list > .aside-list-item .content > .title, +#aside-content .aside-list > .aside-list-item .content > .comment { + color: var(--font-color); + font-size: 95%; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#aside-content .aside-list > .aside-list-item .content > .title:hover, +#aside-content .aside-list > .aside-list-item .content > .comment:hover { + color: #49b1f5; +} +#aside-content .aside-list > .aside-list-item.no-cover { + min-height: 4.4em; +} +#aside-content .card-archives ul.card-archive-list, +#aside-content .card-categories ul.card-category-list { + margin: 0; + padding: 0; + list-style: none; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: horizontal; + -moz-box-orient: horizontal; + -o-box-orient: horizontal; + -webkit-flex-direction: row; + -ms-flex-direction: row; + flex-direction: row; + padding: 3px 10px; + color: var(--font-color); + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a:hover, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a:hover { + padding: 3px 17px; + background-color: var(--text-bg-hover); +} +#aside-content .card-archives ul.card-archive-list > .card-archive-list-item a span:first-child, +#aside-content .card-categories ul.card-category-list > .card-category-list-item a span:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} +#aside-content .card-categories .card-category-list.child { + padding: 0 0 0 16px; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-name { + width: 70% !important; +} +#aside-content .card-categories .card-category-list > .parent > a .card-category-list-count { + width: calc(100% - 70% - 20px); + text-align: right; +} +#aside-content .card-categories .card-category-list > .parent i { + float: right; + margin-right: -0.5em; + padding: 0.5em; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; + -webkit-transform: rotate(0); + -moz-transform: rotate(0); + -o-transform: rotate(0); + -ms-transform: rotate(0); + transform: rotate(0); +} +#aside-content .card-categories .card-category-list > .parent i.expand { + -webkit-transform: rotate(-90deg); + -moz-transform: rotate(-90deg); + -o-transform: rotate(-90deg); + -ms-transform: rotate(-90deg); + transform: rotate(-90deg); +} +#aside-content .card-webinfo .webinfo .webinfo-item { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 2px 10px 0; +} +#aside-content .card-webinfo .webinfo .webinfo-item div:first-child { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; + padding-right: 20px; +} +@media screen and (min-width: 901px) { + #aside-content #card-toc { + right: 0 !important; + } +} +@media screen and (max-width: 900px) { + #aside-content #card-toc { + position: fixed; + right: -100%; + bottom: 30px; + z-index: 100; + max-width: 380px; + max-height: calc(100% - 60px); + width: calc(100% - 80px); + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: initial; + -moz-transition: initial; + -o-transition: initial; + -ms-transition: initial; + transition: initial; + -webkit-transform-origin: right bottom; + -moz-transform-origin: right bottom; + -o-transform-origin: right bottom; + -ms-transform-origin: right bottom; + transform-origin: right bottom; + } +} +#aside-content #card-toc .toc-percentage { + float: right; + margin-top: -9px; + color: #a9a9a9; + font-style: italic; + font-size: 140%; +} +#aside-content #card-toc .toc-content { + overflow-y: scroll; + overflow-y: overlay; + margin: 0 -24px; + max-height: calc(100vh - 120px); +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content { + max-height: calc(100vh - 140px); + } +} +#aside-content #card-toc .toc-content > * { + margin: 0 20px !important; +} +#aside-content #card-toc .toc-content > * > .toc-item > .toc-child { + margin-left: 10px; + padding-left: 10px; + border-left: 1px solid var(--dark-grey); +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: none; +} +@media screen and (max-width: 900px) { + #aside-content #card-toc .toc-content:not(.is-expand) .toc-child { + display: block !important; + } +} +#aside-content #card-toc .toc-content:not(.is-expand) .toc-item.active .toc-child { + display: block; +} +#aside-content #card-toc .toc-content ol, +#aside-content #card-toc .toc-content li { + list-style: none; +} +#aside-content #card-toc .toc-content > ol { + padding: 0 !important; +} +#aside-content #card-toc .toc-content ol { + margin: 0; + padding-left: 18px; +} +#aside-content #card-toc .toc-content .toc-link { + display: block; + margin: 4px 0; + padding: 1px 6px; + color: var(--toc-link-color); + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#aside-content #card-toc .toc-content .toc-link:hover { + color: #49b1f5; +} +#aside-content #card-toc .toc-content .toc-link.active { + background: #00c4b6; + color: #fff; +} +#aside-content :only-child > .card-widget { + margin-top: 0; +} +#aside-content .card-more-btn { + float: right; + color: inherit; +} +#aside-content .card-more-btn:hover { + -webkit-animation: more-btn-move 1s infinite; + -moz-animation: more-btn-move 1s infinite; + -o-animation: more-btn-move 1s infinite; + -ms-animation: more-btn-move 1s infinite; + animation: more-btn-move 1s infinite; +} +#aside-content .card-announcement .item-headline i { + color: #f00; +} +.avatar-img { + overflow: hidden; + margin: 0 auto; + width: 110px; + height: 110px; + border-radius: 70px; +} +.avatar-img img { + width: 100%; + height: 100%; + -webkit-transition: filter 375ms ease-in 0.2s, -webkit-transform 0.3s; + -moz-transition: filter 375ms ease-in 0.2s, -moz-transform 0.3s; + -o-transition: filter 375ms ease-in 0.2s, -o-transform 0.3s; + -ms-transition: filter 375ms ease-in 0.2s, -ms-transform 0.3s; + transition: filter 375ms ease-in 0.2s, transform 0.3s; + object-fit: cover; +} +.avatar-img img:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +.site-data { + display: table; + width: 100%; + table-layout: fixed; +} +.site-data > a { + display: table-cell; +} +.site-data > a div { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +.site-data > a:hover div { + color: #49b1f5 !important; +} +.site-data > a .headline { + color: var(--font-color); +} +.site-data > a .length-num { + margin-top: -0.32em; + color: var(--text-highlight-color); + font-size: 1.4em; +} +@media screen and (min-width: 900px) { + html.hide-aside .layout { + -webkit-box-pack: center; + -moz-box-pack: center; + -o-box-pack: center; + -ms-flex-pack: center; + -webkit-justify-content: center; + justify-content: center; + } + html.hide-aside .layout > .aside-content { + display: none; + } + html.hide-aside .layout > div:first-child { + width: 80%; + } +} +.page .sticky_layout { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-orient: vertical; + -moz-box-orient: vertical; + -o-box-orient: vertical; + -webkit-flex-direction: column; + -ms-flex-direction: column; + flex-direction: column; +} +@-moz-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-webkit-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-o-keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@keyframes more-btn-move { + 0%, 100% { + -webkit-transform: translateX(0); + -moz-transform: translateX(0); + -o-transform: translateX(0); + -ms-transform: translateX(0); + transform: translateX(0); + } + 50% { + -webkit-transform: translateX(3px); + -moz-transform: translateX(3px); + -o-transform: translateX(3px); + -ms-transform: translateX(3px); + transform: translateX(3px); + } +} +@-moz-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-webkit-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-o-keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@keyframes toc-open { + 0% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } + 100% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } +} +@-moz-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-webkit-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@-o-keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +@keyframes toc-close { + 0% { + -webkit-transform: scale(1); + -moz-transform: scale(1); + -o-transform: scale(1); + -ms-transform: scale(1); + transform: scale(1); + } + 100% { + -webkit-transform: scale(0.7); + -moz-transform: scale(0.7); + -o-transform: scale(0.7); + -ms-transform: scale(0.7); + transform: scale(0.7); + } +} +#post-comment .comment-head { + margin-bottom: 20px; +} +#post-comment .comment-head .comment-headline { + display: inline-block; + vertical-align: middle; + font-weight: 700; + font-size: 1.43em; +} +#post-comment .comment-head #comment-switch { + display: inline-block; + float: right; + margin: 2px auto 0; + padding: 4px 16px; + width: max-content; + border-radius: 8px; + background: #f6f8fa; +} +#post-comment .comment-head #comment-switch .first-comment { + color: #49b1f5; +} +#post-comment .comment-head #comment-switch .second-comment { + color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn { + position: relative; + display: inline-block; + margin: -4px 8px 0; + width: 42px; + height: 22px; + border-radius: 34px; + background-color: #49b1f5; + vertical-align: middle; + cursor: pointer; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn:before { + position: absolute; + bottom: 4px; + left: 4px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #fff; + content: ''; + -webkit-transition: 0.4s; + -moz-transition: 0.4s; + -o-transition: 0.4s; + -ms-transition: 0.4s; + transition: 0.4s; +} +#post-comment .comment-head #comment-switch .switch-btn.move { + background-color: #ff7242; +} +#post-comment .comment-head #comment-switch .switch-btn.move:before { + -webkit-transform: translateX(20px); + -moz-transform: translateX(20px); + -o-transform: translateX(20px); + -ms-transform: translateX(20px); + transform: translateX(20px); +} +#post-comment .comment-wrap > div:nth-child(2) { + display: none; +} +#footer { + position: relative; + background: #49b1f5; + background-attachment: scroll; + background-position: bottom; + background-size: cover; +} +#footer:before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.5); + content: ''; +} +#footer-wrap { + position: relative; + padding: 40px 20px; + color: var(--light-grey); + text-align: center; +} +#footer-wrap a { + color: var(--light-grey); +} +#footer-wrap a:hover { + text-decoration: underline; +} +#footer-wrap .footer-separator { + margin: 0 4px; +} +#footer-wrap .icp-icon { + padding: 0 4px; + max-height: 1.4em; + width: auto; + vertical-align: text-bottom; +} +#page-header { + position: relative; + width: 100%; + background-color: #49b1f5; + background-position: center center; + background-size: cover; + background-repeat: no-repeat; + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#page-header:not(.not-top-img):before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.3); + content: ''; +} +#page-header.full_page { + height: 100vh; + background-attachment: fixed; +} +#page-header.full_page #site-info { + position: absolute; + top: 43%; + padding: 0 10px; + width: 100%; +} +#page-header #site-title, +#page-header #site-subtitle, +#page-header #scroll-down .scroll-down-effects { + text-align: center; + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + line-height: 1.5; +} +#page-header #site-title { + margin: 0; + color: var(--white); + font-size: 1.85em; +} +@media screen and (min-width: 768px) { + #page-header #site-title { + font-size: 2.85em; + } +} +#page-header #site-subtitle { + color: var(--light-grey); + font-size: 1.15em; +} +@media screen and (min-width: 768px) { + #page-header #site-subtitle { + font-size: 1.72em; + } +} +#page-header #site_social_icons { + display: none; + margin: 0 auto; + width: 300px; + text-align: center; +} +@media screen and (max-width: 768px) { + #page-header #site_social_icons { + display: block; + } +} +#page-header #site_social_icons .social-icon { + margin: 0 10px; + color: var(--light-grey); + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-size: 1.43em; +} +#page-header #scroll-down { + position: absolute; + bottom: 0; + width: 100%; + cursor: pointer; +} +#page-header #scroll-down .scroll-down-effects { + position: relative; + width: 100%; + color: var(--light-grey); + font-size: 30px; +} +#page-header.not-home-page { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.not-home-page { + height: 280px; + } +} +#page-header #page-site-info { + position: absolute; + top: 200px; + padding: 0 10px; + width: 100%; +} +@media screen and (max-width: 768px) { + #page-header #page-site-info { + top: 140px; + } +} +#page-header.post-bg { + height: 400px; +} +@media screen and (max-width: 768px) { + #page-header.post-bg { + height: 360px; + } +} +#page-header.post-bg:before { + background-color: rgba(0,0,0,0.5); +} +#page-header #post-info { + position: absolute; + bottom: 100px; + padding: 0 8%; + width: 100%; + text-align: center; +} +@media screen and (max-width: 900px) { + #page-header #post-info { + bottom: 30px; + text-align: left; + } +} +@media screen and (max-width: 768px) { + #page-header #post-info { + bottom: 22px; + padding: 0 22px; + } +} +#page-header.not-top-img { + margin-bottom: 10px; + height: 60px; + background: 0; +} +#page-header.not-top-img #nav { + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); +} +#page-header.not-top-img #nav a { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav { + position: fixed; + top: -60px; + z-index: 91; + background: rgba(255,255,255,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0.6); + -webkit-transition: -webkit-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -moz-transition: -moz-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -o-transition: -o-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + -ms-transition: -ms-transform 0.2s ease-in-out, opacity 0.2s ease-in-out; + transition: transform 0.2s ease-in-out, opacity 0.2s ease-in-out; +} +#page-header.nav-fixed #nav a, +#page-header.nav-fixed #nav #site-name, +#page-header.nav-fixed #nav #toggle-menu { + color: var(--font-color); + text-shadow: none; +} +#page-header.nav-fixed #nav a:hover, +#page-header.nav-fixed #nav #site-name:hover, +#page-header.nav-fixed #nav #toggle-menu:hover { + color: #49b1f5; +} +#page-header.nav-visible #nav { + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; + -webkit-transform: translate3d(0, 100%, 0); + -moz-transform: translate3d(0, 100%, 0); + -o-transform: translate3d(0, 100%, 0); + -ms-transform: translate3d(0, 100%, 0); + transform: translate3d(0, 100%, 0); +} +#page-header.nav-visible + .layout > .aside-content > .sticky_layout { + top: 70px; + -webkit-transition: top 0.5s; + -moz-transition: top 0.5s; + -o-transition: top 0.5s; + -ms-transition: top 0.5s; + transition: top 0.5s; +} +#page h1.page-title { + margin: 8px 0 20px; +} +#post > #post-info { + margin-bottom: 30px; +} +#post > #post-info .post-title { + padding-bottom: 4px; + border-bottom: 1px solid var(--light-grey); + color: var(--text-highlight-color); +} +#post > #post-info .post-title .post-edit-link { + float: right; +} +#post > #post-info #post-meta, +#post > #post-info #post-meta a { + color: #78818a; +} +#post-info .post-title { + margin-bottom: 8px; + color: var(--white); + font-weight: normal; + font-size: 2.5em; + line-height: 1.5; + -webkit-line-clamp: 3; +} +@media screen and (max-width: 768px) { + #post-info .post-title { + font-size: 2.1em; + } +} +#post-info .post-title .post-edit-link { + padding-left: 10px; +} +#post-info #post-meta { + color: var(--light-grey); + font-size: 95%; +} +@media screen and (min-width: 768px) { + #post-info #post-meta > .meta-secondline > span:first-child { + display: none; + } +} +@media screen and (max-width: 768px) { + #post-info #post-meta { + font-size: 90%; + } + #post-info #post-meta > .meta-firstline, + #post-info #post-meta > .meta-secondline { + display: inline; + } +} +#post-info #post-meta .post-meta-separator { + margin: 0 5px; +} +#post-info #post-meta .post-meta-icon { + margin-right: 4px; +} +#post-info #post-meta .post-meta-label { + margin-right: 4px; +} +#post-info #post-meta a { + color: var(--light-grey); + -webkit-transition: all 0.3s ease-out; + -moz-transition: all 0.3s ease-out; + -o-transition: all 0.3s ease-out; + -ms-transition: all 0.3s ease-out; + transition: all 0.3s ease-out; +} +#post-info #post-meta a:hover { + color: #49b1f5; + text-decoration: underline; +} +#nav { + position: absolute; + top: 0; + z-index: 90; + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-align: center; + -moz-box-align: center; + -o-box-align: center; + -ms-flex-align: center; + -webkit-align-items: center; + align-items: center; + padding: 0 36px; + width: 100%; + height: 60px; + font-size: 1.3em; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +@media screen and (max-width: 768px) { + #nav { + padding: 0 16px; + } +} +#nav.show { + opacity: 1; + -ms-filter: none; + filter: none; +} +#nav #blog_name { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + box-flex: 1; + -webkit-flex: 1; + -ms-flex: 1; + flex: 1; +} +#nav #toggle-menu { + display: none; + padding: 2px 0 0 6px; + vertical-align: top; +} +#nav #toggle-menu:hover { + color: var(--white); +} +#nav a { + color: var(--light-grey); +} +#nav a:hover { + color: var(--white); +} +#nav #site-name { + text-shadow: 2px 2px 4px rgba(0,0,0,0.15); + font-weight: bold; + cursor: pointer; +} +#nav .menus_items { + display: inline; +} +#nav .menus_items .menus_item { + position: relative; + display: inline-block; + padding: 0 0 0 14px; +} +#nav .menus_items .menus_item:hover .menus_item_child { + display: block; +} +#nav .menus_items .menus_item:hover > a > i:last-child { + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -o-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +#nav .menus_items .menus_item > a > i:last-child { + padding: 4px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#nav .menus_items .menus_item .menus_item_child { + position: absolute; + right: 0; + display: none; + margin-top: 8px; + padding: 0; + width: max-content; + background-color: var(--sidebar-bg); + -webkit-box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + box-shadow: 0 5px 20px -4px rgba(0,0,0,0.5); + -webkit-animation: sub_menus 0.3s 0.1s ease both; + -moz-animation: sub_menus 0.3s 0.1s ease both; + -o-animation: sub_menus 0.3s 0.1s ease both; + -ms-animation: sub_menus 0.3s 0.1s ease both; + animation: sub_menus 0.3s 0.1s ease both; + border-radius: 5px; +} +#nav .menus_items .menus_item .menus_item_child:before { + position: absolute; + top: -8px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +#nav .menus_items .menus_item .menus_item_child li { + list-style: none; +} +#nav .menus_items .menus_item .menus_item_child li:hover { + background: var(--text-bg-hover); +} +#nav .menus_items .menus_item .menus_item_child li:first-child { + border-radius: 5px 5px 0 0; +} +#nav .menus_items .menus_item .menus_item_child li:last-child { + border-radius: 0 0 5px 5px; +} +#nav .menus_items .menus_item .menus_item_child li a { + display: inline-block; + padding: 8px 16px; + width: 100%; + color: var(--font-color) !important; + text-shadow: none !important; +} +#nav.hide-menu #toggle-menu { + display: inline-block !important; +} +#nav.hide-menu #toggle-menu .site-page { + font-size: inherit; +} +#nav.hide-menu .menus_items { + display: none; +} +#nav.hide-menu #search-button span { + display: none; +} +#nav #search-button { + display: inline; + padding: 0 0 0 14px; +} +#nav .site-page { + position: relative; + padding-bottom: 6px; + text-shadow: 1px 1px 2px rgba(0,0,0,0.3); + font-size: 0.78em; + cursor: pointer; +} +#nav .site-page:not(.child):after { + position: absolute; + bottom: 0; + left: 0; + z-index: -1; + width: 0; + height: 3px; + background-color: #80c8f8; + content: ''; + -webkit-transition: all 0.3s ease-in-out; + -moz-transition: all 0.3s ease-in-out; + -o-transition: all 0.3s ease-in-out; + -ms-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; +} +#nav .site-page:not(.child):hover:after { + width: 100%; +} +#pagination .pagination { + margin-top: 20px; + text-align: center; +} +#pagination .page-number.current { + background: #00c4b6; + color: var(--white); +} +#pagination .pagination-info { + position: absolute; + top: 50%; + padding: 20px 40px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +#pagination .prev_info, +#pagination .next_info { + color: var(--white); + font-weight: 500; +} +#pagination .next-post .pagination-info { + text-align: right; +} +#pagination .pull-full { + width: 100% !important; +} +#pagination .prev-post .label, +#pagination .next-post .label { + color: var(--light-grey); + text-transform: uppercase; + font-size: 90%; +} +#pagination .prev-post, +#pagination .next-post { + width: 50%; +} +@media screen and (max-width: 768px) { + #pagination .prev-post, + #pagination .next-post { + width: 100%; + } +} +#pagination .prev-post a, +#pagination .next-post a { + position: relative; + display: block; + overflow: hidden; + height: 150px; +} +#pagination.pagination-post { + overflow: hidden; + margin-top: 40px; + width: 100%; + background: #000; +} +.layout > .recent-posts .pagination > * { + display: inline-block; + margin: 0 6px; + width: 2.5em; + height: 2.5em; + line-height: 2.5em; +} +.layout > .recent-posts .pagination > *:not(.space):hover { + background: var(--btn-hover-color); + color: var(--btn-color); +} +.layout > div:not(.recent-posts) .pagination .page-number { + display: inline-block; + margin: 0 4px; + min-width: 24px; + height: 24px; + text-align: center; + line-height: 24px; + cursor: pointer; +} +#article-container { + word-wrap: break-word; + overflow-wrap: break-word; +} +#article-container a { + color: #49b1f5; +} +#article-container a:hover { + text-decoration: underline; +} +#article-container img { + display: block; + margin: 0 auto 20px; + max-width: 100%; + -webkit-transition: filter 375ms ease-in 0.2s; + -moz-transition: filter 375ms ease-in 0.2s; + -o-transition: filter 375ms ease-in 0.2s; + -ms-transition: filter 375ms ease-in 0.2s; + transition: filter 375ms ease-in 0.2s; +} +#article-container p { + margin: 0 0 16px; +} +#article-container iframe { + margin: 0 0 20px; +} +#article-container kbd { + margin: 0 3px; + padding: 3px 5px; + border: 1px solid #b4b4b4; + border-radius: 3px; + background-color: #f8f8f8; + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + box-shadow: 0 1px 3px rgba(0,0,0,0.25), 0 2px 1px 0 rgba(255,255,255,0.6) inset; + color: #34495e; + white-space: nowrap; + font-weight: 600; + font-size: 0.9em; + font-family: Monaco, 'Ubuntu Mono', monospace; + line-height: 1em; +} +#article-container ol ol, +#article-container ul ol, +#article-container ol ul, +#article-container ul ul { + padding-left: 20px; +} +#article-container ol li, +#article-container ul li { + margin: 4px 0; +} +#article-container ol p, +#article-container ul p { + margin: 0 0 8px; +} +#article-container.post-content h1, +#article-container.post-content h2, +#article-container.post-content h3, +#article-container.post-content h4, +#article-container.post-content h5, +#article-container.post-content h6 { + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +#article-container.post-content h1:before, +#article-container.post-content h2:before, +#article-container.post-content h3:before, +#article-container.post-content h4:before, +#article-container.post-content h5:before, +#article-container.post-content h6:before { + position: absolute; + top: calc(50% - 7px); + color: #f47466; + content: '\f0c1'; + line-height: 1; + -webkit-transition: all 0.2s ease-out; + -moz-transition: all 0.2s ease-out; + -o-transition: all 0.2s ease-out; + -ms-transition: all 0.2s ease-out; + transition: all 0.2s ease-out; +} +#article-container.post-content h1:hover:before, +#article-container.post-content h2:hover:before, +#article-container.post-content h3:hover:before, +#article-container.post-content h4:hover:before, +#article-container.post-content h5:hover:before, +#article-container.post-content h6:hover:before { + color: #49b1f5; +} +#article-container.post-content h1 { + padding-left: 32px; +} +#article-container.post-content h1:before { + margin-left: -26px; + font-size: 20px; +} +#article-container.post-content h1:hover { + padding-left: 38px; +} +#article-container.post-content h2 { + padding-left: 30px; +} +#article-container.post-content h2:before { + margin-left: -24px; + font-size: 18px; +} +#article-container.post-content h2:hover { + padding-left: 36px; +} +#article-container.post-content h3 { + padding-left: 28px; +} +#article-container.post-content h3:before { + margin-left: -22px; + font-size: 16px; +} +#article-container.post-content h3:hover { + padding-left: 34px; +} +#article-container.post-content h4 { + padding-left: 26px; +} +#article-container.post-content h4:before { + margin-left: -20px; + font-size: 14px; +} +#article-container.post-content h4:hover { + padding-left: 32px; +} +#article-container.post-content h5 { + padding-left: 24px; +} +#article-container.post-content h5:before { + margin-left: -18px; + font-size: 12px; +} +#article-container.post-content h5:hover { + padding-left: 30px; +} +#article-container.post-content h6 { + padding-left: 24px; +} +#article-container.post-content h6:before { + margin-left: -18px; + font-size: 12px; +} +#article-container.post-content h6:hover { + padding-left: 30px; +} +#article-container.post-content ol p, +#article-container.post-content ul p { + margin: 0 0 8px; +} +#article-container.post-content li::marker { + color: #49b1f5; + font-weight: 600; + font-size: 1.05em; +} +#article-container.post-content li:hover::marker { + color: var(--pseudo-hover); +} +#article-container.post-content ul > li { + list-style-type: circle; +} +#article-container > :last-child { + margin-bottom: 0 !important; +} +#post .tag_share:after { + display: block; + clear: both; + content: ''; +} +#post .tag_share .post-meta__tag-list { + display: inline-block; +} +#post .tag_share .post-meta__tags { + display: inline-block; + margin: 8px 8px 8px 0; + padding: 0 12px; + width: fit-content; + border: 1px solid #49b1f5; + border-radius: 12px; + color: #49b1f5; + font-size: 0.85em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#post .tag_share .post-meta__tags:hover { + background: #49b1f5; + color: var(--white); +} +#post .tag_share .post_share { + display: inline-block; + float: right; + margin: 8px 0 0; + width: fit-content; +} +#post .tag_share .post_share .social-share { + font-size: 0.85em; +} +#post .tag_share .post_share .social-share .social-share-icon { + margin: 0 4px; + width: 1.85em; + height: 1.85em; + font-size: 1.2em; + line-height: 1.85em; +} +#post .post-copyright { + position: relative; + margin: 40px 0 10px; + padding: 10px 16px; + border: 1px solid var(--light-grey); + -webkit-transition: box-shadow 0.3s ease-in-out; + -moz-transition: box-shadow 0.3s ease-in-out; + -o-transition: box-shadow 0.3s ease-in-out; + -ms-transition: box-shadow 0.3s ease-in-out; + transition: box-shadow 0.3s ease-in-out; +} +#post .post-copyright:before { + position: absolute; + top: 2px; + right: 12px; + color: #49b1f5; + content: '\f1f9'; + font-size: 1.3em; +} +#post .post-copyright:hover { + -webkit-box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); + box-shadow: 0 0 8px 0 rgba(232,237,250,0.6), 0 2px 4px 0 rgba(232,237,250,0.5); +} +#post .post-copyright .post-copyright-meta { + color: #49b1f5; + font-weight: bold; +} +#post .post-copyright .post-copyright-info { + padding-left: 6px; +} +#post .post-copyright .post-copyright-info a { + text-decoration: underline; + word-break: break-word; +} +#post .post-copyright .post-copyright-info a:hover { + text-decoration: none; +} +#post .post-outdate-notice { + position: relative; + margin: 0 0 20px; + padding: 0.5em 1.2em; + border-radius: 3px; + background-color: #ffe6e6; + color: #f66; + padding: 0.5em 1em 0.5em 2.6em; + border-left: 5px solid #ff8080; +} +#post .post-outdate-notice:before { + position: absolute; + top: 50%; + left: 0.9em; + color: #ff8080; + content: '\f071'; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); +} +#post .ads-wrap { + margin: 40px 0; +} +.relatedPosts { + margin-top: 40px; +} +.relatedPosts > .headline { + margin-bottom: 5px; + font-weight: 700; + font-size: 1.43em; +} +.relatedPosts > .relatedPosts-list > div { + position: relative; + display: inline-block; + overflow: hidden; + margin: 3px; + width: calc(33.333% - 6px); + height: 200px; + background: #000; + vertical-align: bottom; +} +@media screen and (max-width: 768px) { + .relatedPosts > .relatedPosts-list > div { + margin: 2px; + width: calc(50% - 4px); + height: 150px; + } +} +@media screen and (max-width: 600px) { + .relatedPosts > .relatedPosts-list > div { + width: calc(100% - 4px); + } +} +.relatedPosts > .relatedPosts-list .content { + position: absolute; + top: 50%; + padding: 0 20px; + width: 100%; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +.relatedPosts > .relatedPosts-list .content .date { + color: var(--light-grey); + font-size: 90%; +} +.relatedPosts > .relatedPosts-list .content .title { + color: var(--white); + -webkit-line-clamp: 2; +} +.post-reward { + position: relative; + margin-top: 80px; + width: 100%; + text-align: center; + pointer-events: none; +} +.post-reward > * { + pointer-events: auto; +} +.post-reward .reward-button { + display: inline-block; + padding: 4px 24px; + background: var(--btn-bg); + color: var(--btn-color); + cursor: pointer; +} +.post-reward:hover .reward-button { + background: var(--btn-hover-color); +} +.post-reward:hover > .reward-main { + display: block; +} +.post-reward .reward-main { + position: absolute; + bottom: 40px; + left: 0; + z-index: 100; + display: none; + padding: 0 0 15px; + width: 100%; +} +.post-reward .reward-main .reward-all { + display: inline-block; + margin: 0; + padding: 20px 10px; + border-radius: 4px; + background: var(--reward-pop); +} +.post-reward .reward-main .reward-all:before { + position: absolute; + bottom: -10px; + left: 0; + width: 100%; + height: 20px; + content: ''; +} +.post-reward .reward-main .reward-all:after { + position: absolute; + right: 0; + bottom: 2px; + left: 0; + margin: 0 auto; + width: 0; + height: 0; + border-top: 13px solid var(--reward-pop); + border-right: 13px solid transparent; + border-left: 13px solid transparent; + content: ''; +} +.post-reward .reward-main .reward-all .reward-item { + display: inline-block; + padding: 0 8px; + list-style-type: none; + vertical-align: top; +} +.post-reward .reward-main .reward-all .reward-item img { + width: 130px; + height: 130px; +} +.post-reward .reward-main .reward-all .reward-item .post-qr-code-desc { + width: 130px; + color: #858585; +} +#rightside { + position: fixed; + right: -48px; + bottom: 40px; + z-index: 100; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#rightside #rightside-config-hide { + height: 0; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: -webkit-transform 0.4s; + -moz-transition: -moz-transform 0.4s; + -o-transition: -o-transform 0.4s; + -ms-transition: -ms-transform 0.4s; + transition: transform 0.4s; + -webkit-transform: translate(45px, 0); + -moz-transform: translate(45px, 0); + -o-transform: translate(45px, 0); + -ms-transform: translate(45px, 0); + transform: translate(45px, 0); +} +#rightside #rightside-config-hide.show { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate(0, 0); + -moz-transform: translate(0, 0); + -o-transform: translate(0, 0); + -ms-transform: translate(0, 0); + transform: translate(0, 0); +} +#rightside #rightside-config-hide.status { + height: auto; + opacity: 1; + -ms-filter: none; + filter: none; +} +#rightside > div > button, +#rightside > div > a { + display: block; + margin-bottom: 5px; + width: 35px; + height: 35px; + border-radius: 5px; + background-color: var(--btn-bg); + color: var(--btn-color); + text-align: center; + font-size: 16px; + line-height: 35px; +} +#rightside > div > button:hover, +#rightside > div > a:hover { + background-color: var(--btn-hover-color); +} +#rightside #mobile-toc-button { + display: none; +} +@media screen and (max-width: 900px) { + #rightside #mobile-toc-button { + display: block; + } +} +@media screen and (max-width: 900px) { + #rightside #hide-aside-btn { + display: none; + } +} +#sidebar #menu-mask { + position: fixed; + z-index: 102; + display: none; + width: 100%; + height: 100%; + background: rgba(0,0,0,0.8); +} +#sidebar #sidebar-menus { + position: fixed; + top: 0; + right: -300px; + z-index: 103; + overflow-x: hidden; + overflow-y: auto; + width: 300px; + height: 100%; + background: var(--sidebar-bg); + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#sidebar #sidebar-menus.open { + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#sidebar #sidebar-menus > .avatar-img { + margin: 20px auto; +} +#sidebar #sidebar-menus .sidebar-site-data { + padding: 0 10px; +} +#sidebar #sidebar-menus hr { + margin: 20px auto; +} +#sidebar #sidebar-menus .menus_items { + padding: 0 10px 40px; +} +#sidebar #sidebar-menus .menus_items .site-page { + position: relative; + display: block; + padding: 6px 30px 6px 22px; + color: var(--font-color); + font-size: 1.15em; +} +#sidebar #sidebar-menus .menus_items .site-page:hover { + background: var(--text-bg-hover); +} +#sidebar #sidebar-menus .menus_items .site-page i:first-child { + width: 15%; + text-align: left; +} +#sidebar #sidebar-menus .menus_items .site-page.group > i:last-child { + position: absolute; + top: 0.78em; + right: 18px; + -webkit-transition: -webkit-transform 0.3s; + -moz-transition: -moz-transform 0.3s; + -o-transition: -o-transform 0.3s; + -ms-transition: -ms-transform 0.3s; + transition: transform 0.3s; +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide > i:last-child { + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -o-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +#sidebar #sidebar-menus .menus_items .site-page.group.hide + .menus_item_child { + display: none; +} +#sidebar #sidebar-menus .menus_items .menus_item_child { + margin: 0; + list-style: none; +} +#vcomment { + font-size: 1.1em; +} +#vcomment .vbtn { + border: none; + background: var(--btn-bg); + color: var(--btn-color); +} +#vcomment .vbtn:hover { + background: var(--btn-hover-color); +} +#vcomment .vimg { + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; +} +#vcomment .vimg:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +#vcomment .vcards .vcard .vcontent.expand:before, +#vcomment .vcards .vcard .vcontent.expand:after { + z-index: 22; +} +#waline-wrap { + --waline-font-size: 1.1em; + --waline-theme-color: #49b1f5; + --waline-active-color: #ff7242; +} +#waline-wrap .vuser { + -webkit-transition: all 0.5s; + -moz-transition: all 0.5s; + -o-transition: all 0.5s; + -ms-transition: all 0.5s; + transition: all 0.5s; +} +#waline-wrap .vuser:hover { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -o-transform: rotate(360deg); + -ms-transform: rotate(360deg); + transform: rotate(360deg); +} +.fireworks { + position: fixed; + top: 0; + left: 0; + z-index: 999; + pointer-events: none; +} +.medium-zoom-image--opened { + z-index: 99999 !important; + margin: 0 !important; +} +.medium-zoom-overlay { + z-index: 99999 !important; +} +.mermaid-wrap { + margin: 0 0 20px; + text-align: center; +} +.mermaid-wrap > svg { + height: 100%; +} +.utterances, +.fb-comments iframe { + width: 100% !important; +} +#gitalk-container .gt-meta { + margin: 0 0 0.8em; + padding: 6px 0 16px; +} +.katex-wrap { + overflow: auto; +} +.katex-wrap::-webkit-scrollbar { + display: none; +} +mjx-container[display], +.has-jax { + overflow-x: auto; + overflow-y: hidden; + line-height: normal !important; +} +.aplayer { + color: #4c4948; +} +#article-container .aplayer { + margin: 0 0 20px; +} +#article-container .aplayer ol, +#article-container .aplayer ul { + margin: 0; + padding: 0; +} +#article-container .aplayer ol li, +#article-container .aplayer ul li { + margin: 0; + padding: 0 15px; +} +#article-container .aplayer ol li:before, +#article-container .aplayer ul li:before { + content: none; +} +.snackbar-css { + border-radius: 5px !important; +} +#article-container .btn-center { + margin: 0 0 20px; + text-align: center; +} +#article-container .btn-beautify { + display: inline-block; + margin: 0 4px 6px; + padding: 0 15px; + background-color: var(--btn-beautify-color, #777); + color: #fff; + line-height: 2; +} +#article-container .btn-beautify.blue { + --btn-beautify-color: #428bca; +} +#article-container .btn-beautify.pink { + --btn-beautify-color: #ff69b4; +} +#article-container .btn-beautify.red { + --btn-beautify-color: #f00; +} +#article-container .btn-beautify.purple { + --btn-beautify-color: #6f42c1; +} +#article-container .btn-beautify.orange { + --btn-beautify-color: #ff8c00; +} +#article-container .btn-beautify.green { + --btn-beautify-color: #5cb85c; +} +#article-container .btn-beautify:hover { + background-color: var(--btn-hover-color); +} +#article-container .btn-beautify i + span { + margin-left: 6px; +} +#article-container .btn-beautify:not(.block) + .btn-beautify:not(.block) { + margin: 0 4px 20px; +} +#article-container .btn-beautify.block { + display: block; + margin: 0 0 20px; + width: fit-content; + width: -moz-fit-content; +} +#article-container .btn-beautify.block.center { + margin: 0 auto 20px; +} +#article-container .btn-beautify.block.right { + margin: 0 0 20px auto; +} +#article-container .btn-beautify.larger { + padding: 6px 15px; +} +#article-container .btn-beautify:hover { + text-decoration: none; +} +#article-container .btn-beautify.outline { + border: 1px solid transparent; + border-color: var(--btn-beautify-color, #777); + background-color: transparent; + color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + background-color: var(--btn-beautify-color, #777); +} +#article-container .btn-beautify.outline:hover { + color: #fff !important; +} +#article-container figure.gallery-group { + position: relative; + float: left; + overflow: hidden; + margin: 6px 4px; + width: calc(50% - 8px); + height: 250px; + border-radius: 8px; + background: #000; + -webkit-transform: translate3d(0, 0, 0); +} +@media screen and (max-width: 600px) { + #article-container figure.gallery-group { + width: calc(100% - 8px); + } +} +#article-container figure.gallery-group:hover img { + opacity: 0.4; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)"; + filter: alpha(opacity=40); + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover .gallery-group-name::after { + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group:hover p { + opacity: 1; + -ms-filter: none; + filter: none; + -webkit-transform: translate3d(0, 0, 0); + -moz-transform: translate3d(0, 0, 0); + -o-transform: translate3d(0, 0, 0); + -ms-transform: translate3d(0, 0, 0); + transform: translate3d(0, 0, 0); +} +#article-container figure.gallery-group img { + position: relative; + margin: 0; + max-width: none; + width: calc(100% + 20px); + height: 250px; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + opacity: 0.8; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)"; + filter: alpha(opacity=80); + -webkit-transition: all 0.3s, filter 375ms ease-in 0.2s; + -moz-transition: all 0.3s, filter 375ms ease-in 0.2s; + -o-transition: all 0.3s, filter 375ms ease-in 0.2s; + -ms-transition: all 0.3s, filter 375ms ease-in 0.2s; + transition: all 0.3s, filter 375ms ease-in 0.2s; + -webkit-transform: translate3d(-10px, 0, 0); + -moz-transform: translate3d(-10px, 0, 0); + -o-transform: translate3d(-10px, 0, 0); + -ms-transform: translate3d(-10px, 0, 0); + transform: translate3d(-10px, 0, 0); + object-fit: cover; +} +#article-container figure.gallery-group figcaption { + position: absolute; + top: 0; + left: 0; + padding: 30px; + width: 100%; + height: 100%; + color: #fff; + text-transform: uppercase; + -webkit-backface-visibility: hidden; + -moz-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; +} +#article-container figure.gallery-group figcaption > a { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container figure.gallery-group p { + margin: 0; + padding: 8px 0 0; + letter-spacing: 1px; + font-size: 1.1em; + line-height: 1.5; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); + -webkit-transition: opacity 0.35s, -webkit-transform 0.35s; + -moz-transition: opacity 0.35s, -moz-transform 0.35s; + -o-transition: opacity 0.35s, -o-transform 0.35s; + -ms-transition: opacity 0.35s, -ms-transform 0.35s; + transition: opacity 0.35s, transform 0.35s; + -webkit-transform: translate3d(100%, 0, 0); + -moz-transform: translate3d(100%, 0, 0); + -o-transform: translate3d(100%, 0, 0); + -ms-transform: translate3d(100%, 0, 0); + transform: translate3d(100%, 0, 0); + -webkit-line-clamp: 4; +} +#article-container figure.gallery-group .gallery-group-name { + position: relative; + margin: 0; + padding: 8px 0; + font-weight: bold; + font-size: 1.65em; + line-height: 1.5; + -webkit-line-clamp: 2; +} +#article-container figure.gallery-group .gallery-group-name:after { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 2px; + background: #fff; + content: ''; + -webkit-transition: -webkit-transform 0.35s; + -moz-transition: -moz-transform 0.35s; + -o-transition: -o-transform 0.35s; + -ms-transition: -ms-transform 0.35s; + transition: transform 0.35s; + -webkit-transform: translate3d(-100%, 0, 0); + -moz-transform: translate3d(-100%, 0, 0); + -o-transform: translate3d(-100%, 0, 0); + -ms-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); +} +#article-container .gallery-group-main { + overflow: auto; + padding: 0 0 16px; +} +#article-container .fj-gallery { + margin: 0 0 16px; + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +#article-container .fj-gallery .img-alt { + display: none; +} +blockquote.pullquote { + position: relative; + max-width: 45%; + font-size: 110%; +} +blockquote.pullquote.left { + float: left; + margin: 1em 0.5em 0 0; +} +blockquote.pullquote.right { + float: right; + margin: 1em 0 0 0.5em; +} +.video-container { + position: relative; + overflow: hidden; + margin-bottom: 16px; + padding-top: 56.25%; + height: 0; +} +.video-container iframe { + position: absolute; + top: 0; + left: 0; + margin-top: 0; + width: 100%; + height: 100%; +} +.hide-inline > .hide-button, +.hide-block > .hide-button { + display: inline-block; + padding: 5px 18px; + background: #49b1f5; + color: var(--white); +} +.hide-inline > .hide-button:hover, +.hide-block > .hide-button:hover { + background-color: var(--btn-hover-color); +} +.hide-inline > .hide-button.open, +.hide-block > .hide-button.open { + display: none; +} +.hide-inline > .hide-button.open + div, +.hide-block > .hide-button.open + div { + display: block; +} +.hide-inline > .hide-button.open + span, +.hide-block > .hide-button.open + span { + display: inline; +} +.hide-inline > .hide-content, +.hide-block > .hide-content { + display: none; +} +.hide-inline > .hide-button { + margin: 0 6px; +} +.hide-inline > .hide-content { + margin: 0 6px; +} +.hide-block { + margin: 0 0 16px; +} +.toggle { + margin-bottom: 20px; + border: 1px solid #f0f0f0; +} +.toggle > .toggle-button { + padding: 6px 15px; + background: #f0f0f0; + color: #1f2d3d; + cursor: pointer; +} +.toggle > .toggle-content { + margin: 30px 24px; +} +#article-container .inline-img { + display: inline; + margin: 0 3px; + height: 1.1em; + vertical-align: text-bottom; +} +.hl-label { + padding: 2px 4px; + border-radius: 3px; + color: #fff; +} +.hl-label.default { + background-color: #777; +} +.hl-label.blue { + background-color: #428bca; +} +.hl-label.pink { + background-color: #ff69b4; +} +.hl-label.red { + background-color: #f00; +} +.hl-label.purple { + background-color: #6f42c1; +} +.hl-label.orange { + background-color: #ff8c00; +} +.hl-label.green { + background-color: #5cb85c; +} +.note { + position: relative; + margin: 0 0 20px; + padding: 15px; + border-radius: 3px; +} +.note.icon-padding { + padding-left: 3em; +} +.note > .note-icon { + position: absolute; + top: calc(50% - 0.5em); + left: 0.8em; + font-size: larger; +} +.note.blue:not(.disabled) { + border-left-color: #428bca !important; +} +.note.blue:not(.disabled).modern { + border-left-color: transparent !important; + color: #428bca; +} +.note.blue:not(.disabled):not(.simple) { + background: #e3eef7 !important; +} +.note.blue > .note-icon { + color: #428bca; +} +.note.pink:not(.disabled) { + border-left-color: #ff69b4 !important; +} +.note.pink:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff69b4; +} +.note.pink:not(.disabled):not(.simple) { + background: #ffe9f4 !important; +} +.note.pink > .note-icon { + color: #ff69b4; +} +.note.red:not(.disabled) { + border-left-color: #f00 !important; +} +.note.red:not(.disabled).modern { + border-left-color: transparent !important; + color: #f00; +} +.note.red:not(.disabled):not(.simple) { + background: #ffd9d9 !important; +} +.note.red > .note-icon { + color: #f00; +} +.note.purple:not(.disabled) { + border-left-color: #6f42c1 !important; +} +.note.purple:not(.disabled).modern { + border-left-color: transparent !important; + color: #6f42c1; +} +.note.purple:not(.disabled):not(.simple) { + background: #e9e3f6 !important; +} +.note.purple > .note-icon { + color: #6f42c1; +} +.note.orange:not(.disabled) { + border-left-color: #ff8c00 !important; +} +.note.orange:not(.disabled).modern { + border-left-color: transparent !important; + color: #ff8c00; +} +.note.orange:not(.disabled):not(.simple) { + background: #ffeed9 !important; +} +.note.orange > .note-icon { + color: #ff8c00; +} +.note.green:not(.disabled) { + border-left-color: #5cb85c !important; +} +.note.green:not(.disabled).modern { + border-left-color: transparent !important; + color: #5cb85c; +} +.note.green:not(.disabled):not(.simple) { + background: #e7f4e7 !important; +} +.note.green > .note-icon { + color: #5cb85c; +} +.note.simple { + border: 1px solid #eee; + border-left-width: 5px; +} +.note.modern { + border: 1px solid transparent !important; + background-color: #f5f5f5; + color: #4c4948; +} +.note.flat { + border: initial; + border-left: 5px solid #eee; + background-color: #f9f9f9; + color: #4c4948; +} +.note h2, +.note h3, +.note h4, +.note h5, +.note h6 { + margin-top: 3px; + margin-bottom: 0; + padding-top: 0 !important; + border-bottom: initial; +} +.note p:first-child, +.note ul:first-child, +.note ol:first-child, +.note table:first-child, +.note pre:first-child, +.note blockquote:first-child, +.note img:first-child { + margin-top: 0 !important; +} +.note p:last-child, +.note ul:last-child, +.note ol:last-child, +.note table:last-child, +.note pre:last-child, +.note blockquote:last-child, +.note img:last-child { + margin-bottom: 0 !important; +} +.note:not(.no-icon) { + padding-left: 3em; +} +.note:not(.no-icon)::before { + position: absolute; + top: calc(50% - 0.95em); + left: 0.8em; + font-size: larger; +} +.note.default.flat { + background: #f7f7f7; +} +.note.default.modern { + border-color: #e1e1e1; + background: #f3f3f3; + color: #666; +} +.note.default.modern a:not(.btn) { + color: #666; +} +.note.default.modern a:not(.btn):hover { + color: #454545; +} +.note.default:not(.modern) { + border-left-color: #777; +} +.note.default:not(.modern) h2, +.note.default:not(.modern) h3, +.note.default:not(.modern) h4, +.note.default:not(.modern) h5, +.note.default:not(.modern) h6 { + color: #777; +} +.note.default:not(.no-icon)::before { + content: '\f0a9'; +} +.note.default:not(.no-icon):not(.modern)::before { + color: #777; +} +.note.primary.flat { + background: #f5f0fa; +} +.note.primary.modern { + border-color: #e1c2ff; + background: #f3daff; + color: #6f42c1; +} +.note.primary.modern a:not(.btn) { + color: #6f42c1; +} +.note.primary.modern a:not(.btn):hover { + color: #453298; +} +.note.primary:not(.modern) { + border-left-color: #6f42c1; +} +.note.primary:not(.modern) h2, +.note.primary:not(.modern) h3, +.note.primary:not(.modern) h4, +.note.primary:not(.modern) h5, +.note.primary:not(.modern) h6 { + color: #6f42c1; +} +.note.primary:not(.no-icon)::before { + content: '\f055'; +} +.note.primary:not(.no-icon):not(.modern)::before { + color: #6f42c1; +} +.note.info.flat { + background: #eef7fa; +} +.note.info.modern { + border-color: #b3e5ef; + background: #d9edf7; + color: #31708f; +} +.note.info.modern a:not(.btn) { + color: #31708f; +} +.note.info.modern a:not(.btn):hover { + color: #215761; +} +.note.info:not(.modern) { + border-left-color: #428bca; +} +.note.info:not(.modern) h2, +.note.info:not(.modern) h3, +.note.info:not(.modern) h4, +.note.info:not(.modern) h5, +.note.info:not(.modern) h6 { + color: #428bca; +} +.note.info:not(.no-icon)::before { + content: '\f05a'; +} +.note.info:not(.no-icon):not(.modern)::before { + color: #428bca; +} +.note.success.flat { + background: #eff8f0; +} +.note.success.modern { + border-color: #d0e6be; + background: #dff0d8; + color: #3c763d; +} +.note.success.modern a:not(.btn) { + color: #3c763d; +} +.note.success.modern a:not(.btn):hover { + color: #32562c; +} +.note.success:not(.modern) { + border-left-color: #5cb85c; +} +.note.success:not(.modern) h2, +.note.success:not(.modern) h3, +.note.success:not(.modern) h4, +.note.success:not(.modern) h5, +.note.success:not(.modern) h6 { + color: #5cb85c; +} +.note.success:not(.no-icon)::before { + content: '\f058'; +} +.note.success:not(.no-icon):not(.modern)::before { + color: #5cb85c; +} +.note.warning.flat { + background: #fdf8ea; +} +.note.warning.modern { + border-color: #fae4cd; + background: #fcf4e3; + color: #8a6d3b; +} +.note.warning.modern a:not(.btn) { + color: #8a6d3b; +} +.note.warning.modern a:not(.btn):hover { + color: #714f30; +} +.note.warning:not(.modern) { + border-left-color: #f0ad4e; +} +.note.warning:not(.modern) h2, +.note.warning:not(.modern) h3, +.note.warning:not(.modern) h4, +.note.warning:not(.modern) h5, +.note.warning:not(.modern) h6 { + color: #f0ad4e; +} +.note.warning:not(.no-icon)::before { + content: '\f06a'; +} +.note.warning:not(.no-icon):not(.modern)::before { + color: #f0ad4e; +} +.note.danger.flat { + background: #fcf1f2; +} +.note.danger.modern { + border-color: #ebcdd2; + background: #f2dfdf; + color: #a94442; +} +.note.danger.modern a:not(.btn) { + color: #a94442; +} +.note.danger.modern a:not(.btn):hover { + color: #84333f; +} +.note.danger:not(.modern) { + border-left-color: #d9534f; +} +.note.danger:not(.modern) h2, +.note.danger:not(.modern) h3, +.note.danger:not(.modern) h4, +.note.danger:not(.modern) h5, +.note.danger:not(.modern) h6 { + color: #d9534f; +} +.note.danger:not(.no-icon)::before { + content: '\f056'; +} +.note.danger:not(.no-icon):not(.modern)::before { + color: #d9534f; +} +#article-container .tabs { + position: relative; + margin: 0 0 20px; + border-right: 1px solid var(--tab-border-color); + border-bottom: 1px solid var(--tab-border-color); + border-left: 1px solid var(--tab-border-color); +} +#article-container .tabs > .nav-tabs { + display: -webkit-box; + display: -moz-box; + display: -webkit-flex; + display: -ms-flexbox; + display: box; + display: flex; + -webkit-box-lines: multiple; + -moz-box-lines: multiple; + -o-box-lines: multiple; + -webkit-flex-wrap: wrap; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + margin: 0; + padding: 0; + background: var(--tab-botton-bg); +} +#article-container .tabs > .nav-tabs > .tab { + margin: 0; + padding: 0; + list-style: none; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .nav-tabs > .tab { + -webkit-box-flex: 1; + -moz-box-flex: 1; + -o-box-flex: 1; + -ms-box-flex: 1; + box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; + } +} +#article-container .tabs > .nav-tabs > .tab button { + display: block; + padding: 8px 18px; + width: 100%; + border-top: 2px solid var(--tab-border-color); + background: var(--tab-botton-bg); + color: var(--tab-botton-color); + line-height: 2; + -webkit-transition: all 0.4s; + -moz-transition: all 0.4s; + -o-transition: all 0.4s; + -ms-transition: all 0.4s; + transition: all 0.4s; +} +#article-container .tabs > .nav-tabs > .tab button i { + width: 1.5em; +} +#article-container .tabs > .nav-tabs > .tab.active button { + border-top: 2px solid #49b1f5; + background: var(--tab-button-active-bg); + cursor: default; +} +#article-container .tabs > .nav-tabs > .tab:not(.active) button:hover { + border-top: 2px solid var(--tab-button-hover-bg); + background: var(--tab-button-hover-bg); +} +#article-container .tabs > .tab-contents .tab-item-content { + position: relative; + display: none; + padding: 36px 24px; +} +@media screen and (max-width: 768px) { + #article-container .tabs > .tab-contents .tab-item-content { + padding: 24px 14px; + } +} +#article-container .tabs > .tab-contents .tab-item-content.active { + display: block; + -webkit-animation: tabshow 0.5s; + -moz-animation: tabshow 0.5s; + -o-animation: tabshow 0.5s; + -ms-animation: tabshow 0.5s; + animation: tabshow 0.5s; +} +#article-container .tabs .tab-to-top { + position: relative; + display: block; + margin: 0 0 0 auto; + color: #99a9bf; +} +@-moz-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-webkit-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@-o-keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes tabshow { + 0% { + -webkit-transform: translateY(15px); + -moz-transform: translateY(15px); + -o-transform: translateY(15px); + -ms-transform: translateY(15px); + transform: translateY(15px); + } + 100% { + -webkit-transform: translateY(0); + -moz-transform: translateY(0); + -o-transform: translateY(0); + -ms-transform: translateY(0); + transform: translateY(0); + } +} +#article-container .timeline { + margin: 0 0 20px 10px; + padding: 14px 20px 5px; + border-left: 2px solid var(--timeline-color, #49b1f5); +} +#article-container .timeline.blue { + --timeline-color: #428bca; + --timeline-bg: rgba(66,139,202, 0.2); +} +#article-container .timeline.pink { + --timeline-color: #ff69b4; + --timeline-bg: rgba(255,105,180, 0.2); +} +#article-container .timeline.red { + --timeline-color: #f00; + --timeline-bg: rgba(255,0,0, 0.2); +} +#article-container .timeline.purple { + --timeline-color: #6f42c1; + --timeline-bg: rgba(111,66,193, 0.2); +} +#article-container .timeline.orange { + --timeline-color: #ff8c00; + --timeline-bg: rgba(255,140,0, 0.2); +} +#article-container .timeline.green { + --timeline-color: #5cb85c; + --timeline-bg: rgba(92,184,92, 0.2); +} +#article-container .timeline .timeline-item { + margin: 0 0 15px; +} +#article-container .timeline .timeline-item:hover .item-circle:before { + border-color: var(--timeline-color, #49b1f5); +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle > p { + font-weight: 600; + font-size: 1.2em; +} +#article-container .timeline .timeline-item.headline .timeline-item-title .item-circle:before { + left: -28px; + border: 4px solid var(--timeline-color, #49b1f5); +} +#article-container .timeline .timeline-item.headline:hover .item-circle:before { + border-color: var(--pseudo-hover); +} +#article-container .timeline .timeline-item .timeline-item-title { + position: relative; +} +#article-container .timeline .timeline-item .item-circle:before { + position: absolute; + top: 50%; + left: -27px; + width: 6px; + height: 6px; + border: 3px solid var(--pseudo-hover); + border-radius: 50%; + background: var(--card-bg); + content: ''; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + -o-transition: all 0.3s; + -ms-transition: all 0.3s; + transition: all 0.3s; + -webkit-transform: translate(0, -50%); + -moz-transform: translate(0, -50%); + -o-transform: translate(0, -50%); + -ms-transform: translate(0, -50%); + transform: translate(0, -50%); +} +#article-container .timeline .timeline-item .item-circle > p { + margin: 0 0 8px; + font-weight: 500; +} +#article-container .timeline .timeline-item .timeline-item-content { + position: relative; + padding: 12px 15px; + border-radius: 8px; + background: var(--timeline-bg, #e4f3fd); + font-size: 0.93em; +} +#article-container .timeline .timeline-item .timeline-item-content > :last-child { + margin-bottom: 0; +} +#article-container .timeline + .timeline { + margin-top: -20px; +} +[data-theme='dark'] { + --global-bg: #0d0d0d; + --font-color: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.4); + --hr-before-color: rgba(255,255,255,0.7); + --search-bg: #121212; + --search-input-color: rgba(255,255,255,0.7); + --search-result-title: rgba(255,255,255,0.9); + --preloader-bg: #0d0d0d; + --preloader-color: rgba(255,255,255,0.7); + --tab-border-color: #2c2c2c; + --tab-botton-bg: #2c2c2c; + --tab-botton-color: rgba(255,255,255,0.7); + --tab-button-hover-bg: #383838; + --tab-button-active-bg: #121212; + --card-bg: #121212; + --sidebar-bg: #121212; + --btn-hover-color: #787878; + --btn-color: rgba(255,255,255,0.7); + --btn-bg: #1f1f1f; + --text-bg-hover: #383838; + --light-grey: rgba(255,255,255,0.7); + --dark-grey: rgba(255,255,255,0.2); + --white: rgba(255,255,255,0.9); + --text-highlight-color: rgba(255,255,255,0.9); + --blockquote-color: rgba(255,255,255,0.7); + --blockquote-bg: #2c2c2c; + --reward-pop: #2c2c2c; + --toc-link-color: rgba(255,255,255,0.6); + --hl-color: rgba(255,255,255,0.7); + --hl-bg: #171717; + --hltools-bg: #1a1a1a; + --hltools-color: #90a4ae; + --hlnumber-bg: #171717; + --hlnumber-color: rgba(255,255,255,0.4); + --hlscrollbar-bg: #1f1f1f; + --hlexpand-bg: linear-gradient(180deg, rgba(23,23,23,0.6), rgba(23,23,23,0.9)); + --scrollbar-color: #1f1f1f; + --timeline-bg: #1f1f1f; +} +[data-theme='dark'] #web_bg:before, +[data-theme='dark'] #footer:before, +[data-theme='dark'] #page-header:before { + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.7); + content: ''; +} +[data-theme='dark'] #article-container code { + background: #2c2c2c; +} +[data-theme='dark'] #article-container pre > code { + background: #171717; +} +[data-theme='dark'] #article-container figure.highlight { + -webkit-box-shadow: none; + box-shadow: none; +} +[data-theme='dark'] #article-container .note code { + background: rgba(27,31,35,0.05); +} +[data-theme='dark'] #article-container .aplayer { + filter: brightness(0.8); +} +[data-theme='dark'] #article-container kbd { + border-color: #696969; + background-color: #525252; + color: #e2f1ff; +} +[data-theme='dark'] #page-header.nav-fixed > #nav, +[data-theme='dark'] #page-header.not-top-img > #nav { + background: rgba(18,18,18,0.8); + -webkit-box-shadow: 0 5px 6px -5px rgba(133,133,133,0); + box-shadow: 0 5px 6px -5px rgba(133,133,133,0); +} +[data-theme='dark'] #post-comment #comment-switch { + background: #2c2c2c !important; +} +[data-theme='dark'] #post-comment #comment-switch .switch-btn { + filter: brightness(0.8); +} +[data-theme='dark'] .note { + filter: brightness(0.8); +} +[data-theme='dark'] .hide-button, +[data-theme='dark'] .btn-beautify, +[data-theme='dark'] .hl-label, +[data-theme='dark'] .post-outdate-notice, +[data-theme='dark'] .error-img, +[data-theme='dark'] #article-container iframe, +[data-theme='dark'] .gist, +[data-theme='dark'] .ads-wrap { + filter: brightness(0.8); +} +[data-theme='dark'] img { + filter: brightness(0.8); +} +[data-theme='dark'] #aside-content .aside-list > .aside-list-item:not(:last-child) { + border-bottom: 1px dashed rgba(255,255,255,0.1); +} +[data-theme='dark'] #gitalk-container { + filter: brightness(0.8); +} +[data-theme='dark'] #gitalk-container svg { + fill: rgba(255,255,255,0.9) !important; +} +[data-theme='dark'] #disqusjs #dsqjs:hover, +[data-theme='dark'] #disqusjs #dsqjs:focus, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-tab-active, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-no-comment { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-order-label { + background-color: #1f1f1f; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body code, +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body pre { + background: #2c2c2c; +} +[data-theme='dark'] #disqusjs #dsqjs .dsqjs-post-body blockquote { + color: rgba(255,255,255,0.7); +} +[data-theme='dark'] #artitalk_main #lazy { + background: #121212; +} +[data-theme='dark'] #operare_artitalk .c2 { + background: #121212; +} +@media screen and (max-width: 900px) { + [data-theme='dark'] #card-toc { + background: #1f1f1f; + } +} +.read-mode { + --font-color: #4c4948; + --readmode-light-color: #fff; + --white: #4c4948; + --light-grey: #4c4948; + --gray: #d6dbdf; + --hr-border: #d6dbdf; + --hr-before-color: #b9c2c9; + --highlight-bg: #f7f7f7; + --exit-btn-bg: #c0c0c0; + --exit-btn-color: #fff; + --exit-btn-hover: #8d8d8d; + --pseudo-hover: none; +} +[data-theme='dark'] .read-mode { + --font-color: rgba(255,255,255,0.7); + --readmode-light-color: #0d0d0d; + --white: rgba(255,255,255,0.9); + --light-grey: rgba(255,255,255,0.7); + --gray: rgba(255,255,255,0.7); + --hr-border: rgba(255,255,255,0.5); + --hr-before-color: rgba(255,255,255,0.7); + --highlight-bg: #171717; + --exit-btn-bg: #1f1f1f; + --exit-btn-color: rgba(255,255,255,0.9); + --exit-btn-hover: #525252; +} +.read-mode { + background: var(--readmode-light-color); +} +.read-mode .exit-readmode { + position: fixed; + top: 30px; + right: 30px; + z-index: 100; + width: 40px; + height: 40px; + border-radius: 8px; + background: var(--exit-btn-bg); + color: var(--exit-btn-color); + font-size: 16px; + -webkit-transition: background 0.3s; + -moz-transition: background 0.3s; + -o-transition: background 0.3s; + -ms-transition: background 0.3s; + transition: background 0.3s; +} +@media screen and (max-width: 768px) { + .read-mode .exit-readmode { + top: initial; + bottom: 30px; + } +} +.read-mode .exit-readmode:hover { + background: var(--exit-btn-hover); +} +.read-mode #aside-content { + display: none; +} +.read-mode #page-header.post-bg { + background-color: transparent; + background-image: none !important; +} +.read-mode #page-header.post-bg:before { + opacity: 0; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; + filter: alpha(opacity=0); +} +.read-mode #page-header.post-bg > #post-info { + text-align: center; +} +.read-mode #post { + margin: 0 auto; + background: transparent; + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode #post:hover { + -webkit-box-shadow: none; + box-shadow: none; +} +.read-mode > canvas { + display: none !important; +} +.read-mode .highlight-tools, +.read-mode #footer, +.read-mode #post > *:not(#post-info):not(.post-content), +.read-mode #nav, +.read-mode .post-outdate-notice, +.read-mode #web_bg, +.read-mode #rightside, +.read-mode .not-top-img { + display: none !important; +} +.read-mode #article-container a { + color: #99a9bf; +} +.read-mode #article-container pre, +.read-mode #article-container .highlight:not(.js-file-line-container) { + background: var(--highlight-bg) !important; +} +.read-mode #article-container pre *, +.read-mode #article-container .highlight:not(.js-file-line-container) * { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight { + border-radius: 0 !important; + -webkit-box-shadow: none !important; + box-shadow: none !important; +} +.read-mode #article-container figure.highlight > :not(.highlight-tools) { + display: block !important; +} +.read-mode #article-container figure.highlight .line:before { + color: var(--font-color) !important; +} +.read-mode #article-container figure.highlight .hljs { + background: var(-highlight-bg) !important; +} +.read-mode #article-container h1, +.read-mode #article-container h2, +.read-mode #article-container h3, +.read-mode #article-container h4, +.read-mode #article-container h5, +.read-mode #article-container h6 { + padding: 0; +} +.read-mode #article-container h1:before, +.read-mode #article-container h2:before, +.read-mode #article-container h3:before, +.read-mode #article-container h4:before, +.read-mode #article-container h5:before, +.read-mode #article-container h6:before { + content: ''; +} +.read-mode #article-container h1:hover, +.read-mode #article-container h2:hover, +.read-mode #article-container h3:hover, +.read-mode #article-container h4:hover, +.read-mode #article-container h5:hover, +.read-mode #article-container h6:hover { + padding: 0; +} +.read-mode #article-container ul:hover:before, +.read-mode #article-container li:hover:before, +.read-mode #article-container ol:hover:before { + -webkit-transform: none !important; + -moz-transform: none !important; + -o-transform: none !important; + -ms-transform: none !important; + transform: none !important; +} +.read-mode #article-container ol:before, +.read-mode #article-container li:before { + background: transparent !important; + color: var(--font-color) !important; +} +.read-mode #article-container ul >li:before { + border-color: var(--gray) !important; +} +.read-mode #article-container .tabs { + border: 2px solid var(--tab-border-color); +} +.read-mode #article-container .tabs > .nav-tabs { + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab { + border-bottom: 0; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button { + border-top: none !important; + background: transparent; +} +.read-mode #article-container .tabs > .nav-tabs > .tab button:hover { + background: none !important; +} +.read-mode #article-container .tabs > .nav-tabs > .tab.active button { + text-decoration: underline; +} +.read-mode #article-container .tabs > .tab-contents .tab-item-content.active { + -webkit-animation: none; + -moz-animation: none; + -o-animation: none; + -ms-animation: none; + animation: none; +} +.read-mode #article-container code { + color: var(--font-color); +} +.read-mode #article-container blockquote { + border-color: var(--gray); + background-color: var(--readmode-light-color); +} +.read-mode #article-container kbd { + border: 1px solid var(--gray); + background-color: transparent; + -webkit-box-shadow: none; + box-shadow: none; + color: var(--font-color); +} +.read-mode #article-container .hide-toggle { + border: 1px solid var(--gray) !important; +} +.read-mode #article-container .hide-button, +.read-mode #article-container .btn-beautify, +.read-mode #article-container .hl-label { + border: 1px solid var(--gray) !important; + background: var(--readmode-light-color) !important; + color: var(--font-color) !important; +} +.read-mode #article-container .note { + border: 2px solid var(--gray); + border-left-color: var(--gray) !important; + filter: none; + background-color: var(--readmode-light-color) !important; + color: var(--font-color); +} +.read-mode #article-container .note:before, +.read-mode #article-container .note .note-icon { + color: var(--font-color); +} +.search-dialog { + position: fixed; + top: 10%; + left: 50%; + z-index: 1001; + display: none; + margin-left: -300px; + padding: 20px; + width: 600px; + border-radius: 8px; + background: var(--search-bg); +} +@media screen and (max-width: 768px) { + .search-dialog { + top: 0; + left: 0; + margin: 0; + width: 100%; + height: 100%; + border-radius: 0; + } +} +.search-dialog hr { + margin: 20px auto; +} +.search-dialog .search-nav { + margin: 0 0 14px; + color: #49b1f5; + font-size: 1.4em; + line-height: 1; +} +.search-dialog .search-nav .search-dialog-title { + margin-right: 10px; +} +.search-dialog .search-nav .search-close-button { + float: right; + color: #858585; + -webkit-transition: color 0.2s ease-in-out; + -moz-transition: color 0.2s ease-in-out; + -o-transition: color 0.2s ease-in-out; + -ms-transition: color 0.2s ease-in-out; + transition: color 0.2s ease-in-out; +} +.search-dialog .search-nav .search-close-button:hover { + color: #49b1f5; +} +#search-mask { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 1000; + display: none; + background: rgba(0,0,0,0.6); +} +#local-search .search-dialog .local-search-box { + margin: 0 auto; + max-width: 100%; + width: 100%; +} +#local-search .search-dialog .local-search-box input { + padding: 5px 14px; + width: 100%; + outline: none; + border: 2px solid #49b1f5; + border-radius: 40px; + background: var(--search-bg); + color: var(--search-input-color); + -webkit-appearance: none; +} +#local-search .search-dialog .search-wrap { + display: none; +} +#local-search .search-dialog .local-search__hit-item { + position: relative; + padding-left: 24px; + line-height: 1.7; +} +#local-search .search-dialog .local-search__hit-item:hover:before { + border-color: var(--pseudo-hover); +} +#local-search .search-dialog .local-search__hit-item:before { + position: absolute; + top: 0.45em; + left: 0; + width: 0.5em; + height: 0.5em; + border: 3px solid #49b1f5; + border-radius: 0.5em; + background: transparent; + content: ''; + line-height: 0.5em; + -webkit-transition: all 0.2s ease-in-out; + -moz-transition: all 0.2s ease-in-out; + -o-transition: all 0.2s ease-in-out; + -ms-transition: all 0.2s ease-in-out; + transition: all 0.2s ease-in-out; +} +#local-search .search-dialog .local-search__hit-item a { + display: block; + color: var(--search-result-title); + font-weight: 600; + cursor: pointer; +} +#local-search .search-dialog .local-search__hit-item a:hover { + color: #49b1f5; +} +#local-search .search-dialog .local-search__hit-item .search-result { + margin: 0 8px 8px 0; + word-break: break-all; +} +#local-search .search-dialog .local-search__hit-item .search-keyword { + color: #f47466; + font-weight: bold; +} +#local-search .search-dialog .search-result-list { + overflow-y: auto; + max-height: calc(80vh - 130px); +} +@media screen and (max-width: 768px) { + #local-search .search-dialog .search-result-list { + padding-bottom: 40px; + max-height: 75vh !important; + } +} diff --git a/css/mine.css b/css/mine.css new file mode 100644 index 000000000..40e5f1da6 --- /dev/null +++ b/css/mine.css @@ -0,0 +1,21 @@ +/* 滚动条 */ + +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-thumb { + background-color: #e58a8a; + background-image: -webkit-linear-gradient( 45deg, rgba(255, 255, 255, 0.4) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.4) 50%, rgba(255, 255, 255, 0.4) 75%, transparent 75%, transparent); + border-radius: 2em; +} + +::-webkit-scrollbar-corner { + background-color: transparent; +} + +::-moz-selection { + color: #fff; + background-color: #e58a8a; +} diff --git a/placeholder b/css/var.css similarity index 100% rename from placeholder rename to css/var.css diff --git a/img/404.jpg b/img/404.jpg new file mode 100644 index 000000000..4bab3c3f2 Binary files /dev/null and b/img/404.jpg differ diff --git a/img/aniya.jpg b/img/aniya.jpg new file mode 100644 index 000000000..09f2894c0 Binary files /dev/null and b/img/aniya.jpg differ diff --git a/img/back.jpg b/img/back.jpg new file mode 100644 index 000000000..66e0aa840 Binary files /dev/null and b/img/back.jpg differ diff --git a/img/cover/anaconda.jpeg b/img/cover/anaconda.jpeg new file mode 100644 index 000000000..ff1dac4cc Binary files /dev/null and b/img/cover/anaconda.jpeg differ diff --git a/img/cover/hexo.png b/img/cover/hexo.png new file mode 100644 index 000000000..80c750160 Binary files /dev/null and b/img/cover/hexo.png differ diff --git a/img/cover/jupyter.jpeg b/img/cover/jupyter.jpeg new file mode 100644 index 000000000..9f3e0abdc Binary files /dev/null and b/img/cover/jupyter.jpeg differ diff --git a/img/cover/neurons.jpeg b/img/cover/neurons.jpeg new file mode 100644 index 000000000..0e9388d2a Binary files /dev/null and b/img/cover/neurons.jpeg differ diff --git a/img/cover/python.jpeg b/img/cover/python.jpeg new file mode 100644 index 000000000..5f5ff2558 Binary files /dev/null and b/img/cover/python.jpeg differ diff --git a/img/cover/sw.jpeg b/img/cover/sw.jpeg new file mode 100644 index 000000000..9c7eeb141 Binary files /dev/null and b/img/cover/sw.jpeg differ diff --git a/img/cover/upyun.jpeg b/img/cover/upyun.jpeg new file mode 100644 index 000000000..f15c587c7 Binary files /dev/null and b/img/cover/upyun.jpeg differ diff --git a/img/cover/windows.png b/img/cover/windows.png new file mode 100644 index 000000000..4d75e41ab Binary files /dev/null and b/img/cover/windows.png differ diff --git a/img/cover/zju.jpeg b/img/cover/zju.jpeg new file mode 100644 index 000000000..413886f73 Binary files /dev/null and b/img/cover/zju.jpeg differ diff --git a/img/favicon.png b/img/favicon.png new file mode 100644 index 000000000..862ebe858 Binary files /dev/null and b/img/favicon.png differ diff --git a/img/friend_404.gif b/img/friend_404.gif new file mode 100644 index 000000000..91dd56a28 Binary files /dev/null and b/img/friend_404.gif differ diff --git a/img/link/desmos.jpeg b/img/link/desmos.jpeg new file mode 100644 index 000000000..7ba59757a Binary files /dev/null and b/img/link/desmos.jpeg differ diff --git a/img/link/dlyt.jpg b/img/link/dlyt.jpg new file mode 100644 index 000000000..137010bc8 Binary files /dev/null and b/img/link/dlyt.jpg differ diff --git a/img/logo.png b/img/logo.png new file mode 100644 index 000000000..9927df4ca Binary files /dev/null and b/img/logo.png differ diff --git "a/img/post/CNAME\350\247\243\346\236\220.PNG" "b/img/post/CNAME\350\247\243\346\236\220.PNG" new file mode 100644 index 000000000..28499748c Binary files /dev/null and "b/img/post/CNAME\350\247\243\346\236\220.PNG" differ diff --git a/img/post/catalogue.png b/img/post/catalogue.png new file mode 100644 index 000000000..4bb4423c6 Binary files /dev/null and b/img/post/catalogue.png differ diff --git a/img/post/hddm_test.PNG b/img/post/hddm_test.PNG new file mode 100644 index 000000000..e78f3170c Binary files /dev/null and b/img/post/hddm_test.PNG differ diff --git a/img/post/jupyter_extension.png b/img/post/jupyter_extension.png new file mode 100644 index 000000000..788e2526d Binary files /dev/null and b/img/post/jupyter_extension.png differ diff --git a/img/post/ping.jpg b/img/post/ping.jpg new file mode 100644 index 000000000..5a06d11ee Binary files /dev/null and b/img/post/ping.jpg differ diff --git a/img/post/toc2.png b/img/post/toc2.png new file mode 100644 index 000000000..facd625e6 Binary files /dev/null and b/img/post/toc2.png differ diff --git "a/img/post/\345\210\233\345\273\272CDN\346\234\215\345\212\241.PNG" "b/img/post/\345\210\233\345\273\272CDN\346\234\215\345\212\241.PNG" new file mode 100644 index 000000000..d3dc26f49 Binary files /dev/null and "b/img/post/\345\210\233\345\273\272CDN\346\234\215\345\212\241.PNG" differ diff --git "a/img/post/\345\217\210\346\213\215\344\272\221\350\201\224\347\233\237-\346\255\245\351\252\244.JPEG" "b/img/post/\345\217\210\346\213\215\344\272\221\350\201\224\347\233\237-\346\255\245\351\252\244.JPEG" new file mode 100644 index 000000000..52f0c31f5 Binary files /dev/null and "b/img/post/\345\217\210\346\213\215\344\272\221\350\201\224\347\233\237-\346\255\245\351\252\244.JPEG" differ diff --git "a/img/post/\345\274\200\345\220\257\346\234\215\345\212\241.png" "b/img/post/\345\274\200\345\220\257\346\234\215\345\212\241.png" new file mode 100644 index 000000000..ca5d3876e Binary files /dev/null and "b/img/post/\345\274\200\345\220\257\346\234\215\345\212\241.png" differ diff --git "a/img/post/\346\210\220\345\212\237\345\212\240\345\205\245\350\201\224\347\233\237.JPEG" "b/img/post/\346\210\220\345\212\237\345\212\240\345\205\245\350\201\224\347\233\237.JPEG" new file mode 100644 index 000000000..2717f0d77 Binary files /dev/null and "b/img/post/\346\210\220\345\212\237\345\212\240\345\205\245\350\201\224\347\233\237.JPEG" differ diff --git "a/img/post/\346\226\255\345\274\200\351\223\276\346\216\245.jpg" "b/img/post/\346\226\255\345\274\200\351\223\276\346\216\245.jpg" new file mode 100644 index 000000000..6ffa9fe32 Binary files /dev/null and "b/img/post/\346\226\255\345\274\200\351\223\276\346\216\245.jpg" differ diff --git "a/img/post/\346\227\240\346\263\225\350\216\267\345\276\227\350\256\270\345\217\257.png" "b/img/post/\346\227\240\346\263\225\350\216\267\345\276\227\350\256\270\345\217\257.png" new file mode 100644 index 000000000..6367153fc Binary files /dev/null and "b/img/post/\346\227\240\346\263\225\350\216\267\345\276\227\350\256\270\345\217\257.png" differ diff --git "a/img/post/\347\224\263\350\264\255\350\257\201\344\271\246.PNG" "b/img/post/\347\224\263\350\264\255\350\257\201\344\271\246.PNG" new file mode 100644 index 000000000..ff4f9f306 Binary files /dev/null and "b/img/post/\347\224\263\350\264\255\350\257\201\344\271\246.PNG" differ diff --git "a/img/post/\347\224\263\350\264\255\350\257\201\344\271\2462.PNG" "b/img/post/\347\224\263\350\264\255\350\257\201\344\271\2462.PNG" new file mode 100644 index 000000000..b615b2611 Binary files /dev/null and "b/img/post/\347\224\263\350\264\255\350\257\201\344\271\2462.PNG" differ diff --git "a/img/post/\347\255\211\345\276\205\350\257\206\345\210\253.jpg" "b/img/post/\347\255\211\345\276\205\350\257\206\345\210\253.jpg" new file mode 100644 index 000000000..5346850b0 Binary files /dev/null and "b/img/post/\347\255\211\345\276\205\350\257\206\345\210\253.jpg" differ diff --git "a/img/post/\347\273\221\345\256\232\345\237\237\345\220\215.PNG" "b/img/post/\347\273\221\345\256\232\345\237\237\345\220\215.PNG" new file mode 100644 index 000000000..9fc96c110 Binary files /dev/null and "b/img/post/\347\273\221\345\256\232\345\237\237\345\220\215.PNG" differ diff --git "a/img/post/\350\257\206\345\210\253\345\211\215.jpg" "b/img/post/\350\257\206\345\210\253\345\211\215.jpg" new file mode 100644 index 000000000..c1c3bbbb7 Binary files /dev/null and "b/img/post/\350\257\206\345\210\253\345\211\215.jpg" differ diff --git "a/img/post/\350\257\206\345\210\253\346\210\220\345\212\237.jpg" "b/img/post/\350\257\206\345\210\253\346\210\220\345\212\237.jpg" new file mode 100644 index 000000000..44be15806 Binary files /dev/null and "b/img/post/\350\257\206\345\210\253\346\210\220\345\212\237.jpg" differ diff --git "a/img/post/\350\257\206\345\210\253\347\211\271\345\276\201.jpg" "b/img/post/\350\257\206\345\210\253\347\211\271\345\276\201.jpg" new file mode 100644 index 000000000..78b0b8db1 Binary files /dev/null and "b/img/post/\350\257\206\345\210\253\347\211\271\345\276\201.jpg" differ diff --git "a/img/post/\351\205\215\347\275\256HTTPS.PNG" "b/img/post/\351\205\215\347\275\256HTTPS.PNG" new file mode 100644 index 000000000..8c4eb2567 Binary files /dev/null and "b/img/post/\351\205\215\347\275\256HTTPS.PNG" differ diff --git a/img/rabbit.jpg b/img/rabbit.jpg new file mode 100644 index 000000000..cd1a812ba Binary files /dev/null and b/img/rabbit.jpg differ diff --git a/index.html b/index.html new file mode 100644 index 000000000..14de1720f --- /dev/null +++ b/index.html @@ -0,0 +1,203 @@ +Stray Birds + + + + + + + + +
Hexo基本使用方法
Hexo标签外挂
小鼠脑立体定位手术
【arduino探索】点亮ST7789 1.3寸TFT屏幕
【文献学习】前额叶皮层在反转学习中预测状态转换
Github Desktop同步代码
下载教育版origin
记录电极支架制作步骤
在网页中实时显示当前时间
2023年度总结
\ No newline at end of file diff --git a/js/main.js b/js/main.js new file mode 100644 index 000000000..c185dbe0a --- /dev/null +++ b/js/main.js @@ -0,0 +1,778 @@ +document.addEventListener('DOMContentLoaded', function () { + let blogNameWidth, menusWidth, searchWidth, $nav + let mobileSidebarOpen = false + + const adjustMenu = (init) => { + if (init) { + blogNameWidth = document.getElementById('site-name').offsetWidth + const $menusEle = document.querySelectorAll('#menus .menus_item') + menusWidth = 0 + $menusEle.length && $menusEle.forEach(i => { menusWidth += i.offsetWidth }) + const $searchEle = document.querySelector('#search-button') + searchWidth = $searchEle ? $searchEle.offsetWidth : 0 + $nav = document.getElementById('nav') + } + + let hideMenuIndex = '' + if (window.innerWidth < 768) hideMenuIndex = true + else hideMenuIndex = blogNameWidth + menusWidth + searchWidth > $nav.offsetWidth - 120 + + if (hideMenuIndex) { + $nav.classList.add('hide-menu') + } else { + $nav.classList.remove('hide-menu') + } + } + + // 初始化header + const initAdjust = () => { + adjustMenu(true) + $nav.classList.add('show') + } + + // sidebar menus + const sidebarFn = { + open: () => { + btf.sidebarPaddingR() + document.body.style.overflow = 'hidden' + btf.animateIn(document.getElementById('menu-mask'), 'to_show 0.5s') + document.getElementById('sidebar-menus').classList.add('open') + mobileSidebarOpen = true + }, + close: () => { + const $body = document.body + $body.style.overflow = '' + $body.style.paddingRight = '' + btf.animateOut(document.getElementById('menu-mask'), 'to_hide 0.5s') + document.getElementById('sidebar-menus').classList.remove('open') + mobileSidebarOpen = false + } + } + + /** + * 首頁top_img底下的箭頭 + */ + const scrollDownInIndex = () => { + const $scrollDownEle = document.getElementById('scroll-down') + $scrollDownEle && $scrollDownEle.addEventListener('click', function () { + btf.scrollToDest(document.getElementById('content-inner').offsetTop, 300) + }) + } + + /** + * 代碼 + * 只適用於Hexo默認的代碼渲染 + */ + const addHighlightTool = function () { + const highLight = GLOBAL_CONFIG.highlight + if (!highLight) return + + const isHighlightCopy = highLight.highlightCopy + const isHighlightLang = highLight.highlightLang + const isHighlightShrink = GLOBAL_CONFIG_SITE.isHighlightShrink + const highlightHeightLimit = highLight.highlightHeightLimit + const isShowTool = isHighlightCopy || isHighlightLang || isHighlightShrink !== undefined + const $figureHighlight = highLight.plugin === 'highlighjs' ? document.querySelectorAll('figure.highlight') : document.querySelectorAll('pre[class*="language-"]') + + if (!((isShowTool || highlightHeightLimit) && $figureHighlight.length)) return + + const isPrismjs = highLight.plugin === 'prismjs' + + let highlightShrinkEle = '' + let highlightCopyEle = '' + const highlightShrinkClass = isHighlightShrink === true ? 'closed' : '' + + if (isHighlightShrink !== undefined) { + highlightShrinkEle = `` + } + + if (isHighlightCopy) { + highlightCopyEle = '
' + } + + const copy = (text, ctx) => { + if (document.queryCommandSupported && document.queryCommandSupported('copy')) { + document.execCommand('copy') + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.success) + } else { + const prevEle = ctx.previousElementSibling + prevEle.innerText = GLOBAL_CONFIG.copy.success + prevEle.style.opacity = 1 + setTimeout(() => { prevEle.style.opacity = 0 }, 700) + } + } else { + if (GLOBAL_CONFIG.Snackbar !== undefined) { + btf.snackbarShow(GLOBAL_CONFIG.copy.noSupport) + } else { + ctx.previousElementSibling.innerText = GLOBAL_CONFIG.copy.noSupport + } + } + } + + // click events + const highlightCopyFn = (ele) => { + const $buttonParent = ele.parentNode + $buttonParent.classList.add('copy-true') + const selection = window.getSelection() + const range = document.createRange() + if (isPrismjs) range.selectNodeContents($buttonParent.querySelectorAll('pre code')[0]) + else range.selectNodeContents($buttonParent.querySelectorAll('table .code pre')[0]) + selection.removeAllRanges() + selection.addRange(range) + const text = selection.toString() + copy(text, ele.lastChild) + selection.removeAllRanges() + $buttonParent.classList.remove('copy-true') + } + + const highlightShrinkFn = (ele) => { + const $nextEle = [...ele.parentNode.children].slice(1) + ele.firstChild.classList.toggle('closed') + if (btf.isHidden($nextEle[$nextEle.length - 1])) { + $nextEle.forEach(e => { e.style.display = 'block' }) + } else { + $nextEle.forEach(e => { e.style.display = 'none' }) + } + } + + const highlightToolsFn = function (e) { + const $target = e.target.classList + if ($target.contains('expand')) highlightShrinkFn(this) + else if ($target.contains('copy-button')) highlightCopyFn(this) + } + + const expandCode = function () { + this.classList.toggle('expand-done') + } + + function createEle (lang, item, service) { + const fragment = document.createDocumentFragment() + + if (isShowTool) { + const hlTools = document.createElement('div') + hlTools.className = `highlight-tools ${highlightShrinkClass}` + hlTools.innerHTML = highlightShrinkEle + lang + highlightCopyEle + hlTools.addEventListener('click', highlightToolsFn) + fragment.appendChild(hlTools) + } + + if (highlightHeightLimit && item.offsetHeight > highlightHeightLimit + 30) { + const ele = document.createElement('div') + ele.className = 'code-expand-btn' + ele.innerHTML = '' + ele.addEventListener('click', expandCode) + fragment.appendChild(ele) + } + + if (service === 'hl') { + item.insertBefore(fragment, item.firstChild) + } else { + item.parentNode.insertBefore(fragment, item) + } + } + + if (isHighlightLang) { + if (isPrismjs) { + $figureHighlight.forEach(function (item) { + const langName = item.getAttribute('data-language') ? item.getAttribute('data-language') : 'Code' + const highlightLangEle = `
${langName}
` + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle(highlightLangEle, item) + }) + } else { + $figureHighlight.forEach(function (item) { + let langName = item.getAttribute('class').split(' ')[1] + if (langName === 'plain' || langName === undefined) langName = 'Code' + const highlightLangEle = `
${langName}
` + createEle(highlightLangEle, item, 'hl') + }) + } + } else { + if (isPrismjs) { + $figureHighlight.forEach(function (item) { + btf.wrap(item, 'figure', { class: 'highlight' }) + createEle('', item) + }) + } else { + $figureHighlight.forEach(function (item) { + createEle('', item, 'hl') + }) + } + } + } + + /** + * PhotoFigcaption + */ + function addPhotoFigcaption () { + document.querySelectorAll('#article-container img').forEach(function (item) { + const parentEle = item.parentNode + const altValue = item.title || item.alt + if (altValue && !parentEle.parentNode.classList.contains('justified-gallery')) { + const ele = document.createElement('div') + ele.className = 'img-alt is-center' + ele.textContent = altValue + parentEle.insertBefore(ele, item.nextSibling) + } + }) + } + + /** + * Lightbox + */ + const runLightbox = () => { + btf.loadLightbox(document.querySelectorAll('#article-container img:not(.no-lightbox)')) + } + + /** + * justified-gallery 圖庫排版 + */ + const runJustifiedGallery = function (ele) { + ele.forEach(item => { + const $imgList = item.querySelectorAll('img') + + $imgList.forEach(i => { + const dataLazySrc = i.getAttribute('data-lazy-src') + if (dataLazySrc) i.src = dataLazySrc + btf.wrap(i, 'div', { class: 'fj-gallery-item' }) + }) + }) + + if (window.fjGallery) { + setTimeout(() => { btf.initJustifiedGallery(ele) }, 100) + return + } + + const newEle = document.createElement('link') + newEle.rel = 'stylesheet' + newEle.href = GLOBAL_CONFIG.source.justifiedGallery.css + document.body.appendChild(newEle) + getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(() => { btf.initJustifiedGallery(ele) }) + } + + /** + * 滾動處理 + */ + const scrollFn = function () { + const $rightside = document.getElementById('rightside') + const innerHeight = window.innerHeight + 56 + + // 當滾動條小于 56 的時候 + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 1; transform: translateX(-58px)' + return + } + + // find the scroll direction + function scrollDirection (currentTop) { + const result = currentTop > initTop // true is down & false is up + initTop = currentTop + return result + } + + let initTop = 0 + let isChatShow = true + const $header = document.getElementById('page-header') + const isChatBtnHide = typeof chatBtnHide === 'function' + const isChatBtnShow = typeof chatBtnShow === 'function' + + window.scrollCollect = () => { + return btf.throttle(function (e) { + const currentTop = window.scrollY || document.documentElement.scrollTop + const isDown = scrollDirection(currentTop) + if (currentTop > 56) { + if (isDown) { + if ($header.classList.contains('nav-visible')) $header.classList.remove('nav-visible') + if (isChatBtnShow && isChatShow === true) { + chatBtnHide() + isChatShow = false + } + } else { + if (!$header.classList.contains('nav-visible')) $header.classList.add('nav-visible') + if (isChatBtnHide && isChatShow === false) { + chatBtnShow() + isChatShow = true + } + } + $header.classList.add('nav-fixed') + if (window.getComputedStyle($rightside).getPropertyValue('opacity') === '0') { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + } else { + if (currentTop === 0) { + $header.classList.remove('nav-fixed', 'nav-visible') + } + $rightside.style.cssText = "opacity: ''; transform: ''" + } + + if (document.body.scrollHeight <= innerHeight) { + $rightside.style.cssText = 'opacity: 0.8; transform: translateX(-58px)' + } + }, 200)() + } + + window.addEventListener('scroll', scrollCollect) + } + + /** + * toc,anchor + */ + const scrollFnToDo = function () { + const isToc = GLOBAL_CONFIG_SITE.isToc + const isAnchor = GLOBAL_CONFIG.isAnchor + const $article = document.getElementById('article-container') + + if (!($article && (isToc || isAnchor))) return + + let $tocLink, $cardToc, scrollPercent, autoScrollToc, isExpand + + if (isToc) { + const $cardTocLayout = document.getElementById('card-toc') + $cardToc = $cardTocLayout.getElementsByClassName('toc-content')[0] + $tocLink = $cardToc.querySelectorAll('.toc-link') + const $tocPercentage = $cardTocLayout.querySelector('.toc-percentage') + isExpand = $cardToc.classList.contains('is-expand') + + scrollPercent = currentTop => { + const docHeight = $article.clientHeight + const winHeight = document.documentElement.clientHeight + const headerHeight = $article.offsetTop + const contentMath = (docHeight > winHeight) ? (docHeight - winHeight) : (document.documentElement.scrollHeight - winHeight) + const scrollPercent = (currentTop - headerHeight) / (contentMath) + const scrollPercentRounded = Math.round(scrollPercent * 100) + const percentage = (scrollPercentRounded > 100) ? 100 : (scrollPercentRounded <= 0) ? 0 : scrollPercentRounded + $tocPercentage.textContent = percentage + } + + window.mobileToc = { + open: () => { + $cardTocLayout.style.cssText = 'animation: toc-open .3s; opacity: 1; right: 55px' + }, + + close: () => { + $cardTocLayout.style.animation = 'toc-close .2s' + setTimeout(() => { + $cardTocLayout.style.cssText = "opacity:''; animation: ''; right: ''" + }, 100) + } + } + + // toc元素點擊 + $cardToc.addEventListener('click', e => { + e.preventDefault() + const target = e.target.classList + if (target.contains('toc-content')) return + const $target = target.contains('toc-link') + ? e.target + : e.target.parentElement + btf.scrollToDest(btf.getEleTop(document.getElementById(decodeURI($target.getAttribute('href')).replace('#', ''))), 300) + if (window.innerWidth < 900) { + window.mobileToc.close() + } + }) + + autoScrollToc = item => { + const activePosition = item.getBoundingClientRect().top + const sidebarScrollTop = $cardToc.scrollTop + if (activePosition > (document.documentElement.clientHeight - 100)) { + $cardToc.scrollTop = sidebarScrollTop + 150 + } + if (activePosition < 100) { + $cardToc.scrollTop = sidebarScrollTop - 150 + } + } + } + + // find head position & add active class + const list = $article.querySelectorAll('h1,h2,h3,h4,h5,h6') + let detectItem = '' + const findHeadPosition = function (top) { + if (top === 0) { + return false + } + + let currentId = '' + let currentIndex = '' + + list.forEach(function (ele, index) { + if (top > btf.getEleTop(ele) - 80) { + const id = ele.id + currentId = id ? '#' + encodeURI(id) : '' + currentIndex = index + } + }) + + if (detectItem === currentIndex) return + + if (isAnchor) btf.updateAnchor(currentId) + + detectItem = currentIndex + + if (isToc) { + $cardToc.querySelectorAll('.active').forEach(i => { i.classList.remove('active') }) + + if (currentId === '') { + return + } + + const currentActive = $tocLink[currentIndex] + currentActive.classList.add('active') + + setTimeout(() => { + autoScrollToc(currentActive) + }, 0) + + if (isExpand) return + let parent = currentActive.parentNode + + for (; !parent.matches('.toc'); parent = parent.parentNode) { + if (parent.matches('li')) parent.classList.add('active') + } + } + } + + // main of scroll + window.tocScrollFn = function () { + return btf.throttle(function () { + const currentTop = window.scrollY || document.documentElement.scrollTop + isToc && scrollPercent(currentTop) + findHeadPosition(currentTop) + }, 100)() + } + window.addEventListener('scroll', tocScrollFn) + } + + /** + * Rightside + */ + const rightSideFn = { + switchReadMode: () => { // read-mode + const $body = document.body + $body.classList.add('read-mode') + const newEle = document.createElement('button') + newEle.type = 'button' + newEle.className = 'fas fa-sign-out-alt exit-readmode' + $body.appendChild(newEle) + + function clickFn () { + $body.classList.remove('read-mode') + newEle.remove() + newEle.removeEventListener('click', clickFn) + } + + newEle.addEventListener('click', clickFn) + }, + switchDarkMode: () => { // Switch Between Light And Dark Mode + const nowMode = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light' + if (nowMode === 'light') { + activateDarkMode() + saveToLocal.set('theme', 'dark', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.day_to_night) + } else { + activateLightMode() + saveToLocal.set('theme', 'light', 2) + GLOBAL_CONFIG.Snackbar !== undefined && btf.snackbarShow(GLOBAL_CONFIG.Snackbar.night_to_day) + } + // handle some cases + typeof utterancesTheme === 'function' && utterancesTheme() + typeof changeGiscusTheme === 'function' && changeGiscusTheme() + typeof FB === 'object' && window.loadFBComment() + typeof runMermaid === 'function' && window.runMermaid() + }, + showOrHideBtn: (e) => { // rightside 點擊設置 按鈕 展開 + const rightsideHideClassList = document.getElementById('rightside-config-hide').classList + rightsideHideClassList.toggle('show') + if (e.classList.contains('show')) { + rightsideHideClassList.add('status') + setTimeout(() => { + rightsideHideClassList.remove('status') + }, 300) + } + e.classList.toggle('show') + }, + scrollToTop: () => { // Back to top + btf.scrollToDest(0, 500) + }, + hideAsideBtn: () => { // Hide aside + const $htmlDom = document.documentElement.classList + $htmlDom.contains('hide-aside') + ? saveToLocal.set('aside-status', 'show', 2) + : saveToLocal.set('aside-status', 'hide', 2) + $htmlDom.toggle('hide-aside') + }, + + runMobileToc: () => { + if (window.getComputedStyle(document.getElementById('card-toc')).getPropertyValue('opacity') === '0') window.mobileToc.open() + else window.mobileToc.close() + } + } + + document.getElementById('rightside').addEventListener('click', function (e) { + const $target = e.target.id ? e.target : e.target.parentNode + switch ($target.id) { + case 'go-up': + rightSideFn.scrollToTop() + break + case 'rightside_config': + rightSideFn.showOrHideBtn($target) + break + case 'mobile-toc-button': + rightSideFn.runMobileToc() + break + case 'readmode': + rightSideFn.switchReadMode() + break + case 'darkmode': + rightSideFn.switchDarkMode() + break + case 'hide-aside-btn': + rightSideFn.hideAsideBtn() + break + default: + break + } + }) + + /** + * menu + * 側邊欄sub-menu 展開/收縮 + */ + const clickFnOfSubMenu = () => { + document.querySelectorAll('#sidebar-menus .site-page.group').forEach(function (item) { + item.addEventListener('click', function () { + this.classList.toggle('hide') + }) + }) + } + + /** + * 複製時加上版權信息 + */ + const addCopyright = () => { + const copyright = GLOBAL_CONFIG.copyright + document.body.oncopy = (e) => { + e.preventDefault() + let textFont; const copyFont = window.getSelection(0).toString() + if (copyFont.length > copyright.limitCount) { + textFont = copyFont + '\n' + '\n' + '\n' + + copyright.languages.author + '\n' + + copyright.languages.link + window.location.href + '\n' + + copyright.languages.source + '\n' + + copyright.languages.info + } else { + textFont = copyFont + } + if (e.clipboardData) { + return e.clipboardData.setData('text', textFont) + } else { + return window.clipboardData.setData('text', textFont) + } + } + } + + /** + * 網頁運行時間 + */ + const addRuntime = () => { + const $runtimeCount = document.getElementById('runtimeshow') + if ($runtimeCount) { + const publishDate = $runtimeCount.getAttribute('data-publishDate') + $runtimeCount.innerText = btf.diffDate(publishDate) + ' ' + GLOBAL_CONFIG.runtime + } + } + + /** + * 最後一次更新時間 + */ + const addLastPushDate = () => { + const $lastPushDateItem = document.getElementById('last-push-date') + if ($lastPushDateItem) { + const lastPushDate = $lastPushDateItem.getAttribute('data-lastPushDate') + $lastPushDateItem.innerText = btf.diffDate(lastPushDate, true) + } + } + + /** + * table overflow + */ + const addTableWrap = () => { + const $table = document.querySelectorAll('#article-container :not(.highlight) > table, #article-container > table') + if ($table.length) { + $table.forEach(item => { + btf.wrap(item, 'div', { class: 'table-wrap' }) + }) + } + } + + /** + * tag-hide + */ + const clickFnOfTagHide = function () { + const $hideInline = document.querySelectorAll('#article-container .hide-button') + if ($hideInline.length) { + $hideInline.forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + $this.classList.add('open') + const $fjGallery = $this.nextElementSibling.querySelectorAll('.fj-gallery') + $fjGallery.length && btf.initJustifiedGallery($fjGallery) + }) + }) + } + } + + const tabsFn = { + clickFnOfTabs: function () { + document.querySelectorAll('#article-container .tab > button').forEach(function (item) { + item.addEventListener('click', function (e) { + const $this = this + const $tabItem = $this.parentNode + + if (!$tabItem.classList.contains('active')) { + const $tabContent = $tabItem.parentNode.nextElementSibling + const $siblings = btf.siblings($tabItem, '.active')[0] + $siblings && $siblings.classList.remove('active') + $tabItem.classList.add('active') + const tabId = $this.getAttribute('data-href').replace('#', '') + const childList = [...$tabContent.children] + childList.forEach(item => { + if (item.id === tabId) item.classList.add('active') + else item.classList.remove('active') + }) + const $isTabJustifiedGallery = $tabContent.querySelectorAll(`#${tabId} .fj-gallery`) + if ($isTabJustifiedGallery.length > 0) { + btf.initJustifiedGallery($isTabJustifiedGallery) + } + } + }) + }) + }, + backToTop: () => { + document.querySelectorAll('#article-container .tabs .tab-to-top').forEach(function (item) { + item.addEventListener('click', function () { + btf.scrollToDest(btf.getEleTop(btf.getParents(this, '.tabs')), 300) + }) + }) + } + } + + const toggleCardCategory = function () { + const $cardCategory = document.querySelectorAll('#aside-cat-list .card-category-list-item.parent i') + if ($cardCategory.length) { + $cardCategory.forEach(function (item) { + item.addEventListener('click', function (e) { + e.preventDefault() + const $this = this + $this.classList.toggle('expand') + const $parentEle = $this.parentNode.nextElementSibling + if (btf.isHidden($parentEle)) { + $parentEle.style.display = 'block' + } else { + $parentEle.style.display = 'none' + } + }) + }) + } + } + + const switchComments = function () { + let switchDone = false + const $switchBtn = document.querySelector('#comment-switch > .switch-btn') + $switchBtn && $switchBtn.addEventListener('click', function () { + this.classList.toggle('move') + document.querySelectorAll('#post-comment > .comment-wrap > div').forEach(function (item) { + if (btf.isHidden(item)) { + item.style.cssText = 'display: block;animation: tabshow .5s' + } else { + item.style.cssText = "display: none;animation: ''" + } + }) + + if (!switchDone && typeof loadOtherComment === 'function') { + switchDone = true + loadOtherComment() + } + }) + } + + const addPostOutdateNotice = function () { + const data = GLOBAL_CONFIG.noticeOutdate + const diffDay = btf.diffDate(GLOBAL_CONFIG_SITE.postUpdate) + if (diffDay >= data.limitDay) { + const ele = document.createElement('div') + ele.className = 'post-outdate-notice' + ele.textContent = data.messagePrev + ' ' + diffDay + ' ' + data.messageNext + const $targetEle = document.getElementById('article-container') + if (data.position === 'top') { + $targetEle.insertBefore(ele, $targetEle.firstChild) + } else { + $targetEle.appendChild(ele) + } + } + } + + const lazyloadImg = () => { + window.lazyLoadInstance = new LazyLoad({ + elements_selector: 'img', + threshold: 0, + data_src: 'lazy-src' + }) + } + + const relativeDate = function (selector) { + selector.forEach(item => { + const $this = item + const timeVal = $this.getAttribute('datetime') + $this.innerText = btf.diffDate(timeVal, true) + $this.style.display = 'inline' + }) + } + + const unRefreshFn = function () { + window.addEventListener('resize', () => { + adjustMenu(false) + btf.isHidden(document.getElementById('toggle-menu')) && mobileSidebarOpen && sidebarFn.close() + }) + + document.getElementById('menu-mask').addEventListener('click', e => { sidebarFn.close() }) + + clickFnOfSubMenu() + GLOBAL_CONFIG.islazyload && lazyloadImg() + GLOBAL_CONFIG.copyright !== undefined && addCopyright() + } + + window.refreshFn = function () { + initAdjust() + + if (GLOBAL_CONFIG_SITE.isPost) { + GLOBAL_CONFIG.noticeOutdate !== undefined && addPostOutdateNotice() + GLOBAL_CONFIG.relativeDate.post && relativeDate(document.querySelectorAll('#post-meta time')) + } else { + GLOBAL_CONFIG.relativeDate.homepage && relativeDate(document.querySelectorAll('#recent-posts time')) + GLOBAL_CONFIG.runtime && addRuntime() + addLastPushDate() + toggleCardCategory() + } + + scrollFnToDo() + GLOBAL_CONFIG_SITE.isHome && scrollDownInIndex() + addHighlightTool() + GLOBAL_CONFIG.isPhotoFigcaption && addPhotoFigcaption() + scrollFn() + + const $jgEle = document.querySelectorAll('#article-container .fj-gallery') + $jgEle.length && runJustifiedGallery($jgEle) + + runLightbox() + addTableWrap() + clickFnOfTagHide() + tabsFn.clickFnOfTabs() + tabsFn.backToTop() + switchComments() + document.getElementById('toggle-menu').addEventListener('click', () => { sidebarFn.open() }) + } + + refreshFn() + unRefreshFn() +}) diff --git a/js/search/algolia.js b/js/search/algolia.js new file mode 100644 index 000000000..f0b9f3a97 --- /dev/null +++ b/js/search/algolia.js @@ -0,0 +1,163 @@ +window.addEventListener('load', () => { + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn(document.getElementById('search-mask'), 'to_show 0.5s') + btf.animateIn(document.querySelector('#algolia-search .search-dialog'), 'titleScale 0.5s') + setTimeout(() => { document.querySelector('#algolia-search .ais-SearchBox-input').focus() }, 100) + + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut(document.querySelector('#algolia-search .search-dialog'), 'search_close .5s') + btf.animateOut(document.getElementById('search-mask'), 'to_hide 0.5s') + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchClickFnOnce = () => { + document.getElementById('search-mask').addEventListener('click', closeSearch) + document.querySelector('#algolia-search .search-close-button').addEventListener('click', closeSearch) + } + + const cutContent = content => { + if (content === '') return '' + + const firstOccur = content.indexOf('') + + let start = firstOccur - 30 + let end = firstOccur + 120 + let pre = '' + let post = '' + + if (start <= 0) { + start = 0 + end = 140 + } else { + pre = '...' + } + + if (end > content.length) { + end = content.length + } else { + post = '...' + } + + let matchContent = pre + content.substring(start, end) + post + return matchContent + } + + const algolia = GLOBAL_CONFIG.algolia + const isAlgoliaValid = algolia.appId && algolia.apiKey && algolia.indexName + if (!isAlgoliaValid) { + return console.error('Algolia setting is invalid!') + } + + const search = instantsearch({ + indexName: algolia.indexName, + searchClient: algoliasearch(algolia.appId, algolia.apiKey), + searchFunction(helper) { + helper.state.query && helper.search() + }, + }) + + const configure = instantsearch.widgets.configure({ + hitsPerPage: 5 + }) + + const searchBox = instantsearch.widgets.searchBox({ + container: '#algolia-search-input', + showReset: false, + showSubmit: false, + placeholder: GLOBAL_CONFIG.algolia.languages.input_placeholder, + showLoadingIndicator: true + }) + + const hits = instantsearch.widgets.hits({ + container: '#algolia-hits', + templates: { + item(data) { + const link = data.permalink ? data.permalink : (GLOBAL_CONFIG.root + data.path) + const result = data._highlightResult + const content = result.contentStripTruncate + ? cutContent(result.contentStripTruncate.value) + : result.contentStrip + ? cutContent(result.contentStrip.value) + : result.content + ? cutContent(result.content.value) + : '' + return ` + + ${result.title.value || 'no-title'} + +

${content}

` + }, + empty: function (data) { + return ( + '
' + + GLOBAL_CONFIG.algolia.languages.hits_empty.replace(/\$\{query}/, data.query) + + '
' + ) + } + } + }) + + const stats = instantsearch.widgets.stats({ + container: '#algolia-info > .algolia-stats', + templates: { + text: function (data) { + const stats = GLOBAL_CONFIG.algolia.languages.hits_stats + .replace(/\$\{hits}/, data.nbHits) + .replace(/\$\{time}/, data.processingTimeMS) + return ( + `
${stats}` + ) + } + } + }) + + const powerBy = instantsearch.widgets.poweredBy({ + container: '#algolia-info > .algolia-poweredBy', + }) + + const pagination = instantsearch.widgets.pagination({ + container: '#algolia-pagination', + totalPages: 5, + templates: { + first: '', + last: '', + previous: '', + next: '' + } + }) + + + search.addWidgets([configure,searchBox,hits,stats,powerBy,pagination]) // add the widgets to the instantsearch instance + + search.start() + + searchClickFn() + searchClickFnOnce() + + window.addEventListener('pjax:complete', () => { + getComputedStyle(document.querySelector('#algolia-search .search-dialog')).display === 'block' && closeSearch() + searchClickFn() + }) + + window.pjax && search.on('render', () => { + window.pjax.refresh(document.getElementById('algolia-hits')) + }) +}) diff --git a/js/search/local-search.js b/js/search/local-search.js new file mode 100644 index 000000000..6c1ca7dc5 --- /dev/null +++ b/js/search/local-search.js @@ -0,0 +1,188 @@ +window.addEventListener('load', () => { + let loadFlag = false + let dataObj = [] + const $searchMask = document.getElementById('search-mask') + + const openSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '100%' + bodyStyle.overflow = 'hidden' + btf.animateIn($searchMask, 'to_show 0.5s') + btf.animateIn(document.querySelector('#local-search .search-dialog'), 'titleScale 0.5s') + setTimeout(() => { document.querySelector('#local-search-input input').focus() }, 100) + if (!loadFlag) { + search() + loadFlag = true + } + // shortcut: ESC + document.addEventListener('keydown', function f (event) { + if (event.code === 'Escape') { + closeSearch() + document.removeEventListener('keydown', f) + } + }) + } + + const closeSearch = () => { + const bodyStyle = document.body.style + bodyStyle.width = '' + bodyStyle.overflow = '' + btf.animateOut(document.querySelector('#local-search .search-dialog'), 'search_close .5s') + btf.animateOut($searchMask, 'to_hide 0.5s') + } + + const searchClickFn = () => { + document.querySelector('#search-button > .search').addEventListener('click', openSearch) + } + + const searchClickFnOnce = () => { + document.querySelector('#local-search .search-close-button').addEventListener('click', closeSearch) + $searchMask.addEventListener('click', closeSearch) + if (GLOBAL_CONFIG.localSearch.preload) dataObj = fetchData(GLOBAL_CONFIG.localSearch.path) + } + + // check url is json or not + const isJson = url => { + const reg = /\.json$/ + return reg.test(url) + } + + const fetchData = async (path) => { + let data = [] + const response = await fetch(path) + if (isJson(path)) { + data = await response.json() + } else { + const res = await response.text() + const t = await new window.DOMParser().parseFromString(res, 'text/xml') + const a = await t + data = [...a.querySelectorAll('entry')].map(item =>{ + return { + title: item.querySelector('title').textContent, + content: item.querySelector('content') && item.querySelector('content').textContent, + url: item.querySelector('url').textContent + } + }) + } + if (response.ok) { + const $loadDataItem = document.getElementById('loading-database') + $loadDataItem.nextElementSibling.style.display = 'block' + $loadDataItem.remove() + } + return data + } + + const search = () => { + if (!GLOBAL_CONFIG.localSearch.preload) { + dataObj = fetchData(GLOBAL_CONFIG.localSearch.path) + } + + const $input = document.querySelector('#local-search-input input') + const $resultContent = document.getElementById('local-search-results') + const $loadingStatus = document.getElementById('loading-status') + + $input.addEventListener('input', function () { + const keywords = this.value.trim().toLowerCase().split(/[\s]+/) + if (keywords[0] !== '') $loadingStatus.innerHTML = '' + + $resultContent.innerHTML = '' + let str = '
' + if (keywords.length <= 0) return + let count = 0 + // perform local searching + dataObj.then(data => { + data.forEach(data => { + let isMatch = true + let dataTitle = data.title ? data.title.trim().toLowerCase() : '' + const dataContent = data.content ? data.content.trim().replace(/<[^>]+>/g, '').toLowerCase() : '' + const dataUrl = data.url.startsWith('/') ? data.url : GLOBAL_CONFIG.root + data.url + let indexTitle = -1 + let indexContent = -1 + let firstOccur = -1 + // only match articles with not empty titles and contents + if (dataTitle !== '' || dataContent !== '') { + keywords.forEach((keyword, i) => { + indexTitle = dataTitle.indexOf(keyword) + indexContent = dataContent.indexOf(keyword) + if (indexTitle < 0 && indexContent < 0) { + isMatch = false + } else { + if (indexContent < 0) { + indexContent = 0 + } + if (i === 0) { + firstOccur = indexContent + } + } + }) + } else { + isMatch = false + } + + // show search results + if (isMatch) { + if (firstOccur >= 0) { + // cut out 130 characters + // let start = firstOccur - 30 < 0 ? 0 : firstOccur - 30 + // let end = firstOccur + 50 > dataContent.length ? dataContent.length : firstOccur + 50 + let start = firstOccur - 30 + let end = firstOccur + 100 + let pre = '' + let post = '' + + if (start < 0) { + start = 0 + } + + if (start === 0) { + end = 100 + } else { + pre = '...' + } + + if (end > dataContent.length) { + end = dataContent.length + } else { + post = '...' + } + + let matchContent = dataContent.substring(start, end) + + // highlight all keywords + keywords.forEach(keyword => { + const regS = new RegExp(keyword, 'gi') + matchContent = matchContent.replace(regS, '' + keyword + '') + dataTitle = dataTitle.replace(regS, '' + keyword + '') + }) + + str += '
' + dataTitle + '' + count += 1 + + if (dataContent !== '') { + str += '

' + pre + matchContent + post + '

' + } + } + str += '
' + } + }) + if (count === 0) { + str += '
' + GLOBAL_CONFIG.localSearch.languages.hits_empty.replace(/\$\{query}/, this.value.trim()) + + '
' + } + str += '
' + $resultContent.innerHTML = str + if (keywords[0] !== '') $loadingStatus.innerHTML = '' + window.pjax && window.pjax.refresh($resultContent) + }) + }) + } + + searchClickFn() + searchClickFnOnce() + + // pjax + window.addEventListener('pjax:complete', () => { + !btf.isHidden($searchMask) && closeSearch() + searchClickFn() + }) +}) diff --git a/js/tw_cn.js b/js/tw_cn.js new file mode 100644 index 000000000..78dbd6d90 --- /dev/null +++ b/js/tw_cn.js @@ -0,0 +1,100 @@ +/* eslint-disable no-undef */ +document.addEventListener('DOMContentLoaded', function () { + const translate = GLOBAL_CONFIG.translate + const snackbarData = GLOBAL_CONFIG.Snackbar + const defaultEncoding = translate.defaultEncoding // 網站默認語言,1: 繁體中文, 2: 簡體中文 + const translateDelay = translate.translateDelay // 延遲時間,若不在前, 要設定延遲翻譯時間, 如100表示100ms,默認為0 + const msgToTraditionalChinese = translate.msgToTraditionalChinese // 此處可以更改為你想要顯示的文字 + const msgToSimplifiedChinese = translate.msgToSimplifiedChinese // 同上,但兩處均不建議更改 + let currentEncoding = defaultEncoding + const targetEncodingCookie = 'translate-chn-cht' + let targetEncoding = + saveToLocal.get(targetEncodingCookie) === undefined + ? defaultEncoding + : Number(saveToLocal.get('translate-chn-cht')) + let translateButtonObject + const isSnackbar = GLOBAL_CONFIG.Snackbar !== undefined + + function translateText (txt) { + if (txt === '' || txt == null) return '' + if (currentEncoding === 1 && targetEncoding === 2) return Simplized(txt) + else if (currentEncoding === 2 && targetEncoding === 1) { return Traditionalized(txt) } else return txt + } + function translateBody (fobj) { + let objs + if (typeof fobj === 'object') objs = fobj.childNodes + else objs = document.body.childNodes + for (let i = 0; i < objs.length; i++) { + const obj = objs.item(i) + if ( + '||BR|HR|'.indexOf('|' + obj.tagName + '|') > 0 || + obj === translateButtonObject + ) { continue } + if (obj.title !== '' && obj.title != null) { obj.title = translateText(obj.title) } + if (obj.alt !== '' && obj.alt != null) obj.alt = translateText(obj.alt) + if (obj.placeholder !== '' && obj.placeholder != null) obj.placeholder = translateText(obj.placeholder) + if ( + obj.tagName === 'INPUT' && + obj.value !== '' && + obj.type !== 'text' && + obj.type !== 'hidden' + ) { obj.value = translateText(obj.value) } + if (obj.nodeType === 3) obj.data = translateText(obj.data) + else translateBody(obj) + } + } + function translatePage () { + if (targetEncoding === 1) { + currentEncoding = 1 + targetEncoding = 2 + translateButtonObject.innerHTML = msgToTraditionalChinese + saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + translateBody() + if (isSnackbar) btf.snackbarShow(snackbarData.cht_to_chs) + } else if (targetEncoding === 2) { + currentEncoding = 2 + targetEncoding = 1 + translateButtonObject.innerHTML = msgToSimplifiedChinese + saveToLocal.set(targetEncodingCookie, targetEncoding, 2) + translateBody() + if (isSnackbar) btf.snackbarShow(snackbarData.chs_to_cht) + } + } + function JTPYStr () { + return '万与丑专业丛东丝丢两严丧个丬丰临为丽举么义乌乐乔习乡书买乱争于亏云亘亚产亩亲亵亸亿仅从仑仓仪们价众优伙会伛伞伟传伤伥伦伧伪伫体余佣佥侠侣侥侦侧侨侩侪侬俣俦俨俩俪俭债倾偬偻偾偿傥傧储傩儿兑兖党兰关兴兹养兽冁内冈册写军农冢冯冲决况冻净凄凉凌减凑凛几凤凫凭凯击凼凿刍划刘则刚创删别刬刭刽刿剀剂剐剑剥剧劝办务劢动励劲劳势勋勐勚匀匦匮区医华协单卖卢卤卧卫却卺厂厅历厉压厌厍厕厢厣厦厨厩厮县参叆叇双发变叙叠叶号叹叽吁后吓吕吗吣吨听启吴呒呓呕呖呗员呙呛呜咏咔咙咛咝咤咴咸哌响哑哒哓哔哕哗哙哜哝哟唛唝唠唡唢唣唤唿啧啬啭啮啰啴啸喷喽喾嗫呵嗳嘘嘤嘱噜噼嚣嚯团园囱围囵国图圆圣圹场坂坏块坚坛坜坝坞坟坠垄垅垆垒垦垧垩垫垭垯垱垲垴埘埙埚埝埯堑堕塆墙壮声壳壶壸处备复够头夸夹夺奁奂奋奖奥妆妇妈妩妪妫姗姜娄娅娆娇娈娱娲娴婳婴婵婶媪嫒嫔嫱嬷孙学孪宁宝实宠审宪宫宽宾寝对寻导寿将尔尘尧尴尸尽层屃屉届属屡屦屿岁岂岖岗岘岙岚岛岭岳岽岿峃峄峡峣峤峥峦崂崃崄崭嵘嵚嵛嵝嵴巅巩巯币帅师帏帐帘帜带帧帮帱帻帼幂幞干并广庄庆庐庑库应庙庞废庼廪开异弃张弥弪弯弹强归当录彟彦彻径徕御忆忏忧忾怀态怂怃怄怅怆怜总怼怿恋恳恶恸恹恺恻恼恽悦悫悬悭悯惊惧惨惩惫惬惭惮惯愍愠愤愦愿慑慭憷懑懒懔戆戋戏戗战戬户扎扑扦执扩扪扫扬扰抚抛抟抠抡抢护报担拟拢拣拥拦拧拨择挂挚挛挜挝挞挟挠挡挢挣挤挥挦捞损捡换捣据捻掳掴掷掸掺掼揸揽揿搀搁搂搅携摄摅摆摇摈摊撄撑撵撷撸撺擞攒敌敛数斋斓斗斩断无旧时旷旸昙昼昽显晋晒晓晔晕晖暂暧札术朴机杀杂权条来杨杩杰极构枞枢枣枥枧枨枪枫枭柜柠柽栀栅标栈栉栊栋栌栎栏树栖样栾桊桠桡桢档桤桥桦桧桨桩梦梼梾检棂椁椟椠椤椭楼榄榇榈榉槚槛槟槠横樯樱橥橱橹橼檐檩欢欤欧歼殁殇残殒殓殚殡殴毁毂毕毙毡毵氇气氢氩氲汇汉污汤汹沓沟没沣沤沥沦沧沨沩沪沵泞泪泶泷泸泺泻泼泽泾洁洒洼浃浅浆浇浈浉浊测浍济浏浐浑浒浓浔浕涂涌涛涝涞涟涠涡涢涣涤润涧涨涩淀渊渌渍渎渐渑渔渖渗温游湾湿溃溅溆溇滗滚滞滟滠满滢滤滥滦滨滩滪漤潆潇潋潍潜潴澜濑濒灏灭灯灵灾灿炀炉炖炜炝点炼炽烁烂烃烛烟烦烧烨烩烫烬热焕焖焘煅煳熘爱爷牍牦牵牺犊犟状犷犸犹狈狍狝狞独狭狮狯狰狱狲猃猎猕猡猪猫猬献獭玑玙玚玛玮环现玱玺珉珏珐珑珰珲琎琏琐琼瑶瑷璇璎瓒瓮瓯电画畅畲畴疖疗疟疠疡疬疮疯疱疴痈痉痒痖痨痪痫痴瘅瘆瘗瘘瘪瘫瘾瘿癞癣癫癯皑皱皲盏盐监盖盗盘眍眦眬着睁睐睑瞒瞩矫矶矾矿砀码砖砗砚砜砺砻砾础硁硅硕硖硗硙硚确硷碍碛碜碱碹磙礼祎祢祯祷祸禀禄禅离秃秆种积称秽秾稆税稣稳穑穷窃窍窑窜窝窥窦窭竖竞笃笋笔笕笺笼笾筑筚筛筜筝筹签简箓箦箧箨箩箪箫篑篓篮篱簖籁籴类籼粜粝粤粪粮糁糇紧絷纟纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线绀绁绂练组绅细织终绉绊绋绌绍绎经绐绑绒结绔绕绖绗绘给绚绛络绝绞统绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿缀缁缂缃缄缅缆缇缈缉缊缋缌缍缎缏缐缑缒缓缔缕编缗缘缙缚缛缜缝缞缟缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵罂网罗罚罢罴羁羟羡翘翙翚耢耧耸耻聂聋职聍联聩聪肃肠肤肷肾肿胀胁胆胜胧胨胪胫胶脉脍脏脐脑脓脔脚脱脶脸腊腌腘腭腻腼腽腾膑臜舆舣舰舱舻艰艳艹艺节芈芗芜芦苁苇苈苋苌苍苎苏苘苹茎茏茑茔茕茧荆荐荙荚荛荜荞荟荠荡荣荤荥荦荧荨荩荪荫荬荭荮药莅莜莱莲莳莴莶获莸莹莺莼萚萝萤营萦萧萨葱蒇蒉蒋蒌蓝蓟蓠蓣蓥蓦蔷蔹蔺蔼蕲蕴薮藁藓虏虑虚虫虬虮虽虾虿蚀蚁蚂蚕蚝蚬蛊蛎蛏蛮蛰蛱蛲蛳蛴蜕蜗蜡蝇蝈蝉蝎蝼蝾螀螨蟏衅衔补衬衮袄袅袆袜袭袯装裆裈裢裣裤裥褛褴襁襕见观觃规觅视觇览觉觊觋觌觍觎觏觐觑觞触觯詟誉誊讠计订讣认讥讦讧讨让讪讫训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访诀证诂诃评诅识诇诈诉诊诋诌词诎诏诐译诒诓诔试诖诗诘诙诚诛诜话诞诟诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿谀谁谂调谄谅谆谇谈谊谋谌谍谎谏谐谑谒谓谔谕谖谗谘谙谚谛谜谝谞谟谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷豮贝贞负贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿赀赁赂赃资赅赆赇赈赉赊赋赌赍赎赏赐赑赒赓赔赕赖赗赘赙赚赛赜赝赞赟赠赡赢赣赪赵赶趋趱趸跃跄跖跞践跶跷跸跹跻踊踌踪踬踯蹑蹒蹰蹿躏躜躯车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿辀辁辂较辄辅辆辇辈辉辊辋辌辍辎辏辐辑辒输辔辕辖辗辘辙辚辞辩辫边辽达迁过迈运还这进远违连迟迩迳迹适选逊递逦逻遗遥邓邝邬邮邹邺邻郁郄郏郐郑郓郦郧郸酝酦酱酽酾酿释里鉅鉴銮錾钆钇针钉钊钋钌钍钎钏钐钑钒钓钔钕钖钗钘钙钚钛钝钞钟钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿铀铁铂铃铄铅铆铈铉铊铋铍铎铏铐铑铒铕铗铘铙铚铛铜铝铞铟铠铡铢铣铤铥铦铧铨铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿销锁锂锃锄锅锆锇锈锉锊锋锌锍锎锏锐锑锒锓锔锕锖锗错锚锜锞锟锠锡锢锣锤锥锦锨锩锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿镀镁镂镃镆镇镈镉镊镌镍镎镏镐镑镒镕镖镗镙镚镛镜镝镞镟镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镶长门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿阀阁阂阃阄阅阆阇阈阉阊阋阌阍阎阏阐阑阒阓阔阕阖阗阘阙阚阛队阳阴阵阶际陆陇陈陉陕陧陨险随隐隶隽难雏雠雳雾霁霉霭靓静靥鞑鞒鞯鞴韦韧韨韩韪韫韬韵页顶顷顸项顺须顼顽顾顿颀颁颂颃预颅领颇颈颉颊颋颌颍颎颏颐频颒颓颔颕颖颗题颙颚颛颜额颞颟颠颡颢颣颤颥颦颧风飏飐飑飒飓飔飕飖飗飘飙飚飞飨餍饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿馀馁馂馃馄馅馆馇馈馉馊馋馌馍馎馏馐馑馒馓馔馕马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿骀骁骂骃骄骅骆骇骈骉骊骋验骍骎骏骐骑骒骓骔骕骖骗骘骙骚骛骜骝骞骟骠骡骢骣骤骥骦骧髅髋髌鬓魇魉鱼鱽鱾鱿鲀鲁鲂鲄鲅鲆鲇鲈鲉鲊鲋鲌鲍鲎鲏鲐鲑鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜鲝鲞鲟鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿鳀鳁鳂鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌鳍鳎鳏鳐鳑鳒鳓鳔鳕鳖鳗鳘鳙鳛鳜鳝鳞鳟鳠鳡鳢鳣鸟鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿鹀鹁鹂鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌鹍鹎鹏鹐鹑鹒鹓鹔鹕鹖鹗鹘鹚鹛鹜鹝鹞鹟鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹯鹰鹱鹲鹳鹴鹾麦麸黄黉黡黩黪黾' + } + function FTPYStr () { + return '萬與醜專業叢東絲丟兩嚴喪個爿豐臨為麗舉麼義烏樂喬習鄉書買亂爭於虧雲亙亞產畝親褻嚲億僅從侖倉儀們價眾優夥會傴傘偉傳傷倀倫傖偽佇體餘傭僉俠侶僥偵側僑儈儕儂俁儔儼倆儷儉債傾傯僂僨償儻儐儲儺兒兌兗黨蘭關興茲養獸囅內岡冊寫軍農塚馮衝決況凍淨淒涼淩減湊凜幾鳳鳧憑凱擊氹鑿芻劃劉則剛創刪別剗剄劊劌剴劑剮劍剝劇勸辦務勱動勵勁勞勢勳猛勩勻匭匱區醫華協單賣盧鹵臥衛卻巹廠廳曆厲壓厭厙廁廂厴廈廚廄廝縣參靉靆雙發變敘疊葉號歎嘰籲後嚇呂嗎唚噸聽啟吳嘸囈嘔嚦唄員咼嗆嗚詠哢嚨嚀噝吒噅鹹呱響啞噠嘵嗶噦嘩噲嚌噥喲嘜嗊嘮啢嗩唕喚呼嘖嗇囀齧囉嘽嘯噴嘍嚳囁嗬噯噓嚶囑嚕劈囂謔團園囪圍圇國圖圓聖壙場阪壞塊堅壇壢壩塢墳墜壟壟壚壘墾坰堊墊埡墶壋塏堖塒塤堝墊垵塹墮壪牆壯聲殼壺壼處備複夠頭誇夾奪奩奐奮獎奧妝婦媽嫵嫗媯姍薑婁婭嬈嬌孌娛媧嫻嫿嬰嬋嬸媼嬡嬪嬙嬤孫學孿寧寶實寵審憲宮寬賓寢對尋導壽將爾塵堯尷屍盡層屭屜屆屬屢屨嶼歲豈嶇崗峴嶴嵐島嶺嶽崠巋嶨嶧峽嶢嶠崢巒嶗崍嶮嶄嶸嶔崳嶁脊巔鞏巰幣帥師幃帳簾幟帶幀幫幬幘幗冪襆幹並廣莊慶廬廡庫應廟龐廢廎廩開異棄張彌弳彎彈強歸當錄彠彥徹徑徠禦憶懺憂愾懷態慫憮慪悵愴憐總懟懌戀懇惡慟懨愷惻惱惲悅愨懸慳憫驚懼慘懲憊愜慚憚慣湣慍憤憒願懾憖怵懣懶懍戇戔戲戧戰戩戶紮撲扡執擴捫掃揚擾撫拋摶摳掄搶護報擔擬攏揀擁攔擰撥擇掛摯攣掗撾撻挾撓擋撟掙擠揮撏撈損撿換搗據撚擄摑擲撣摻摜摣攬撳攙擱摟攪攜攝攄擺搖擯攤攖撐攆擷擼攛擻攢敵斂數齋斕鬥斬斷無舊時曠暘曇晝曨顯晉曬曉曄暈暉暫曖劄術樸機殺雜權條來楊榪傑極構樅樞棗櫪梘棖槍楓梟櫃檸檉梔柵標棧櫛櫳棟櫨櫟欄樹棲樣欒棬椏橈楨檔榿橋樺檜槳樁夢檮棶檢欞槨櫝槧欏橢樓欖櫬櫚櫸檟檻檳櫧橫檣櫻櫫櫥櫓櫞簷檁歡歟歐殲歿殤殘殞殮殫殯毆毀轂畢斃氈毿氌氣氫氬氳彙漢汙湯洶遝溝沒灃漚瀝淪滄渢溈滬濔濘淚澩瀧瀘濼瀉潑澤涇潔灑窪浹淺漿澆湞溮濁測澮濟瀏滻渾滸濃潯濜塗湧濤澇淶漣潿渦溳渙滌潤澗漲澀澱淵淥漬瀆漸澠漁瀋滲溫遊灣濕潰濺漵漊潷滾滯灩灄滿瀅濾濫灤濱灘澦濫瀠瀟瀲濰潛瀦瀾瀨瀕灝滅燈靈災燦煬爐燉煒熗點煉熾爍爛烴燭煙煩燒燁燴燙燼熱煥燜燾煆糊溜愛爺牘犛牽犧犢強狀獷獁猶狽麅獮獰獨狹獅獪猙獄猻獫獵獼玀豬貓蝟獻獺璣璵瑒瑪瑋環現瑲璽瑉玨琺瓏璫琿璡璉瑣瓊瑤璦璿瓔瓚甕甌電畫暢佘疇癤療瘧癘瘍鬁瘡瘋皰屙癰痙癢瘂癆瘓癇癡癉瘮瘞瘺癟癱癮癭癩癬癲臒皚皺皸盞鹽監蓋盜盤瞘眥矓著睜睞瞼瞞矚矯磯礬礦碭碼磚硨硯碸礪礱礫礎硜矽碩硤磽磑礄確鹼礙磧磣堿镟滾禮禕禰禎禱禍稟祿禪離禿稈種積稱穢穠穭稅穌穩穡窮竊竅窯竄窩窺竇窶豎競篤筍筆筧箋籠籩築篳篩簹箏籌簽簡籙簀篋籜籮簞簫簣簍籃籬籪籟糴類秈糶糲粵糞糧糝餱緊縶糸糾紆紅紂纖紇約級紈纊紀紉緯紜紘純紕紗綱納紝縱綸紛紙紋紡紵紖紐紓線紺絏紱練組紳細織終縐絆紼絀紹繹經紿綁絨結絝繞絰絎繪給絢絳絡絕絞統綆綃絹繡綌綏絛繼綈績緒綾緓續綺緋綽緔緄繩維綿綬繃綢綯綹綣綜綻綰綠綴緇緙緗緘緬纜緹緲緝縕繢緦綞緞緶線緱縋緩締縷編緡緣縉縛縟縝縫縗縞纏縭縊縑繽縹縵縲纓縮繆繅纈繚繕繒韁繾繰繯繳纘罌網羅罰罷羆羈羥羨翹翽翬耮耬聳恥聶聾職聹聯聵聰肅腸膚膁腎腫脹脅膽勝朧腖臚脛膠脈膾髒臍腦膿臠腳脫腡臉臘醃膕齶膩靦膃騰臏臢輿艤艦艙艫艱豔艸藝節羋薌蕪蘆蓯葦藶莧萇蒼苧蘇檾蘋莖蘢蔦塋煢繭荊薦薘莢蕘蓽蕎薈薺蕩榮葷滎犖熒蕁藎蓀蔭蕒葒葤藥蒞蓧萊蓮蒔萵薟獲蕕瑩鶯蓴蘀蘿螢營縈蕭薩蔥蕆蕢蔣蔞藍薊蘺蕷鎣驀薔蘞藺藹蘄蘊藪槁蘚虜慮虛蟲虯蟣雖蝦蠆蝕蟻螞蠶蠔蜆蠱蠣蟶蠻蟄蛺蟯螄蠐蛻蝸蠟蠅蟈蟬蠍螻蠑螿蟎蠨釁銜補襯袞襖嫋褘襪襲襏裝襠褌褳襝褲襇褸襤繈襴見觀覎規覓視覘覽覺覬覡覿覥覦覯覲覷觴觸觶讋譽謄訁計訂訃認譏訐訌討讓訕訖訓議訊記訒講諱謳詎訝訥許訛論訩訟諷設訪訣證詁訶評詛識詗詐訴診詆謅詞詘詔詖譯詒誆誄試詿詩詰詼誠誅詵話誕詬詮詭詢詣諍該詳詫諢詡譸誡誣語誚誤誥誘誨誑說誦誒請諸諏諾讀諑誹課諉諛誰諗調諂諒諄誶談誼謀諶諜謊諫諧謔謁謂諤諭諼讒諮諳諺諦謎諞諝謨讜謖謝謠謗諡謙謐謹謾謫譾謬譚譖譙讕譜譎讞譴譫讖穀豶貝貞負貟貢財責賢敗賬貨質販貪貧貶購貯貫貳賤賁貰貼貴貺貸貿費賀貽賊贄賈賄貲賃賂贓資賅贐賕賑賚賒賦賭齎贖賞賜贔賙賡賠賧賴賵贅賻賺賽賾贗讚贇贈贍贏贛赬趙趕趨趲躉躍蹌蹠躒踐躂蹺蹕躚躋踴躊蹤躓躑躡蹣躕躥躪躦軀車軋軌軒軑軔轉軛輪軟轟軲軻轤軸軹軼軤軫轢軺輕軾載輊轎輈輇輅較輒輔輛輦輩輝輥輞輬輟輜輳輻輯轀輸轡轅轄輾轆轍轔辭辯辮邊遼達遷過邁運還這進遠違連遲邇逕跡適選遜遞邐邏遺遙鄧鄺鄔郵鄒鄴鄰鬱郤郟鄶鄭鄆酈鄖鄲醞醱醬釅釃釀釋裏钜鑒鑾鏨釓釔針釘釗釙釕釷釺釧釤鈒釩釣鍆釹鍚釵鈃鈣鈈鈦鈍鈔鍾鈉鋇鋼鈑鈐鑰欽鈞鎢鉤鈧鈁鈥鈄鈕鈀鈺錢鉦鉗鈷缽鈳鉕鈽鈸鉞鑽鉬鉭鉀鈿鈾鐵鉑鈴鑠鉛鉚鈰鉉鉈鉍鈹鐸鉶銬銠鉺銪鋏鋣鐃銍鐺銅鋁銱銦鎧鍘銖銑鋌銩銛鏵銓鉿銚鉻銘錚銫鉸銥鏟銃鐋銨銀銣鑄鐒鋪鋙錸鋱鏈鏗銷鎖鋰鋥鋤鍋鋯鋨鏽銼鋝鋒鋅鋶鐦鐧銳銻鋃鋟鋦錒錆鍺錯錨錡錁錕錩錫錮鑼錘錐錦鍁錈錇錟錠鍵鋸錳錙鍥鍈鍇鏘鍶鍔鍤鍬鍾鍛鎪鍠鍰鎄鍍鎂鏤鎡鏌鎮鎛鎘鑷鐫鎳鎿鎦鎬鎊鎰鎔鏢鏜鏍鏰鏞鏡鏑鏃鏇鏐鐔钁鐐鏷鑥鐓鑭鐠鑹鏹鐙鑊鐳鐶鐲鐮鐿鑔鑣鑞鑲長門閂閃閆閈閉問闖閏闈閑閎間閔閌悶閘鬧閨聞闥閩閭闓閥閣閡閫鬮閱閬闍閾閹閶鬩閿閽閻閼闡闌闃闠闊闋闔闐闒闕闞闤隊陽陰陣階際陸隴陳陘陝隉隕險隨隱隸雋難雛讎靂霧霽黴靄靚靜靨韃鞽韉韝韋韌韍韓韙韞韜韻頁頂頃頇項順須頊頑顧頓頎頒頌頏預顱領頗頸頡頰頲頜潁熲頦頤頻頮頹頷頴穎顆題顒顎顓顏額顳顢顛顙顥纇顫顬顰顴風颺颭颮颯颶颸颼颻飀飄飆飆飛饗饜飣饑飥餳飩餼飪飫飭飯飲餞飾飽飼飿飴餌饒餉餄餎餃餏餅餑餖餓餘餒餕餜餛餡館餷饋餶餿饞饁饃餺餾饈饉饅饊饌饢馬馭馱馴馳驅馹駁驢駔駛駟駙駒騶駐駝駑駕驛駘驍罵駰驕驊駱駭駢驫驪騁驗騂駸駿騏騎騍騅騌驌驂騙騭騤騷騖驁騮騫騸驃騾驄驏驟驥驦驤髏髖髕鬢魘魎魚魛魢魷魨魯魴魺鮁鮃鯰鱸鮋鮓鮒鮊鮑鱟鮍鮐鮭鮚鮳鮪鮞鮦鰂鮜鱠鱭鮫鮮鮺鯗鱘鯁鱺鰱鰹鯉鰣鰷鯀鯊鯇鮶鯽鯒鯖鯪鯕鯫鯡鯤鯧鯝鯢鯰鯛鯨鯵鯴鯔鱝鰈鰏鱨鯷鰮鰃鰓鱷鰍鰒鰉鰁鱂鯿鰠鼇鰭鰨鰥鰩鰟鰜鰳鰾鱈鱉鰻鰵鱅鰼鱖鱔鱗鱒鱯鱤鱧鱣鳥鳩雞鳶鳴鳲鷗鴉鶬鴇鴆鴣鶇鸕鴨鴞鴦鴒鴟鴝鴛鴬鴕鷥鷙鴯鴰鵂鴴鵃鴿鸞鴻鵐鵓鸝鵑鵠鵝鵒鷳鵜鵡鵲鶓鵪鶤鵯鵬鵮鶉鶊鵷鷫鶘鶡鶚鶻鶿鶥鶩鷊鷂鶲鶹鶺鷁鶼鶴鷖鸚鷓鷚鷯鷦鷲鷸鷺鸇鷹鸌鸏鸛鸘鹺麥麩黃黌黶黷黲黽' + } + function Traditionalized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && ss.indexOf(cc.charAt(i)) !== -1) { str += tt.charAt(ss.indexOf(cc.charAt(i))) } else str += cc.charAt(i) + } + return str + } + function Simplized (cc) { + let str = '' + const ss = JTPYStr() + const tt = FTPYStr() + for (let i = 0; i < cc.length; i++) { + if (cc.charCodeAt(i) > 10000 && tt.indexOf(cc.charAt(i)) !== -1) { str += ss.charAt(tt.indexOf(cc.charAt(i))) } else str += cc.charAt(i) + } + return str + } + function translateInitialization () { + translateButtonObject = document.getElementById('translateLink') + if (translateButtonObject) { + if (currentEncoding !== targetEncoding) { + setTimeout(translateBody, translateDelay) + if (targetEncoding === 1) translateButtonObject.innerHTML = msgToSimplifiedChinese + else translateButtonObject.innerHTML = msgToTraditionalChinese + } + translateButtonObject.addEventListener('click', translatePage, false) + } + } + translateInitialization() + document.addEventListener('pjax:complete', translateInitialization) +}) diff --git a/js/utils.js b/js/utils.js new file mode 100644 index 000000000..a1be36800 --- /dev/null +++ b/js/utils.js @@ -0,0 +1,278 @@ +const btf = { + debounce: function (func, wait, immediate) { + let timeout + return function () { + const context = this + const args = arguments + const later = function () { + timeout = null + if (!immediate) func.apply(context, args) + } + const callNow = immediate && !timeout + clearTimeout(timeout) + timeout = setTimeout(later, wait) + if (callNow) func.apply(context, args) + } + }, + + throttle: function (func, wait, options) { + let timeout, context, args + let previous = 0 + if (!options) options = {} + + const later = function () { + previous = options.leading === false ? 0 : new Date().getTime() + timeout = null + func.apply(context, args) + if (!timeout) context = args = null + } + + const throttled = function () { + const now = new Date().getTime() + if (!previous && options.leading === false) previous = now + const remaining = wait - (now - previous) + context = this + args = arguments + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + previous = now + func.apply(context, args) + if (!timeout) context = args = null + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(later, remaining) + } + } + + return throttled + }, + + sidebarPaddingR: () => { + const innerWidth = window.innerWidth + const clientWidth = document.body.clientWidth + const paddingRight = innerWidth - clientWidth + if (innerWidth !== clientWidth) { + document.body.style.paddingRight = paddingRight + 'px' + } + }, + + snackbarShow: (text, showAction = false, duration = 2000) => { + const { position, bgLight, bgDark } = GLOBAL_CONFIG.Snackbar + const bg = document.documentElement.getAttribute('data-theme') === 'light' ? bgLight : bgDark + Snackbar.show({ + text: text, + backgroundColor: bg, + showAction: showAction, + duration: duration, + pos: position, + customClass: 'snackbar-css' + }) + }, + + diffDate: (d, more = false) => { + const dateNow = new Date() + const datePost = new Date(d) + const dateDiff = dateNow.getTime() - datePost.getTime() + const minute = 1000 * 60 + const hour = minute * 60 + const day = hour * 24 + const month = day * 30 + + let result + if (more) { + const monthCount = dateDiff / month + const dayCount = dateDiff / day + const hourCount = dateDiff / hour + const minuteCount = dateDiff / minute + + if (monthCount > 12) { + result = datePost.toLocaleDateString().replace(/\//g, '-') + } else if (monthCount >= 1) { + result = parseInt(monthCount) + ' ' + GLOBAL_CONFIG.date_suffix.month + } else if (dayCount >= 1) { + result = parseInt(dayCount) + ' ' + GLOBAL_CONFIG.date_suffix.day + } else if (hourCount >= 1) { + result = parseInt(hourCount) + ' ' + GLOBAL_CONFIG.date_suffix.hour + } else if (minuteCount >= 1) { + result = parseInt(minuteCount) + ' ' + GLOBAL_CONFIG.date_suffix.min + } else { + result = GLOBAL_CONFIG.date_suffix.just + } + } else { + result = parseInt(dateDiff / day) + } + return result + }, + + loadComment: (dom, callback) => { + if ('IntersectionObserver' in window) { + const observerItem = new IntersectionObserver((entries) => { + if (entries[0].isIntersecting) { + callback() + observerItem.disconnect() + } + }, { threshold: [0] }) + observerItem.observe(dom) + } else { + callback() + } + }, + + scrollToDest: (pos, time = 500) => { + const currentPos = window.pageYOffset + if (currentPos > pos) pos = pos - 70 + + if ('scrollBehavior' in document.documentElement.style) { + window.scrollTo({ + top: pos, + behavior: 'smooth' + }) + return + } + + let start = null + pos = +pos + window.requestAnimationFrame(function step (currentTime) { + start = !start ? currentTime : start + const progress = currentTime - start + if (currentPos < pos) { + window.scrollTo(0, ((pos - currentPos) * progress / time) + currentPos) + } else { + window.scrollTo(0, currentPos - ((currentPos - pos) * progress / time)) + } + if (progress < time) { + window.requestAnimationFrame(step) + } else { + window.scrollTo(0, pos) + } + }) + }, + + animateIn: (ele, text) => { + ele.style.display = 'block' + ele.style.animation = text + }, + + animateOut: (ele, text) => { + ele.addEventListener('animationend', function f () { + ele.style.display = '' + ele.style.animation = '' + ele.removeEventListener('animationend', f) + }) + ele.style.animation = text + }, + + getParents: (elem, selector) => { + for (; elem && elem !== document; elem = elem.parentNode) { + if (elem.matches(selector)) return elem + } + return null + }, + + siblings: (ele, selector) => { + return [...ele.parentNode.children].filter((child) => { + if (selector) { + return child !== ele && child.matches(selector) + } + return child !== ele + }) + }, + + /** + * @param {*} selector + * @param {*} eleType the type of create element + * @param {*} options object key: value + */ + wrap: (selector, eleType, options) => { + const creatEle = document.createElement(eleType) + for (const [key, value] of Object.entries(options)) { + creatEle.setAttribute(key, value) + } + selector.parentNode.insertBefore(creatEle, selector) + creatEle.appendChild(selector) + }, + + unwrap: el => { + const elParentNode = el.parentNode + if (elParentNode !== document.body) { + elParentNode.parentNode.insertBefore(el, elParentNode) + elParentNode.parentNode.removeChild(elParentNode) + } + }, + + isHidden: ele => ele.offsetHeight === 0 && ele.offsetWidth === 0, + + getEleTop: ele => { + let actualTop = ele.offsetTop + let current = ele.offsetParent + + while (current !== null) { + actualTop += current.offsetTop + current = current.offsetParent + } + + return actualTop + }, + + loadLightbox: ele => { + const service = GLOBAL_CONFIG.lightbox + + if (service === 'mediumZoom') { + const zoom = mediumZoom(ele) + zoom.on('open', e => { + const photoBg = document.documentElement.getAttribute('data-theme') === 'dark' ? '#121212' : '#fff' + zoom.update({ + background: photoBg + }) + }) + } + + if (service === 'fancybox') { + ele.forEach(i => { + if (i.parentNode.tagName !== 'A') { + const dataSrc = i.dataset.lazySrc || i.src + const dataCaption = i.title || i.alt || '' + btf.wrap(i, 'a', { href: dataSrc, 'data-fancybox': 'gallery', 'data-caption': dataCaption, 'data-thumb': dataSrc }) + } + }) + + if (!window.fancyboxRun) { + Fancybox.bind('[data-fancybox]', { + Hash: false, + Thumbs: { + autoStart: false + } + }) + window.fancyboxRun = true + } + } + }, + + initJustifiedGallery: function (selector) { + selector.forEach(function (i) { + if (!btf.isHidden(i)) { + fjGallery(i, { + itemSelector: '.fj-gallery-item', + rowHeight: 220, + gutter: 4, + onJustify: function () { + this.$container.style.opacity = '1' + } + }) + } + }) + }, + + updateAnchor: (anchor) => { + if (anchor !== window.location.hash) { + if (!anchor) anchor = location.pathname + const title = GLOBAL_CONFIG_SITE.title + window.history.replaceState({ + url: location.href, + title: title + }, title, anchor) + } + } +} diff --git a/lab/index.html b/lab/index.html new file mode 100644 index 000000000..f4d320ab9 --- /dev/null +++ b/lab/index.html @@ -0,0 +1,343 @@ +计算神经科学领域的著名实验室 | Stray Birds + + + + + + + + + + + + +
\ No newline at end of file diff --git a/lib/hbe.js b/lib/hbe.js new file mode 100644 index 000000000..71205dd75 --- /dev/null +++ b/lib/hbe.js @@ -0,0 +1,297 @@ +(() => { + 'use strict'; + + const cryptoObj = window.crypto || window.msCrypto; + const storage = window.localStorage; + + const storageName = 'hexo-blog-encrypt:#' + window.location.pathname; + const keySalt = textToArray('hexo-blog-encrypt的作者们都是大帅比!'); + const ivSalt = textToArray('hexo-blog-encrypt是地表最强Hexo加密插件!'); + +// As we can't detect the wrong password with AES-CBC, +// so adding an empty div and check it when decrption. +const knownPrefix = ""; + + const mainElement = document.getElementById('hexo-blog-encrypt'); + const wrongPassMessage = mainElement.dataset['wpm']; + const wrongHashMessage = mainElement.dataset['whm']; + const dataElement = mainElement.getElementsByTagName('script')['hbeData']; + const encryptedData = dataElement.innerText; + const HmacDigist = dataElement.dataset['hmacdigest']; + + function hexToArray(s) { + return new Uint8Array(s.match(/[\da-f]{2}/gi).map((h => { + return parseInt(h, 16); + }))); + } + + function textToArray(s) { + var i = s.length; + var n = 0; + var ba = new Array() + + for (var j = 0; j < i;) { + var c = s.codePointAt(j); + if (c < 128) { + ba[n++] = c; + j++; + } else if ((c > 127) && (c < 2048)) { + ba[n++] = (c >> 6) | 192; + ba[n++] = (c & 63) | 128; + j++; + } else if ((c > 2047) && (c < 65536)) { + ba[n++] = (c >> 12) | 224; + ba[n++] = ((c >> 6) & 63) | 128; + ba[n++] = (c & 63) | 128; + j++; + } else { + ba[n++] = (c >> 18) | 240; + ba[n++] = ((c >> 12) & 63) | 128; + ba[n++] = ((c >> 6) & 63) | 128; + ba[n++] = (c & 63) | 128; + j += 2; + } + } + return new Uint8Array(ba); + } + + function arrayBufferToHex(arrayBuffer) { + if (typeof arrayBuffer !== 'object' || arrayBuffer === null || typeof arrayBuffer.byteLength !== 'number') { + throw new TypeError('Expected input to be an ArrayBuffer') + } + + var view = new Uint8Array(arrayBuffer) + var result = '' + var value + + for (var i = 0; i < view.length; i++) { + value = view[i].toString(16) + result += (value.length === 1 ? '0' + value : value) + } + + return result + } + + async function getExecutableScript(oldElem) { + let out = document.createElement('script'); + const attList = ['type', 'text', 'src', 'crossorigin', 'defer', 'referrerpolicy']; + attList.forEach((att) => { + if (oldElem[att]) + out[att] = oldElem[att]; + }) + + return out; + } + + async function convertHTMLToElement(content) { + let out = document.createElement('div'); + out.innerHTML = content; + out.querySelectorAll('script').forEach(async (elem) => { + elem.replaceWith(await getExecutableScript(elem)); + }); + + return out; + } + + function getKeyMaterial(password) { + let encoder = new TextEncoder(); + return cryptoObj.subtle.importKey( + 'raw', + encoder.encode(password), + { + 'name': 'PBKDF2', + }, + false, + [ + 'deriveKey', + 'deriveBits', + ] + ); + } + + function getHmacKey(keyMaterial) { + return cryptoObj.subtle.deriveKey({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': keySalt.buffer, + 'iterations': 1024 + }, keyMaterial, { + 'name': 'HMAC', + 'hash': 'SHA-256', + 'length': 256, + }, true, [ + 'verify', + ]); + } + + function getDecryptKey(keyMaterial) { + return cryptoObj.subtle.deriveKey({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': keySalt.buffer, + 'iterations': 1024, + }, keyMaterial, { + 'name': 'AES-CBC', + 'length': 256, + }, true, [ + 'decrypt', + ]); + } + + function getIv(keyMaterial) { + return cryptoObj.subtle.deriveBits({ + 'name': 'PBKDF2', + 'hash': 'SHA-256', + 'salt': ivSalt.buffer, + 'iterations': 512, + }, keyMaterial, 16 * 8); + } + + async function verifyContent(key, content) { + const encoder = new TextEncoder(); + const encoded = encoder.encode(content); + + let signature = hexToArray(HmacDigist); + + const result = await cryptoObj.subtle.verify({ + 'name': 'HMAC', + 'hash': 'SHA-256', + }, key, signature, encoded); + console.log(`Verification result: ${result}`); + if (!result) { + alert(wrongHashMessage); + console.log(`${wrongHashMessage}, got `, signature, ` but proved wrong.`); + } + return result; + } + + async function decrypt(decryptKey, iv, hmacKey) { + let typedArray = hexToArray(encryptedData); + + const result = await cryptoObj.subtle.decrypt({ + 'name': 'AES-CBC', + 'iv': iv, + }, decryptKey, typedArray.buffer).then(async (result) => { + const decoder = new TextDecoder(); + const decoded = decoder.decode(result); + + // check the prefix, if not then we can sure here is wrong password. + if (!decoded.startsWith(knownPrefix)) { + throw "Decode successfully but not start with KnownPrefix."; + } + + const hideButton = document.createElement('button'); + hideButton.textContent = 'Encrypt again'; + hideButton.type = 'button'; + hideButton.classList.add("hbe-button"); + hideButton.addEventListener('click', () => { + window.localStorage.removeItem(storageName); + window.location.reload(); + }); + + document.getElementById('hexo-blog-encrypt').style.display = 'inline'; + document.getElementById('hexo-blog-encrypt').innerHTML = ''; + document.getElementById('hexo-blog-encrypt').appendChild(await convertHTMLToElement(decoded)); + document.getElementById('hexo-blog-encrypt').appendChild(hideButton); + + // support html5 lazyload functionality. + document.querySelectorAll('img').forEach((elem) => { + if (elem.getAttribute("data-src") && !elem.src) { + elem.src = elem.getAttribute('data-src'); + } + }); + + // support theme-next refresh + window.NexT && NexT.boot && typeof NexT.boot.refresh === 'function' && NexT.boot.refresh(); + + // TOC part + var tocDiv = document.getElementById("toc-div"); + if (tocDiv) { + tocDiv.style.display = 'inline'; + } + + var tocDivs = document.getElementsByClassName('toc-div-class'); + if (tocDivs && tocDivs.length > 0) { + for (var idx = 0; idx < tocDivs.length; idx++) { + tocDivs[idx].style.display = 'inline'; + } + } + + // trigger event + var event = new Event('hexo-blog-decrypt'); + window.dispatchEvent(event); + + return await verifyContent(hmacKey, decoded); + }).catch((e) => { + alert(wrongPassMessage); + console.log(e); + return false; + }); + + return result; + + } + + function hbeLoader() { + + const oldStorageData = JSON.parse(storage.getItem(storageName)); + + if (oldStorageData) { + console.log(`Password got from localStorage(${storageName}): `, oldStorageData); + + const sIv = hexToArray(oldStorageData.iv).buffer; + const sDk = oldStorageData.dk; + const sHmk = oldStorageData.hmk; + + cryptoObj.subtle.importKey('jwk', sDk, { + 'name': 'AES-CBC', + 'length': 256, + }, true, [ + 'decrypt', + ]).then((dkCK) => { + cryptoObj.subtle.importKey('jwk', sHmk, { + 'name': 'HMAC', + 'hash': 'SHA-256', + 'length': 256, + }, true, [ + 'verify', + ]).then((hmkCK) => { + decrypt(dkCK, sIv, hmkCK).then((result) => { + if (!result) { + storage.removeItem(storageName); + } + }); + }); + }); + } + + mainElement.addEventListener('keydown', async (event) => { + if (event.isComposing || event.keyCode === 13) { + const password = document.getElementById('hbePass').value; + const keyMaterial = await getKeyMaterial(password); + const hmacKey = await getHmacKey(keyMaterial); + const decryptKey = await getDecryptKey(keyMaterial); + const iv = await getIv(keyMaterial); + + decrypt(decryptKey, iv, hmacKey).then((result) => { + console.log(`Decrypt result: ${result}`); + if (result) { + cryptoObj.subtle.exportKey('jwk', decryptKey).then((dk) => { + cryptoObj.subtle.exportKey('jwk', hmacKey).then((hmk) => { + const newStorageData = { + 'dk': dk, + 'iv': arrayBufferToHex(iv), + 'hmk': hmk, + }; + storage.setItem(storageName, JSON.stringify(newStorageData)); + }); + }); + } + }); + } + }); + } + + hbeLoader(); + +})(); diff --git a/link/index.html b/link/index.html new file mode 100644 index 000000000..8432ed23d --- /dev/null +++ b/link/index.html @@ -0,0 +1,278 @@ +友情链接 | Stray Birds + + + + + + + + + + +

评论
\ No newline at end of file diff --git a/page/2/index.html b/page/2/index.html new file mode 100644 index 000000000..66557015c --- /dev/null +++ b/page/2/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
【MATLAB App Designer使用教程】可拖拽的线
脑电数据分析
【arduino探索】搭建触摸给水装置
神经元类型和活动状态判断标准
【综述】神经环路的架构
神经编码和神经解码
【arduino探索】使用ArControl编写“炸弹💣游戏”
【arduino探索】控制蠕动泵出水
【arduino探索】按键控制LED灯
在Mac电脑上安装VMware Fusion
\ No newline at end of file diff --git a/page/3/index.html b/page/3/index.html new file mode 100644 index 000000000..9e4e97cc5 --- /dev/null +++ b/page/3/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
VSCode无法正常打开.ipynb文件
ImageJ插件开发
基底神经节环路
neurogym学习笔记【01】
二维脑片配准插件开发
认识你自己
Imairs细胞计数教程
BIRDS插件代码学习【07】
《神经动力学》学习笔记【01】
RNN学习笔记【01】
\ No newline at end of file diff --git a/page/4/index.html b/page/4/index.html new file mode 100644 index 000000000..e63bc6a07 --- /dev/null +++ b/page/4/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
windows设置代理及取消代理
BrainPy学习笔记【01】
BIRDS插件代码学习【06】
解决mac电脑更新后V2rayU无法启动
BIRDS插件代码学习【05】
BIRDS插件代码学习【04】
Java基础知识
BIRDS插件代码学习【03】
BIRDS插件代码学习【02】
BIRDS插件代码学习【01】
\ No newline at end of file diff --git a/page/5/index.html b/page/5/index.html new file mode 100644 index 000000000..12d26b535 --- /dev/null +++ b/page/5/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
小鼠脑图谱第四版
做选择
图像风格迁移
爬取网站数据
Matlab常用命令
愉快的周末
取钱小记
冬学期结束感想
及时按下暂停键⏸
动态思维
\ No newline at end of file diff --git a/page/6/index.html b/page/6/index.html new file mode 100644 index 000000000..b5ccbb106 --- /dev/null +++ b/page/6/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
2023年的第一天
2022年的最后一天
2022年度总结
英语结课感想
本地文件上传到Github
模型加工方法汇总
Hexo迁移至新电脑
初来浙里,我曾经的那些疑惑
使用又拍云提供CDN加速服务
HDDM的安装方法
\ No newline at end of file diff --git a/page/7/index.html b/page/7/index.html new file mode 100644 index 000000000..3e6b6b6de --- /dev/null +++ b/page/7/index.html @@ -0,0 +1,201 @@ +Stray Birds + + + + + + + + +
Windows常用快捷键汇总
无法获得下列许可SOLIDWORKS Standard
在Anaconda中创建新环境
Solidworks 自动识别特征
Jupyter Notebook中添加目录
\ No newline at end of file diff --git a/random/index.html b/random/index.html new file mode 100644 index 000000000..31ea0c04d --- /dev/null +++ b/random/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resource/index.html b/resource/index.html new file mode 100644 index 000000000..669cb3624 --- /dev/null +++ b/resource/index.html @@ -0,0 +1,402 @@ +宝贝网站 | Stray Birds + + + + + + + + + + + + +
\ No newline at end of file diff --git a/search.xml b/search.xml new file mode 100644 index 000000000..1381aeea8 --- /dev/null +++ b/search.xml @@ -0,0 +1,1670 @@ + + + + + + + 小鼠脑立体定位手术 + + /2024/01/09/stereotexic-localization-of-brain/ + + 脑立体定位手术

在神经科学的研究方法中,为了使各种处理手段(给药、毁损、病毒注射等)或信号采集(微电极、探针)到达目的脑区的相应位置,需要使用脑立体定位技术。通过向目标脑区注射红墨水,练习脑立体定位手术,注射完后需要灌流取脑,然后固定、沉糖、切片看位点,最终成像。

查找目标核团坐标

根据研究目的和小鼠种类不同,选择合适的闹立体定位图谱,动物的体重应该尽量与图谱一致,具体信息可在Introduction部分找到,如C57BL/J6成年小鼠,体重26~30g。
在脑图谱List of structures中查找眶额叶皮层的缩写:

  • DLO dorsolateral orbital cortex
  • LO lateral orbital cortex
  • MO medial orbital cortex
  • VO ventral orbital cortex

按照缩写在Index of Abbreviations定位到目标核团所在的页码:

  • LO lateral orbital cortex 0, 4-15, 17, 112-120

经目标核团中心点画水平线和垂直线,即可读出核团的颅骨下深度坐标和中线旁开左右坐标,右下角的Bregma值是核团的前后坐标(正值代表前囟前,负值代表前囟后)。

最终确认位点:(+2.6mm, ±1.3mm, -1.6mm)

实验操作流程

  1. 准备手术器具并喷酒精消毒
  2. 小鼠称重,腹腔注射水合氯醛(用量:体重*0.01)
  3. 酒精擦拭后,用刀片剃除小鼠头部毛发
  4. 通过适配器门齿夹和耳杆固定头部(检查是否固定成功:鼻对正中,头部不动,提尾不掉,目测大脑放置水平)
  5. 涂上红霉素眼膏,避免强光损失小鼠眼睛
  6. 剪开小鼠头部皮肤
  7. 双氧水腐蚀脑膜,去除颅骨表面结缔组织,暴露前后囟
  8. 定位(以bregma点为原点)要先保证小鼠头部X轴方向左右齐平(左右深度相同即可),Y轴方向前后齐平(误差在0.03mm内)
  9. 钻孔 颅骨钻在钻孔点轻磨颅骨,将颅骨打薄,最后用针头挑破(避免损失脑组织)
  10. 生理盐水打湿棉球,放在钻孔处保持湿润,防止伤口干燥
  11. 埋电极/光纤/打病毒,停针10~15min
  12. 涂牙科水泥(两次)

注意事项

  • 注射位点的坐标一定要记牢,前后和左右的坐标是以前囟为原点,深度是以钻孔后的脑表面为原点
  • 固定小鼠两侧的位置类似于人的太阳穴,按压会让小鼠的眼球凸起
  • 气相泵用完之后记得关
  • 拉针仪参数是预设号的,打开开关就能使用,下面固定针管的那部分记得推上去玻璃针管很容易断,
  • 注射病毒切勿来回拔插,尽量一次到位,注射后要停针10~15分钟,一方面等待病毒扩散,一方面防止病毒随着针拔出而漏出核团

心脏灌流取脑

实验材料

动物:成年健康小鼠。
试剂:2%戊巴比妥钠麻醉剂,灌注盐溶液PBS(可用生理盐水代替),中性缓冲多聚甲醛固定液PFA。
用具:注射器(15 ml),带软导管的头皮针,手术剪,眼科剪,平镊,止血钳,手术刀片,小烧杯,15 ml离心管,标签,标记笔,生物垃圾桶。
设备:通风橱,电子称,冰箱。

后续步骤

  1. 将鼠脑放入4%PFA溶液,4℃冰箱中固定一夜
  2. 将固定结束的鼠脑转入30%蔗糖溶液,放入4℃冰箱等待沉底(2天左右)

注意事项

  • 小鼠灌流完空鼠笼中的饲料及时清理,倒入医疗废物垃圾桶,清水清洗后喷酒精消毒
  • 夹住剑突,沿着左右肋骨剪开,暴露心脏和肝脏针管不要扎太深
  • 最后要把针管中的液体都排出,充满空气(速度开到最大150,灌流时70~80)
  • 废液倒入脚下的废液桶中,因为液体有毒,所以最好拿到通风橱中进行(用小桶,小桶满了倒入大桶)
  • 器材使用完清洗归位
  • 取脑时不要着急,操作不要太过粗暴,尽量保持脑的完整性

冰冻切片

实验材料准备

将沉糖的鼠脑取出,倒掉蔗糖溶液,用吸水纸擦干鼠脑表面的水分,用剪刀修剪脑干部分,保证鼠脑底部水平。剪一块方形锡纸制作长方体模具,模具底部铺一层包埋剂,用镊子将鼠脑腹侧向下平放入模具中,使大脑中缝平行于模具长边,加入包埋剂至完全没过鼠脑(高于脑组织2~3mm),用记号笔标记哪边是鼠脑前侧,然后放-80℃冰箱快速冷冻。
去5楼使用冰冻切片机时,记得带上6孔板、脑图谱和酒精喷壶。

冰冻切片机

  1. 开机后首先设置参数,温度设置为-20℃,粗调和微调均设为40μm
  2. 安装刀片
  3. 在样品托上加入一层包埋剂,将鼠脑放在样品托上(前侧朝上),放入速冻区快速冷冻,等待OCT包埋剂凝固后,将样品托固定在样品头上
  4. 修整样品(粗调)
  5. 放下防卷板并调整位置,收集脑片至6孔板中的PBS溶液中
  6. 收集完后清理冰冻切片机和样品托,并用酒精擦拭
  7. 将脑片放入4℃冰箱保存

问题记录

  • 切片时防卷板有点卡顿不顺畅

贴片染色成像

  1. 将脑片用细毛笔捞取到干净的PBS溶液中洗片
  2. 将脑片均匀的贴到盖玻片中央,一张载玻片可以贴4~8片
  3. 贴完后用擦镜纸擦干载玻片边缘和底部的液体,等待晾干
  4. 在载玻片中央加入80μl的DAPI(尽量避免出现气泡),然后盖上盖玻片
  5. 如果立即成像,则无需封片;否则用指甲油封住盖玻片和载玻片的边缘

参考教程

]]>
+ + + + + 生物实验 + + + + + + + 生物 + + + +
+ + + + + 【arduino探索】点亮ST7789 1.3寸TFT屏幕 + + /2024/01/09/arduino-tft/ + + Adafruit-GFX-Library

该类库为所有彩色屏幕的基础类库,安装方式:在Arduino的项目-加载库-库管理器中搜索Adafruit GFX Library,选择最新版本进行安装。Github下载地址
Arduino中的第三方库的存放地址可以在首选项-项目文件夹位置处查看,该路径下的libraries文件夹下即为第三方库的存放地址。

Arduino-ST7789-Library

该类库为ST7789的专用驱动库。Github下载地址
运行画直线的程序,用时约32.6s,太慢了,每次黑屏都要等半天!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#include <Adafruit_GFX.h>    // Core graphics library by Adafruit
#include <Arduino_ST7789.h> // Hardware-specific library for ST7789 (with or without CS pin)
#include <SPI.h>

#define TFT_DC 8
#define TFT_RST 7 //9
#define TFT_CS 9 //10 // only for displays with CS pin
#define TFT_MOSI 11 // for hardware SPI data pin (all of available pins)
#define TFT_SCLK 13 // for hardware SPI sclk pin (all of available pins)

#define w 240
#define h 240


Arduino_ST7789 tft = Arduino_ST7789(TFT_DC, TFT_RST, TFT_MOSI, TFT_SCLK, TFT_CS); //for display with CS pin

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}


void setup(){
Serial.begin(9600);
tft.init(w, h);
}

void loop(){
uint32_t start = micros_start();

tft.fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;
tft.setCursor(0, 20);
tft.setTextSize(3);
tft.setTextColor(RED);
tft.println("Cost Time:");

tft.setCursor(0, 50);
tft.setTextSize(4);
tft.setTextColor(RED);
tft.println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
tft.drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}

Arduino_GFX

安装方式:在Arduino的项目-加载库-库管理器中搜索GFX Library For Arduino,选择最新版本进行安装。Github下载地址
运行画直线的程序,用时约5.7s,速度超级快!在测试Arduino_GFX的时候还发生了一个小插曲,我连线明明是正确的,但屏幕没有任何反应,排了很久的bug,最后发现是我的arduino开发板有问题,果然太便宜了容易出问题,以后还是用正版的arduino开发板吧!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <Arduino_GFX_Library.h>
int32_t w, h;

/* More dev device declaration: https://github.com/moononournation/Arduino_GFX/wiki/Dev-Device-Declaration */
#if defined(DISPLAY_DEV_KIT)
Arduino_GFX *gfx = create_default_Arduino_GFX();
#else /* !defined(DISPLAY_DEV_KIT) */

/* More data bus class: https://github.com/moononournation/Arduino_GFX/wiki/Data-Bus-Class */
Arduino_DataBus *bus = create_default_Arduino_DataBus();

/* More display class: https://github.com/moononournation/Arduino_GFX/wiki/Display-Class */
Arduino_GFX *gfx = new Arduino_ST7789(bus, DF_GFX_RST, 0 /* rotation */, true /* IPS */);

#endif /* !defined(DISPLAY_DEV_KIT) */

static inline uint32_t micros_start() __attribute__((always_inline));
static inline uint32_t micros_start()
{
uint8_t oms = millis();
while ((uint8_t)millis() == oms)
;
return micros();
}

void setup(){
Serial.begin(9600);
gfx->begin();
w = gfx->width();
h = gfx->height();

#ifdef DF_GFX_BL
pinMode(DF_GFX_BL, OUTPUT);
digitalWrite(DF_GFX_BL, HIGH);
#endif
}

void loop(){
uint32_t start = micros_start();

gfx->fillScreen(BLACK);
testLines();

uint32_t usecLines = micros() - start;

gfx->setCursor(0, 20);
gfx->setTextSize(3);
gfx->setTextColor(RED);
gfx->println(F("Cost Time:"));

gfx->setCursor(0, 50);
gfx->setTextSize(4);
gfx->setTextColor(RED);
gfx->println(usecLines);

delay(60 * 1000L);
}

int32_t testLines()
{
uint32_t start;
int32_t x1, y1, x2, y2;

start = micros_start();

x1 = y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = 0;
y2 = h - 1;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = 0;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = w - 1;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x1 = w - 1;
y1 = h - 1;
y2 = 0;
for (x2 = 0; x2 < w; x2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

x2 = 0;
for (y2 = 0; y2 < h; y2 += 6)
{
gfx->drawLine(x1, y1, x2, y2, BLUE);
}
#ifdef ESP8266
yield(); // avoid long run triggered ESP8266 WDT restart
#endif

return micros() - start;
}

参考内容

]]>
+ + + + + 硬件开发 + + + + + + + arduino + + + +
+ + + + + 【文献学习】前额叶皮层在反转学习中预测状态转换 + + /2024/01/05/dlPFC-bayesian-inference/ + +

作者:Bartolo R, Averbeck B B.
标题:Prefrontal cortex predicts state switches during reversal learning
期刊:Neuron, 2020

具体内容

研究目的/科学问题

研究背景

研究结果

研究结论

想法记录

可以跟进的参考文献

可以借鉴的内容

其它

]]>
+ + + + + 课题积累 + + + + + + + 状态推断 + + 强化学习 + + + +
+ + + + + Github Desktop同步代码 + + /2024/01/05/github-desktop/ + + Github Desktop主要有三个添加仓库的选项:

  1. Clone a Repository
  2. Create a new Repository
  3. Add Existing/Local Repository

如果想把github远程仓库的代码克隆到本地,选择Clone a Repository,即可把远程仓库下载到指定的本地路径。

如果想创建新的仓库,选择Create a new Repository

如果想把本地文件夹作为新的仓库上传到github,选择Add Local Repository

如果本地改动了仓库中的代码,点击Commit to main,然后Push origin,即将新的代码推送到github上。Fetching origin是把github上的代码拉到本地。

  • 不要轻易同意删除本地仓库!!!警惕带local的选项!如果不小心删除了,尝试去回收站找回。
  • 大部分情况下,创建仓库时选择Keep this code private
  • 不要一次性上传很多文件,也不要反复push代码,撤销push操作可能会误删本地代码!
  • 同步重要数据时提前把数据复制到别的地方,做好备份,给自己留个后路!
]]>
+ + + + + 方法教程 + + + + + + + Github Desktop + + + +
+ + + + + 下载教育版origin + + /2024/01/04/install-origin/ + + 之前在联想电脑上安装过origin,今天想在mac的虚拟机上也安一个origin,结果发现我不记得怎么下载了,也不记得之前是从哪里找到的正版安装途径,今天在搜索过程中竟然连官网都找错了,索性记录一下安装过程。

进入origin官网,点击顶部的Try Origin for Free,选择I have NEVER used OriginStudent,点击继续,即可看到如下的界面。

选择Learning Edition,填写姓名、学校、邮箱等信息。填写完提交后去教育邮箱中验证,即可收到软件的下载链接、序列号和密钥。

用同一个教育邮箱申请账号的话,得到的密钥是同一个,如果已经激活过origin软件,就不能在别的电脑上安装origin时使用了。┭┮﹏┭┮

]]>
+ + + + + 方法教程 + + + + + + + 软件安装 + + + +
+ + + + + 记录电极支架制作步骤 + + /2024/01/02/electrode-holder/ + +

利用转动螺杆驱动螺母移动的机械推进原理,利用3D打印的滑片、支架、螺杆和螺母等材料,组装成可推进式多通道电极驱动装置。通过转动螺杆,可以使固定于其上的电极同步推进。当电极记录位点附近的神经元失活后,还可以推进记录电极到更深部的脑组织,从而在实验中观察到更多的神经元活动。

步骤

  1. 用钳子剪下一段排母,包含10个排针
  2. 将电路板卡到排母中间,用焊锡焊接(注意焊接手法,需要多练习)
  3. 剪两段银丝作地线(不需要剪太长,一小段即可),焊接在电路板两侧的孔里
  4. 用电钻(选用合适的钻头,一般选最细的)打磨滑片和底座的孔,尽量保持垂直
  5. 准备三个点胶针,两粗一细,截断处打磨平整,可以借助昆虫针疏通针管
  6. 螺杆穿过滑片中间的孔,拧上两颗螺母,一颗紧靠滑片底部(也不要拧太紧),并涂AB胶固定,用钳子剪去多余的螺杆,留大概7mm的长度
  7. 将滑片放入底座,根据孔的距离判断左右,左侧用粗点胶针固定,右侧用粗点胶针套细点胶针
  8. 放置好后用AB胶固定下面两层,及滑片下方与细点胶针的连接处,胶干后可以尝试拧一下螺丝,看是否可以正常滑动,以及细点胶针是否可以正常向下走
  9. 使用AB胶将底座固定在电路板上(可能需要打磨电路板上的两个孔),注意保持底座和电路板平行

注意事项

  • 涂AB胶固定时一定要小心,搞清楚哪里是需要移动的,哪里是需要固定住的,螺母下端固定,涂胶时避免粘住螺母与滑片上端
  • 以后做电极时戴上口罩,焊锡和AB胶味道太大了
  • 将细针管、螺杆🔩和粗针管的孔径分别修改为0.7mm、1.1mm和0.9mm,针管孔径距两侧均为0.8mm,支架背部柱子直径改为1.65mm
  • AB胶完全干要一定的时间,耐心等待,或第二天再测试电极支架
  • 螺杆的长度预留大概7mm,不能超出电极支架底部
  • 焊接时,先用电烙铁同时加热针脚和焊盘,将焊锡靠近电烙铁的焊头,焊锡粘在焊盘上后,快速抽走焊锡
  • 剪排母时,钳子对准第10列和第11列中间靠右的位置,多剪下来一列没关系,至少要保证前10排排针是完好的

参考文章

  • 多通道在体记录技术——小鼠可推进式微电极阵列帽制作与植入手术
]]>
+ + + + + 方法教程 + + + + + + + 电极 + + + +
+ + + + + 在网页中实时显示当前时间 + + /2024/01/01/html-show-current-time/ + + 早上吃完早饭去浙大图书馆主馆逛了一圈,终于见识到了传说中的自习区域墨水屏幕,确实很高级,如果这个座位被人预约了,屏幕上会显示预约人的姓名和预约时间!之前的基础图书馆里面很少有计算机相关的书籍,没想到新开的主馆里弥补了这个缺憾。

我上午看了一本arduino编程相关的书籍,对蓝牙和wifi模块很感兴趣,书中对这两个模块的使用只是举了一个很简单的例子,连接的都是arduino开发板的串口收发口,可以实现手机与arduino串口监视器的通信。

书中最后举了一个智能温室大棚的例子,我一直不太理解怎么实现手机远程控制arduino端的传感器。中午请教了一下康康,梳理了一下大致流程:arduino板连接wifi模块,接入校园网,向服务器发送传感器数据,可以存入txt文件或数据库中,手机或网页端通过服务器获取到传感器的数据,可以每隔1s请求一次数据。

上位机:指可以直接发送操作指令的计算机或单片机,一般提供用户操作交互界面并向用户展示反馈数据。

下位机:指直接与机器相连接的计算机或单片机,一般用于接收和反馈上位机的指令,并且根据指令控制机器执行动作以及从机器传感器读取数据

上位机给下位机发送控制命令,下位机收到此命令并执行相应的动作。
上位机给下位机发送状态获取命令,下位机收到此命令后调用传感器测量,然后转为数字信息反馈给上位机。
下位机主动发送状态信息或报警信息给上位机。

我一直困惑间隔1s请求一次数据,是否会在网页上看到数据刷新时的闪烁,为了解决这个困惑,康康建议我写个简单的网页测试一下,每个1s获取一下当前的时间。经实践测试,人眼并不会看到数据刷新时的闪烁。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>

</head>
<body>
<div id="time-now">

</div>
<script>
setInterval(function (){
$('#time-now').text(new Date())
}, 1000)
</script>
</body>
</html>

参考文章

]]>
+ + + + + 方法教程 + + + + + + + 物联网 + + HTML + + + +
+ + + + + 2023年度总结 + + /2023/12/29/experience-2023/ + + 小确幸

科研

和去年的我相比,我最大的感触就是我开始去做一些事情了,我能渐渐抛开过去的成绩,正视自己存在的不足,耐心去学习、去积累。从一开始辅助课题组同事做数据分析,到后来争取到合作课题,再到现在慢慢有了自己的课题,很多事情在一开始我并不能看清未来的走向,但我还是选择坚定的走下去,我相信只有这样才能把路走远走宽。

我原本以为这五年我都不会碰生物实验,我相信或许我跨专业就不该碰生物实验,但我常常内心动摇,一方面是对我已有的能力能否支撑我顺利毕业信心不足,另一方面是希望可以自己做实验收集数据,不想一直依附于其他人。

我经常感觉很多事情困难,其实是因为它们一直停留在我的想象中,从未付诸实践。今年下半年我的做事态度转变很大,我开始敢于提出自己的数据分析思路,开始尝试稍微复杂一些的算法,开始学做生物实验,开始自己焊接线路搭建行为装置。我才发现我有能力做到这么多事情,我可以用数据分析结果影响课题的走向,我可以一个人完成小鼠脑立体定位手术,我可以搭建好硬件电路!

希望新的一年我可以进一步提升专业技能,努力做一个有价值的、值得信赖的人,也希望科研方面可以有新的突破,加油加油!我的2024一定很哇塞!🥳

电影🎬

  • 航海王:红发歌姬
  • 满江红
  • 人生路不熟
  • 变形金刚:超能勇士崛起
  • 消失的她
  • 八角笼中
  • 长安三万里
  • 流浪地球2
  • 孤注一掷
  • 无价之宝
  • 刀尖
  • 指环王
  • 三大队

旅行

  • 聊城
  • 杭州
    • 浙大紫金港
    • 动物园和植物园
    • 湘湖
    • 西湖
    • 灵隐寺
    • 浙江升非物质文化遗产馆
    • 塘栖古镇
    • 闲逛
  • 北京
  • 南京
  • 绍兴
  • 邢台
  • 西安

鸟🐦

喜事

  • 我的小侄子出生啦~
  • 实验室三位同门都在今年结婚了,喜糖不断!🍬
  • 康康要来杭州工作啦!

小技能

  • 催眠课上学到了一个小魔术🥰
  • 做饭!

讲座

经验

  1. 生活不是一成不变的,路是越走越宽的
  2. 不要一味地获取资源,对已有资源的消化和吸收更重要
  3. 在做重大决定之前要给自己想好后路,不要心血来潮
  4. 想学的东西很多不要怕,每次学多少也不用太过死板,重要的是持续去学习
  5. 从论文中摘录的观点或数据图,要注明文献出处,以免后续找不到哪一篇文献
  6. 代码要规范命名,写好注释及文档说明,及时同步到github
  7. 做事情要有逻辑,数据分析要紧紧围绕科研问题
  8. 我们并不仅仅是被动处于一个环境之中,我们也可以通过努力去影响和改变周围的环境
  9. 做事要善始善终,别人交代的事情要及时反馈
  10. 笔记中注明当天时间,便于复盘
  11. 对自己的能力有合理的评估,既要量力而行,又要适当突破舒适圈
  12. 要相信每次讨论都是有价值的,及时记录
  13. 文件多平台同步会极大提高工作效率
  14. 学到的知识及时整理,尽量可以用自己的话写出来,有机会的话还可以讲给别人,这样对知识的理解更深刻
  15. 要警惕一直做别人安排的事情,要有自己的思想,对自己做的事情有清晰的认知和规划,明确任务的优先级
  16. 事情并不会总按预期进行,要考虑全面,接受有可能发生的不好的结果
  17. 实践是最快速的学习方式
  18. 成绩不等于个人能力,要想证明自己就要拿出成果
  19. 过去偷懒绕开的困难也许在不久的将来又会变成拦路石,总是要面对的
]]>
+ + + + + 生活随笔 + + + + + + + 年度总结 + + + +
+ + + + + 【MATLAB App Designer使用教程】可拖拽的线 + + /2023/12/29/matlab-app-designer-1/ + + + + + + + 方法教程 + + + + + + + Matlab + + + + + + + + + 脑电数据分析 + + /2023/12/29/eeg-emg-analysis/ + + 睡眠分期

小鼠的睡眠周期主要包括清醒、非快速眼动和快速眼动三个阶段,有时也会考虑微觉醒状态,即发生在NREM阶段的短暂(小于10s)觉醒状态。

  • WAKE:desynchronized EEG and high EMG activity
  • NREM:synchronized EEG with high-amplitude, low-frequency (1–4 Hz) activity and low EMG activity
  • REM:high EEG power at theta frequencies (6–9 Hz) and low EMG activity

睡眠阶段示意图

脑电频段

脑电波通常被分为以下几个频段,每个频段对应不同发脑功能活动。需要注意这些频段的划分并非绝对,不同的研究可能会对频段的划分略有不同。
脑电波

时域分析

频域分析

时频分析

快速傅里叶变换

小波变换

参考文章

]]>
+ + + + + 学习笔记 + + + + + + + 睡眠 + + 脑电 + + + +
+ + + + + 【arduino探索】搭建触摸给水装置 + + /2023/12/29/arduino-touch-pump/ + + 实验材料准备
  • 电容触摸传感器*1

    触摸传感器
  • 蠕动泵*1

  • 可孚一次性无菌加药器 50ml(粗针管)

  • 杜邦线公对公

  • Arduino Uno R3*1

  • 粗针头*2

  • 绝缘胶带

电容触摸传感器和蠕动泵需要焊接杜邦线,用剪刀减去杜邦线一端的公头,用剥线钳暴露铜丝,短暂加热焊锡覆盖暴露的铜丝。

配件功能测试

首先测试给水装置核心配件的功能是否正常。

电容触摸传感器

电容触摸传感器上标有VCC、GND和DAT引脚,VCC是电源引脚,用于给传感器供电;GND是接地引脚;DAT是数据引脚,用于传输触摸信号。经过Arduino程序测试,发现电容触摸传感器默认为高电平,触摸时为低电平。

1
2
3
4
5
6
7
8
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
}

用绝缘胶带缠绕触摸传感器引脚的杜邦线(起到保护和固定的作用),将粗针头固定到传感器较平整的一面,该装置即可作为小鼠的舔水口,小鼠通过针头舔水时,针头另一端会按压触摸传感器,因此可以根据触摸传感器电平的变化检测舔水事件。

蠕动泵

上次买的蠕动泵有一个小配件被我弄坏了,这次测试新买的蠕动泵,通过转接头连接硅胶管,进水口放入粗针管内。给蠕动泵提供5V的电压,经测试,可以正常工作,出水口正常出水。
由于要控制训练过程中每个试次的给水量,因此对蠕动泵的出水量进行测试。经询问师弟,可以采用给水0.1s,间隔0.1s,并重复40次的方式测量,测量前称纸巾的重量,测量后再对纸巾称重,即可计算出每次给水的体积。连续两天测量蠕动泵的出水量,如果保持不变,即认为可正常工作。
$$m=\rho V$$

$$\rho_{水} =1g/cm^3 $$

$$1cm^3=1000\mu L$$

  • 12.29 测试结果:40次 给水0.1s 间隔0.1s 称重:0.05g
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
delay(1000);
int i = 0;
for(i = 1; i <= 40; i ++){ // 测出水量
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
delay(100); // ms
}
}

void loop() {
Serial.println(digitalRead(A0));
}

实验装置

触摸给水装置实物连线

触摸给水

接下来测试触摸传感器控制蠕动泵给水的功能,经测试,功能正常。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void setup() {
pinMode(A0, INPUT); // 电容触摸传感器
pinMode(2, OUTPUT); // 蠕动泵
Serial.begin(9600);
}

void loop() {
Serial.println(digitalRead(A0));
if (digitalRead(A0) == LOW){ // 测试触摸给水
digitalWrite(2, HIGH);
delay(100); // ms
digitalWrite(2, LOW);
}
}

经验

  1. 小鼠训练过程中每天摄入水量为1ml~1.2ml
  2. 测试时针管内的气泡一定要排干净,且传感器的放置方式与实际任务期间保持一致
]]>
+ + + + + 硬件开发 + + + + + + + arduino + + + +
+ + + + + 神经元类型和活动状态判断标准 + + /2023/12/28/neurons-exc-or-inh/ + + 神经元发放率标准化方法

Z-score是用来衡量数据点与其所在数据集平均值之间偏差程度的一种统计量。它通常将数据点减去均值,再除以标准差,将数据标准化到一个标准正态分布上。点击查看标准正态分布表
$$Zscore=\frac{x-\bar{x}}{\sigma}$$

标准正态分布
68-95-99.7法则:
约有 68% 的数据点落在均值左右一个标准差的范围内。
约有 95% 的数据点落在均值左右两个标准差的范围内。
约有 99.7% 的数据点落在均值左右三个标准差的范围内。

相关概念

标准差

$$\sigma =\sqrt{\frac{\sum_{1}^{n}(x_i-\bar x)^2 }{n}}$$

标准差是方差的平方根,用于描述一组数据的离散程度或变异程度。标准差衡量数据集中各个数据值与其平均值之间的偏离程度。标准差消除了平方的影响,数值更接近于原始数据的数量级,更易于直观理解和比较。

标准误

$$SEM=\frac{\sigma}{\sqrt{n}}$$

标准误差是一种用于衡量样本平均值估计的变异程度或不确定性的统计量。它表示样本平均值估计与总体平均值之间的偏差,标准误差的值越小,代表样本均值估计越接近总体均值,或者说样本均值的可靠性越高。

兴奋or抑制

参考文献1
We first examined whether a neuron was excited or inhibited by light stimulation by asking whether its firing rate during the first 500 ms after light onset was higher or lower, respectively, than its firing rate in the 500 ms immediately before light onset. This was examined separately for each light intensity (Wilcoxon signed-rank test, p < 0.05, corrected for multiple comparisons). In order to quantify the strength of inhibition we calculated the normalized firing rate by dividing the mean firing in the first 500 ms after laser onset by the mean baseline firing in the 500 ms before laser onset.

Babl S S, Rummell B P, Sigurdsson T. The spatial extent of optogenetic silencing in transgenic mice expressing channelrhodopsin in inhibitory interneurons[J]. Cell reports, 2019, 29(5): 1381-1395. e4.

参考文献2
Food-cue, lever-press, and dish-entry responses were calculated as Z-scores normalized to 20 pre-cue bins of 300 ms. Neurons showing a Z-score >2.58 (P < 0.01) during the first two bins following the onset of the food cue, lever press, or dish entry were classified as excitatory responses, whereas neurons showing a Z-score < −1.96 (P < 0.05) during the same first two bins were classified as inhibitory responses.

Engelke D S, Zhang X O, O’Malley J J, et al. A hypothalamic-thalamostriatal circuit that controls approach-avoidance conflict in rats[J]. Nature communications, 2021, 12(1): 2517.

神经元类型

The spike width, defined as the time from the valley to the return to baseline after the peak, and the ratio between peak and valley amplitudes.

]]>
+ + + + + 学习笔记 + + + + + + + 生物 + + + +
+ + + + + 【综述】神经环路的架构 + + /2023/12/27/architectures-of-neuronal-circuits/ + + + + + + + 学习笔记 + + + + + + + 神经环路 + + + + + + + + + 神经编码和神经解码 + + /2023/12/27/neural-encoding-and-decoding/ + + 神经系统的编码方式

信息是怎样在大脑🧠中编码的?几个世纪以来,这个问题一直吸引着医学生、科学家和哲学家。然而,每当有人提出如何在大脑中处理和表征信息的建议时,这些建议往往被证明是简单化和理想主义的。下面简单介绍一下信息可能怎样存储在神经活动中的理论和概念。

频率编码 Rate/Frequency coding

频率编码被大多数的研究者视为主要的信息编码方式。如皮肤上的温度感受器就是通过频率编码将温度信息从输入系统转为神经活动的,低温刺激时,皮肤中的温度敏感性外周神经元的放电比较缓慢,随着温度的升高,神经元的发放率升高。在听觉系统中也存在频率编码,神经元的发放率与声音频率直接相关,但高于1kHz这个阈值会采用不同的编码方式。
需要注意的是,传递温度信息的神经元的活动与传递触觉或痛觉信息的神经元的活动没有什么不同,频率编码和动作电位是相似的。感觉被识别为触觉或痛觉是由信息来自的感觉输入系统类型决定的。

时间编码 Temporal coding

在我们考虑必须从神经响应中精确测量神经元的放电时间以提取额大部分的信息时,时间编码的概念就产生了。这种精确性决定了神经编码的时间分辨率。大量的研究发现这种时间分辨率在毫秒级别,提示精确的放电时间是神经编码中的一个重要因素。当发现精确的放电时间或高频发放波动携带信息时,神经编码通常被确认为时间编码。
下图为猴子MT脑区的一个神经元在三个不同视觉刺激下的响应模式,最上方面板的发放模式通常被认为是频率编码,最下方面板的发放模式反映时间编码。
时间编码

多路复用编码 Multiplexed coding

群体编码 Population coding

稀疏编码 Sparse coding

拓扑结构编码 Topological coding

相位编码 Phase coding

序列编码 Sequence coding


编码模型与解码模型

向量x表示众多神经元的活动 ,如:神经元峰电位Spikes、局部场电位LFP、颅内脑电信号iEEG和脑电图EEG等。
向量y表示感兴趣的行为、认知等状态 ,如:运动意图、记忆状态、情感和各种疾病状态等。

编码模型encoder():描述感兴趣的行为、认知等状态y如何表征于神经元的活动x
$$x = encoder(y)$$

$$f(stimulus)\to neural\ activity$$

解码模型decoder():描述如何从神经元的活动x中估计感兴趣的行为、认知等状态y
$$y = decoder(x)$$

$$f(neural\ activity)\to stimulus$$

神经编码

广义线性模型 GLM

可以使用广义线性模型根据提示、刺激、奖励、惩罚等行为和任务变量预测神经元的活动,进而评估行为和任务变量(如)对神经元活动的贡献。

神经解码

neural content:在特定脑区有哪些信息?在什么时间?
neural coding:神经活动的什么特征包含信息?
神经解码背后的思想是通过神经活动尝试预测刺激本身或动物的行为。本质上,如果我们可以从许多脑区做记录,并辨别出不同部分的内容, 我们可以追踪大脑的信息流并试图解开使我们能执行特定任务的算法。
群体解码示意图

例如,我们向猴子展示一张猕猴桃🥝的照片,同时我们记录某个脑区神经元的活动。神经解码就是我们把神经活动模式“喂进”机器学习算法,我们称之为模式分类器。这个算法学习建立特定刺激和特定神经活动模式的关联。然后用另外的照片重复这个过程,获得另一组神经活动模式,喂进分类器,然后分类器学习这个关联。一旦分类器学到这个关联,我们可以使用或测试这个分类器,用于预测呈现的刺激,与实际呈现的刺激相比,即可判断分类器预测是否正确。

交叉验证

在进行交叉验证时,通常是将数据集划分为训练集和测试集,然后在训练集上进行交叉验证来评估模型性能和选择最佳超参数,最后使用选定的最佳模型配置在测试集上进行最终的性能评估。

交叉验证

最大相关系数分类器 Maximum Correlation Coefficient Classifier

Maximum Correlation Coefficient (MCC) Classifier(最大相关系数分类器)是一种用于模式识别和分类任务的统计学方法,其核心思想是寻找能最大化特征与类别之间相关性的投影方向。计算测试向量与不同刺激下神经元群体活动的原型向量的相关性,相关性最高的即为分类器的预测结果。解码可以视为评估下游神经元可获得的信息,分类器要学习的是神经元的突触权重,待分类的神经元活动模式为突触前活动。
在同一时间窗下训练和测试数据,如果是在baseline阶段,即刺激呈现之前,不同刺激的baseline阶段活动应差别不大,所以解码准确率大概维持在chance level(1/刺激的类别数)。
数据组织方式
原型

梯度提升树解码器 Gradient Boosted Trees Decoder

支持向量机 Support Vector Machine

支持向量机是一种监督式学习算法,通常用于分类和回归分析。其目标是在特征空间中找到一个最优的超平面,能够有效地将不同类别的数据分开。SVM的主要思想是找到能够最大化类别间间隔(Margin)的超平面,即找到一个决策边界,使得两个不同类别的数据点到这个边界的距离尽可能远。而支持向量则是离这个决策边界最近的那些数据点。

基本数据分析

计算神经元的发放速率 Firing rate

神经元的概率性发放:即使是相同刺激下的不同试次,同一神经元不是确定性地发放,而是按照一定概率分布发放。
神经元的发放概率Pr(t至t+∆t):某个特定时间段内发放的概率;
神经元的发放速率r(t):某个特定时间点发放的概率密度
$$Pr(t至t+\Delta t)=r(t)\Delta t$$

补充知识:连续型随机变量X落在区间(x1,x2]上的概率P{x1<X≤x2}等于区间(x1,x2]上曲线y=f(x)之下的曲边梯形的面积。介于曲线y=f(x)与x轴之间的面积等于1。

概率密度

当∆x充分小时,有
$$P \{x<X\le x+\Delta x \} \approx f(x)\Delta x$$

对于具有相同试次结构的trial-by-trial的实验,一般认为试次之间是同质的。在有多次同等条件试验的情况下,假定有N个试次,选定一个足够小的时间窗∆t(如50ms),计算t至t+∆t范围内所有试次中神经元发放的次数n,则发放速率
$$r(t) ≈ \frac{n}{N\Delta t}$$

单位为spikes/s或Hz。

对于单个试次条件下,假定刺激是缓慢变化的,沿着时间进行平均,可以通过较长时间窗T内的平均发放次数估计发放速率,时间窗T内的发放次数记为n,则
$$r = \frac{n}{T}$$

作图

栅格图(Raster plot)可以直观地展示神经元的发放事件,一行代表神经元在一次试验中的发放,每个点代表一次放电。刺激前后反应直方图(Peri-Stimulus Time Histogram PSTH)用于展示特定刺激事件发生前后在各个时间点神经元的发放速率。

  1. 将N个试次按照感兴趣的刺激事件发生的时间对齐,如灯亮/蜂鸣器响等
  2. 选择合适的时间窗∆t,将时间分为长度为∆t的小段
  3. 每个小段内,统计所有试次中该神经元的总发放次数n
  4. 用n/N∆t(单位为spikes/s或Hz)作为每个小段内的发放速率的估计
  5. 绘制发放速率沿着时间变化的直方图

光栅图和PSTH

参考内容

  • 《Information processing by neuronal populations》
  • 浙江大学现代神经生物学课程
  • 《From molecules to networks: an introduction to cellular and molecular neuroscience》
  • 《Theoretical neuroscience: computational and mathematical modeling of neural systems》
  • 梯度提升树(Gradient Boosted Trees):模型理解
]]>
+ + + + + 学习笔记 + + + + + + + 神经编码 + + 神经解码 + + + +
+ + + + + 【arduino探索】使用ArControl编写“炸弹💣游戏” + + /2023/12/26/arcontrol-boom-game/ + +

游戏规则:
简易版:游戏有一个5秒倒计时炸弹,时间到了就会爆炸,马里奥玩家就会死亡。如果玩家可以在这5s内按下停止开关,炸弹不会爆炸,玩家马里奥任务成功。

实验材料:
Arduino UNO R3 * 1
面包板 * 1
发光二极管 * 1(模拟炸弹)
按钮 * 1(模拟开关)

Arduino引脚映射

ArControl对Arduino UNO开发板做了端口映射,定义好了6个输入端口和8个输出端口,示意图如下。IN和OUT都是相对于Arduino开发板来说的。在这个小游戏中,我们使用pinA0IN1接收按钮的状态,pin2OUT1控制LED灯的状态。

Arduino引脚映射

Arduino测试程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//测试按钮控制led灯是否正常
int ledPin = 2;

void setup() {
pinMode(A0, INPUT);
pinMode(ledPin, OUTPUT);
}

void loop() {
if (digitalRead(A0) == HIGH){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}

Arduino实物连接图

关于接线我还闹了个笑话,我在ArControl上进行测试,发现按下按钮之后,IN1端口会持续很久的高电平,而且不按按钮时也会有通道闪烁的情况。我在arduino IDE中测试按钮控制LED灯的情况,发现了类似的问题,当我不按按钮时,LED灯也是亮的,按下按钮之后,LED灯只是变得更亮了。我检查线路并没发现什么问题,去请教师兄,才发现我接线时按钮旁边的下拉电阻没接上!!!😅按我那样的接法,电阻纯属摆设,跟按钮的电路半毛钱关系都没有。重新接好电阻之后,再测试就正常了。(^-^)V

实物连接图

ArControl使用流程

ArControl的软件部分主要包括两个应用程序,其中ArControl Designer用于编写行为范式的protocol,ArControl Recorder用于监控端口的运行状态并采集实验数据。

ArControl Designer

ArControl Designer借鉴了状态机的原理,把行为实验流程等效分解为一系列时序上相互衔接的子任务(State),可以根据实验逻辑在状态之间进行跳转。

每一个State可以对6种功能进行配置,包括改变任务变量(do-var)、控制输出通道(do-pin)、 检测任务变量(when-var)、检测实验计数(when-count)、检测等待时间 (when-time)以及检测输入端口(when-pin)。其中每个功能的详细配置是在子窗体中进行的。

在这个小游戏中,逻辑比较简单,可以分为倒计时、炸弹爆炸和炸弹不爆炸三个状态,分别记为S1S2S3。如果在没有在5s内按下停止开关,则跳转到S2;如果在5s内按下停止开关,则跳转到S3。编写完实验流程之后,保存。

ArControl Designer
如果想查看实验流程图,也可以点击File→Export pdf,这个功能真的很方便检查实验逻辑!
流程图

ArControl Recorder

选择Arduino开发板对应的端口,载入实验流程并烧录进开发板。点击Start按钮即可运行,点击Stop按钮即可手动终止程序,也可以等程序运行完自动结束。中间的板块可以实时观察输入/输出端口的电平变化,如果为绿色,则表示当前端口是高电平。下图分别为炸弹💣爆炸💥和成功按下停止开关时的端口状态。

Boom
No boom

参考内容

]]>
+ + + + + 硬件开发 + + + + + + + arduino + + ArControl + + + +
+ + + + + 【arduino探索】控制蠕动泵出水 + + /2023/12/26/arduino-pump/ + + 前几天在淘宝上买的蠕动泵终于到货了,早上拆开快递一脸懵,摆在我面前两个难题:第一,我该怎么给这个蠕动泵供电呢?虽然顶部标有正负极,但我还是不知道该怎么办;第二,蠕动泵自带了管子,比较短,我怎么换成我们实验室自己的硅胶管呢?

对于第一个问题,我请教了师弟。拿剪刀将杜邦线剪去一头,然后用剥线钳暴露电线,将电线穿过蠕动泵顶部的孔,折叠后焊锡,另一个孔也同样操作即可。接好线后我在arduino板上测试了一下,一端接入5V电压,另一端接地,测试发现可以正常工作!

对于第二个问题,我的第一反应是把自带的管抽出来,换成我们实验室自己的硅胶管。但我抽出来才发现,泵头的孔太小,硅胶管穿不进去。后来尝试把管口剪尖,终于穿进去了,结果泵头的一个小组件崩飞了,┭┮﹏┭┮。后来师弟和师姐意外发现快递里面的转接头(我早就看到了,但不知道是干啥用的),告诉我说这个可以直接接到自带的管上,然后另一端连自己的硅胶管,我才恍然大悟!

图片说明

虽然小零件崩飞了,但我还是完整地测试了一下蠕动泵的功能(用led blink的程序测试的),一端接pin12,一端接地,arduino写入程序后蠕动泵可以实现间隔1s给水。静待我买的新蠕动泵!
蠕动泵实物连线

]]>
+ + + + + 硬件开发 + + + + + + + arduino + + + +
+ + + + + 【arduino探索】按键控制LED灯 + + /2023/12/25/arduino-button-led-demo/ + + Arudino Uno R3开发板简介

Arudino Uno R3开发板引脚说明

电路图

目标:使用四角按键开关控制LED灯,当按钮按下时灯亮,松开时灯灭。

实现思路:将引脚2改为input mode,反映按键的状态。引脚12为output mode,控制led灯的亮灭。当按键按下时,引脚2为高电平,此时led灯亮;当按钮松开时,引脚2为低电平,此时led灯灭。(对应仿真图连线)

如果引脚2的状态为input pullup mode(如果外部组件未启用,上拉电阻将输入端口处的电压拉到高电平),当按键按下时,引脚2为低电平,此时led灯亮;当按钮松开时,引脚2为高电平,此时led灯灭。(对应实物连线)

注意事项:四角按键同侧不相连,相连不同侧。

仿真
实物

Arduino程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int buttonPin = 2;
int ledPin = 12;

void setup() {
// put your setup code here, to run once:
pinMode(buttonPin, INPUT_PULLUP);
pinMode(ledPin, OUTPUT);
}

void loop() {
// put your main code here, to run repeatedly:
if (digitalRead(buttonPin) == LOW){
digitalWrite(ledPin, HIGH);
} else{
digitalWrite(ledPin, LOW);
}
}

参考文章

]]>
+ + + + + 硬件开发 + + + + + + + arduino + + + +
+ + + + + 在Mac电脑上安装VMware Fusion + + /2023/12/23/mac-vmware-fusion/ + + 大学毕业以后买了一台新的联想电脑,当时还因为终于可以用GPU而兴奋了很久,后来去北京出差背着电脑来回走了很久,不插着电源很快就会没电。从北京回来我就斥巨资买了一台苹果电脑,续航能力没得说,平时用的大部分软件也都是有mac版的。因为工位空间有限,我就把苹果电脑放在了工位,联想电脑留在了宿舍,平时偶尔会远程控制一下宿舍的电脑,但有时会很卡,操作也不太方便。

之前有想过安装mac双系统,但又怕对电脑不好,就一直将就着使用了。最近有一些软件只能在windows系统上运行,狠了狠心,在mac上安了个虚拟机(VMware Fusion 13),可以比较方便地使用windows系统。(存储空间一下子少了很多,┻┳|・ω・|)

VMware Fusion有个人免费版,但我实在是注册不上这个网站,曲线救国选择下载Fusion 13 Pro,然后输入网上找到的序列号(5N400-4AH82-M88Q3-0LC0P-0TRL0 ),就可以正常使用了。

注意事项

  1. 可以直接通过Microsoft安装win11
  2. 新建虚拟磁盘
  3. 记住密码并存储在mac钥匙串中
  4. 安装VMware Tools之后全屏可以铺满且有原始mac电脑的分辨率(以管理员身份运行windows powershell→输入Set-ExecutionPolicy RemoteSigned→A→菜单栏选择虚拟机→安装VMware Tools)
  5. 我安装的时候没有遇到网上教程所说的网络问题

参考文章

]]>
+ + + + + 方法教程 + + + + + + + 虚拟机 + + + +
+ + + + + VSCode无法正常打开.ipynb文件 + + /2023/12/23/vscode-ipynb-error/ + + 上午原本想写程序,打开VSCode之后发现不能打开.ipynb文件了,报错信息如下:

Error loading webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

The editor could not be opened due to an unexpected error: Could not initialize webview: Error: Could not register service worker: InvalidStateError: Failed to register a ServiceWorker: The document is in an invalid state..

在网上查了一些解决方法,尝试过删除vscode缓存(~/Library/Application Support/Code/)、重新安装插件和重启VSCode,但都不起作用。经过不懈努力,终于在stack overflow上找到了适合我的解决方案,删除Service Worker文件夹之后重启VSCode,.ipynb文件就可以正常显示了!

There is another possible reason for OSX, that the files in the following paths are restricted by user permissions.

MAC: ~/Library/Application Support/Code/Service Worker

You can directly delete folders with restricted permissions.

After restarting VScode, he will generate it again.

]]>
+ + + + + 方法教程 + + + + + + + Jupyter Notebook + + VSCode + + + +
+ + + + + ImageJ插件开发 + + /2023/07/21/imagej-plugin-9/ + + 开发流程
  1. 安装Java8 JDK (Windows x86 64-bit) ​https://docs.azul.com/core/zulu-openjdk/install/windows
  2. 安装Eclipse IDE for Java Developers ​https://www.eclipse.org/downloads/
  3. 在github下载示例插件并修改 ​GitHub - imagej/example-imagej2-command: Simple Maven project for an ImageJ2 command
  • 修改pom.xml:重点修改groupId、artifactId、version、name、的内容
  • Eclipse-Import-Maven-Existing Maven Projects
  • 重命名:项目名、包名、java文件中类名和菜单路径
  1. Run as Java application 确保程序可以正常运行
  2. Run as Maven build 控制台输出BUILD SUCCESS 则表示程序成功打包为jar包(保存在target目录下)
  3. 将jar包粘贴至Fiji的plugin目录,运行软件测试插件效果

问题记录

  1. 如果pom.xml中报错,则尝试修改,并等待右下角更新完成
  2. 打包好的插件在ImageJ中无法正常运行,报错java.lang.ClassCastException: com.chen.brain.pluginMain cannot be cast to org.scijava.plugin.SciJavaPlugin
    报错原因:pluginMain类没有实现org.scijava.command.Command接口,而这是必须的,才能将其识别为有效的SciJava插件。@Plugin注解用于指定该类应注册为一个命令插件,但由于它没有实现所需的接口,因此会导致ClassCastException异常。
    解决方案:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import org.scijava.command.Command;
    import org.scijava.plugin.Plugin;

    @Plugin(type = Command.class, menuPath = "Plugins>brainRegistration")
    public class pluginMain implements Command {

    // 省略其他部分

    @Override
    public void run() {
    // 在这里实现插件的逻辑
    }

    public static void main(String[] args) {
    new pluginMain().location();
    }
    }
  3. 在Eclipse中初次导入项目时,要等待build(可能需要等待几分钟)
  4. 最好在官方提供的模板基础上写自己的代码,而不是用自己新建的maven项目

参考内容

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + 基底神经节环路 + + /2023/07/21/basal-ganglia/ + +

术语解释:
Cortex 大脑皮层
STR(striatum) 纹状体
STN(subthalamic nucleus)丘脑底核
GPe(globus pallidus )苍白球外侧
GPi(globus pallidus in)苍白球内侧
Subthalamic nucleaus 丘脑底核
Thalamus 丘脑
SNr(substantia nigra pars reticulata)黑质网状部

红色和灰色的箭头分别表示兴奋性和抑制性的连接
直接通路促进运动
间接通路抑制运动
直接通路和间接通路

参考内容

]]>
+ + + + + 学习笔记 + + + + +
+ + + + + neurogym学习笔记【01】 + + /2023/07/17/neurogym/ + +

NeuroGym是一个经过仔细挑选的神经科学任务集合,具有公共接口。其目标是促进在神经科学任务上神经网络模型的训练。

NeuroGym是一个工具包,可以让您在许多已建立的神经科学任务技术上训练任何神经网络模型,如标准的监督学习或强化学习。

该教程用于理解Neurogym的任务结构,程序运行环境为Google Colab。本文翻译自Neurogym官方文档,对应的代码 [Open in Colab]

neurogym是基于gym开发的,很多参数的设置用起来不是很顺手,不清楚源代码怎么写的,有些代码不太好理解。但本质上就是继承了gym的一些方法,生成行为任务的数据。后面可能不会直接用neurogym,而是仿写并实现课题组内已有的范式。

安装

1
2
3
4
! pip install gym
! git clone https://github.com/gyyang/neurogym.git
%cd neurogym
! pip install -e .

OpenAI gym 任务

Neurogym任务遵循基本的OpenAI gym任务形式。每个任务定义为一个Python类,继承自gym.Env类。

在这一节中,我们描述一个OpenAI gym任务的基本结构。

__init__方法中,必须定义两个属性,self.observation_spaceself.action_space,它们描述了观测(网络输入)和动作(网络输出)的空间类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import warnings
warnings.filterwarnings("ignore")

import numpy as np
import gym

class MyEnv(gym.Env):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(low=0., high=1., shape=(2,))
self.action_space = gym.spaces.Discrete(3)
def step(self, action):
ob = self.observation_space.sample()
reward = 1.
done = False
info = {}
return ob, reward, done, info
def reset(self):
ob = self.observation_space.sample()
return ob
env = MyEnv()
print('sample random observation value')
print(env.observation_space.sample())
print('sample random action value')
print(env.action_space.sample())
# 输出:
# sample random observation value
# [0.23197113 0.8055692 ]
# sample random action value
# 0

另一个需要定义的关键方法是step方法,用于接收智能体的动作后更新环境、输出观测和奖励。

step方法将action作为输入,并输出智能体的下一个观测observation,智能体获得的标量奖励reward,用于描述环境是否需要重置的布尔值done,以及包含任何额外信息的字典info

如果环境通过内部状态描述,reset方法需要重置这些内部状态。该方法返回一个初始观测observation

下面我们定义一个简单的任务,智能体沿着一维直线采取动作。奖励由智能体在直线上的位置决定。

1
2
3
4
5
6
7
8
9
import matplotlib.pyplot as plt

def get_reward(x):
return np.sin(x) * np.exp(-np.abs(x)/3)

xs = np.linspace(-10, 10, 100)
plt.plot(xs, get_reward(xs))
plt.xlabel('State value(observation)')
plt.ylabel('Reward')

运行结果
智能体可以与环节迭代地互动,红色星星表示智能体的初始状态。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class MyEnv(gym.Env):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(-10,10,(1,))
self.action_space = gym.spaces.Discrete(3) # 0,1,2
self.state = 0.
def step(self,action):
self.state += (action - 1.) * 0.1 # action 0 1 2 对应状态 -0.1 0 0.1
self.state = np.clip(self.state, -10, 10) # 限制取值范围
ob = self.state
reward = get_reward(self.state)
done = False
info = {}
return ob, reward, done, info
def reset(self):
# 重新初始化状态
self.state = self.observation_space.sample()
return self.state
env = MyEnv()
ob = env.reset()
ob_log = list()
reward_log = list()
for i in range(1000):
action = env.action_space.sample()
ob, reward, done, info = env.step(action)
ob_log.append(ob)
reward_log.append(reward)
plt.plot(ob_log, reward_log)
plt.xlabel('State value(observation)')
plt.ylabel('Reward')

运行结果

基于试次(trial)的Neurogym任务

许多神经科学和认知科学的任务有试次结构。neurogym.TrialEnv为常见的基于试次任务提供了类。它与gym.Env的主要不同在于_new_trial()方法,该方法可以生成新试次的摘要信息,并且可选择地,生成观测和真实值输出。除此之外,用户提供了_step()方法而不是step()方法。

_new_trial()方法接收任意键-值参数**kwargs,输出一个包含该试次相关信息的字典trial。这个字典在_step中可以作为self.trial访问。

这里我们定义一个简单的任务,智能体在每个试次需要基于它的观测做出一个二元决策。每个试次只有一个时间步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import neurogym as ngym
from neurogym import TrialEnv

class MyTrialEnv(TrialEnv):
def __init__(self):
super().__init__()
self.observation_space = gym.spaces.Box(-1., 1., (1,))
self.action_space = gym.spaces.Discrete(2) # 0 1
self.next_ob = np.random.uniform(-1, 1, size=(1,)) # 用于生成[-1,1)范围内均分分布的随机数
def _new_trial(self): # 实现父类TrialEnv中的_new_trial和_step方法
ob = self.next_ob
self.next_ob = np.random.uniform(-1, 1, size=(1,))
trial = dict()
trial['ground_truth'] = (ob > 0) * 1.0
return trial
def _step(self, action):
ob = self.next_ob
reward = (action == self.trial['ground_truth']) * 1.0

done = False
info = {'new_trial': True}
return ob, reward, done, info

env = MyTrialEnv()
ob = env.reset()
print('Trial', 0)
print('Observation', ob)

for i in range(5):
action = env.action_space.sample()
print('Action', action)
ob, reward, done, info = env.step(action)
print('Reward', reward)
print('Trial', i+1)
print('Observation', ob)
Trial 0
# 输出:
# Observation [0.37521716]
# Action 1
# Reward [1.]
# Trial 1
# Observation [0.88569181]
# Action 1
# Reward [1.] ···

TrialEnv类定义了两个抽象方法:_new_trial()_step()。这两个方法没有具体的实现,只有方法的声明和文档字符串。这样做的目的是强制任何继承TrialEnv的子类必须实现这两个方法,以便成为一个完整的环境。

环境reset时会调用new_trial()方法,step之后也会调用new_trial()方法,只不过这些是在父类中实现的,我们创建环境时只需要把_new_trial()方法实现即可。

具体可见neurogym目录下的core.py文件。

在基于试次的任务中包含时间,阶段和观测

许多神经科学和认知科学任务遵循额外的时间结构,这些结构被包含进neurogym.TrialEnv。这些任务通常

  1. 描述为实际时间而不是离散时间步。例如,任务可以持续3s
  2. 每个试次包含许多时间阶段,比如刺激阶段和响应阶段。

为了包含这些特征,neurogym任务通常支持设置每一步的时间长度dt(单位为ms),以及每个时间阶段的时间长度timing

例如,考虑下面的二元决策任务,有500ms的刺激阶段,跟着500ms的决策阶段。可以通过self._new_trial()中的self.add_period()在每个试次中添加阶段。在_step()中,你可以通过self.in_period(period_name)检查任务当前所处的阶段。

关于这段代码,我真的向多说几句:官方文档给的这段示例代码有点问题,按它原本的写法,stimulus阶段不应该获得奖励,但是奖励却为1。我调试了很久,总觉得observation、action和reward之间错位了,但看代码又找不出具体问题。今天上午终于发现了,在env.reset()时stimulus阶段就开始了,等进入循环时时间步已经走了一步了,但是此时仍用初始的观测执行env.step(action),就会造成reward不匹配。所以采取的修改方式是删掉循环外存储的ob,直接从第二个时间步开始,这样就不会错位了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import numpy as np
import neurogym as ngym
import gym
from neurogym import TrialEnv
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'DejaVu Sans'


class MyDecisionEnv(TrialEnv):
def __init__(self, dt=100, timing=None):
super().__init__(dt=dt)
self.timing = {'stimulus':500, 'decision':500}
if timing:
self.timing.update(timing)
self.observation_space = gym.spaces.Box(-1., 1., (1,))
self.action_space = gym.spaces.Discrete(2)
def _new_trial(self):
periods = ['stimulus', 'decision']
self.add_period(periods)

stimulus = np.random.uniform(-1, 1, (1,))
trial = dict()
trial['stimulus'] = stimulus
trial['ground_truth'] = (stimulus > 0) * 1.0
trial['new_trial'] = True
return trial

def _step(self, action):
if self.in_period('stimulus'):
ob = np.array([self.trial['stimulus']])
reward = 0.
else:
ob = np.array([0.])
reward = (action==self.trial['ground_truth'])*1.0

done = False
info = {'new_trial': False}
return ob, reward, done, info

log = {'ob':[], 'action':[], 'reward':[]}
env = MyDecisionEnv(dt=100)
ob = env.reset()

# log['ob'].append(ob)
for i in range(20):
action = env.action_space.sample()
log['action'].append(action)
ob, reward, done, info = env.step(action)
log['reward'].append(reward)
log['ob'].append(ob)

log['ob'] = log['ob'][:-1]
f, axes = plt.subplots(3, 1, sharex=True)
for ax, key in zip(axes, ['ob', 'action', 'reward']):
ax.plot(log[key], 'o-')
ax.set_ylabel(key)

运行结果

在每个试次的开始设置观测和真实值

在许多任务中,每个试次的观测和真实值是提前确定的,可以在self._new_trial()中设置。生成的观测和真实值可以用作监督学习的输入和目标。

观测和真实值可以在self._new_trial()中通过self.add_ob()self.set_groundtruth()方法设置。用户可以用它们的名字指明观测的阶段和位置。比如,self.add_ob(1, period='stimulus', where='fixation')

允许用户通过self.obself.gt访问整个试次的观测和真实值,并通过self.ob_nowself.gt_now访问它们的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import numpy as np
import neurogym as ngym
import gym
from neurogym import TrialEnv
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'DejaVu Sans'

class MyDecisionEnv(TrialEnv):
def __init__(self, dt=100, timing=None):
# 初始化,关键是设置观测空间和动作空间
super().__init__(dt=dt)
self.timing = {'stimulus':500, 'decision':500}
if timing:
self.timing.update(timing)

name = {'fixation': 0, 'stimulus': 1}
self.observation_space = ngym.spaces.Box(low=-1, high=1, shape=(2,), name=name) # 可以给每个维度命名
name = {'fixation':0, 'choice':[1,2]}
self.action_space = ngym.spaces.Discrete(3, name=name)
def _new_trial(self):
# 返回试次相关信息:阶段,刺激,真实值等
periods = ['stimulus', 'decision']
self.add_period(periods)
stimulus = np.random.uniform(-1, 1, (1,))
self.add_ob(1, period="stimulus", where="fixation")
self.add_ob(stimulus, period="stimulus", where="stimulus")
# where对应的是维度名
ground_truth = int(stimulus > 0)
self.set_groundtruth(ground_truth, period="decision", where="choice")

trial = dict()
trial['stimulus'] = stimulus
trial['ground_truth'] = ground_truth

return trial

def _step(self, action):
# 执行动作,返回观测,奖励等信息
reward = (action==self.gt_now) * 1.0
done = False # 环境是否需要重置
info = {'new_trial': False}
return self.ob_now, reward, done, info
env = MyDecisionEnv()
_ = env.reset()

trial = env.new_trial()
ob, gt = env.ob, env.gt

print(trial)
print(ob)
print(gt)
fig = ngym.utils.plot_env(env, num_trials=2)

补充知识

  1. self: 在Python中,当定义一个类方法时,第一个参数通常被称为self,它代表类的实例对象,允许在类的方法中访问对象的属性和其他方法。
  2. super().init(): 在面向对象编程中,当创建一个子类时,通常需要继承父类的属性和方法,可以使用super().__init__()来调用父类的构造方法,确保父类的初始化代码得以执行。当super().__init__()不带参数时,它会调用父类的构造方法,并将子类的实例作为第一个参数传递给父类的构造方法。
  3. 继承: 在面向对象编程中,继承是一种重要的概念,它允许你创建一个新的类(子类),从一个现有的类(父类)继承属性和方法。子类可以访问父类的属性和方法,并且还可以添加自己的属性和方法。如class Child(Parent): 这样的语法表示子类 Child 继承了父类 Parent。
  4. 时间步(time step): 在计算机科学和数学中,时间步长通常用于描述在离散时间模型中的时间间隔。理解时间步长的关键是认识到许多模型和系统在仿真或模拟时需要将时间划分成离散的部分,而时间步长就是这个离散化的单位。在每个时间步长内,系统的状态会被更新,从而使得系统在连续时间范围内的变化可以通过离散时间步长来近似。
  5. 抽象方法: 抽象方法是指在父类中声明但没有具体实现的方法,它只有方法名、参数列表和文档字符串,没有具体的代码实现。子类继承这个父类时,必须实现这些抽象方法,否则子类也会被视为抽象类,无法实例化。

参考内容

]]>
+ + + + + 课题积累 + + + + +
+ + + + + 二维脑片配准插件开发 + + /2023/07/16/imagej-plugin-8/ + +
]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + + +
+ + + + + 认识你自己 + + /2023/07/16/life-review/ + + 不知道是从什么时候开始,我变了。刚入学那会我多么希望可以有个朋友和我一起上课、吃饭、坐校车啊,那种一个人走在路上突然冒出来的孤独感,我已经很久没有感受到了。我的内心愈发平静,我的喜好愈发明确,我似乎看见了一个更清晰的自我。

说实话,我对自己之前的学习习惯不是很满意,知识不成体系,记笔记零零散散,记忆随着时间的推移渐渐消退,我却好像什么也没留下,总有一种学了但没学扎实的感觉。这个习惯被我带到了新学校,每天八点半来到实验室,一整天的时间点开了各种网页,检索了各种知识,看过了但不清楚自己是否记住了,下次遇到问题又是同样的搜索路径。我分析数据、写应用程序,却总觉得这种东拼西凑的知识来得不踏实。

大约是两周前我开始尝试写博客记录每天的学习内容,不是在一天结束的时候写,而是从早上来到工位开始,每日计划、优质博客、学习进展、方法教程等,什么都可以写,总之就是每天结束时要有所收获。和之前全是随笔的博客相比,工作日写下的博客可以说是干货满满。如果我是做一个小项目或是翻译教材,会在博客标题中标上序号,这个小细节在无形之中转化为我坚持的动力。

我原本就喜欢写博客,但一般把写博客安排在周末,但周末有时又有别的事情,所以总是断断续续的写。现在把自己喜欢的事情融入到每天的学习中,我的情绪变得更稳定,做事更有底气,效率也更高了。最近这几天不到九点回到宿舍,竟觉得待在宿舍好无聊,明明再有两个小时就要睡觉了,可我却觉得非常难熬,刷短视频没意思,对电视剧、电影或者综艺节目没有任何兴趣,有时躺在床上还会怀念白天的工作时光,真怪。

之前我总想着早早下班,周末坚决不来实验室,但现在我觉得我想在实验室多学一会,周末在宿舍也没事干不如来实验室,我知道我不是在做给老板看,也不是在为他学,我是为我自己的成长和进步付出时间和精力。

最近还有一个神奇的变化,我现在晚上十一点基本上倒头就睡,早上六点会自然醒,虽然我现在还是会再睡到闹钟响起,但我还是为这个小小的变化感到惊喜。今天早上买了几本字帖,打算以后六点醒来洗漱完练会字,这是我能想到的相对不打扰舍友又能充分利用清晨时间的一种方式,我想变得更好。

我很享受现在的生活,自我与工作近乎达到平衡状态,我没有因为忙碌的工作丢掉自我,而是将主动权掌握在自己手中,努力借助更优质的平台实现能力跃迁。

]]>
+ + + + + 生活随笔 + + + + +
+ + + + + Imairs细胞计数教程 + + /2023/07/14/imaris-cell-counting/ + + 操作步骤
  1. fuseImage导入Imaris
  2. Ctrl+D打开通道面板
  3. 点击Slice测量细胞的直径(取个平均值即可)
  4. 点击Add new Spots(图标为一团黄色的小球) → 点击▶️ → 选择source channel(此处为红色) → 填写直径(此处为1.5µm)→ 点击▶️ → 根据实际情况调整阈值 → 点击绿色箭头 → 点击折线图即可看到整张脑片的细胞计数情况
  5. 点击Add new Surfaces(图标为蓝色的椭球) → 点击Skip automatic creation, edit manually → 界面右侧改为Select → 左下角Draw → 沿着要统计的脑区轮廓绘制闭合曲线 → 点击Create Surface → 点击Edit(图标为一支铅笔✏)选择Mask Selection → 保持勾选Duplicate channel before applying mask → 点击OK之后可以在右侧通道处看到新增的通道(Channel 4) → 取消左侧界面Surfaces的勾选,右侧通道仅保留刚刚复制的通道,其余通道取消勾选 → 接下来对该区域进行细胞计数
  6. 点击Add new Spots(图标为一团黄色的小球) → 点击▶️ → 选择source channel(此处注意改为Channel 4) → 填写直径(此处为1.5µm)→ 点击▶️ → 根据实际情况调整阈值 → 点击绿色箭头 → 点击折线图即可看到特定脑区的细胞计数情况

操作演示

参考文章

]]>
+ + + + + 方法教程 + + + + + + + Imaris + + + +
+ + + + + BIRDS插件代码学习【07】 + + /2023/07/14/imagej-plugin-7/ + + 图像降采样

原始脑片分辨率过高,与Allen平均脑模板的分辨率相差过大,为得到更好的配准效果,需要将原始脑片的分辨率降低。
😎我原本是在ImageJ软件上操作的,没想到用代码实现也并不复杂!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package I.plugin;

import ij.ImagePlus;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.process.ImageProcessor;

public class Test07 {
public static void main(String[] args) {
ImagePlus brainImage = new ImagePlus("D:/Desktop/elastix-5.1.0-win64/input/result1.tif");
ImageProcessor bp = brainImage.getProcessor();
int width = bp.getWidth();
int height = bp.getHeight();
brainImage.show();

double scale = 0.1;
int newWidth = (int)(width*scale);
int newHeight = (int)(height*scale);
ImagePlus resizedImage = NewImage.createByteImage("resizedImage", newWidth, newHeight, 0, NewImage.FILL_BLACK);
ImageProcessor rp = resizedImage.getProcessor();

rp = bp.resize(newWidth, newHeight, false);
resizedImage.setProcessor(rp);
resizedImage.show();

new FileSaver(resizedImage).saveAsTiff("D:/Desktop/elastix-5.1.0-win64/input/resized-result1.tif");
}
}

脑区识别

代码效果:鼠标移动到图片的哪个位置,就在Eclipse控制台输出对应的脑区,超出全脑范围则输出null。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package I.plugin;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.plugin.RGBStackMerge;
import ij.process.ImageProcessor;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;

public class Test06 implements MouseListener, MouseMotionListener {

public static ImagePlus fuseImage = null;
public static ImagePlus brainImage = null;
public static ImagePlus annoImage = null;
public Map<Integer,String> grayMap = new HashMap<>();

// 提取脑区轮廓
public ImageProcessor getLineImg(ImageProcessor ip, ImageProcessor op) {
int lenX = ip.getWidth();
int lenY = ip.getHeight();
for(int i = 0; i < lenX; i ++) { //按列
int begin = 0; //初始像素值为黑色
for(int j = 0; j < lenY; j ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
for(int j = 0; j < lenY; j ++) {
int begin = 0; //初始像素值为黑色
for(int i = 0; i < lenX; i ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
return op;
}
// 监听鼠标 将excel中的灰度值-脑区读取到HashMap中
public void addMouseListener() throws Exception, IOException {
File file = new File("D:/Desktop/rgb_name.xls");
Workbook wb = Workbook.getWorkbook(file);
Sheet sheet = wb.getSheet("test1");
for(int i = 0; i < sheet.getRows(); i ++) {
Cell[] cell = sheet.getRow(i);
grayMap.put(Integer.valueOf(cell[0].getContents()),cell[1].getContents());
}
//System.out.println(grayMap);
wb.close();

fuseImage.show();
fuseImage.getCanvas().addMouseListener(this);
fuseImage.getCanvas().addMouseMotionListener(this);
}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}

@Override
public void mouseExited(MouseEvent e) {}

@Override
public void mouseDragged(MouseEvent e) {}

@Override
public void mouseMoved(MouseEvent e) {
// 监听鼠标的移动
int currentSlice = fuseImage.getCurrentSlice();
Point point = fuseImage.getCanvas().getCursorLoc();
int val = (int)annoImage.getImageStack().getVoxel(point.x, point.y, currentSlice-1);

System.out.println(grayMap.get(val));
}
// 主程序
public static void main(String[] args) throws IOException, Exception {
brainImage = new ImagePlus("D:\\Desktop\\elastix-5.1.0-win64\\input\\result1-1.tif");
ImageStack brainStack = brainImage.getStack();

annoImage = new ImagePlus("D:\\Desktop\\elastix-5.1.0-win64\\result\\result.tif");
ImageProcessor ap = annoImage.getProcessor();
int width = ap.getWidth();
int height = ap.getHeight();

ImagePlus lineImage = NewImage.createByteImage("lineImage", width, height, 0, NewImage.FILL_BLACK);
ImageStack lineStack = lineImage.getStack();
ImageProcessor lp = lineImage.getProcessor();

ImageProcessor op = new Test06().getLineImg(ap, lp);

lineImage.setProcessor(op);
lineImage.show();

fuseImage = NewImage.createByteImage("fuseImage", width, height, 0, NewImage.FILL_BLACK);

ImageStack fuseStack = RGBStackMerge.mergeStacks(brainStack, lineStack, null, true);
fuseImage.setStack(fuseStack);
new FileSaver(fuseImage).saveAsTiff("D:/Desktop/fuseImage-1.tif");

new Test06().addMouseListener();
}
}

操作演示

操作演示

注意事项

  1. Eclipse中导入jxl.jar包,具体方法可参考博客,需要注意jxl.jar包只能处理.xls文件
  2. 脑片降低分辨率后统计出的各个脑区的细胞数目,需要与人工计数的结果进行对比,如果差别不大,则后续采用降低分辨率的脑片进行配准。
  3. 配准后的图像使用Imaris软件计数,具体操作步骤见文章Imairs细胞计数教程

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + 《神经动力学》学习笔记【01】 + + /2023/07/13/neuronal-dynamics-1/ + +

课程地址:[进入哔哩哔哩观看 资源1] [进入哔哩哔哩观看 资源2] [进入youtube观看]
课件汇总:[PPT下载]
参考教材:Neuronal Dynamics: From Single Neurons to Networks and Models of Cognition
[下载地址]
提取码: rk96

神经动力学:从单个神经元到网络和认知模型

当我们做决策时,我们的大脑中发生了什么?是什么触发了神经元发送信号?神经编码是什么?

这本面向高年级本科生和初级研究生的教科书,为计算和理论神经科学提供了全面而最新的的介绍。它涵盖了经典的主题,包括Hodgkin-Huxley方程和Hopfield模型,以及该领域在现代的发展,如广义线性模型和决策理论。概念通过清晰的逐步解释引入,适合仅有基础微分方程和概率知识的读者,并辅以丰富的图表和详细的实例说明。

章末总结和随堂练习使本书非常适合课堂教学或者自学。作者也指出了文献和大量的参考数目,对于有兴趣进一步研究的读者来说将非常有价值。

目录

前言

这本面向高年级本科生和初级研究生的教科书系统地介绍了关于神经建模、神经动力学、神经编码以及神经网络领域。它可以作为计算和理论神经科学的入门课程的教材,也可以作为研究生级别更加专注于神经动力学和神经建模的课程的主要教材。对于想学习不同神经元模型和神经活动描述之间关系的研究人员和学生来说,本书也是一个有用的资源。

所有的数学概念都以一步一步的方式进行介绍。所有的章节都有丰富的图表和实例。每一章都以简短的总结和一系列数学练习结尾。在作者的网页上提供了用于数值模拟的python源代码,以阐述章节的主要观点和模型。

本书分为4部分,共20章。Part I对计算神经科学及其数学工具的基础知识进行了概括性介绍。它涵盖了经典的内容,比如Hodgkin-Huxley模型、离子通道和树突等,以及二维微分方程系统的相平面分析。本书特别关注在Hodgkin-Huxley模型和Morris-Lecar模型等简化的二维神经元模型中触发动作电位的阈值问题。

Part II着重介绍单个神经元动力学的简化模型。它涵盖了带有适应性和不带适应性的非线性积分-放电模型integrate-and-fire model,尤其是二次和指数的积分-放电模型,以及Izhikevich模型和自适应指数积分-发放模型。还讨论了神经动力学中噪声的问题,并呈现了两种经典的噪声描述。首先,通过随机尖峰到达引起的随机性:这个方法导致电压微分方程中的噪声项,可以用朗之万方程表示。其次,神经元内在的随机性导致在亚阈区域时跨越触发阈值的“逃逸”:这个方法引出了广义线性模型的框架,该模型会在神经编码和解码的应用中系统地介绍和讨论。强调第二部分中神经元模型和生物数据之间的关系,并介绍了系统的参数优化算法。

Part III将第二部分得出的简化模型用于构建网络。以群体活动方程,也称为群体发放率,描述神经网络动力学的集体特性。确定了可以使用标准发放速率模型描述群体活动的条件。

Part IV将动力学与认知联系起来。使用群体活动方程分析计算和认知神经科学中著名的范式,比如在决策或记忆检索过程中的神经活动。在第四部分,我们也概述了与突触可塑性相关的学习理论。本书以极有吸引力的神经动力学原理帮助帕金森病人的应用结尾。

本书的一小部分内容基于《Spiking Neuron Models》,该书于2002年首次出版,并在此后多次重印。与此同时,这个领域在发生变化,我们认为简单更新《Spiking Neuron Models》的第二版不足以肯定到目前所出现的发展。

从更一般的角度来看,我们设计一本从一开始就作为教科书而不是专题著作的书将非常有用。因此,本书更突出与实验数据的联系,有更多解释性文字,并且最重要的是,提供了一系列在多年的课堂教学中已经经过测试的练习题。

我们希望这本书对学生和研究人员都能有所帮助。

给读者的建议

每一章以一个具体的问题开始,并在第一节给出直观的答案。随着章节的进行,内容变得更加高级,呈现方式也更加技术化。在第一次阅读本书时,可以先只阅读每一章的第一节或前两节,然后快速浏览后续节。

更具体的建议取决于读者的背景。比如,建议初次接触计算神经科学领域的读者在开始第二部分和第四部分之前,建议花足够的时间学习第一部分的经典材料。专业的读者可以完全跳过第一部分,直接开始阅读第二部分。

在第三部分,主要思想在第12章和第15章进行了阐述,这些章节为第四部分的速率模型打下了基础。第三部分更具技术性的章节在第一次阅读时可以跳过,但有必要对当下计算神经科学领域的最新发展有一个深入的理解。

第四部分涉及神经动力学到认知问题的应用,可以按任意的顺序阅读。

*标记的小节在数学上更高级,第一次阅读本书时可以忽略。

]]>
+ + + + + 学习笔记 + + + + + + + 神经动力学 + + + +
+ + + + + RNN学习笔记【01】 + + /2023/07/12/RNN-1/ + +

第一次找到和我要做的课题那么接近的教程,人工翻译一遍不过分吧!😎
本文对应的代码在这里!😽[Open in colab]😽

任务优化的循环神经网络建模

引言

这里,我们基于人工神经网络的方法构建循环神经网络。学习人工神经网络或深度学习,不仅是当今机器学习的主导框架,对计算神经科学而言也是一个有用的工具。

深度学习本身可能并不符合生物现实。然而,深度学习最终的结果可能是有用的大脑模型(不保证,但是可能)。由于人工神经网络的复杂性,它们可以模拟复杂的行为和神经活动。

从优化的角度来说,人工神经网络建模可以提供规范性解释,即为什么一个网络可以以某种方式完成某个任务,因为我们可以设计目标函数,类似于生物进化的视角。

任务介绍

2AFC

双向强迫选择任务PerceptualDecisionMaking,被试需要整合两个刺激来决定哪一个刺激的平均水平更高。
在刺激阶段会呈现一个有噪声的刺激。刺激的强度(coherence)在每个试次中是随机抽样的。因为刺激中存在噪声,智能体需要随时间整合刺激信息。
参数介绍:
dt:Timestep duration. (def: 100 (ms) int)
rewards

  • R_ABORTED: given when breaking fixation. (def: -0.1 float)
  • R_CORRECT:given when correct. (def: +1. float)
  • R_FAIL:given when incorrect. (def: 0. float)

timing:Description and duration of periods forming a trial.
stim_scale:Controls the difficulty of the experiment. (def: 1., float)
cohs:list of float, coherence levels controlling the difficulty of the task
sigma:float, input noise level
dim_ring:int, dimension of ring input and output

环境配置

  • NeuroGym是一个精选的神经科学任务集合,具有统一的接口。其目标是促进关于神经科学任务的神经网络模型的训练。
    NeuroGym
  • Google Colab是一个基于云端的免费Jupyter笔记本环境,为用户提供了方便、免费的编码环境,并具备强大的计算资源和协作功能,适用于数据科学家、研究人员和机器学习工程师等进行代码开发、实验和协作。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # install neurogym (for training environments)
    ! git clone https://github.com/gyyang/neurogym.git
    %cd neurogym
    ! pip install -e .

    # import packages
    import time # for measuring time
    import numpy as np # for numerical computation
    from matplotlib import cm # for plotting figures
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    from matplotlib.colors import ListedColormap, LinearSegmentedColormap
    from matplotlib.lines import Line2D
    from IPython import display # for controlling colab

    import gym # for neurogym
    import neurogym as ngym # for training environments
    import torch # for training neural nets
    import torch.nn.functional as F

    from sklearn.decomposition import PCA # for principal component analysis
    from scipy.special import softmax
    mpl.rcParams.update(mpl.rcParamsDefault)

模型概览

RNN模型概览

$x(t)$:输入变量

$r(t)$:循环变量

$o(t)$:输出

$W_x$:输入权重【可训练】

$W_r, b_r$:循环权重 & 偏置

$W_o, b_o$:输出权重 & 偏置

$\alpha=\frac{\bigtriangleup t}{\tau }$

此外,在人工神经网络建模中,我们可以使用各种各样的激活函数,比如ReLUsigmoidsoftplus函数。

激活函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Parameter definition
# Hyperparameters
hpar = dict(
# Task parameters
dt = 20, # simulation time step [ms]
stim_len = 1000, # stimulus input duration [ms]
stim_noise = 0.3, # stimulus input noise [unitless]
seq_len = 60, # trial duration in time steps
# Network parameters
n_neurons = 64, # number of recurrent neurons
network_noise = 0.1, # noise to network [unitless]
tau = 100, # network time constant [ms]
activation_fun = 'relu', # activation function(sigmoid, relu, softplus)
# Network parameters:training
batch_size = 16, # size of batch
n_iteration = 1000, # number of epochs
learning_rate = 0.01, # training learning rate
optimizer = 'Adam', # optimizer(Adam, RMSprop, SGD)
loss = 'CrossEntropy' # loss function(CrossEntropy, L1, L2)
)

batch:指每次迭代中用于训练模型的样本数量。批大小的选择会影响训练的效果和速度。较大的批大小可以提高训练的效率,因为可以同时处理更多的样本,但会消耗更多的内存。较小的批大小可以提供更多的随机性和模型收敛的稳定性,但可能会导致训练时间增加。
iteration:指完成整个训练数据集的一次遍历。迭代的数量取决于训练数据集的大小和训练过程的要求。通常,较大的数据集需要更多的迭代来使模型收敛,而较小的数据集可能需要较少的迭代。

训练 RNN 执行任务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# make neurogym environment
task_name = 'PerceptualDecisionMaking-v0'
kwargs = {'dt': hpar['dt'],
'timing': {'stimulus': hpar['stim_len']},
'sigma': hpar['stim_noise']}
env = gym.make(task_name, **kwargs)

# make supervised dataset
dataset = ngym.Dataset(env, batch_size=hpar['batch_size'], seq_len=hpar['seq_len'])

# generate one batch of data when called
inputs, target = dataset()
print('Input to network has shape(SeqLen,Batch,Dim)=', inputs.shape)
print('Target to network has shape(SeqLen,Batch)=', target.shape)
# 输出
# Input to network has shape(SeqLen,Batch,Dim)= (60, 16, 3)
# Target to network has shape(SeqLen,Batch)= (60, 16)

gym.make(task_name, **kwargs):是OpenAI Gym库中用于创建一个与特定任务相关的环境对象。task_name表示要创建的任务的名称,例如CartPole-v1,每个名称对应一个特定的任务环境。**kwargs是一个可选的关键字参数,用于传递额外的配置选项给环境。
在Python中,**用于将一个字典(dictionary)解包为关键字参数传递给函数。字典的关键字需与函数的参数名称匹配,参数顺序可以改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Task structure
i_trial = np.random.choice(hpar['batch_size']) # 随机从一个batch内选择一个trial
end = sum([v for _,v in env.timing.items()])/1000 # 单位换为s
times = np.arange(end, step=env.dt/1000)
rules = end - env.timing['decision']/1000, end

f, ax = plt.subplots(1, 2, figsize=(16,5))
ax[0].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[0].plot(times, inputs[:,i_trial,1], 'blue', label='Evidence for right motion')
ax[0].plot(times, inputs[:,i_trial,2], 'red', label='Evidence for left motion')
ax[0].plot(times, inputs[:,i_trial,0], 'green', label='Fixation rule')
ax[0].set_ylabel('input')
ax[0].set_ylim([-0.1,1.1])
ax[0].legend(loc='upper left')
ax[0].set_xlabel('time(s)')
ax[0].set_title(f'Input to RNN(trial number={i_trial})')

ax[1].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[1].hlines(y=1, xmin=times[0], xmax=times[-1], color='gray', linestyle="dashed")
ax[1].hlines(y=2, xmin=times[0], xmax=times[-1], color='gray', linestyle="dashed")
ax[1].text(0, 0.08, 'Fixation')
ax[1].text(0, 0.9, 'Right Decision')
ax[1].text(0, 1.9, 'Left Decision')
ax[1].plot(times, target[:,i_trial], 'k')
ax[1].set_ylabel('desired output')
ax[1].set_ylim([-0.1,2.1])
ax[1].set_xlabel('time(s)')
ax[1].set_title(f'Desired output from RNN(trial number={i_trial})')
plt.show()

示例trial的输入和输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# Model definition
class RNN(torch.nn.Module):
def __init__(self, input_size, output_size, **hpar):
super().__init__()
self.input_size = input_size
self.output_size = output_size
self.hidden_size = hpar['n_neurons']
self.noise = hpar['network_noise']
self.tau = hpar['tau']
self.alpha = hpar['dt']/self.tau
self.input2rec = torch.nn.Linear(self.input_size, self.hidden_size, bias=False)
self.rec2rec = torch.nn.Linear(self.hidden_size, self.hidden_size)
self.rec2output = torch.nn.Linear(self.hidden_size, self.output_size)
self.normal = torch.distributions.normal.Normal(0,1)
self.set_activation_fun(**hpar)

def set_activation_fun(self, **hpar):
if hpar['activation_fun'] == 'sigmoid':
self.activation = torch.sigmoid
elif hpar['activation_fun'] == 'relu':
self.activation = torch.relu
elif hpar['activation_fun'] == 'softplus':
self.activation = F.softplus
else:
raise NotImplementedError('Activation functions should be either ReLU, Sigmoid, or Softplus')

def init_hidden(self, input_shape):
batch_size = input_shape[1]
return torch.zeros(batch_size, self.hidden_size)

def recurrence(self, input, hidden):
noise = self.noise * self.normal.sample(hidden.shape)
h_new = self.activation(self.input2rec(input) + self.rec2rec(hidden))
h_new = hidden * (1-self.alpha) + h_new * self.alpha
h_new += noise * (2*self.alpha) ** 0.5
return h_new

def forward(self, input, hidden=None):
if hidden is None:
hidden = self.init_hidden(input.shape).to(input.device)
rnn_output = []
steps = range(input.size(0))
for i in steps:
hidden = self.recurrence(input[i], hidden)
rnn_output.append(hidden)

rnn_output = torch.stack(rnn_output, dim=0)
output = self.rec2output(rnn_output)

return output, rnn_output

input_size = env.observation_space.shape[0]
print(input_size) #
output_size = env.action_space.n
net = RNN(input_size, output_size, **hpar)
print(net)
for name, param in net.named_parameters():
if param.requires_grad:
print('\t', name, "," , param.data.shape)
# 输出
# RNN(
# (input2rec): Linear(in_features=3, out_features=64, bias=False)
# (rec2rec): Linear(in_features=64, out_features=64, bias=True)
# (rec2output): Linear(in_features=64, out_features=3, bias=True)
# )
# input2rec.weight , torch.Size([64, 3])
# rec2rec.weight , torch.Size([64, 64])
# rec2rec.bias , torch.Size([64])
# rec2output.weight , torch.Size([3, 64])
# rec2output.bias , torch.Size([3])

__init__:在Python中,__init__是一个特殊的方法(也称为构造方法),用于在创建类的实例时进行初始化操作。__init__方法在创建类的实例时自动调用,并用于设置对象的初始状态。它接受类的实例作为第一个参数(通常被命名为self),以便可以访问和操作该实例的属性和方法。除了self参数外,__init__方法可以接受其他参数,这些参数可以用来初始化对象的属性。
super().__init__():调用父类的构造方法,确保父类的初始化操作得以执行。
Activation function:ReLU、Sigmoid、Softplus
Optimizer:Adam、RMSprop、SGD
loss function:CrossEntropy、L1、L2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# train model
learning_rate = 0.01
optimizer = 'Adam'
loss_function = 'CrossEntropy'

hpar['learning_rate'] = learning_rate
hpar['optimizer'] = optimizer
hpar['loss_function'] = loss_function

def train_model(net, dataset, **hpar):
# define an optimizer
learning_rate = hpar['learning_rate']
if hpar['optimizer'] == 'Adam':
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)
elif hpar['optimizer'] == 'RMSprop':
optimizer = torch.optim.RMSprop(net.parameters(), lr=learning_rate)
elif hpar['optimizer'] == 'SGD':
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)
else:
raise NotImplementedError('Optimizer should be either Adam, RMSprop, or SGD')
# define a loss function
if hpar['loss'] == 'CrossEntropy':
criterion = torch.nn.CrossEntropyLoss()
elif hpar['loss'] == 'L1':
criterion = torch.nn.L1loss()
elif hpar['loss'] == 'L2':
criterion = torch.nn.MSELoss()
else:
raise NotImplementedError('Loss function should be either CrossEntropy, l1, or L2')

start_time = time.time()
losses = []
accs = []

# Plot
fig = plt.figure(figsize=[18,6])
plt.tight_layout()
ax0 = fig.add_subplot(121)
ax0.set_xlim([0,hpar['n_iteration']])
plt.ylim([0,0.5])
ax0.set_xlabel('Number of iteration')
ax0.set_ylabel('Loss')
ax0.set_title('RNN model training curve')
ax1 = fig.add_subplot(121, sharex=ax0, frameon=False)
ax1.yaxis.tick_right()
ax1.yaxis.set_label_position('right')
ax1.set_ylabel('Accuracy(%)')
ax1.set_ylim([0,100])
ax1.yaxis.label.set_color('r')
ax0.spines['right'].set_color('r')
ax1.tick_params(axis='y', colors='r')
ax2 = fig.add_subplot(122)
ax2.set_title('RNN model recurrent weight $W_r$')

# Loop
for i in range(hpar['n_iteration']):
inputs, labels = dataset() # 一个batch的数据
inputs = torch.from_numpy(inputs).type(torch.float)
labels = torch.from_numpy(labels.flatten()).type(torch.long)

optimizer.zero_grad() # clear the gradient buffers
output, _ = net(inputs) # run the network
output = output.view(-1, output_size)

if hpar['loss'] == 'CrossEntropy':
loss = criterion(output, labels)
else:
loss = criterion(output, F.one_hot(labels).type(torch.float))
loss.backward() # backpropagation
optimizer.step() # gradient descent

# compute the running loss every 100 steps
losses.append(loss.item())
# 将输出张量转换为 NumPy 数组,然后选择最后 hpar['batch_size'] 行,并找到选定数组中每个样本的预测类别的索引。最终,pred 是一个包含每个样本预测类别索引的数组。
pred = np.argmax(output.detach().numpy()[(-hpar['batch_size']):,:],axis=-1)
true = labels.detach().numpy()[(-hpar['batch_size']):]
accs.append((pred==true).mean()*100)

if i % 100 == 99:
accs_ma = accs.copy()
accs_ma[10:] = np.convolve(accs_ma, np.ones(10)/10, mode='valid')

ax0.plot(losses, color='k', linewidth=2)
ax1.plot(accs_ma, color='r', linewidth=1)

recurrent_weight = net.get_parameter('rec2rec.weight').detach().numpy()
im = ax2.imshow(recurrent_weight, clim=[-0.6,0.6], cmap='RdBu_r')
ax2.set_xlabel('Presynaptic neuron index')
ax2.set_ylabel('Postsynaptic neuron index')
cb = plt.colorbar(im, ax=ax2)

display.clear_output(wait=True)
display.display(plt.gcf())
if i != hpar['n_iteration'] -1:
cb.remove()
if i == hpar['n_iteration'] -1:
display.clear_output(wait=True)
print(f'Final training loss={np.round(np.mean(losses[(-100):]),2)}')
print(f'Final training accuracy(%)={np.round(np.mean(accs[(-100):]),2)}')
return net
net = RNN(input_size, output_size, **hpar)
net = train_model(net, dataset, **hpar)

训练误差及准确率

分析训练好的 RNN 模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Analysis
def run_model(net, env, num_trial=200):
env.reset(no_step=True)
input_dict = {}
activity_dict = {}
trial_infos = {}
for i in range(num_trial):
trial_info = env.new_trial()
ob, gt = env.ob, env.gt # observation and ground-truth
inputs = torch.from_numpy(ob[:, np.newaxis, :]).type(torch.float)

action_pred, rnn_activity = net(inputs)
action_pred = action_pred.detach().numpy()[:, 0, :]
choice = np.argmax(action_pred[-1, :])
correct = choice==gt[-1]

_input = inputs[:, 0, :].detach().numpy()
rnn_activity = rnn_activity[:, 0, :].detach().numpy()
input_dict[i] = _input
activity_dict[i] = rnn_activity
trial_infos[i] = trial_info
trial_infos[i].update({
'correct': correct,
'pred': action_pred,
'target': dataset.env.gt
})
return input_dict, activity_dict, trial_infos

run_inputs, activity_dict, trial_infos = run_model(net, dataset.env)
test_acc = np.round(np.mean([val['correct'] for val in trial_infos.values()])*100, 2)
print(f'Testing accuracy(%)={test_acc}')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# randomly choose an example trial
i_trial = np.random.choice(200)
coh = trial_infos[i_trial]['coh']
print(f'coherence={coh}')
# dict_items([('fixation', 100), ('stimulus', 1000), ('delay', 0), ('decision', 100)])
end = sum([v for _,v in env.timing.items()])/1000
times = np.arange(end, step=env.dt/1000) # 0~(end-1)
rules = end - env.timing['decision']/1000, end

f, ax = plt.subplots(1, 2, figsize=(16,5))
ax[0].axvspan(rules[0], rules[1], facecolor='grey', alpha=0.2)
ax[0].plot(times, run_inputs[i_trial][:,1], 'blue', label='Evidence for right motion')
ax[0].plot(times, run_inputs[i_trial][:,2], 'red', label='Evidence for left motion')
ax[0].plot(times, run_inputs[i_trial][:,0], 'green', label='Fixation rule')
ax[0].legend(loc='upper left')
ax[0].set_xlabel('time(s)')
ax[0].set_ylabel('input')
ax[0].set_title(f'Input to RNN(trial number={i_trial} coherence={coh})')

im = ax[1].imshow(softmax(trial_infos[i_trial]['pred'],axis=-1).T, extent=[times[0],end,-0.5,2.5], aspect='auto', origin='lower')
ax[1].text(0.05,0.1,'Fixation', color='r')
ax[1].text(0.05,1,'Right decision', color='r')
ax[1].text(0.05,2,'Left decision', color='r')
ax[1].plot(times, trial_infos[i_trial]['target'], 'k', linewidth=5, label='ground truth')
ax[1].set_xlabel('time(s)')
ax[1].set_ylabel('RNN output')
ax[1].set_yticks([0,1,2])
ax[1].set_title(f'RNN output(trial number={i_trial} coherence={coh})')
ax[1].legend()

cb = plt.colorbar(im, ax=ax[1])
cb.ax.set_title('Predicted probabolity')
plt.tight_layout()
plt.show()

示例试次输出结果展示

RNN模型测试准确率达到90%以上时,PCA分析不同运动一致比例条件下RNN群体活动轨迹比较容易分开。如果模型的准确率不高,则轨迹比较集中。🦁也就是说,模型是否训练好要设定一个performance threshold~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# PCA(2 principal components)
activity = np.concatenate(list(activity_dict[i] for i in range(200)), axis=0)
pca = PCA(n_components=3)
pca.fit(activity)
activity_pc = pca.transform(activity)

blues = cm.get_cmap('Blues', len(env.cohs)+1)
reds = cm.get_cmap('Reds', len(env.cohs)+1)

figure = plt.figure(figsize=([7,7]))
for i in range(100):
activity_pc = pca.transform(activity_dict[i])
trial = trial_infos[i]
color_c = blues if trial['ground_truth'] == 0 else reds
color = color_c(np.where(env.cohs == trial['coh'])[0][0])
plt.plot(activity_pc[:,0], activity_pc[:,1], 'o-', color=color)

plt.plot(activity_pc[0,0], activity_pc[0,1], '^', color='black', markersize=10)

handles, labels = plt.gca().get_legend_handles_labels()
dot = Line2D([], [], marker='^', label='Starting point', color='black', linestyle='None', markersize=10)
lines = []
for i_coh, v_coh in reversed(list(enumerate(env.cohs))): # index value
line_r = Line2D([], [], label=f'L motion trial, c={v_coh}', color=reds(i_coh))
lines.append(line_r)
for i_coh, v_coh in enumerate(env.cohs):
line_b = Line2D([], [], label=f'R motion trial, c={v_coh}', color=blues(i_coh))
lines.append(line_b)
handles.extend([dot]+lines)
plt.legend(title='Legend', bbox_to_anchor=(1.4,1.0), handles=handles, frameon=False)
plt.xlabel('PC 1')
plt.ylabel('PC 2')
plt.title('State space based on principal component analysis')
plt.show()
图片说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# PCA(3 principal components)
from mpl_toolkits.mplot3d import Axes3D
activity = np.concatenate(list(activity_dict[i] for i in range(200)), axis=0)
pca = PCA(n_components=3)
pca.fit(activity)
activity_pc = pca.transform(activity)

blues = cm.get_cmap('Blues', len(env.cohs)+1)
reds = cm.get_cmap('Reds', len(env.cohs)+1)

fig = plt.figure(figsize=([7,7]))
ax = fig.add_subplot(111, projection='3d')
for i in range(100):
activity_pc = pca.transform(activity_dict[i])
trial = trial_infos[i]
color_c = blues if trial['ground_truth'] == 0 else reds
color = color_c(np.where(env.cohs == trial['coh'])[0][0])
ax.plot(activity_pc[:,0], activity_pc[:,1], activity_pc[:,2], 'o-', color=color)

ax.plot(activity_pc[0,0], activity_pc[0,1], activity_pc[0,2],'^', color='black', markersize=10)

handles, labels = plt.gca().get_legend_handles_labels()
dot = Line2D([], [], marker='^', label='Starting point', color='black', linestyle='None', markersize=10)
lines = []
for i_coh, v_coh in reversed(list(enumerate(env.cohs))): # index value
line_r = Line2D([], [], label=f'L motion trial, c={v_coh}', color=reds(i_coh))
lines.append(line_r)
for i_coh, v_coh in enumerate(env.cohs):
line_b = Line2D([], [], label=f'R motion trial, c={v_coh}', color=blues(i_coh))
lines.append(line_b)
handles.extend([dot]+lines)
ax.set_xlabel('PC 1')
ax.set_ylabel('PC 2')
ax.set_zlabel('PC 3')
ax.set_title('State space based on principal component analysis')
plt.legend(title='Legend', bbox_to_anchor=(1.6,0.9), handles=handles, frameon=False)
plt.show()

PCA(三个主成分)

补充知识

**kwargs

1
2
3
4
5
6
7
8
9
10
11
kwargs = {'arg1': 10, 'arg3': True, 'arg2': 'hello'}

def example_function(arg1, arg2, arg3):
print(arg1)
print(arg2)
print(arg3)

example_function(**kwargs)
# 10
# hello
# True

字典

在Python中,字典是一种可变的数据结构,用于存储键-值对的集合。字典可以使用{}来创建,也可以通过dict()函数创建。
update方法可以接受一个字典对象或包含键值对的可迭代对象作为参数,并将其中的键值对添加到调用update方法的字典中。

1
2
3
4
5
6
7
8
9
10
11
12
my_dict = {'key1': 'value1', 'key2': 'value2'}
my_dict = dict(
key1 = value1,
key2 = value2,
)

my_dict = {'key1': 'value1', 'key2': 'value2'}
new_dict = {'key3': 'value3', 'key4': 'value4'}

my_dict.update(new_dict)
print(my_dict)
# 输出:{'key1': 'value1', 'key2': 'value2', 'key3': 'value3', 'key4': 'value4'}

time.time()

1
2
3
4
5
6
7
import time

start_time = time.time()
for i in range(10):
print(i)
end_time = time.time() # 可用于计算程序运行的时间
print(f'程序用时:{end_time-start_time}s')

参考内容

]]>
+ + + + + 课题积累 + + + + + + + RNN + + + +
+ + + + + windows设置代理及取消代理 + + /2023/07/11/set-proxy/ + +

本来想用coursera-dl下载coursera上面的网课,结果一直报错,想找找下载视频的插件,也没找到好用的,最终还是回归伟大的哔哩哔哩!😽

设置代理

1
2
3
4
5
6
# 翻墙后设置代理
set http_proxy=http://127.0.0.1(代理的IP地址):1080(代理的端口号)
set https_proxy=http://127.0.0.1(代理的IP地址):1080(代理的端口号)
# 不翻墙的话需要取消代理,否则打开一些页面会很慢
set http_proxy=
set https_proxy=

油猴插件

点击网站右上角(篡改猴)图标→获取新脚本→搜索用户脚本→安装

参考文章

]]>
+ + + + + 方法教程 + + + + + + + 代理 + + + +
+ + + + + BrainPy学习笔记【01】 + + /2023/07/10/brainpy-1/ + + 安装教程(Windows环境)
1
2
3
4
5
6
7
8
9
10
11
12
conda env list
conda create --name bdp python=3.9 -y
conda activate bdp

python -m pip install git+https://git.openi.org.cn/OpenI/BrainPy
conda install numpy
pip install "jax[cpu]" -f https://whls.blob.core.windows.net/unstable/index.html
python -m pip install brainpylib # 报错 需要安装matplotlib
conda install matplotlib
python -m pip install brainpylib

conda install ipykernel

参考文章

]]>
+ + + + + 课题积累 + + + + + + + BrainPy + + 计算建模 + + + +
+ + + + + BIRDS插件代码学习【06】 + + /2023/07/10/imagej-plugin-6/ + + 今日计划
  • 准备和刘越老师讨论的PPT,主要整理计算建模的思路以及难点
  • 提取单张脑片的脑区轮廓
  • BrainPy环境搭建
  • 整理计算神经科学领域比较有名的实验室和科学家

提取脑区轮廓

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package I.plugin;

import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.NewImage;
import ij.io.FileSaver;
import ij.plugin.RGBStackMerge;
import ij.process.ImageProcessor;

public class Test06 {

public ImageProcessor getLineImg(ImageProcessor ip, ImageProcessor op) {
int lenX = ip.getWidth();
int lenY = ip.getHeight();
for(int i = 0; i < lenX; i ++) { //按列
int begin = 0; //初始像素值为黑色
for(int j = 0; j < lenY; j ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
for(int j = 0; j < lenY; j ++) {
int begin = 0; //初始像素值为黑色
for(int i = 0; i < lenX; i ++) {
int temp = (int)ip.getPixelValue(i, j);
if(temp != begin) {
op.set(i, j, 255);
begin = temp;
}
}
}
return op;
}

public static void main(String[] args) {
ImagePlus brainImage = new ImagePlus("D:/Desktop/downSampleImage0160.tif");
ImageStack brainStack = brainImage.getStack();

ImagePlus annoImage = new ImagePlus("D:/Desktop/anno_output/result0160.tif");
ImageProcessor ap = annoImage.getProcessor();
int width = ap.getWidth();
int height = ap.getHeight();

ImagePlus lineImage = NewImage.createByteImage("lineImage", width, height, 0, NewImage.FILL_BLACK);
ImageStack lineStack = lineImage.getStack();
ImageProcessor lp = lineImage.getProcessor();

ImageProcessor op = new Test06().getLineImg(ap, lp);

lineImage.setProcessor(op);
lineImage.show();

ImagePlus fuseImage = NewImage.createByteImage("fuseImage", width, height, 0, NewImage.FILL_BLACK);

ImageStack fuseStack = RGBStackMerge.mergeStacks(brainStack, lineStack, null, true);

fuseImage.setStack(fuseStack);
fuseImage.show();
// 保存图片
new FileSaver(fuseImage).saveAsTiff("D:/Desktop/fuseImage.tif");
}
}

细胞计数

没想到BIRDS里细胞计数是通过调用Imaris的方法实现的,看来还是要学一下这个软件的用法🥲运行Imaris前记得先运行license server.bat~
.tif → .ims可以通过ImarisFileConverter.exe实现,Imaris默认安装在C盘。
没有找到很方便的API,看代码似乎是要现在Imaris里面操作完成之后,Java再获取对应的数据,这好像和我想要达到的效果不一样。
👻不想动脑子,怎么办!!!

流程测试

⭐脑片与标准脑模板的尺寸要大致相同,为了不过度损失脑片分辨率,此处对标准脑模板进行上采样
elastix.exe配准的参数使用para-Standard_bspline.txtpara-Standard_affine.txtpara-Standard_rigid.txt(去掉了对图片维度的限制)效果比较好
👻不知道为什么提取的脑区轮廓有很明显的锯齿,难道是因为我把注释图片分辨率调高了?不过问题不大~
👻由于原始脑片本身边缘有破损,因此与轮廓边缘处会出现明显的变形

  1. 将标准脑模板和注释图片的分辨率提高至与脑片匹配的程度(尽量不损失原始脑片的图像分辨率)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    from PIL import Image

    Image.MAX_IMAGE_PIXELS = None
    raw = Image.open(r"D:/Desktop/elastix-5.1.0-win64/input/result1.tif")
    img = Image.open(r"D:/Desktop/elastix-5.1.0-win64/out_anno/annotationImage0270.tif")
    # img = Image.open(r"D:/Desktop/elastix-5.1.0-win64/out_temp/tempImage0270.tif")

    target_width = raw.size[0]
    scale = round(target_width/img.size[0],1)
    width = int(img.size[0]*scale)
    height = int(img.size[1]*scale)

    out = img.resize((width, height))
    type = img.format
    out.save('D:/Desktop/elastix-5.1.0-win64/out_anno/annotationImage0270-1.tif',type)
    # out.save('D:/Desktop/elastix-5.1.0-win64/out_temp/tempImage0270-1.tif',type)
  2. 脑片与图谱配准
    1
    2
    3
    elastix -f input/result1.tif -m out_temp/tempImage0270-1.tif -out output -p input/para-Standard_rigid.txt -p input/para-Standard_affine.txt -p input/para-Standard_bspline_2.txt

    transformix -in out_anno/annotationImage0270-1.tif -out result -tp output/TransformParameters.2.txt

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + 解决mac电脑更新后V2rayU无法启动 + + /2023/07/09/v2rayu-mac/ + +

电脑更新完以后,突然一直弹出警告让我卸载V2rayU,┭┮﹏┭┮,这可是我的宝贝软件,怎么能卸载呢???在网上搜索了半天,终于找到解决方案了!

1
2
3
4
5
6
7
# 1. 命令行输入
sudo codesign --force --deep --sign - /Applications/V2rayU.app
# 2. 右键单击软件→显示简介→勾选☑️覆盖恶意软件保护
# 3. 打开软件
# 4. 命令行输入
sudo codesign --force --deep --sign - ~/.V2rayU/V2rayUTool
sudo codesign --force --deep --sign - ~/.V2rayU/v2ray-core/v2ray

参考文章

]]>
+ + + + + 方法教程 + + + + + + + V2rayU + + + +
+ + + + + BIRDS插件代码学习【05】 + + /2023/07/08/imagej-plugin-5/ + + Java 调用命令行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Test05 {
public static void main(String[] args) {
String cmd = "calc";
try {
Process ps = Runtime.getRuntime().exec(cmd);//打开计算器
// ps.getInputStream() 获取进程的输出流
BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
String line;
while((line = br.readLine()) != null) {
System.out.println(line);
}
}catch(Exception e) {
e.printStackTrace();
}
}
}

elastix 使用

  1. 下载 elastix-5.1.0-win64,解压后得到elastix.exetransformix.exe
  2. 下载 elastix 用户手册
  3. 命令行调用elastix.exetransformix.exe得到配准后的脑片
    1
    2
    3
    4
    5
    6
    elastix.exe --help
    elastix -f input/downSampleImage.tif -m input/tempImage.tif -out output -p input/Parameters_BSpline.txt

    transformix.exe --help
    transformix -in input/annotationImage.tif -out result -tp output/TransformParameters.0.txt
    # 参数文件中可以设置输出格式,默认为mhd,此处修改为tif

ImageJ 合并通道

  1. 将待合并的两张图像载入ImageJ
  2. Image→Color→Merge Channels
  3. 脑片保留红色通道,脑区轮廓保留绿色通道(注意不要勾选create composite,以免保存时仅有最上层的通道)
    合并通道
  4. 保存为tif文件合并后的图像

二维脑片配准关键步骤

  1. 定位与脑片最匹配的图谱(相似度最高)
  2. 获取Allen全脑平均模板tempImage和对应的注释文件annotationImage
  3. 通过elastix.exetransformix.exe对脑片配准(模板→脑片 注释→脑片)
  4. 根据注释文件获取脑区轮廓lineImage
  5. 轮廓与脑片合并得到fuseImage
  6. 根据annotationImage的像素值匹配脑区
  7. 脑区细胞计数
    二维脑片配准流程图

今日总结

到目前为止感觉BIRDS的配准是通过elastix实现的,需要看一下elastix的论文,然后试一下elastix进行脑片配准的效果。

不管老板对我的要求是怎样的,我对自己的要求就是把一个小项目做完再做下一个小项目,不能三心二意。我的课题要根据我自己的兴趣来,广泛涉猎给自己找一条出路,我现在没有能力回绝老板的各种要求就是因为我没有能够给出其他方案,要行动起来。

每天拿出1~2个小时跟着吴思老师实验室出的书《神经计算建模实战——基于brainpy》实操一下,总要下点功夫入门计算神经科学吧!可能需要补一下微积分的知识😎

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + BIRDS插件代码学习【04】 + + /2023/07/06/imagej-plugin-4/ + + 体素 voxel

体素是三维空间的像素。体素网格是用固定大小的立方块作为最小单元来表示三维物体的一种数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* 该程序实现鼠标事实获取stack当前图像(slice)的体素值(16unit 颜色值)
* 备注:通过该体素值可以进一步匹配到对应的脑区(该程序不包含此部分)
* 代码主要参考了BIRDS配准源码
* @author 文欣
* @version 1.0
*/
package I.plugin;

import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import ij.IJ;
import ij.ImageJ;
import ij.ImagePlus;
import ij.ImageStack;

public class Test04 implements MouseListener,MouseMotionListener{
private Test04() {}
public static ImagePlus brainImg;
public static void main(String[] args) {
new ImageJ();

brainImg = IJ.openImage("D:/Desktop/annotationOrgImage.tif");
brainImg.show();

System.out.println(brainImg.getTitle());
System.out.println(brainImg.getStackSize());
new Test04().addMouseListener();
}
public void addMouseListener() {

brainImg.getCanvas().addMouseListener(this);
brainImg.getCanvas().addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e) {
ImageStack brainStack = brainImg.getImageStack();
int currentSlice = brainImg.getCurrentSlice();
Point tempPoint = brainImg.getCanvas().getCursorLoc();
int val = (int)(brainStack.getVoxel(tempPoint.x, tempPoint.y, currentSlice-1));//16位像素值
System.out.println(val); //打印
}

@Override
public void mouseDragged(MouseEvent e) {}

@Override
public void mouseClicked(MouseEvent e) {}

@Override
public void mousePressed(MouseEvent e) {}

@Override
public void mouseReleased(MouseEvent e) {}

@Override
public void mouseEntered(MouseEvent e) {}

@Override
public void mouseExited(MouseEvent e) {}

}

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + Java基础知识 + + /2023/07/05/eclipse-icons/ + + Eclipse中图标含义

Java 修饰符

访问修饰符
非访问修饰符

Java 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
// 示例
public static int max(int num1, int num2){
int result;
if (num1 > num2){
result = num1;
}else{
result = num2;
}
return result;
}

参考文章

]]>
+ + + + + 学习笔记 + + + + + + + Eclipse + + + +
+ + + + + BIRDS插件代码学习【03】 + + /2023/07/05/imagej-plugin-3/ + + 图像预处理过程

图像介绍

DownSample.java文件中主要涉及了以下图像:

  • ourBrainImage:导入ImageJ的原始图像
  • Atlas132labelImage:Allen小鼠脑图谱(冠状面)570×400×660
  • tempInvertOrgImage:Allen小鼠脑平均模板反转
  • tempOrgImage:Allen小鼠脑平均模板
  • annotationImage:注释图谱
    其中Atlas132labelImage、annotationImage、tempOrgImage和tempInvertOrgImage是直接存入cache的。Atlas132labelImage仅仅是用于展示脑图谱,并没有做过多的处理。tempOrgImage和annotationImage均由Allen Brain提供(CCFv3)。

获取CCFv3小鼠全脑平均模板和注释

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import nrrd # pip install pynrrd
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image

AVGT, metaAVGT = nrrd.read('average_template_25.nrrd'); # 25 voxel
ANO, metaANO = nrrd.read('CCFv3_annotation_25.nrrd');

AVGT.shape # (528, 320, 456)
# 存储average template
for i in range(526):
slice = AVGT[i+1,:,:].astype(float)
slice /= np.max(slice)
im = Image.fromarray(np.uint8(plt.cm.gray(slice)*255))
im.save('avgt/avgt_coronal_%d.png'%(i+1))
# 存储annotation
for i in range(526):
slice = ANO[i+1,:,:].astype(float)
slice /= 2000
im = Image.fromarray(np.uint8(plt.cm.gray(slice)*255))
im.save('anno/ano_coronal_%d.png'%(i+1))

今日总结

我之前并没有留意BIRDS插件一开始载入缓存文件夹中的内容,本以为就是把github下载下来的压缩包解压,但今天仔细看了一下代码,才发现中间调用了AddtionalFile.java,用于生成orgInvertImage.tif,该代码又使用了InverTool.java,看来细节还是蛮多的。

我花了很长时间找annotationImage的原始出处,最终发现最有可能的来源是CCFv3,但下载后是nrrd格式,用ImageJ打开是矢状面。我在github、Allen社区以及文章提供的数据中下载到的模板和注释,打开后都是矢状面。晚上回到宿舍以后我还是不甘心,总觉得作者不应该没有提供冠状面的模板,我从nrrd这个文件格式入手,意外看到了一篇博客下面的评论,ImageJ里面可以查看stacks的正交视角!!!我试了一下,果然可以看到冠状面!

接下来的问题就是怎么把全脑冠状面存储为tif格式,昨天没想到好的解决办法,今天早上试了一下Allen提供的API,写了个循环获取冠状面(按顺序命名),然后用ImageJ读取Image sequence并存储为tif格式。(我没有找到BIRDS里面用的voxel是20µm的模板,但感觉问题不大~)

┭┮﹏┭┮ 今天早上喜提周六文献汇报,看论文去了!

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + BIRDS插件代码学习【02】 + + /2023/07/04/imagej-plugin-2/ + + ImageJ常用方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 创建新的图像窗口
ImagePlus lineImage = NewImage.createByteImage(null, 500, 300, 10, NewImage.FILL_WHITE);
ImageStack lineImageStack = PreciseRegistration.lineImage.getImageStack();
PreciseRegistration.lineImage.setStack(lineImageStack);

// 展示图像
lineImage.show();

// 查看stack的某一张
// getProcessor:Returns an ImageProcessor for the specified slice, where 1<=n<=nslices.
ImageProcessor imageProcessor = annotationImageStack.getProcessor(120);
ImagePlus myImg = new ImagePlus("ip2", imageProcessor);
myImg.show();

// 保存图像
new FileSaver(PreciseRegistration.lineImage).saveAsTiff(GlobalValue.URL+"/registration/precise/line.tif");

线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
/**
创建一个 CountDownLatch 对象时,需要指定一个初始计数值,该计数值表示需要等待的线程数量。
每当一个线程完成了其任务,它调用 CountDownLatch 的 countDown() 方法,计数器的值就会减一。
当计数器的值变成 0 时,等待的线程就会被唤醒,继续执行它们的任务。
*/
import java.util.concurrent.CountDownLatch;

public class Test03 {
public static void main(String[] args) throws InterruptedException {

CountDownLatch count = new CountDownLatch(5);//在线程执行完之前,会阻塞主程序的执行

for (int i = 0; i < 5; i++) {
final int num = i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+" "+(num+1));
count.countDown();
}).start();
}
try {
count.await();
} catch(Exception e){
System.out.println(e.getMessage());
}
System.out.println(Runtime.getRuntime().availableProcessors()); // 返回可用的计算资源
System.out.println(Thread.currentThread().getName()+" 执行完毕···");
}
}
/**
输出结果:
Thread-0 1
Thread-4 5
Thread-3 4
Thread-2 3
Thread-1 2
16
main 执行完毕···
*/

使用多线程处理图像

脑片配准 fuseImage

1
2
3
RGBStackMerge rgbStackMerge = new RGBStackMerge();
fuseImageStack = rgbStackMerge.mergeStacks(lenX, lenY, lenZ, downSampleImageStack, lineImageStack, null, true);
PreciseRegistration.getPreciseregistration().fuseImage.setStack(fuseImageStack);

脑区识别

鼠标悬停即可识别脑区

今日总结

昨天看了一整天代码,今天再看这些java和ImageJ的方法就没有那么生疏了,今天还掌握了一个java新技能:多线程!(本科四年一直听说但从未使用过的谜之知识)。昨天研究了半天的ImageProcessor,今天发现BIRDS里很多地方也用到了,不过主要是对stack的处理。昨天发现界面中切换到precise面板时,会弹出配准后的脑片,即使不手动校正,效果已经能达到我的预期了,所以今天就从这个地方入手,希望能找到脑片配准的核心代码。

BIRDS中主要涉及了annotationImage、lineImage、fuseImage和downsampleImage这四组图片,脑片配准的效果就是通过合并downsampleImage和lineImage得到的。起初我主要在看脑区的轮廓线是如何得到的,似乎是遍历像素,特定位置赋为白色,但我最开始不懂为什么annotationImage会实现这种效果。后面我发现脑区识别也是获取鼠标位置以后根据像素灰度值与脑区进行匹配(提前存在一个excel文件里面),这些功能的实现都不算复杂,最关键的点就是如何给不同的脑区赋不同的颜色(虽然我还没有找到这部分代码,但大胆猜测是将脑图谱直接灰度化,不过怎么脑区和对应的灰度值是怎么得到的我还没想清楚)。

本以为图像预处理部分不是很重要,但今天的代码看下来,downsample部分是必须要看的,里面就包括我比较关心的annotationImage.tif,coarse部分也会得到一个类似的图像文件,只不过是和脑片配准之后的。明天可以重点看预处理这部分代码,慢慢来。

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + BIRDS插件代码学习【01】 + + /2023/07/03/imagej-plugin/ + + BIRDS简介

BIRDS(Bi-channel Image Registration and Deep-learning Segmentation for efficient, versatile mapping of mouse brain)是ImageJ的一个插件,由费鹏老师实验室开发,主要用于小鼠脑片配准和细胞计数。BIRDS改进了脑片与图谱的配准算法,并借助Imaris实现了全脑的三维可视化。

BIRDS界面

BIRDS主要包括downsample、coarse、precise、visual和setSeg五个部分,分别用于图像预处理、图片配准、可视化检查和手动校正以及脑区分割预测。

我关注的主要是前三部分,核心是脑片和图谱的配准,具体流程如下图。

BIRDS脑片配准流程

Java GUI 组件

JPanel 面板

1
JPanel northPanel = new JPanel();

JLabel 标签

1
JLabel urlLabel = new JLabel("url:");

JTextField 单行文本框

1
JTextField urlText = new JTextField(20);

JOptionPane

1
JOptionPane.showMessageDialog(null,"Pay attention to the cache url!","warning",JOptionPane.WARNING_MESSAGE);

JTabbedPane

1
2
3
4
5
6
JTabbedPane centerPanel;
JPanel mypanel = new JPanel();
Button mybutton = new Button("import");
mypanel.add(mybutton);
centerPanel.addTab("rawImg", new ImageIcon(tabImage), mypanel);
centerPanel.setSelectedIndex(0);

JButton 按钮

1
JButton urlButton = new JButton("choose");

JTextArea 多行文本框

1
JTextArea logText = new JTextArea("Welcome!");

JFrame 窗

1
2
3
4
5
6
7
8
frame = new JFrame("BIRDS01");
frame.add(southJsp, BorderLayout.SOUTH);
frame.add(centerPanel, BorderLayout.CENTER);
frame.add(northPanel, BorderLayout.NORTH);
frame.setSize(500, 600);
frame.setVisible(true);
//frame.setLocation(600, 300);
frame.setLocationRelativeTo(null);

组件触发事件

1
2
3
4
5
6
7
8
9
10
11
urlButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("o((>ω< ))o");
}
});
centerPanel.addChangeListener(new ChangeListener(){
public void stateChanged(ChangeEvent e){
System.out.println("目前选中的是面板" + centerPanel.getSelectedIndex());
}
})

获取ImageJ图片

1
2
3
4
5
import ij.ImageJ;
import ij.IJ;

new ImageJ(); //打开ImageJ
brainImg = IJ.getImage(); //获取导入ImageJ的图片

今日总结

不知道是不是因为把显示器搬到实验室的原因,今天工作非常有动力,面对BIRDS源码中超级多的包和类,一点都没有害怕,就奔着一个很小的目标去了:我要搞清楚这个插件是怎么获取到我导入ImageJ中的图片的。今天主要就是学习了BirdsPlugin.java这个文件的代码,对应的是BIRDS插件的GUI,组件布局和触发事件等都在这个文件里面。虽然还不太熟悉java中图像处理的一些方法,但今天学会了看API(要是有具体的使用示例就更好了),也是一个进步!

下一步还是要明确目标:学习脑片与图谱配准的算法!!!BirdsPlugin.java中case2要仔细读一下,我一切换到precise板块,极短的时间内就会弹出配准后的脑片序列,而且也不像提前存好的图片,这个tab触发的逻辑要仔细读一下。不过脑片与图谱配准的核心算法应该是在coarse那部分,明天认真读一下!!!

参考文章

]]>
+ + + + + 项目实战 + + + + + + + Eclipse + + ImageJ + + Java + + + +
+ + + + + 小鼠脑图谱第四版 + + /2023/07/02/mice-brain-atlas/ + + ]]> + + + + + 学习笔记 + + + + + + + 脑图谱 + + + + + + + + + 做选择 + + /2023/07/02/making-choices/ + +

我不得不承认,除了友情上的一些小挫折,我的大学生活真的是太顺利了,似乎没有太用力就一步一步走到了保研升学这个岔路口。曾经我并没有觉得这样有什么问题,直到我读博一年以后,我愈发觉得做出明智的选择是多么重要,而大学时的我是多么稚嫩和无知。

那些年少无知做出的选择

  1. 关于学习:身边的老师、同学都说成绩很重要,学校的保研政策也只有加权排名这一项,我在大学的工作重心就只放在的课程学习上,准确的说是应试上。缺少了知识体系的构建和课程内容的实践,课程设计和实践项目代码也没有很好的归档,导致毕业以后沉淀的内容很少。
  2. 关于比赛:其实我一直对自己的能力没有太多自信,大家对计算机专业的第一印象就是编程能力强,可我却没参加过程序设计竞赛,除了学校开设的课程以外,我没有花额外的时间提升自己的编程水平。现在在课题组内做一些具体的任务,我可以很明显的感觉到解决问题没有一个完整的思路,写代码也离不开CSDN(呜呜呜),太丢人了!
  3. 关于自学:大学的时候,尤其是大三、大四的时候,我有大把的空余时间,明明知道项目很重要,机器学习和人工智能很火,但却始终没有学起来,网课反复观看前几集。我现在的数据分析大量需要机器学习的算法,导师天天提神经网络,可我脑子里却没有一个成型的概念。
  4. 关于文档:我大学里学习专业课程,每次考完试笔记和学习资料就扔一边了,从来没有试着整理成电子文档保存下来,或者和其他课程建立联系。课程设计完成以后代码就丢一边了,没有系统的保管代码。现在做项目需要用到以前的专业知识,我都差不多要重新学,知识储备干净地像一张白纸。
  5. 关于跨专业:我之前对专业没有什么概念,什么专业好,什么专业天坑,我都没怎么了解过。关于跨专业到神经生物学,我当时只是觉得我不是很喜欢用别人写好的模型做项目,我想有自己的东西,做研究也挺好的,这个专业挺需要计算机的,于是我就跨专业了。但我当时至少应该了解一下这个专业是干什么的,就业前景如何,也可以试着听几节神经生物学相关的课,看看自己是否对这个专业真的感兴趣。这样我也不会来到新的课题组之后不知道自己可以干什么,不知道自己对什么研究方向感兴趣,苦苦摸索。
  6. 关于选导师:保研那段时间,除了上科大是我主动联系的导师以外,我入营的其他学校都是老师主动联系的我。我当时很天真,我认为应该答应第一个联系我的老师,毕竟是这个老师先联系我的,却忽视了选导师最重要的是适合自己。如果时光机让我回到一年前,我会对当时的我说:了解一下这个老师的研究方向、课题组规模和人员配置、工资情况、有无科研助理、出勤要求、课题组氛围、课题组内部对导师的评价,不要不好意思问,不要轻易做决定,在提交系统之前,你有选择导师的主动权。
  7. 关于直博:当时脑院只招直博生,于是我稀里糊涂直博了。我知道直博只需要五年就可以拿到博士学位,但我不知道导师会上来就拿博士生的标准要求一个本科毕业的学生,不知道博士延毕的比例这么高,不知道博士读不完会一无所有。如果可以重来,我希望自己先读一个硕士,既可以从本科慢慢过渡提升自己的能力,也可以探索自己是否有意愿读博。既然走上了这条路,就好好地走下去吧!

建议

  1. 无论是做计划还是做选择,给自己至少三个选项,从中选最优的那一个
  2. 现在过得难一点是好事,未来或许会轻松一点
  3. 我们的记忆是有限的,学到的知识要及时整理,不要觉得麻烦,这些都是宝贵的财富
  4. 在决定做出改变之前,先进行原型设计,以最小的成本体验要做出的改变(有点类似于创业过程中的MVP)
  5. 不要害怕向别人寻求帮助和建议,事前暴露自己的无知也比掉坑里再呼救要好得多
  6. 时刻保持清醒
  7. 学习要有连续性,不要每个东西都只学个皮毛
  8. 成事之根本:行动起来
]]>
+ + + + + 生活随笔 + + + + + + + 思考 + + + +
+ + + + + 图像风格迁移 + + /2023/06/26/style-transfer/ + + 数据集准备

按照该链接下载coco数据集的指定类,作为训练数据集。YOLO-Coco-Dataset-Custom-Classes-Extractor

开源模型介绍

风格迁移模型参照该github开源项目。onnx_small_style

  • images/目录下包含输入图片文件夹、输出图片文件夹及风格图片文件夹
  • model/目录下有按特定风格图片及尺寸训练好的模型,可以直接使用
  • 风格迁移在线demo1:风格迁移网站
  • 风格迁移在线demo2:风格迁移网站

项目内容介绍

模型训练及测试

1
2
3
4
# 使用训练好的模型
python neural_style/neural_style.py eval --content-image images/content-images/birds.jpeg --model model/rain_princess.model --output-image images/output-images/birds_rain.jpg --cuda 0 # cpu
# 训练自己的模型
python neural_style/neural_style.py train --dataset dataset --style-image images/style-images/girl.jpg --save-model-dir model --epochs 2 --cuda 1 # gpu

注意事项

  1. 训练过程中报内存不足时,考虑风格图片的尺寸是否过大,或者减小batchsize
  2. 如果使用自己的笔记本训练数据,最好不要使用完整的coco数据集,可以只选取某些类别的图像数据
]]>
+ + + + + 项目实战 + + + + + + + Python + + 计算机视觉 + + Pytorch + + + +
+ + + + + 爬取网站数据 + + /2023/06/26/spider/ + + 爬虫基本步骤
1
2
3
4
5
6
7
8
9
10
11
import requests
url = 'https://www.google.com/' #以爬取谷歌页面为例
headers = {
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537 36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58"
}
proxies={
'http':'http://127.0.0.1:10808' #依据本地代理端口填写地址
}
r = requests.get(url=url, headers=headers, proxies=proxies)
print(r.status_code) #200
print(r.text)

经验(●’◡’●)

  1. 静态页面一般可以直接通过get请求获得网页数据
  2. 需要js动态渲染的页面获取数据会稍微复杂一点,可以先查看返回的xhr或json文件是否有想要的数据(预览),或者ctrl+F搜索关键词
  3. 通过“发起程序”可以查看文件的请求程序发起链
  4. 爬虫的关键是抓包!找到我们感兴趣的数据!

应用案例1:爬取网站课件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import json
import os

url = "https://classroom.zju.edu.cn/pptnote/v1/schedule/search-ppt?course_id=49219&sub_id=848702&per_page=100"
headers = {
"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.43"
}

page_num = 2
date = '20230615'
save_dir = 'D:/Desktop/ppt_img/' + date + '/'

for i in range(page_num):
params = {'page':i+1}
r = requests.get(url=url, headers=headers, params=params)
# print(r.status_code)
text = r.text
text_dict = json.loads(text)
ppt_list = text_dict['list']
print(len(ppt_list))
folder = os.path.exists(save_dir + str(i))
if not folder:
os.makedirs(save_dir + str(i))

for j in range(len(ppt_list)):
content = json.loads(ppt_list[j]['content'])
img_url = content['pptimgurl']
r = requests.get(img_url,headers=headers)
save_path = save_dir + str(i) + '/' + str(i) + '_' + str(j) + '.jpg'
with open(save_path, 'wb') as f:#把图片数据写入本地,wb表示二进制储存
f.write(r.content)

应用案例2:爬取Allen小鼠脑图谱

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import requests
import json
import os

url = "https://atlas.brain-map.org/atlasviewer/atlases/602630314/576985993.json"

headers = {
"User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36 Edg/114.0.1823.58"
}

r = requests.get(url=url, headers=headers)
dict = json.loads(r.text)
num = len(dict['msg'][0]['section_images'])
img_dict = dict['msg'][0]['section_images']
# print(img_dict[130]['path'])
add_1 = "https://atlas.brain-map.org/cgi-bin/imageservice?path="
add_2 = "&mime=1&zoom=3&width=1140&height=800"

save_dir = "D:/Desktop/allen_img/"

for i in range(num):
path = img_dict[i]['path']
img_url = add_1 + path[:-4] + '_rendered.aff' + add_2
r = requests.get(img_url, headers=headers)
save_path = save_dir + str(i+1) + '.jpg'
with open(save_path, 'wb') as f:
f.write(r.content)
]]>
+ + + + + 方法教程 + + + + + + + 爬虫 + + + +
+ + + + + Matlab常用命令 + + /2023/01/10/matlab-skills/ + +
  • 矩阵拼接
    1
    2
    cat(2,A,B) % 相当于[A,B]
    cat(1,A,B) % 相当于[A;B]
  • 去除重复元素
    1
    2
    3
    unique(A,'sorted') % 去除重复元素,且升序排列('sorted'一般省略)
    unique(A,'stable') % 去除重复元素,不排序
    unique(A,'rows'); % 去除重复的行
  • 查找元素下标
    1
    2
    3
    4
    5
    find(X):返回一个包含元素索引的向量
    find(X,n):返回 X 中元素的前n个索引
    find(X,n,Direction):根据Direction在X中找到n个索引,其中Direction-'first''last'
    [row,col] = find():返回数组中元素的行列下标
    [row,col,V] = find():返回包含非零元素的向量V
  • 查看矩阵中是否有某个元素
    1
    ismember(1,A) % 若包含则返回值为1,否则为0
  • 打开matlab出现警告“名称不存在或不是目录”
    1
    edit pathdef % 把对应的路径删掉即可
  • 保存变量
    1
    save('abc.mat','m','n') % 将变量m和 保存到abc.mat文件
  • ]]>
    + + + + + 方法教程 + + + + + + + Matlab + + + +
    + + + + + 愉快的周末 + + /2023/01/08/a-happy-weekend/ + + 前几天和小彤彤说好周末出去逛街,十点在百货大楼见面。我今天虽然出门比之前稍晚一会,但等公交并没有花很久,赶在约定的时间点前一分钟到达了目的地,然后又等了她十分钟左右。我早上只喝了玉米糊,她是根本没吃饭。我们在尚街逛到十一点左右,就去金鼎吃重庆火锅啦!店里有免费的甜品,番茄和牛油的鸳鸯锅锅底也很有卖相和食欲,我们点了双人套餐,又加了一份金针菇,后面写了好评,店家又送了两个炸蛋,太幸福了!!!套餐里食物种类不少,肉类也很新鲜,服务人员会及时加汤,我们两个都吃的饱饱的!吃完火锅有点渴,我们去了茶百道买奶茶,我点的店里的新品,喝起来有点像茶和奶酪的结合体。我们坐在店里休息的时候,有一对年纪很小的双胞胎一直看着我们笑,好可爱!休息好后我们一起去了商场,小彤彤帮我选了牛仔裤和毛衣,牛仔裤很有弹性,毛衣也是试了三件以后我最满意的一件,收获满满~

    虽然我一年中大部分时间都不在聊城,但每次回家后都会想和好朋友见一面,一起吃好吃的,一起在热闹的地方逛一逛,一起聊聊天~(●’◡’●)我相信健康的友谊会让彼此受益!

    今日小结
    1. 今天大部分时间是在听小彤彤讲她的事情,有在小小践行《人性的弱点》中作者总结的与人交往的原则
    2. 给爷爷奶奶买的收音机到了,他们看起来很喜欢,很快就学会如何操作了!
    3. 给弟弟买了草莓蛋糕杯,他一口气吃完了,我猜测应该是好吃的
    ]]>
    + + + + + 生活随笔 + + + + + + + 游玩 + + + +
    + + + + + 取钱小记 + + /2023/01/06/draw-money/ + + 过年前陪爷爷奶奶去银行取钱,是我们之间的一个小默契。奶奶说,这钱是一部分是过年给小孩子们发压岁钱用的,剩下的留着用作年后日常花销。我们拿上银行卡和存折,走上十多分钟就可以到银行,顺利地话在自助取款机上就可以完成取钱任务。但偶尔也会有一些突发情况,需要存折、身份证但忘记带,或者不记得银行卡密码了···

    第一次取钱

    往年我都是放寒假回家,今年情况特殊,是临时变更学习场所,回家以后还要准备线上考试。在复习周的某天上午,爷爷奶奶提出想让我带他们去取钱,我想着当天剩下的复习任务不是很重了,便答应了。爷爷需要在中国银行取¥5000,奶奶需要在中国邮政储蓄银行取这一年的养老金。

    我们家离银行很近,各大银行都在一条街上,相互离得也不远。我们先走到中国邮政,就想着先把奶奶卡里的钱取出来。结果我在自助取款机看卡的余额只有两块钱。银行的工作人员说可能是卡没有激活,需要存折才行。但奶奶出门没想那么多,只带了两张银行卡和两张身份证。爷爷心急,把奶奶说了一通,让奶奶回家取存折。奶奶本想和我们一起去中国银行取钱,但爷爷说她来回要很久,现在回家可以节省些时间,奶奶才迈着不太轻快的步伐回家了。

    我和爷爷去中国银行取钱就比较顺利了,自助取款机上没有钱了,我们在大厅里的取款机上取的钱,有工作人员的热心服务,取钱任务很快就完成了。我和爷爷回到中国邮政门口,时不时张望着路口处有没有奶奶的身影,奶奶走路慢,年纪大了又不敢骑自行车,我们等了很久,才看到我们期待的身影。不过坏消息是,存折上查出来的余额依旧是两块钱。奶奶有些着急,念叨着:那我的老年金去哪里了?后来爷爷提出看看社保卡上有没有钱,我就拿着社保卡去自助取款机上试了一下,没想到养老金真在这个卡上!爷爷奶奶悬着的心终于放下了,取钱顺利完成!

    之前从来没有用这张社保卡取过钱,谁能想到钱在这里呢?🥲

    第二次取钱

    第一次取钱结束后,我在饭桌上郑重声明,在我考试结束前谁都别来打扰我。于是,家里人真的让我清净了两天。上次从奶奶的社保卡里取了钱,爷爷一直想去看看他的社保卡里有没有钱,但我在忙考试就没敢提这个事情。昨天下午四点多考完试,爷爷奶奶还又找我确认了一遍:考完试这下你没什么事了吧?🤣

    今天早上爷爷想让我带他查一下他的社保卡里有没有钱,我们拿着社保卡和身份证就出发了,想着应该很快就能回来。我在自助取款机上试了一下,密码竟然还是默认的卡号后六位数字,有了上次的经验,我知道是卡没激活。我们去找工作人员问了一下,激活需要本人到场,需要本人的身份证,但由于爷爷不会写字,我代签的话需要提供身份证。我想着既然来了就帮爷爷把这个事情办好,我让他在大厅坐着等我回去取身份证,爷爷还提醒我骑自行车来,比较快。

    我也不知道来回花了多久,总之戴着口罩有点喘,进了大厅有点出汗。我看了柜台窗口上叫的业务号,我们当时领的号已经过去了,我就重新排了个业务号,前面有6个人。大部分都是老年人取钱的业务,所以没等多久就到我们了。工作人员一听说我要代签,很是诧异,对我爷爷说:大爷,我看你年纪也不大,自己的名字写不了吗?爷爷无奈地摇了摇头。我领了代签,一顿签字以后,爷爷一顿按手印。又是拍合照,又是录密码,又是点确认,前前后后花了半小时左右。

    我当时回头望了下沙发上坐着的一群老年人,他们大部分都在看我们激活银行卡,我不知道他们是觉得我们太慢了,还是在羡慕爷爷有孙女陪着来,我自己更倾向于后者。(❁´◡`❁)社保卡激活以后,我们麻烦工作人员查了下余额,没想到里面有两万多,透过口罩我都能感觉到爷爷的开心。爷爷没有取钱,查完余额我们就回家啦~

    记得以前爷爷奶奶都是拜托爸爸帮他们取钱,不知道什么时候他们开始愿意让我带他们一起去取钱。和爷爷奶奶在一起时,我觉得自己是大孩子了,我可以在这个信息时代为他们抵挡一些风浪,我也很想被爷爷奶奶依靠!👵👧👴

    ]]>
    + + + + + 生活随笔 + + + + + + + 家人 + + + +
    + + + + + 冬学期结束感想 + + /2023/01/05/end-of-winter-semester/ + + 今天下午四点零五结束了冬学期的最后一门考试!考前的时间充实且紧张,可真到开考倒计时变为0时,一切紧张和焦虑就都被抛在身后,关注的只是考题和脑子里的知识。牵绊着我们的一件件事情结束时,会带给我一种很奇妙的感觉,我想是这件事情承载的关注与一切戛然而止造成的落差导致的。我会突然觉得似乎也没什么,再不愿面对的事情总归是过去了。该背的知识点再拗口也背下来了,再难理解的知识也照样听进去了,逼自己一把,没什么是不可能的。

    下午系统自动收卷的那一刻,我感到非常释然,我终于可以回到没有考试任务的生活节奏中来了。每天全部的时间都可以自己安排,这下总不能说没什么做任务了,如果没有考试复习压力,我依旧没有推进任务,那问题就出在我身上了。虽然这段时间我在备考的过程中每天时间利用率都比较高,但我不知道没有了考试这个有紧迫时限且不得不去认真准备的事情之后,我能否把有效的时间用在科研任务上。

    我很期待未来一段时间的实践,我想证明我可以。👍

    ]]>
    + + + + + 生活随笔 + + + + + + + 考试 + + + +
    + + + + + 及时按下暂停键⏸ + + /2023/01/03/press-stop-button/ + +

    牛顿第一定律:任何物体都要保持匀速直线运动或静止状态,直到外力迫使它改变运动状态为止。

    我经常会想,要是生活有replay button该多好,要是我从大一就好好练习编程能力,是不是也有机会参加计算机的竞赛?要是我考完四六级以后听英语老师的话一鼓作气把英语的证书都考下来,或者没有就此把英语扔到一旁,我现在英语的听说读写是不是都超好?要是我坚持把收藏的网课看完,现在是不是已经成为跨界高手了?要是我把时间管理的好习惯坚持到今天,是不是面对多任务就游刃有余了?这种想法其实没有太大意义,时间不会重来,即使让我重新来过,我能否坚定地做出难而正确的选择呢?

    相较于replay button,我认为pause button更常用且可操作性更高。原本拿起手机📱是想看一下群里的通知,却不知不觉看起了推送和短视频;明知道有很紧急的事情要做,却因为别人的一句批评而深陷消极情绪;明明知道任务A更重要,却仍选择将时间花在一个个无关紧要的事情上;本来只想网购一个本子,却不自主地挑起了衣服···这样的场景数不胜数,很多时候我们处于这种失控状态。这时我们需要做的是果断按下暂停键,防止负面情绪伤人伤己。

    我们的大脑中有两个小人,小人A喜欢轻轻松松,小人B喜欢自我约束。我们的大脑乐于处于愉快且低能耗的状态,因此大多数情况下是小人A说了算,但这往往会让我们变得贪玩和懒散。当我们想做出改变时,小人A和小人B会在脑内开始打架,往往还是小人A获胜。就像我们在追剧时,想着看完这一集就去学习或者就去睡觉,但一集结束后,我们还未来得及打败那个想继续看下去的小人,下一级就自动播放了,这时我们往往会想,刚刚的剧情好精彩,不如就再看一集吧。

    那小人B怎样才能打败小人A呢?以我个人经验而言,可以有两种方法。第一种,内心的小人在斗争时,再努力挣扎一下,强迫自己去做另一件可以带来正向影响的事情,在事件的切换中找回对生活的掌控感。就比如我今天下午复习的节奏很乱,经常被别人打断,但我又不能对家人发脾气,晚饭后没复习好的失落感配上饭桌上叽叽喳喳的说话声,我突然陷入一种极强的消极情绪,对什么事情都失去了兴趣,但我强迫自己把刚刚看的视频回放的重点总结出来,但此时心情还是不好,于是我又去洗了个澡(即使我心情不好什么都不想做,但我知道洗澡极大概率会让我的心情变好,于是我就去做了),洗完澡果然心情就恢复正常了,我又可以重新投入学习中了。第二种,借助外界刺激,这种往往是不可控的,而且是可遇不可求的。比如玩手机的时候老板发来消息问任务怎么样了,逛街时看到群消息确定了考试日期等,这种刺激往往会马上给小人B注入能量,从而促使我们立刻放下手头的玩乐活动,转而投入学习或者工作。

    多审视自身状态,面对行为上的自我放逐,及时按下暂停键。

    昨天晚上睡觉时的一点思考
    1. 要想和比自己地位或能力高的人有效对话,首先要在认知领域上有相交,不要习惯做门外汉。
    2. 不要着急看到结果,把功夫花在关键事情上,改变自然就会发生。
    ]]>
    + + + + + 生活随笔 + + + + + + + 思考 + + + +
    + + + + + 动态思维 + + /2023/01/02/dynamic-mind/ + + 导师在某次组会上说,我手头的多个任务并不是互相孤立的,有的任务两两之间存在联系 ,比如arduino和Bpod两者配合实现动物行为的触发和记录,学懂了一方,会对另一方起到促进作用。自此以后,我变得有意识地关注事物之间的联系。我时常会在攻克某个小障碍之后豁然开朗,我不仅明白了事物背后的原理,而且看待其他问题时有了新的视角和思路。

    说实话,我本身存在很强的定式思维,比如我拿到一个任务,如果周围人都说这个任务很难,而我恰巧在这方面也不是很自信,那我很可能就先入为主地认为自己无法很好地完成这个任务,在执行过程中就可能变得畏手畏脚。或者,我会从触发思绪的一个事件点(有可能只是一句话、一个通知、一张图片等)发散思考,悲观地认为很长一段时间甚至一辈子都会是这样。这种思考方式在我很小的时候就出现了,我小时候一直是短头发,我很羡慕别的女孩子头发长长的,扎起来又精神又好看,但我头发一长就会被妈妈带去理发店,我常常躺在床上想,结婚时短发穿婚纱会不会不好看?我会不会一辈子都是短头发呢?但事实是,我从初三就开始留长发了,在我自己有意愿且有能力自己扎头发以后,妈妈并没有阻拦过我留长发。回看过去,很多时候我们忽视了事物发展的动态性,有时只有站在较长的时间尺度上才能看见变化本身

    这几天复习时,把老师讲课的视频回放又看了一遍。其实我上课时有认真听老师讲课,但有的老师讲课时间长,有的老师讲课语速快,有的内容我比较生疏,总之第一遍听下来,我几乎捕获不到老师讲课的框架和重点。渐渐地,这些课程回放在我眼中变成一个个凶狠的怪兽,我在临近期末考试时才不得不选择重新听课。神奇的是,第二次听课时,我发现这些课程之间很多内容是互通的,几乎每个老师都会介绍动作电位、突触以及膜片钳技术,有三位老师都讲到了长时程增强,有两位老师都讲到了量子释放,谷氨酸和GABA受体也是在各个老师口中常出现的词,一个一个回放看下来,似乎曾经在我眼里困难重重的神经生物学知识,变得条理清晰起来。各个老师的讲解互相补充和联系,知识点逐渐串联成了知识面。

    我所说的动态思维 ,也可以说是成长型思维、主观能动性,或者用发展的眼光看问题,在我看来都是一个意思,就是要认识到我们所处的世界的在发展的,事物之间是相互联系而不是孤立的或一成不变的。我们总觉得自己的想法是正确的、有预见性的,但这往往很有迷惑性,我们往往容易忽视事物之间的联系,也很难用静止的思维去评判动态发展的事物。事物在变化,随着对事物的熟悉程度或思考深度增加,我们对事物的认识同样会发生变化。所以不要害怕困难,主动权掌握在我们手里,我们可以用积极的行动改变认知,进而影响任务的走向。

    ]]>
    + + + + + 生活随笔 + + + + + + + 思考 + + + +
    + + + + + 2023年的第一天 + + /2023/01/01/the-first-day-of-2023/ + + 前几天就计划好今天去东昌湖玩,只不过从下午改到了上午。其实往年元旦我都是在学校过的,三天的假期很少有机会回家。今年沾了疫情的光,去年十二月底就回家了,新的一年第一天,一家人就要整整齐齐出去玩!爸爸把车停到摩天轮里面的停车场了,我们就顺便在摩天轮附件逛着玩了一会。之前总是远远的看过摩天轮🎡,这是第一次看到正门,近距离看摩天轮时发现摩天轮转地好慢!没想到旁边还有一个小型的动物园,有好多匹白色的矮马🐎和各种颜色的孔雀🦚,有的小马的毛发还编了辫子,超级可爱🤩

    一路向鼓楼走去,东昌湖结冰了,冰面上零星散落着砖块、摔炮盒和烟花桶,想必先前有很多人想来测试一下冰面的厚度吧,向远处望去,隐约看到一只水鸭踉跄地在冰面上走来走去,画面有些滑稽。本以为今天鼓楼这边会很热闹,没想到却是没多少人,路两侧布满了红色的摊位,出摊的却很少。大冷天的,冰糖葫芦的生意当属第一,比如我们就给商家贡献了五串糖葫芦🍡的交易。路边上有两个大爷在卖气球🎈,是短视频里很流行的花朵🌼笑脸气球,我想:要是康康带我来这里玩,肯定会给我买气球的!

    今天又是喜欢给爷爷奶奶拍照的小陈同学( •̀ ω •́ )~抓紧复习去啦!!!🐇

    ]]>
    + + + + + 生活随笔 + + + + + + + 游玩 + + + +
    + + + + + 2022年的最后一天 + + /2022/12/31/last-day-of-2022/ + + 今天早上赖床了,八点多才起床,早上依旧是喝玉米糊。妈妈今天倒班,白天一直在家。上午我磨蹭到九点才挪动到书桌旁边,开始背大型仪器的问答题,背了大概一小时左右,妈妈说一会陪她逛超市。我第一反应是拒绝的,因为今天安排的复习任务比较多,但妈妈第二次提出这个要求的时候我就同意了,毕竟妈妈很少有空逛超市。我午睡本来打算睡半小时的,结果愣是睡了一个半小时,午睡时长确实是一个大问题,怎么才能控制一下呢?每次醒来都发现下午也快过去了时,真的要命!下午把突触那一节的回放◀看了一遍,老师有划重点,视频大概两个小时左右,所以听起来并不费力。

    晚上看到清一色复盘2022的推文,复习的心❤️一下子乱了,总想再看看人民日报制作的年度温暖视频,再看会搞笑的脱口秀,可是复习的重任和一周一度的周报和组会在心头压着,我突然emo😈起来,逮住男朋友就开始找事。磨蹭到晚上九点才开始继续复习,看了一部分神经环路的视频,然后开始看学习记忆的视频(这个老师有明确说考题)。复习着复习着,就到晚上十一点了,拖延真的是无形中对我们的消耗。很多时候我们一些令人费解的行为,比如一直刷视频、想寻求刺激、觉得身体疲惫等等,可能只是在拖延时间,借此逃避高压的现实。但实际上拖延是在为现实增负,大脑🧠习惯沉溺在舒适区,这就注定成长和突破是要付出一些代价的。

    最近我每天都用Forest 软件记录时间,主要是学习、工作和写博客三大块。我每天都忙活到十一点多,但一看一天的专注时长才三小时左右,不禁感叹时间都去哪儿了?我是不是也在假装很努力,实际上浪费了很多时间呢?前几天写2022年年度复盘时,我给2023年定的主题词是“告别拖延”,我希望这次不仅是说一说,而是真正落实到每一天的生活中,落实到每一个任务中。明年的课程会少很多,要尽快转入科研主线,多做一些为自己增值的事情,少一些无理取闹和胡思乱想。多读书,多写作,多思考,多实践,多锻炼。希望新的一年我可以交到好朋友 ,培养一门兴趣爱好,情绪也更加稳定。无论所处环境如何,要始终热爱生活,踏实做事,真诚待人,逐渐变成自己喜欢的样子。

    最后借用总书记新年贺词中的一句话结尾,路虽远,行则将至;事虽难,做则必成。祝愿大家身体健康、新年快乐、皆得所愿!

    ]]>
    + + + + + 生活随笔 + + + + +
    + + + + + 2022年度总结 + + /2022/12/28/my-2022/ + + 2022我是怎么度过的

    1月

    • 抓拍了几张小侄女在我家玩的照片,打印出来以后她超级喜欢
    • 和爸爸、弟弟还有奶奶一起去了月季公园,玩了呐喊喷泉,还发现了一群鸽子🕊
    • 爸爸给我买了草莓🍓糖葫芦,嘻嘻嘻
    • 和小彤彤吃了海底捞,看了电影🎞️《李茂扮太子》(当时是在是没什么电影可看了)
    • 楼下有小朋友打雪仗,年轻真好
    • 买了手机支架,正好在奶奶包馄饨时录了个视频,就是手机美颜有点重了

    2月

    • 全家出动去月季公园看花灯,逞能玩射箭🏹结果弓都拉不开,箭直接掉出来了,丢人
    • 和爸爸还有弟弟一起放风筝🪁,我不理解:难道跑不快就放不起来风筝吗?
    • 和周敏还有王茹冰一起吃了火锅,收到了她们送的生日礼物🎁
    • 和雨曦一起拼好了积木,摁零件摁地手疼
    • 一家人在赶海人为我过了21周岁的生日,嘻嘻嘻
    • 情人节前一天爸爸去给妈妈买项链,顺便给我买了一条手链!手上戴着四叶草🍀,天天都是幸运girl!
    • 和小彤彤一起吃了串串,看了电影🎞️《这个杀手不太冷静》
    • 收到了康康送的耳机,不过不太习惯全入耳式的耳机
    • 在忙毕业设计里小鼠体态识别的实现!

    3月

    • 妇女节前一天收到了康康送的一大捧花,玫瑰的颜色好温柔🥰
    • 百合花开了,味道太浓郁,只能放在阳台散散味道了
    • 神奇的物物交换:西红柿、草莓、牛油果🥑

    4月

    • 给大一的同学做经验分享,结束后收到了冯导给我准备的礼物!📕
    • 毕业实习时数据库被黑客删了,网络安全很重要哇!
    • 在宿舍门口拍到了红嘴蓝鹊,我愿称之为目前见过的最美的鸟~

    5月

    • 学校的古树上挂满了心愿卡,我总喜欢饭后逛着看一看大家的愿望
    • 筹备并拍摄毕业证,用班费给每个人买了一束玫瑰花🌹
    • 和裴焱一起做了美甲💅,我们选的都是兔子,哈哈哈
    • 拍到了粉紫色的天空!

    6月

    • 毕业答辩,是校优嘿嘿~
    • 小李约我在西区跳蚤市场见面,送了我一个贝壳,嘿嘿
    • 全校组织各个学院拍毕业照,那天阳光很刺眼,照片里很多人眼睛都没睁开
    • 交完毕设材料,第二天我就去西安找康康啦!实现了一起在城墙上骑车的愿望!我竟然还进了创新港!
    • 大四下,国华因为疫情没能回学校,我们约好了在西安见面,去了海洋馆,还一起看了电影🎞️《坏蛋联盟》
    • 拿到驾照啦,不过至今还没碰过车🚗
    • 知道我快去杭州了,舅舅请我们吃了一顿大餐!
    • 月底,爸爸妈妈担心我一个人,硬是要陪我一起去杭州,路线:聊城-济南-济南西-杭州东。那时候我还不懂换乘,只记得我们到杭州以后地贴坐过站了,出了地铁又找不到良渚实验室的位置,天很闷热,汗水把眼睛都弄湿了,最后在手机电量耗尽时终于找舍友拿到了钥匙🔑
    • 爸爸妈妈跟团去乌镇和西湖旅游,他们给我买了好多特产,回聊城前带我吃了顿好吃的,不过那家店比较坑···

    7月

    • 我有自己的工作牌了,也收到了浙江大学的录取通知书~
    • 在肥叔充了100块钱,喜欢吃店里的锅贴
    • 开始学习3D建模,陆陆续续完成了一些小任务,找到了一点点成就感
    • 月底请了五天假,和康康回家见家长啦!幸福幸福幸福!一起遛弯,一起淋雨,一起等蛋糕,一起给玩偶涂颜色,一起吃超好吃的烤肉,一起踩点去看电影🎞️《独行月球》···

    8月

    • 七夕收到了爸爸给的红包还有康康送的项链~
    • 去北京参加暑期培训,CNeuro 2022,被一群大佬虐了十天,呜呜呜
    • 小李趁周末来找我玩,一起吃了火锅,还送了我一捧橘色泡泡!
    • 知道医院健身房位置之后,经常早起去打卡2公里~

    9月

    • 搬进学校宿舍啦,是双人间,舍友人也很nice~
    • 临近中秋节,收到了来自食堂和学校的月饼投喂!
    • 收到了小彤彤送的《云彩收集者手册》,没想到同门师姐也是一位云彩爱好者,嘿嘿~
    • 参加了新生典礼和开学典礼,小夜灯汇成一片蓝海也太震撼了!要做灿若星辰的浙大人!
    • 心血来潮去了西湖,这应该是我今年最肆意洒脱的一次,啃烧饼、看西湖、逛苏堤、看老年人舞蹈团表演,人与人之间的🔗好温暖!
    • 和佳宁学姐还有孟子杰一起吃了烧烤,啥时候我也把我家康康带上呐?
    • 看了校史大戏《求是魂》,当时不知道还要抢票就直接去了,被社团工作人员偷偷放进去了

    10月

    • 国庆去西安找康康了,打卡永兴坊!一起冒着雨在生意火爆的铁锅炖门口等餐、一起吃了超级赞的自助、一起看了电影🎞️《万里归途》···
    • 发现了学校的向日葵🌻,一位老师热心地帮我拍了好多张站在向日葵花海中的照片!
    • 跨专业听课好难,哭了😭
    • 在操场跑完两公里,紧接着点了一份鸭血粉丝汤,罪恶!
    • 看何婷师姐切小鼠脑片,不知道以后我会不会做生物实验呢?
    • 学校的桂花开了,校园里香香的,阳光照下来时,小小的花亮亮的
    • 收到了康康送的丑萌的“羊了个羊”蛋糕,不过超级好吃!

    11月

    • 魔鬼考试周,为什么浙大的一学期只有两个月,┭┮﹏┭┮
    • 打卡西溪国家湿地公园,小孩子比较多,没逛太久就回去了
    • 给爸爸订了一个兔子🐇蛋糕,太可爱了,哈哈哈,不过以后还是顺着大人的心意多来点实在的水果吧!
    • 下课后幸运地看到了完整的日落🌇,各个阶段都绝美!
    • 排练校歌,嗓子经不起折腾,唱一会就会哑,谁懂?!
    • 当英语助教了,虽然只是一个1学分的小课,但还是想尽力和英语有多一点的联系
    • 强迫妈妈听我用平板弹生日快乐歌,哈哈哈
    • 听了陈嘉映和孙周兴两位老师关于“哲学与大学”的讲座,结束后堪称大型粉丝见面会

    12月

    • 紫金港因疫情封校一周,每顿饭送到门口也太幸福了!
    • 杭州下雪了🌨,不过我们还在封控,只能站在阳台看雪。舍友是南方人,确实很兴奋~
    • 行程卡下线了,不查核酸了,新冠改名了···魔幻的2022!
    • 师兄博士答辩完请我们吃饭!每道菜都很好吃!
    • 我回家了,我阳🐏了,我阳康了。嗓子疼真要命,还好我们家经常熬冰糖梨水~

    2022年到处拍拍拍

    天空

    美食

    臭美

    和朋友

    和康康

    小确幸

    关于2022,我想说

    记得年初时我买了一个手账本,附带的卡片上说我今年的主题词是“繁花”,我心想,2022一定会是极好的一年,事实证明的确如此。回顾这一年,上半年是告别,下半年是新生。大学毕业于我而言,一半是逃离,一半是不舍。无论如何,我在太原理工大学的生活画上了句号。我的所谓毕业旅行很短,也没有鼓足勇气和康康去拍写真,在家也没有待很久,就匆匆收拾行囊赶赴了下一站——杭州。新学校很美,学校很包容、很智能、很自由,我在学习之余增加了许多生活中的新奇体验,变得更加独立和勇敢。不过谈到科研,说实话我还没有完全适应跨专业的生活,我花了很长时间适应新身份——神经生物学专业的学生,熟悉新的领域,摸索如何将计算机领域的知识用在生物方面,初学硬件知识···但我现在还是很难平衡好课程和实验室任务,面对许多任务会丧失行动力,对自己的定位和认知还有些模糊,不过也逐渐习惯了和老板的相处之道。小陈同学,要愈挫愈勇才行,你的福气在后头!

    你好,2023

    主题:告别拖延
    目标:10部电影➕10本书➕定期复盘

    ]]>
    + + + + + 生活随笔 + + + + + + + 年度总结 + + + +
    + + + + + 英语结课感想 + + /2022/12/27/English-class/ + + 今天研究生英语结课了,明天把第五组的推文发出来,我助教的工作就完全结束了,竟然有些舍不得。虽然选课时因为六级成绩过期导致无法免修英语,心里有些不甘,但对英语本身我是不排斥的,我喜欢通过英语这个媒介加强与老师和同学们的交流。一直以来口语都是我的心病,我很想得到别人的认可,却又始终不敢开口讲英语,于是My spoken English is poor这句话就常常挂在嘴边,时间久了真就觉得自己口语不行。

    在这八周的英语课上,无论是线上还是线下,课堂互动总是少不了的。最开始上课时小组讨论时不好意思开口讲英语,老师问问题也不敢大声回答,我多少有些不习惯这种形式的英语课堂,我习惯在传统课堂上当一个认真听课的好学生,在需要英语大量进口和出口 的课堂上我不确定能否表现好。后来我才意识到,最初的想法太天真了,回答个问题有啥的?难的在后头!上台配音、一起唱歌、根据话题极限写稿,英语课堂永远花样形式多变,不知不觉中和小组同学的关系就近了,也更能融入课堂氛围了。

    我平时不是一点英语都不看的那种,TED演讲、美剧、电影都会看,只不过会看字幕,英语输入的量也不是很大。还记得老师第一次课问我们看过多少个TED演讲,超过50个的举手🙋‍,我当时一直在脑子里数看过的演讲个数,我知道我看过不少,但脑子里没有确切的数字,也就没敢举手。说实话我自认为我的英语发音还可以,所以课堂上或者随堂作业有稿子的时候,我都很放松,感觉处于自己的舒适区中,甚至狂妄地认为这个课对我的英语提升不会有太大帮助。

    但是我想错了,老师拥有一套完整的方法论。从引入how to speak English in public这一主题,到passionpronunciation、轻重缓急之区分度、sentencestructure of a paragraphacting,循序渐进,最终带领我们呈现一个完整的英语演讲,我总能学到新的东西。每周一晚上大家一起往群里发随堂作业时,我偶尔会心血来潮把每个人的都点开看一遍,总有比我讲的好的同学,每次都会有新的体验和收获。

    虽然我最后考核时的表现并不完美,一开始有点紧张卡词,表情可能也没有很自然,肢体语言不知道是否清楚恰当,不管怎样,我还是尽我所能顺利完成了考试,给冬学期的英语课程画上了完整的句号。

    老师说,Hope you'll keep climbing。我相信,英语会在未来的路上一直陪伴着我!

    ]]>
    + + + + + 生活随笔 + + + + + + + 课程 + + + +
    + + + + + 本地文件上传到Github + + /2022/11/12/upload-doc2github/ + +

    前提:已安装Github Desktop

    1. 通过Github Desktop新建仓库(Create new repository),在本地会新建一个与仓库同名的文件夹
    2. 将带上传的文件代码放入新建的本地文件夹
    3. 通过Github Desktop上传到Github远程仓库

    PS:也可以直接在Github创建仓库,然后克隆仓库,后续步骤同上2-3~

    ]]>
    + + + + + 方法教程 + + + + + + + Github + + + +
    + + + + + 模型加工方法汇总 + + /2022/09/21/solidworks-model-summary/ + +

    3D打印

    1. 文件格式:STL
    2. 加工尺寸:厚度和孔径最低0.5mm
    3. 加工工艺:逐层打印
    4. 注意⚠️
      • .sldprt文件转为.stl文件之后,一般需要通过magics软件扫描并修复问题
      • 一般只需向加工方提供.stl文件
      • 3D打印出的螺纹误差较大
      • 孔的尺寸过小会堵住,一般需要1mm以上
    5. 加工方: 未来工场

    铝合金加工

    1. 文件格式:STEP
    2. 加工精度:±0.1mm或±0.05mm
    3. 加工工艺:轧制、挤压、拉伸和锻造等
    4. 注意⚠️
      • 最好提前向加工方说明零件用途及加工精度,以免出现较大误差导致返工
      • 需向加工方提供.step文件和工程图纸
      • 铝合金加工精度较高,不可随意修改尺寸
      • 最终目的:加工出来的零件能用!🥲
    5. 加工方: inper(加工慢但质量高)或速加网(加工教快但略粗糙)

    有机玻璃(亚克力板)加工

    1. 文件格式:pdf
    2. 加工工艺:切割(误差大概±1mm)
    3. 注意⚠️
      • 一般只需向加工方提供工程图纸
    4. 加工方: 淘宝克洛蒙旗舰店
    ]]>
    + + + + + 方法教程 + + + + + + + SolidWorks + + 公差 + + + +
    + + + + + Hexo迁移至新电脑 + + /2022/09/20/hexo-move/ + +
  • 下载GitHub Desktop并登陆GitHub
  • 将博客所在GitHub仓库clone至本地
  • 下载并安装Git
  • 下载并安装Node.js稳定版
  • 在Github/blog文件目录下安装hexo及相关插件

    需要以管理员权限进入终端,不然运行下面的命令会报错哦~🫣

    1
    2
    3
    npm install hexo-cli -g
    npm install
    npm install hexo-deployer-git --save
  • 测试

    测试能否通过github desktop正常推送博客!推送成功就说明迁移成功✅啦~

    1
    2
    hexo s # 测试本地预览
    hexo new "test" # 测试发布新文章
  • ]]>
    + + + + + 方法教程 + + + + + + + Hexo + + + +
    + + + + + 初来浙里,我曾经的那些疑惑 + + /2022/09/15/zjuer-questions/ + + 1.暑假可以搬进学校宿舍吗?

    其实是可以申请的,不过我们组没有科研助理,很多流程和手续都不太清楚,所以暑假期间我还是老老实实住在老师给租的房子里了。
    医学院提前来校学生申请入驻浙大审批流程(更新)

    2.怎么知道班内同学和辅导员?

    临近开学的时候,医学中心拉了个博士班的群,稀里糊涂就和同学们在一个群里了。至于辅导员的话,最开始是辅导员在钉钉上提醒我去做核酸,我才知道辅导员是谁的,后面也主要是辅导员在群里和我们下发通知。

    3.工资怎么发放?

    工资由两部分组成,学校发一部分(比例大),导师发一部分(比例小),良渚实验室会有¥1000路费补贴。

    4.紫金港校区(申花路)是哪个门?

    东2门~

    5.开学后可以办校园卡吗?

    可以的,新生入学那天,电信和移动都会在外面搭小帐篷,两者的套餐类似,每个月花费¥29,流量超多,通话时长超多,每个月还可以从给定app(爱奇艺、优酷、哔哩哔哩等)中任选一个充会员,真香!

    6.宿舍有空调、吹风机和洗衣机吗?

    宿舍有空调,需要自行租赁(¥450一年);一楼有公共吹风机,宿舍内使用吹风机也不会出现跳闸断电的情况;一楼有公共洗衣机,宿舍内也可以申请安装洗衣机。

    7.体检是在什么时候?

    入学后第二天就可以体检了,需要提前预约。体检的整个过程也很快,十几分钟就可以测完。😭我最后悔的一件事情就是,先抽了血,又去测其他项目,结果中途没止住血,当天又提了重物,导致胳膊上很严重的淤血···

    8.怎么选课?

    研究生迎新网站有选课的安排通知,按时间点来就可以。不过要注意,第一阶段是初选阶段,选课不分先后;初选结束后是初选确认阶段,可以得知自己有没有选上课,选上的课显示“正在修读”,没选上的课是“未选”;下一个阶段是补(退)选阶段,这个时候就是拼网速和手速了,课程有容量的话一般可以选上,不然就只能候补了;选课结果公布以后,课程才算最终确定哦~

    9.怎么找到上课的地点?

    来到宿舍会领到一张学校的手绘地图(我太爱了),趁着刚开学比较清闲,多在学校逛一逛、走一走,对照着地图认一认建筑物,上课的时候就不怕找不到路啦~😎上课地点主要是东教学楼、西教学楼和研究生楼,实验课的话可能会安排在医学院。

    10.学校食堂怎么样?

    学校的食堂超级多,有银泉餐厅、东区食堂、澄月餐厅、玉湖餐厅、麦香餐厅、留食餐厅···我比较喜欢东区食堂,菜品好吃不贵,种类齐全!😁

    ]]>
    + + + + + 生活随笔 + + + + + + + 浙江大学 + + + +
    + + + + + 使用又拍云提供CDN加速服务 + + /2022/09/06/upyun/ + + 加入又拍云联盟

    加入又拍云联盟,免费获取每月10GB存储空间+15GB流量!!!

    注册步骤如下图所示:
    步骤

    页脚添加又拍云徽标
    1. blog根目录安装插件
      1
      npm install hexo-butterfly-footer-beautify --save
    2. 在主题配置文件_config.butterfly.yml中添加
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      # footer_beautify
      # 页脚计时器:[Native JS Timer](https://akilar.top/posts/b941af/)
      # 页脚徽标:[Add Github Badge](https://akilar.top/posts/e87ad7f8/)
      footer_beautify:
      enable:
      timer: false # 计时器开关
      bdage: true # 徽标开关
      priority: 5 #过滤器优先权
      enable_page: all # 应用页面
      exclude: #屏蔽页面
      # - /posts/
      # - /about/
      layout: # 挂载容器类型
      type: id
      name: footer-wrap
      index: 0
      # 计时器部分配置项
      runtime_js: https://npm.elemecdn.com/hexo-butterfly-footer-beautify@1.0.0/lib/runtime.js
      runtime_css: https://npm.elemecdn.com/hexo-butterfly-footer-beautify@1.0.0/lib/runtime.css
      # 徽标部分配置项
      swiperpara: 3 #若非0,则开启轮播功能,每行徽标个数
      bdageitem:
      - link: https://www.upyun.com/?utm_source=lianmeng&utm_medium=referral
      shields: https://img.shields.io/badge/CDN-%E5%8F%88%E6%8B%8D%E4%BA%91-00b6ff?style=flat&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAABS2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iQWRvYmUgWE1QIENvcmUgNS42LWMxNDIgNzkuMTYwOTI0LCAyMDE3LzA3LzEzLTAxOjA2OjM5ICAgICAgICAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIi8+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+nhxg7wAABs1JREFUSInllv2PVFcZxz/n3LfZmdmd3ZndZWGhhV0qYLaFEgzQpog12tZYbVRCSa00mLap6Q+aNERp5QcVlRhi0GjaGElromI08aU1tMRXWmspRaEVbIDtdimwy77M7uy83Xvn3nP84c7b7oD/QE8yyT13znO/z/f7nOcF3m9L1B4OnNYYEoSG165kGZkukLLjdEmXiew4yum7+4qK31u2rduLFXOgEEoQCrQs9RjepaW2f35Nu/9QqRh4Fi4jrkHCMmhTitlCBcOIoP768CoAzGt5owFLQBKfad/Yflau+Mo4qY0IE8qAUbXUgKT9ctFZVJAzqzcivLN+/JGY0H6HKD0riKGvw7gFWAFtUmMTyFPF5C+Gded2LBmBaB2BAigRyeMJ0jGPgxtiyX+MtW18/ZL1DLEMK/TER9eb+Z2GQGU1CK0b8gKy9uCYYJmQcUCgUm+U0qeGw/R2pIwAdbPvAiE0aAGux0MDc7eJAJ57V7+GZYAQjLDo8yd0z6lAqQ5bBbh+iF8JWxmP5XwSJrhCyz9NJU7mdHwwknOBWEKAAq0EuIrPrKp8d3lb+M/HT/qvlsN2pKNRSoDUXAxSN+eKlWMPD7jrFi3pZc4NeHUh4+zcNMW5q/z47dLhi4X4IHYt2hFDBBFDpUmYJXoNb+y23tzPHlgRfu2F8bZ9s4W2zdgSpap2OopbzsysPUHX85YIcdU1YnxLX5pT0+59w+X4NqwmpgIIgUCxNF4+vsaY2bsknjtq+yYTnsGhMx33H8127SFp03KTBBAT/H3U+qTIZe9ambFfagHOl0OOjJs/wjCZdwtCARI2d899Z0iP7Rkv2J0ngu49xUCvu1R2+sJS6g4MAyF11deasY5+CjBs3jE6f3KrMXlDC/Cfr0xuuegtWYIpmjwXUA7YcbP69tb2ypPfO5naPyJ7d4fKioLUDihdVxZEpI4ApGiEyoKLM8aydyx5J/CXeTE+m5PbkFZV4qpBoPlAJnh7R7rw5G8vm9+/4PfvDg0rSiMdgYraeQ0xGVZu78o9tSUx9ViK0pUGc0CbTNtdu1oYG7Geu+vFAaLbqz0+3B1sf2WKnhcvJ79MvCn21JiKiGIAt6amn9scK+4brpiskOHMKRU/jCSS2xG8ddVbVcOrM54KrBvqoERyO4YqLTaKb76ct7+JtufHfuEyYKIkeoKKpN12ySs1QF28qkJmrL8FuBwqv7HTEELC4b/Fks/EjPgcDq05TeO8EJrhSten35KLDjpmhfd8/QBNYY6clp0twC1LAmGQLJdyCF08gub/MtYCECZni+JBTyYwrKS7ML2UbrxplEwpHeoJHkk9IPO/z3QluKen/GC/MXuM8PrIQkc3+sY298hAwsIQbSvnAWuwpSq3AGesyhhh08EwZKBdHi+EDjEkyxLBm9dtNYjqXx5DTnHvsCeXFCoi1fh6VPEsEYy3ACf1zN9qlRE0whAcdzM/GCk5Hz+W1dv+U0jubFy+aqdpFsCD9en8r4ba9fDLU6mfI8wo7Zqc65Ccru3q6dQtC79EVb6AUc1lQzJakP2jOvUSZrqKUgu0QMvqNgBkyOpk7ndfXKruP+11Pf5uwdgqHYWqHwIIGTTLh88tBN7a3/3i+VF/ZtyzujAFut57a0d0A1sDpdzoUkfMdCTNs4Pm3MG1nfL1Fy7bjxwtxn6IXfOzauNDZ6w8u67Pf/7IQuDB3hSfCMtPHDoX/hTDaJKxXgzR1ca/PjnzxOL47IGgXOYG2+U9f/Gyw1Op31yYsz6LKcEEpZryyPe5d1B+dWnf4rrwdeATo+P0yfBQr53cOVHp2oIjWpo/LgwlZp/etdo78MeJ9DeO5cUmM+fflNcdy9E2ONGkoWvZIQSUFGt63ZNb+hPPzPr1S9KUTlYndizDl1Zan+qOlXNUqobVD2gPMubcyP4PlR57Ix979MhI+9fLRsfH8qJ7OYYNhkZo1dRfNATQ3ebmdq2073KFQTmgFfjG7jjprjgrMsncPb2FDXEKkwRV8BCEGbD7g2LNmdnYwLPn257Gro6kNMaixlQlwJckVXbyvszsBseJTU+VqA4JC4DdisavwNUy2Ia4sCk5OdRvzLxCBXAVj64NdvTGtbf337ETaBvMa3V9EQ2BFbgpkf/XnbHpIUuHF2YrYMqGgPNi3OxJIZQgjYmNidIdYwHfyjpZ3ZGtHN6fXXbOVfE0MebncHXMAUiL4uRHlpQP3pJW+04OC3KhST+tw8k152oJeEpQNGxWx0tP+WGeK0Xbcb3SWCYpTS80ul0lECi0EF6n8LNJOzjThvuHobj/603dTnFcORQDQcf1y937bP0Pc6b8FW3Czt0AAAAASUVORK5CYII=she
      message: 本网站由又拍云提供CDN加速/云存储服务
      swiper_css: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css
      swiper_js: https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js
      swiperbdage_init_js: https://npm.elemecdn.com/hexo-butterfly-footer-beautify/lib/swiperbdage_init.min.js
    3. 效果预览可见本博客页脚处

    填写申请表后,等待审核(会有工作人员打电话询问网站的用途,如实回答即可),审核较快,成功加入后即可获得67元代金券。拿到代金券就可以开心地去创建CDN服务啦!😎

    创建CDN服务

    创建服务

    创建服务后,点击配置,绑定域名。

    添加并解析域名

    绑定域名

    以阿里云域名服务商为例,解析CNAME,复制的内容填入“记录值”。

    申请SSL证书

    点击链接申请免费的SSL证书,哪里免费点哪里~审核成功后,回到CDN控制台,点击HTTPS配置。

    第一步
    第二步

    配置HTTPS

    不配置HTTPS的话,网站和存储在又拍云的图片都会无法访问。配置好后耐心等待一段时间,可以通过ping来测试是否已经成功创建CDN加速。

    HTTPS

    测试服务

    未加速时,ping网站网址时指向github.io;加速后,指向又拍云的ip。出现像下图类似的结果,就说明成功啦~

    测试

    参考链接

    ]]>
    + + + + + 方法教程 + + + + + + + 又拍云 + + CDN加速 + + 网站 + + + +
    + + + + + HDDM的安装方法 + + /2022/09/05/install-hddm/ + + 准备工作

    Python Extension Packages 下载所需的Python包和相关依赖。

    1. 注意Python版本和操作系统位宽(一般是64位)
    2. 安装顺序为numpy-pymc-kabuki-hddm,务必按该顺序安装。
    3. kabuki包可通过pip install git+git://github.com:hddm-devs/kabuki.git安装,若失败请看常见问题

    安装步骤

    1
    2
    3
    4
    5
    6
    7
    8
    conda create -n hddm python=3.8 # 在anaconda中新建环境
    conda activate hddm # 激活环境
    pip install --user ipykernel # 安装ipykernel
    python -m ipykernel install --user --name=xxx # 将环境加入jupyter
    pip install numpy-1.22.4+mkl-cp38-cp38-win_amd64.whl #安装HDDM依赖的3个Python包
    pip install pymc-2.3.8-cp38-cp38-win_amd64.whl
    pip install kabuki-0.6.5.tar.gz
    pip install HDDM-0.8.0-cp38-cp38-win_amd64.whl

    Python包安装成功后,重新打开prompt(cmd)命令窗口

    测试安装是否成功

    1. 若可以成功打印HDDM版本号,则安装成功
    2. 使用过程中,不要在hddm前导入matplotlib等包,即先import hddm,在import其他包
    1
    2
    import hddm
    print(hddm.__version__)

    测试HDDM

    常见问题

    pip install git+https:XXX 安装失败

    1. 先通过github下载好原文件(这时候文件夹里往往有一个setup.py文件,但是有些时候并不能简单的python setup.py
    2. 在下载的文件夹下执行 :python setup.py sdist
    3. 打开dist文件夹便可以看到一个打包好的需要安装的项目xxx.tar.gz
    4. pip install xxx.tar.gz ,到此安装完成
    ]]>
    + + + + + 方法教程 + + + + + + + HDDM + + + +
    + + + + + Hexo标签外挂 + + /2022/09/04/hexo-tag-plugin/ + + Note(Bootstrap Callout)

    用法1 语法

    1
    2
    3
    {% note [class] [no-icon] [style] %}
    Any content (support inline tags too.io).
    {% endnote %}
    参数解释
    class【可选】标识,不同的标识有不同的配色(default / primary / success / info / warning / danger)
    no-icon【可选】不显示 icon
    style【可选】可以覆盖配置中的 style(simple/modern/flat/disabled)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {% note simple %}
    默认 提示块标志
    {% endnote %}

    {% note default simple %}
    default 提示块标志
    {% endnote %}

    {% note primary simple %}
    primary 提示块标志
    {% endnote %}

    {% note success simple %}
    success 提示块标志
    {% endnote %}

    {% note info simple %}
    info 提示块标志
    {% endnote %}

    {% note warning simple %}
    warning 提示块标志
    {% endnote %}

    {% note danger simple %}
    danger 提示块标志
    {% endnote %}

    默认 提示块标签

    default 提示块标签

    primary 提示块标签

    success 提示块标签

    info 提示块标签

    warning 提示块标签

    danger 提示块标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    {% note modern %}
    默认 提示块标签
    {% endnote %}

    {% note default modern %}
    default 提示块标签
    {% endnote %}

    {% note primary modern %}
    primary 提示块标签
    {% endnote %}

    {% note success modern %}
    success 提示块标签
    {% endnote %}

    {% note info modern %}
    info 提示块标签
    {% endnote %}

    {% note warning modern %}
    warning 提示块标签
    {% endnote %}

    {% note danger modern %}
    danger 提示块标签
    {% endnote %}

    默认 提示块标签

    default 提示块标签

    primary 提示块标签

    success 提示块标签

    info 提示块标签

    warning 提示块标签

    danger 提示块标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {% note flat %}
    默认 提示块标签
    {% endnote %}

    {% note default flat %}
    default 提示块标签
    {% endnote %}

    {% note primary flat %}
    primary 提示块标签
    {% endnote %}

    {% note success flat %}
    success 提示块标签
    {% endnote %}

    {% note info flat %}
    info 提示块标签
    {% endnote %}

    {% note warning flat %}
    warning 提示块标签
    {% endnote %}

    {% note danger flat %}
    danger 提示块标签
    {% endnote %}

    默认 提示块标签

    default 提示块标签

    primary 提示块标签

    success 提示块标签

    info 提示块标签

    warning 提示块标签

    danger 提示块标签

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    {% note disabled %}
    默认 提示块标签
    {% endnote %}

    {% note default disabled %}
    default 提示块标签
    {% endnote %}

    {% note primary disabled %}
    primary 提示块标签
    {% endnote %}

    {% note success disabled %}
    success 提示块标签
    {% endnote %}

    {% note info disabled %}
    info 提示块标签
    {% endnote %}

    {% note warning disabled %}
    warning 提示块标籤
    {% endnote %}

    {% note danger disabled %}
    danger 提示块标签
    {% endnote %}

    默认 提示块标签

    default 提示块标签

    primary 提示块标签

    success 提示块标签

    info 提示块标签

    warning 提示块标签

    danger 提示块标签

    用法2 语法

    1
    2
    3
    {% note [color] [no-icon] [style] %}
    Any content (support inline tags too.io).
    {% endnote %}
    参数解释
    color【可选】颜色(default / blue / pink / red / purple / orange / green)
    icon【可选】可配置自定义 icon(只支持 fontawesome 图标, 也可以配置 no-icon )
    style【可选】可以覆盖配置中的 style(simple/modern/flat/disabled)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    {% note no-icon %}
    测试1
    {% endnote %}
    {% note blue no-icon %}
    测试2
    {% endnote %}
    {% note pink no-icon %}
    测试3
    {% endnote %}
    {% note red no-icon %}
    测试4
    {% endnote %}
    {% note orange no-icon %}
    测试5
    {% endnote %}
    {% note purple no-icon %}
    测试6
    {% endnote %}
    {% note green no-icon %}
    测试7
    {% endnote %}

    测试1

    测试2

    测试3

    测试4

    测试5

    测试6

    测试7

    tabs分栏

    语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    {% tabs Unique name, [index] %}
    <!-- tab [Tab caption] [@icon] -->
    Any content (support inline tags too).
    <!-- endtab -->
    {% endtabs %}

    Unique name : Unique name of tabs block tag without comma.
    Will be used in #id's as prefix for each tab with their index numbers.
    If there are whitespaces in name, for generate #id all whitespaces will replaced by dashes.
    Only for current url of post/page must be unique!
    [index] : Index number of active tab.
    If not specified, first tab (1) will be selected.
    If index is -1, no tab will be selected. It's will be something like spoiler.
    Optional parameter.
    [Tab caption] : Caption of current tab.
    If not caption specified, unique name with tab index suffix will be used as caption of tab.
    If not caption specified, but specified icon, caption will empty.
    Optional parameter.
    [@icon] : FontAwesome icon name (full-name, look like 'fas fa-font')
    Can be specified with or without space; e.g. 'Tab caption @icon' similar to 'Tab caption@icon'.
    Optional parameter.

    代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    {% tabs test1, 2 %}
    <!-- tab Tab1 -->
    **tab名**
    <!-- endtab -->

    <!-- tab @fas fa-bell -->
    **仅tab图标**

    因为tabs标签头设置了默认展示栏位2,所以优先展示这一栏
    <!-- endtab -->

    <!-- tab Tab3@fas fa-snowflake -->
    **tab名+图标**
    <!-- endtab -->
    {% endtabs %}

    预览

    tab名
    啦啦啦~

    仅tab图标

    因为tabs标签头设置了默认展示栏位2,所以优先展示这一栏

    tab名+图标

    label

    语法

    参数解释
    text文字
    color【可选】背景颜色,默认为 default default/blue/pink/red/purple/orange/green

    代码及预览

    1
    2
    舜发于{% label 畎亩之中 %},傅说举于版筑之中,胶鬲举于鱼盐之中,管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先{% label 苦其心志 pink %},{% label 劳其筋骨 green %},饿其体肤,空乏其身行拂乱其所为,所以{% label 动心忍性 orange %},曾益其所不能。
    人恒过,然后能改;困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡。然后知{% label 生于忧患 red %}而{% label 死于安乐 purple %}也。

    舜发于畎亩之中 ,傅说举于版筑之中,胶鬲举于鱼盐之中,管夷吾举于士,孙叔敖举于海,百里奚举于市。故天将降大任于是人也,必先苦其心志劳其筋骨 ,饿其体肤,空乏其身行拂乱其所为,所以动心忍性 ,曾益其所不能。人恒过,然后能改;困于心,衡于虑,而后作;征于色,发于声,而后喻。入则无法家拂士,出则无敌国外患者,国恒亡。然后知生于忧患死于安乐 也。

    tag-hide

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    {% hideInline content,display,bg,color %} # inline
    {% hideBlock display,bg,color %} # block
    content
    {% endhideBlock %}
    {% hideToggle display,bg,color %} # toggle
    content
    {% endhideToggle %}
    # content: 文本内容
    # display: 按钮显示的文字(可选)
    # bg: 按钮的背景颜色(可选)
    # color: 按钮文字的颜色(可选)
    1
    2
    1+1=?{% hideInline 2,查看答案,#FF7242,#fff %}
    谁最可爱?{% hideInline 当然是你啦~}

    1+1=?2
    谁最可爱?当然是你啦~

    1
    2
    3
    4
    考考你,《七步诗》的作者是
    {% hideBlock 查看答案 %}
    曹植
    {% endhideBlock %}

    考考你,《七步诗》的作者是

    曹植

    1
    2
    3
    4
    5
    6
    7
    8
    {% hideToggle 和HMK在一起的幸福时刻 %}
    1. 牵手、拥抱、kiss~
    2. 国庆假期突然出现在我家楼下,还骗我下楼取快递
    3. 从身后拿出一朵玫瑰花送给我
    4. 一起在西安城墙骑双人车
    5. 一起吃李想大虾!!!
    6. 带我回家
    {% endhideToggle %}
    和HMK在一起的幸福时刻
    1. 牵手、拥抱、kiss~
    2. 国庆假期突然出现在我家楼下,还骗我下楼取快递
    3. 从身后拿出一朵玫瑰花送给我
    4. 一起在西安城墙骑双人车
    5. 一起吃李想大虾!!!
    6. 带我回家

    Gallery相册

    语法

    1
    2
    3
    {% gallery %}
    markdown 图片格式
    {% endgallery %}

    代码示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    {% gallery %}
    ![](https://img.cwxhmk.top/gallary/1.jpg)
    ![](https://img.cwxhmk.top/gallary/2.jpg)
    ![](https://img.cwxhmk.top/gallary/3.jpg)
    ![](https://img.cwxhmk.top/gallary/4.jpg)
    ![](https://img.cwxhmk.top/gallary/6.jpg)
    ![](https://img.cwxhmk.top/gallary/5.jpg)
    ![](https://img.cwxhmk.top/gallary/7.jpg)
    {% endgallery %}

    预览

    timeline

    1
    2
    3
    4
    5
    {% timeline 2018,orange %}
    <!-- timeline 07-21 -->
    我和康康在一起~
    <!-- endtimeline -->
    {% endtimeline %}

    2018

    07-21

    我和康康在一起~

    flink

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    {% flink %}
    - class_name: 友情链接
    class_desc: 那些人,那些事
    link_list:
    - name: JerryC
    link: https://jerryc.me/
    avatar: https://jerryc.me/img/avatar.png
    descr: 今日事,今日毕
    - name: Hexo
    link: https://hexo.io/zh-tw/
    avatar: https://d33wubrfki0l68.cloudfront.net/6657ba50e702d84afb32fe846bed54fba1a77add/827ae/logo.svg
    descr: 快速、简单且强大的网誌框架
    {% endflink %}

    hexo-pdf

    语法

    1
    {% pdf https://img.cwxhmk.top/pdf/mice_brain_atlas_v4.pdf %}

    参考资料

    ]]>
    + + + + + 方法教程 + + + + + + + Hexo + + 标签外挂 + + + +
    + + + + + Windows常用快捷键汇总 + + /2022/09/04/keyboard-shortcuts/ + +
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Ctrl+S 保存
    Ctrl+C 复制
    Ctrl+V 粘贴
    Ctrl+F5 刷新缓存 # 代码上传到github后页面没有变化时,可以试着刷新浏览器缓存
    Win+: 表情符号 😊
    Win+Shift+S 截图
    Ctrl+Shift+N 新建文件夹
    Ctrl+Shift+Esc 打开任务管理器
    Ctrl+Shift+S 在浏览器内捕获区域
    ]]>
    + + + + + 方法教程 + + + + + + + windows + + + +
    + + + + + 无法获得下列许可SOLIDWORKS Standard + + /2022/09/04/solidworks-register-problem/ + + 前几天突然打不开solidworks,说无法获得许可,无法链接到服务器···(见下图)百度了一番终于找到了解决方案。

    打开任务管理器,在服务里找到SolidWorks Flexnet Server,开启服务,如下图所示(注意:该方法并非一劳永逸,下次再遇到时,同样的操作即可)

    开启服务


    每次打开solidworks都要去任务管理器中开启服务,太麻烦了,今天终于找到解决方法了!

    打开任务管理器,选择服务,任意选中一个服务然后右键,选择打开服务,找到SolidWorks Flexnet Server,右键属性,在常规中将启动类型改为自动,在恢复中将失败后设为重新启动服务,在此时间之后重置失败计数0天,在此时间之后重新启动服务0分钟。SolidWorks Licensing Service的启动类型也设为自动。

    经测试,SolidWorks可以正常运行,而不需要手动开启服务了。

    参考文章

    ]]>
    + + + + + 方法教程 + + + + + + + SolidWorks + + + +
    + + + + + 在Anaconda中创建新环境 + + /2022/09/01/anaconda-new-env/ + + conda常用命令
    1
    2
    conda info --envs # 查看anaconda中所有环境
    conda list # 查看当前环境下有哪些包

    添加新环境

    1
    2
    3
    4
    5
    6
    conda create -n xxx # 创建新的环境,不指定python版本;xxx为环境名
    conda create -n xxx python=3.8 # 可指定python版本
    conda activate xxx # 激活xxx环境
    conda deactivate # 退出xxx环境,返回base
    conda uninstall -n xxx --all # 删除环境
    conda install ipykernel # 添加进jupyter notebook环境 vscode中可以识别就可以

    忽略warning信息

    1
    2
    import warnings
    warnings.filterwarnings("ignore")

    将新环境添加进Jupyter Notebook

    1
    2
    3
    4
    jupyter kernelspec list # 查看安装了哪些虚拟环境kernel
    pip install --user ipykernel # 安装ipykernel
    python -m ipykernel install --user --name=xxx # 将环境加入jupyter
    jupyter kernelspec uninstall xxx # 删除指定的kernel
    ]]>
    + + + + + 方法教程 + + + + + + + Anaconda + + Python + + + +
    + + + + + Solidworks 自动识别特征 + + /2022/08/30/solidworks-featureworks/ + +

    最近需要编辑一个.stp的文件,下意识的反应是应该和.stl文件差不多,属于不可编辑的那种文件格式。从师姐那里得知inventor可以编辑.stp文件,但平时已经习惯了用solidworks,不想再学新的建模软件了,这时碰巧在b站看到了solidworks可以自动识别.stp文件的特征!激动!😎

    1. 导入.stp文件
      essay
    2. 断开链接(确认)
    1. 插入-FeatureWorks-识别特征(点确认,点√)
    2. 耐心等待!
    3. 识别成功啦,愉快的开始编辑吧!👍
      essay
    ]]>
    + + + + + 方法教程 + + + + + + + SolidWorks + + + +
    + + + + + Jupyter Notebook中添加目录 + + /2022/08/21/jupyter-notebook-contents/ + + 安装步骤
    1. 安装nbextensions

      若之前安装过nbextensions遇到问题,需要先执行remove 语句

      1
      2
      3
      4
      5
      # conda remove jupyter_nbextensions_configurator 
      conda install -c conda-forge jupyter_nbextensions_configurator
      conda install -c conda-forge jupyter_contrib_nbextensions
      jupyter contrib nbextension install --user
      jupyter nbextensions_configurator enable --user

      上述过程均完成后,打开jupyter notebook就会发现界面多了Nbextensions选项卡
      Nbextensions

    2. 勾选Table of Contents(2)复选框
      toc2

    3. 新建或打开已有的ipynb文件,点击新增的目录按钮即可显示目录 😁
      catalogue

    问题记录

    1. jupyter notebook nbextension常用扩展模块不显示
      按照安装步骤重新安装,先remove,再install
    2. jupyter notebook报错:Bad file descriptor(C:\ci\zeromq_1602704446950\work\src\epoll.cpp:100)
      1
      2
      pip uninstall pyzmq
      pip install pyzmq==19.0.2
    3. 启动Jupyter,cmd窗口出现很多行类似于下述的代码
      1
      Config option `template_path` not recognized by `LenvsLatexExporter`
    • 原因是nbconvert6.0.0版本以上的某些参数的名称发生了更改,与原先版本不兼容,需要将版本降低到5.6.1
      1
      pip install nbconvert==5.6.1 -i https://pypi.mirrors.ustc.edu.cn/simple

    参考文章

    ]]>
    + + + + + 方法教程 + + + + + + + Python + + Jupyter Notebook + + + +
    + + + + + Hexo基本使用方法 + + /2022/08/20/basic-use-of-hexo/ + +

    发布文章常用指令

    1
    2
    3
    4
    5
    6
    hexo new "xxx" # 发布文章
    hexo g # 生成页面
    hexo d # 部署发布
    hexo s # 本地预览 http://localhost:4000/
    hexo clean # 清除缓存
    hexo new page xxx # 新增标签页

    文章Front-matter常用配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    title: xxx
    date: xxx (创建文档时默认生成)
    tags:
    - xxx (默认有多个)
    categories:
    - xxx (一级分类)
    - xxx (二级分类)
    description: xxx
    cover: http://img.cwxhmk.top/cover/hexo.png

    插入图片

    .gif图片也是支持的哦~

    第一种:使用markdown语法

    1
    ![文字](/img/图片名.jpg) 

    第二种:适用于图片较大的情况,可等比例缩小

    1
    <img src="/img/图片名.jpg" alt="图片说明" width="50%" height="50%" /> 

    插入视频

    1
    <iframe src="视频链接" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true"  width="800px" height="470px"> </iframe>

    插入公式

    1
    2
    3
    输入$a$ #行内公式
    $$aabb$$ #独立公式并居中
    $$a+b=c \tag{1.1}$$ #公式编号

    效果展示

    输入$a$
    $$aabb$$
    $$a+b=c \tag{1.1}$$

    文章链接

    1
    2
    3
    4
    5
    {% post_link 'basic-use-of-hexo' %} #链接到本文/站内其他文章
    {% post_link 'tag-plugin' %}
    [跳转到插入图片](#插入图片) #链接本文锚点
    <a href="{% post_path 'tag-plugin' %}#label">标签外挂</a> #链接站外文章锚点
    [又拍云](https://www.upyun.com/) #站外链接

    预览

    Hexo基本使用方法Post not found: tag-plugin

    跳转到插入图片
    标签外挂-label
    又拍云

    ]]>
    + + + + + 方法教程 + + + + + + + Hexo + + + +
    + + + + +
    diff --git a/shine/index.html b/shine/index.html new file mode 100644 index 000000000..c4e636f46 --- /dev/null +++ b/shine/index.html @@ -0,0 +1,322 @@ +生活剪影 | Stray Birds + + + + + + + + + + + + +

    2023

    +

    12-16

    +

    我终于有属于自己的实验服了,以后要开始做生物实验啦!💪🏻

    +

    12-16

    +

    康康带我参加了人生中第一场学术会议,虽然是不同的专业,但依旧参与感满满!在晚宴上吃到了惦记了很久的大闸蟹🦀,吃饭的过程中舞台上还有歌舞和戏剧表演,主持人还一口气来了三轮抽奖,不过中奖绝缘体依旧稳定发挥!😎周日一起去了塘栖古镇,比想象中小太多了,不过风景还是美的!

    +

    12-10

    +

    做出了人生第一碗西红柿手擀面,虽然西红柿🍅放多了,但依旧成就感满满!🥹

    +

    11-29

    +

    康康来杭州体检,公费见面!🥳

    +

    11-19

    +

    参观浙江省非物质文化遗产馆,拿着小本本盖章真有意思!😉

    +

    10-24

    +

    恭喜康康宝贝签约杭州供电局!(我已经提前几天去西安庆祝啦,哈哈哈🎉)

    +

    10-16

    +

    开完组会心情不好,一个人去灵隐寺许愿。

    +

    10-01

    +

    国庆回家啦!新家装修的很舒适!!!不过还是有点怀念之前家附近的大超市!

    +

    06-03

    +

    原本打算一个人去绍兴玩,没想到在高铁上看到了我最爱的康康!!!这个惊喜我太爱了!🥹

    +

    05-26

    +

    偷偷跑去西安找康康玩啦,去的时候坐地高铁,返程坐的飞机,幸运地看到了日落(惨痛教训:不要轻易退票)~

    +

    05-23

    +

    🥑组内聚餐,人均200吃得就是快乐呀!人员组成:全组+中科院长春生化所王晓辉老师

    +

    05-18

    +

    在《高级心理学》的课上体验了催眠,还学会了一个小魔术!

    +

    05-03

    +

    五一和康康在南京玩了五天~回学校后收到了舍友送的书,原来朋友之间还可以送这么珍贵的礼物!

    +

    03-28

    +

    春学期只剩下一门课了,耶耶耶🫣

    +

    02-25

    +

    去北京找康康玩!一起去看了天安门,太酷啦!😎

    +

    01-16

    +

    康康过年前来聊城找我啦,就住在我家阳台对面,哈哈哈!

    +
    +

    2022

    +

    12-19

    +

    小🐑人

    +

    11-08

    +

    看到了月全食,“红月亮”!

    +

    10-08

    +

    组内聚餐,老板请客!

    +

    10-01

    +

    国庆五日游:杭州-西安~

    +

    09-18

    +

    西湖一日游!第一次步数3w+😁

    +

    09-16

    +

    研究生开学典礼~
    要做灿若星辰的浙大人!无愧于己,只争朝夕!

    +

    09-04

    +

    个人博客美化初步完成~😎

    +

    08-12

    +

    去北京参加CNeuro2022暑期班

    +

    评论
    \ No newline at end of file diff --git a/tags/Anaconda/index.html b/tags/Anaconda/index.html new file mode 100644 index 000000000..aac159f3b --- /dev/null +++ b/tags/Anaconda/index.html @@ -0,0 +1,179 @@ +标签: Anaconda | Stray Birds + + + + + + + + +
    标签 - Anaconda
    2022
    在Anaconda中创建新环境
    在Anaconda中创建新环境
    \ No newline at end of file diff --git a/tags/ArControl/index.html b/tags/ArControl/index.html new file mode 100644 index 000000000..7db0838c0 --- /dev/null +++ b/tags/ArControl/index.html @@ -0,0 +1,179 @@ +标签: ArControl | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/BrainPy/index.html b/tags/BrainPy/index.html new file mode 100644 index 000000000..4bcc16386 --- /dev/null +++ b/tags/BrainPy/index.html @@ -0,0 +1,179 @@ +标签: BrainPy | Stray Birds + + + + + + + + +
    标签 - BrainPy
    2023
    BrainPy学习笔记【01】
    BrainPy学习笔记【01】
    \ No newline at end of file diff --git "a/tags/CDN\345\212\240\351\200\237/index.html" "b/tags/CDN\345\212\240\351\200\237/index.html" new file mode 100644 index 000000000..75f9bc01c --- /dev/null +++ "b/tags/CDN\345\212\240\351\200\237/index.html" @@ -0,0 +1,179 @@ +标签: CDN加速 | Stray Birds + + + + + + + + +
    标签 - CDN加速
    2022
    使用又拍云提供CDN加速服务
    使用又拍云提供CDN加速服务
    \ No newline at end of file diff --git a/tags/Eclipse/index.html b/tags/Eclipse/index.html new file mode 100644 index 000000000..d29a62e52 --- /dev/null +++ b/tags/Eclipse/index.html @@ -0,0 +1,179 @@ +标签: Eclipse | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/Github-Desktop/index.html b/tags/Github-Desktop/index.html new file mode 100644 index 000000000..f877b160f --- /dev/null +++ b/tags/Github-Desktop/index.html @@ -0,0 +1,179 @@ +标签: Github Desktop | Stray Birds + + + + + + + + +
    标签 - Github Desktop
    2024
    Github Desktop同步代码
    Github Desktop同步代码
    \ No newline at end of file diff --git a/tags/Github/index.html b/tags/Github/index.html new file mode 100644 index 000000000..0254a8fcd --- /dev/null +++ b/tags/Github/index.html @@ -0,0 +1,179 @@ +标签: Github | Stray Birds + + + + + + + + +
    标签 - Github
    2022
    本地文件上传到Github
    本地文件上传到Github
    \ No newline at end of file diff --git a/tags/HDDM/index.html b/tags/HDDM/index.html new file mode 100644 index 000000000..cdb5c644f --- /dev/null +++ b/tags/HDDM/index.html @@ -0,0 +1,179 @@ +标签: HDDM | Stray Birds + + + + + + + + +
    标签 - HDDM
    2022
    HDDM的安装方法
    HDDM的安装方法
    \ No newline at end of file diff --git a/tags/HTML/index.html b/tags/HTML/index.html new file mode 100644 index 000000000..0634d9f38 --- /dev/null +++ b/tags/HTML/index.html @@ -0,0 +1,179 @@ +标签: HTML | Stray Birds + + + + + + + + +
    标签 - HTML
    2024
    在网页中实时显示当前时间
    在网页中实时显示当前时间
    \ No newline at end of file diff --git a/tags/Hexo/index.html b/tags/Hexo/index.html new file mode 100644 index 000000000..0de3d835e --- /dev/null +++ b/tags/Hexo/index.html @@ -0,0 +1,179 @@ +标签: Hexo | Stray Birds + + + + + + + + +
    标签 - Hexo
    2022
    Hexo迁移至新电脑
    Hexo迁移至新电脑
    Hexo标签外挂
    Hexo标签外挂
    Hexo基本使用方法
    Hexo基本使用方法
    \ No newline at end of file diff --git a/tags/ImageJ/index.html b/tags/ImageJ/index.html new file mode 100644 index 000000000..49cd438bc --- /dev/null +++ b/tags/ImageJ/index.html @@ -0,0 +1,179 @@ +标签: ImageJ | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/Imaris/index.html b/tags/Imaris/index.html new file mode 100644 index 000000000..c45fa2f75 --- /dev/null +++ b/tags/Imaris/index.html @@ -0,0 +1,179 @@ +标签: Imaris | Stray Birds + + + + + + + + +
    标签 - Imaris
    2023
    Imairs细胞计数教程
    Imairs细胞计数教程
    \ No newline at end of file diff --git a/tags/Java/index.html b/tags/Java/index.html new file mode 100644 index 000000000..6abc17255 --- /dev/null +++ b/tags/Java/index.html @@ -0,0 +1,179 @@ +标签: Java | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/Jupyter-Notebook/index.html b/tags/Jupyter-Notebook/index.html new file mode 100644 index 000000000..1d456d3e5 --- /dev/null +++ b/tags/Jupyter-Notebook/index.html @@ -0,0 +1,179 @@ +标签: Jupyter Notebook | Stray Birds + + + + + + + + +
    标签 - Jupyter Notebook
    2023
    VSCode无法正常打开.ipynb文件
    VSCode无法正常打开.ipynb文件
    2022
    Jupyter Notebook中添加目录
    Jupyter Notebook中添加目录
    \ No newline at end of file diff --git a/tags/Matlab/index.html b/tags/Matlab/index.html new file mode 100644 index 000000000..9a6b0fa38 --- /dev/null +++ b/tags/Matlab/index.html @@ -0,0 +1,179 @@ +标签: Matlab | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/Python/index.html b/tags/Python/index.html new file mode 100644 index 000000000..d5010dd0d --- /dev/null +++ b/tags/Python/index.html @@ -0,0 +1,179 @@ +标签: Python | Stray Birds + + + + + + + + +
    标签 - Python
    2023
    图像风格迁移
    图像风格迁移
    2022
    在Anaconda中创建新环境
    在Anaconda中创建新环境
    Jupyter Notebook中添加目录
    Jupyter Notebook中添加目录
    \ No newline at end of file diff --git a/tags/Pytorch/index.html b/tags/Pytorch/index.html new file mode 100644 index 000000000..9ef09db07 --- /dev/null +++ b/tags/Pytorch/index.html @@ -0,0 +1,179 @@ +标签: Pytorch | Stray Birds + + + + + + + + +
    标签 - Pytorch
    2023
    图像风格迁移
    图像风格迁移
    \ No newline at end of file diff --git a/tags/RNN/index.html b/tags/RNN/index.html new file mode 100644 index 000000000..9e0d1f1df --- /dev/null +++ b/tags/RNN/index.html @@ -0,0 +1,179 @@ +标签: RNN | Stray Birds + + + + + + + + +
    标签 - RNN
    2023
    RNN学习笔记【01】
    RNN学习笔记【01】
    \ No newline at end of file diff --git a/tags/SolidWorks/index.html b/tags/SolidWorks/index.html new file mode 100644 index 000000000..746b7b2e5 --- /dev/null +++ b/tags/SolidWorks/index.html @@ -0,0 +1,179 @@ +标签: SolidWorks | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/V2rayU/index.html b/tags/V2rayU/index.html new file mode 100644 index 000000000..e661a9e9d --- /dev/null +++ b/tags/V2rayU/index.html @@ -0,0 +1,179 @@ +标签: V2rayU | Stray Birds + + + + + + + + +
    标签 - V2rayU
    2023
    解决mac电脑更新后V2rayU无法启动
    解决mac电脑更新后V2rayU无法启动
    \ No newline at end of file diff --git a/tags/VSCode/index.html b/tags/VSCode/index.html new file mode 100644 index 000000000..31f3f3e17 --- /dev/null +++ b/tags/VSCode/index.html @@ -0,0 +1,179 @@ +标签: VSCode | Stray Birds + + + + + + + + +
    标签 - VSCode
    2023
    VSCode无法正常打开.ipynb文件
    VSCode无法正常打开.ipynb文件
    \ No newline at end of file diff --git a/tags/arduino/index.html b/tags/arduino/index.html new file mode 100644 index 000000000..677dea272 --- /dev/null +++ b/tags/arduino/index.html @@ -0,0 +1,179 @@ +标签: arduino | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 000000000..67d629933 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,269 @@ +标签 | Stray Birds + + + + + + + + + + +
    \ No newline at end of file diff --git a/tags/windows/index.html b/tags/windows/index.html new file mode 100644 index 000000000..bf9a5a62d --- /dev/null +++ b/tags/windows/index.html @@ -0,0 +1,179 @@ +标签: windows | Stray Birds + + + + + + + + +
    标签 - windows
    2022
    Windows常用快捷键汇总
    Windows常用快捷键汇总
    \ No newline at end of file diff --git "a/tags/\344\273\243\347\220\206/index.html" "b/tags/\344\273\243\347\220\206/index.html" new file mode 100644 index 000000000..6ae0cf390 --- /dev/null +++ "b/tags/\344\273\243\347\220\206/index.html" @@ -0,0 +1,179 @@ +标签: 代理 | Stray Birds + + + + + + + + +
    标签 - 代理
    2023
    windows设置代理及取消代理
    windows设置代理及取消代理
    \ No newline at end of file diff --git "a/tags/\345\205\254\345\267\256/index.html" "b/tags/\345\205\254\345\267\256/index.html" new file mode 100644 index 000000000..f2946b8a0 --- /dev/null +++ "b/tags/\345\205\254\345\267\256/index.html" @@ -0,0 +1,179 @@ +标签: 公差 | Stray Birds + + + + + + + + +
    标签 - 公差
    2022
    模型加工方法汇总
    模型加工方法汇总
    \ No newline at end of file diff --git "a/tags/\345\217\210\346\213\215\344\272\221/index.html" "b/tags/\345\217\210\346\213\215\344\272\221/index.html" new file mode 100644 index 000000000..de46df674 --- /dev/null +++ "b/tags/\345\217\210\346\213\215\344\272\221/index.html" @@ -0,0 +1,179 @@ +标签: 又拍云 | Stray Birds + + + + + + + + +
    标签 - 又拍云
    2022
    使用又拍云提供CDN加速服务
    使用又拍云提供CDN加速服务
    \ No newline at end of file diff --git "a/tags/\345\256\266\344\272\272/index.html" "b/tags/\345\256\266\344\272\272/index.html" new file mode 100644 index 000000000..a90e48c5d --- /dev/null +++ "b/tags/\345\256\266\344\272\272/index.html" @@ -0,0 +1,179 @@ +标签: 家人 | Stray Birds + + + + + + + + +
    标签 - 家人
    2023
    取钱小记
    取钱小记
    \ No newline at end of file diff --git "a/tags/\345\271\264\345\272\246\346\200\273\347\273\223/index.html" "b/tags/\345\271\264\345\272\246\346\200\273\347\273\223/index.html" new file mode 100644 index 000000000..79f139d55 --- /dev/null +++ "b/tags/\345\271\264\345\272\246\346\200\273\347\273\223/index.html" @@ -0,0 +1,179 @@ +标签: 年度总结 | Stray Birds + + + + + + + + +
    标签 - 年度总结
    2023
    2023年度总结
    2023年度总结
    2022
    2022年度总结
    2022年度总结
    \ No newline at end of file diff --git "a/tags/\345\274\272\345\214\226\345\255\246\344\271\240/index.html" "b/tags/\345\274\272\345\214\226\345\255\246\344\271\240/index.html" new file mode 100644 index 000000000..c64c2ba49 --- /dev/null +++ "b/tags/\345\274\272\345\214\226\345\255\246\344\271\240/index.html" @@ -0,0 +1,179 @@ +标签: 强化学习 | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\346\200\235\350\200\203/index.html" "b/tags/\346\200\235\350\200\203/index.html" new file mode 100644 index 000000000..65a95af4a --- /dev/null +++ "b/tags/\346\200\235\350\200\203/index.html" @@ -0,0 +1,179 @@ +标签: 思考 | Stray Birds + + + + + + + + +
    标签 - 思考
    2023
    做选择
    做选择
    及时按下暂停键⏸
    及时按下暂停键⏸
    动态思维
    动态思维
    \ No newline at end of file diff --git "a/tags/\346\240\207\347\255\276\345\244\226\346\214\202/index.html" "b/tags/\346\240\207\347\255\276\345\244\226\346\214\202/index.html" new file mode 100644 index 000000000..51fe5a884 --- /dev/null +++ "b/tags/\346\240\207\347\255\276\345\244\226\346\214\202/index.html" @@ -0,0 +1,179 @@ +标签: 标签外挂 | Stray Birds + + + + + + + + +
    标签 - 标签外挂
    2022
    Hexo标签外挂
    Hexo标签外挂
    \ No newline at end of file diff --git "a/tags/\346\265\231\346\261\237\345\244\247\345\255\246/index.html" "b/tags/\346\265\231\346\261\237\345\244\247\345\255\246/index.html" new file mode 100644 index 000000000..ffc6ff777 --- /dev/null +++ "b/tags/\346\265\231\346\261\237\345\244\247\345\255\246/index.html" @@ -0,0 +1,179 @@ +标签: 浙江大学 | Stray Birds + + + + + + + + +
    标签 - 浙江大学
    2022
    初来浙里,我曾经的那些疑惑
    初来浙里,我曾经的那些疑惑
    \ No newline at end of file diff --git "a/tags/\346\270\270\347\216\251/index.html" "b/tags/\346\270\270\347\216\251/index.html" new file mode 100644 index 000000000..049ec85ae --- /dev/null +++ "b/tags/\346\270\270\347\216\251/index.html" @@ -0,0 +1,179 @@ +标签: 游玩 | Stray Birds + + + + + + + + +
    标签 - 游玩
    2023
    愉快的周末
    愉快的周末
    2023年的第一天
    2023年的第一天
    \ No newline at end of file diff --git "a/tags/\347\210\254\350\231\253/index.html" "b/tags/\347\210\254\350\231\253/index.html" new file mode 100644 index 000000000..4a6df2c79 --- /dev/null +++ "b/tags/\347\210\254\350\231\253/index.html" @@ -0,0 +1,179 @@ +标签: 爬虫 | Stray Birds + + + + + + + + +
    标签 - 爬虫
    2023
    爬取网站数据
    爬取网站数据
    \ No newline at end of file diff --git "a/tags/\347\211\251\350\201\224\347\275\221/index.html" "b/tags/\347\211\251\350\201\224\347\275\221/index.html" new file mode 100644 index 000000000..788137639 --- /dev/null +++ "b/tags/\347\211\251\350\201\224\347\275\221/index.html" @@ -0,0 +1,179 @@ +标签: 物联网 | Stray Birds + + + + + + + + +
    标签 - 物联网
    2024
    在网页中实时显示当前时间
    在网页中实时显示当前时间
    \ No newline at end of file diff --git "a/tags/\347\212\266\346\200\201\346\216\250\346\226\255/index.html" "b/tags/\347\212\266\346\200\201\346\216\250\346\226\255/index.html" new file mode 100644 index 000000000..c381eafe5 --- /dev/null +++ "b/tags/\347\212\266\346\200\201\346\216\250\346\226\255/index.html" @@ -0,0 +1,179 @@ +标签: 状态推断 | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\347\224\237\347\211\251/index.html" "b/tags/\347\224\237\347\211\251/index.html" new file mode 100644 index 000000000..dcf37453b --- /dev/null +++ "b/tags/\347\224\237\347\211\251/index.html" @@ -0,0 +1,179 @@ +标签: 生物 | Stray Birds + + + + + + + + +
    \ No newline at end of file diff --git "a/tags/\347\224\265\346\236\201/index.html" "b/tags/\347\224\265\346\236\201/index.html" new file mode 100644 index 000000000..d8a37d25d --- /dev/null +++ "b/tags/\347\224\265\346\236\201/index.html" @@ -0,0 +1,179 @@ +标签: 电极 | Stray Birds + + + + + + + + +
    标签 - 电极
    2024
    记录电极支架制作步骤
    记录电极支架制作步骤
    \ No newline at end of file diff --git "a/tags/\347\235\241\347\234\240/index.html" "b/tags/\347\235\241\347\234\240/index.html" new file mode 100644 index 000000000..5b8d2ed0e --- /dev/null +++ "b/tags/\347\235\241\347\234\240/index.html" @@ -0,0 +1,179 @@ +标签: 睡眠 | Stray Birds + + + + + + + + +
    标签 - 睡眠
    2023
    脑电数据分析
    脑电数据分析
    \ No newline at end of file diff --git "a/tags/\347\245\236\347\273\217\345\212\250\345\212\233\345\255\246/index.html" "b/tags/\347\245\236\347\273\217\345\212\250\345\212\233\345\255\246/index.html" new file mode 100644 index 000000000..17be4dc77 --- /dev/null +++ "b/tags/\347\245\236\347\273\217\345\212\250\345\212\233\345\255\246/index.html" @@ -0,0 +1,179 @@ +标签: 神经动力学 | Stray Birds + + + + + + + + +
    标签 - 神经动力学
    2023
    《神经动力学》学习笔记【01】
    《神经动力学》学习笔记【01】
    \ No newline at end of file diff --git "a/tags/\347\245\236\347\273\217\347\216\257\350\267\257/index.html" "b/tags/\347\245\236\347\273\217\347\216\257\350\267\257/index.html" new file mode 100644 index 000000000..93088dcc4 --- /dev/null +++ "b/tags/\347\245\236\347\273\217\347\216\257\350\267\257/index.html" @@ -0,0 +1,179 @@ +标签: 神经环路 | Stray Birds + + + + + + + + +
    标签 - 神经环路
    2023
    【综述】神经环路的架构
    【综述】神经环路的架构
    \ No newline at end of file diff --git "a/tags/\347\245\236\347\273\217\347\274\226\347\240\201/index.html" "b/tags/\347\245\236\347\273\217\347\274\226\347\240\201/index.html" new file mode 100644 index 000000000..08da6f59a --- /dev/null +++ "b/tags/\347\245\236\347\273\217\347\274\226\347\240\201/index.html" @@ -0,0 +1,179 @@ +标签: 神经编码 | Stray Birds + + + + + + + + +
    标签 - 神经编码
    2023
    神经编码和神经解码
    神经编码和神经解码
    \ No newline at end of file diff --git "a/tags/\347\245\236\347\273\217\350\247\243\347\240\201/index.html" "b/tags/\347\245\236\347\273\217\350\247\243\347\240\201/index.html" new file mode 100644 index 000000000..8879160ad --- /dev/null +++ "b/tags/\347\245\236\347\273\217\350\247\243\347\240\201/index.html" @@ -0,0 +1,179 @@ +标签: 神经解码 | Stray Birds + + + + + + + + +
    标签 - 神经解码
    2023
    神经编码和神经解码
    神经编码和神经解码
    \ No newline at end of file diff --git "a/tags/\347\275\221\347\253\231/index.html" "b/tags/\347\275\221\347\253\231/index.html" new file mode 100644 index 000000000..bc867f730 --- /dev/null +++ "b/tags/\347\275\221\347\253\231/index.html" @@ -0,0 +1,179 @@ +标签: 网站 | Stray Birds + + + + + + + + +
    标签 - 网站
    2022
    使用又拍云提供CDN加速服务
    使用又拍云提供CDN加速服务
    \ No newline at end of file diff --git "a/tags/\350\200\203\350\257\225/index.html" "b/tags/\350\200\203\350\257\225/index.html" new file mode 100644 index 000000000..b37ac1aa5 --- /dev/null +++ "b/tags/\350\200\203\350\257\225/index.html" @@ -0,0 +1,179 @@ +标签: 考试 | Stray Birds + + + + + + + + +
    标签 - 考试
    2023
    冬学期结束感想
    冬学期结束感想
    \ No newline at end of file diff --git "a/tags/\350\204\221\345\233\276\350\260\261/index.html" "b/tags/\350\204\221\345\233\276\350\260\261/index.html" new file mode 100644 index 000000000..83068d3df --- /dev/null +++ "b/tags/\350\204\221\345\233\276\350\260\261/index.html" @@ -0,0 +1,179 @@ +标签: 脑图谱 | Stray Birds + + + + + + + + +
    标签 - 脑图谱
    2023
    小鼠脑图谱第四版
    小鼠脑图谱第四版
    \ No newline at end of file diff --git "a/tags/\350\204\221\347\224\265/index.html" "b/tags/\350\204\221\347\224\265/index.html" new file mode 100644 index 000000000..78577407f --- /dev/null +++ "b/tags/\350\204\221\347\224\265/index.html" @@ -0,0 +1,179 @@ +标签: 脑电 | Stray Birds + + + + + + + + +
    标签 - 脑电
    2023
    脑电数据分析
    脑电数据分析
    \ No newline at end of file diff --git "a/tags/\350\231\232\346\213\237\346\234\272/index.html" "b/tags/\350\231\232\346\213\237\346\234\272/index.html" new file mode 100644 index 000000000..5f3d2d322 --- /dev/null +++ "b/tags/\350\231\232\346\213\237\346\234\272/index.html" @@ -0,0 +1,179 @@ +标签: 虚拟机 | Stray Birds + + + + + + + + +
    标签 - 虚拟机
    2023
    在Mac电脑上安装VMware Fusion
    在Mac电脑上安装VMware Fusion
    \ No newline at end of file diff --git "a/tags/\350\256\241\347\256\227\345\273\272\346\250\241/index.html" "b/tags/\350\256\241\347\256\227\345\273\272\346\250\241/index.html" new file mode 100644 index 000000000..48e886a0e --- /dev/null +++ "b/tags/\350\256\241\347\256\227\345\273\272\346\250\241/index.html" @@ -0,0 +1,179 @@ +标签: 计算建模 | Stray Birds + + + + + + + + +
    标签 - 计算建模
    2023
    BrainPy学习笔记【01】
    BrainPy学习笔记【01】
    \ No newline at end of file diff --git "a/tags/\350\256\241\347\256\227\346\234\272\350\247\206\350\247\211/index.html" "b/tags/\350\256\241\347\256\227\346\234\272\350\247\206\350\247\211/index.html" new file mode 100644 index 000000000..699f3b220 --- /dev/null +++ "b/tags/\350\256\241\347\256\227\346\234\272\350\247\206\350\247\211/index.html" @@ -0,0 +1,179 @@ +标签: 计算机视觉 | Stray Birds + + + + + + + + +
    标签 - 计算机视觉
    2023
    图像风格迁移
    图像风格迁移
    \ No newline at end of file diff --git "a/tags/\350\257\276\347\250\213/index.html" "b/tags/\350\257\276\347\250\213/index.html" new file mode 100644 index 000000000..dbc105c81 --- /dev/null +++ "b/tags/\350\257\276\347\250\213/index.html" @@ -0,0 +1,179 @@ +标签: 课程 | Stray Birds + + + + + + + + +
    标签 - 课程
    2022
    英语结课感想
    英语结课感想
    \ No newline at end of file diff --git "a/tags/\350\275\257\344\273\266\345\256\211\350\243\205/index.html" "b/tags/\350\275\257\344\273\266\345\256\211\350\243\205/index.html" new file mode 100644 index 000000000..ec1b91c10 --- /dev/null +++ "b/tags/\350\275\257\344\273\266\345\256\211\350\243\205/index.html" @@ -0,0 +1,179 @@ +标签: 软件安装 | Stray Birds + + + + + + + + +
    标签 - 软件安装
    2024
    下载教育版origin
    下载教育版origin
    \ No newline at end of file diff --git a/videos/index.html b/videos/index.html new file mode 100644 index 000000000..39173f610 --- /dev/null +++ b/videos/index.html @@ -0,0 +1,343 @@ +值得反复观看的演讲和视频 | Stray Birds + + + + + + + + + + + + +
    \ No newline at end of file