-
Notifications
You must be signed in to change notification settings - Fork 0
/
feed.json
158 lines (158 loc) · 286 KB
/
feed.json
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
147
148
149
150
151
152
153
154
155
156
157
158
{
"version": "https://jsonfeed.org/version/1",
"title": "lcy's blog",
"description": "学习/科研/生活/阅读",
"home_page_url": "http://example.com",
"items": [
{
"id": "http://example.com/2024/07/19/%E5%A6%82%E4%BD%95%E4%BC%98%E5%8C%96gemm%E7%AE%97%E5%AD%90/",
"url": "http://example.com/2024/07/19/%E5%A6%82%E4%BD%95%E4%BC%98%E5%8C%96gemm%E7%AE%97%E5%AD%90/",
"title": "如何优化gemm算子",
"date_published": "2024-07-19T03:12:35.000Z",
"content_html": "<p>最近在做开源之下的项目,记录一下学习 gemm 的优化过程。</p>\n<span id=\"more\"></span>\n<p>gemm 即矩阵乘法,通常的 gemm 可表示为一个 MxK 的矩阵 A 和一个 KxN 的矩阵 B 相乘得到一个 MxN 的矩阵 C。矩阵计算的优化思路可以总结为以下几步,在这个博客中省去了对计算机组成原理的一些介绍。</p>\n<h2 id=\"优化思路\"><a class=\"markdownIt-Anchor\" href=\"#优化思路\">#</a> 优化思路</h2>\n<ol>\n<li>\n<p><strong>Split MNK</strong></p>\n<p>这一步优化主要是<strong>基于计算机体系架构的 cache 结构,节省计算数据在 cache 和内存间读取的时间</strong>。<br>\n切分 MNK(根据 L1 cache 的大小),比如 arm64 中 FP32M8N12 就是将矩阵 A(MxK)切分为若干个(8xK)矩阵,将矩阵 B(KxN)切分为若干个(Kx12)的矩阵,在第 2 步中提到了为何这么切分。</p>\n</li>\n<li>\n<p><strong>分层计算</strong></p>\n<p>这一步优化主要是<strong>节省中间数据在内存和 cache 之间换入换出</strong>的时间。<br>\n传统的 MNK 矩阵切分计算后,应该是 A 的小矩阵的每一<strong>行</strong>乘上 B 的小矩阵的每一<strong>列</strong>,这种做法比较低效,且存在很多冗余的重复加载。<br>\n分层计算的核心是每次用 A 的小矩阵的每一<strong>列</strong>(8 个元素,1X8 矩阵)和 B 的小矩阵的每一<strong>行</strong>(12 个元素,12X1 矩阵)相乘,得到中间结果矩阵(一层 8x12 矩阵),在这个过程中,把每一个中间结果矩阵累加,就得到了小矩阵 8K 和小矩阵 K12 计算的结果(完整 8x12 矩阵)。<br>\n以 arm64 架构的 CPU 为例子,有 32 个 128 位的 neon 向量寄存器,那么 M8N12 的每次分层计算中,A 需要从内存中读取 8 个元素,占用 2 个寄存器;B 需要从内存中读取 12 个元素,占用 3 个寄存器;C(中间结果)的形状为 8x12,需要占用 24 个寄存器来累加运算。</p>\n</li>\n<li>\n<p><strong>SIMD 优化</strong></p>\n<p>这一步优化主要是<strong>通过并行计算提高数据运算的速度</strong>。在 cache 计算中使用 SIMD 优化,并行计算元素与元素相乘的过程。</p>\n</li>\n<li>\n<p><strong>内存重排(pack)</strong></p>\n<p>这一步的优化主要是<strong>节省数据在内存中读取的时间</strong>。<br>\n以 x86 的 CPU 为例,矩阵在内存中是逐行存储的,一个 4x4 的矩阵 A 的存储顺序(由小到大)为</p>\n<p>| 0 | 1 | 2 | 3 |<br>\n| 4 | 5 | 6 | 7 |<br>\n| 8 | 9 | A | B |<br>\n| C | D | E | F |</p>\n<p>假设该矩阵被分割成 2 个 2x2 的矩阵,在计算中需要逐列读取,那么第一个被读取的元素是 0 处的,第二个被读取的元素是 4 处的,他们的地址并不连续,这会浪费一定的寻址时间。因此,在 2x2 的分割下,需要针对该矩阵进行内存重排,重排后的顺序如下,这种重排叫做 zigzag,因为是按照之字型排序的。</p>\n<p>| 0 | 2 | 4 | 6 |<br>\n| 1 | 3 | 5 | 7 |<br>\n| 8 | A | C | E |<br>\n| 9 | B | D | F |</p>\n</li>\n</ol>\n<h2 id=\"example\"><a class=\"markdownIt-Anchor\" href=\"#example\">#</a> Example</h2>\n<p>以 Megcc 生成的算子 <code>Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS</code> 为例子,分析一下如何实现 gemm 优化过后的算子。这是按照 M8N12K4 的分割的,想象一个三维的长方体分割就可以。</p>\n<ol>\n<li>\n<p><strong>重排内存</strong></p>\n<p>kernel 的执行入口是 <code>void Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS</code> ,该程序首先确认矩阵的内存空间。</p>\n<ul>\n<li>\n<p>Code</p>\n <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"type\">size_t</span> pack_a_size = Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS_workspace_a(<span class=\"number\">0</span>, M, <span class=\"number\">0</span>, K);</span><br><span class=\"line\"><span class=\"type\">float</span>* pack_a = workspace; # 矩阵A的开始地址</span><br><span class=\"line\"><span class=\"type\">float</span>* pack_b = workspace + pack_a_size; #矩阵B的开始地址</span><br><span class=\"line\">Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS_packa_n(pack_a, A, LDA, <span class=\"number\">0</span>, M, <span class=\"number\">0</span>, K); </span><br><span class=\"line\"># 按照上述第<span class=\"number\">4</span>步对矩阵进行重排</span><br><span class=\"line\">Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS_packb_n(pack_b, B, LDB, <span class=\"number\">0</span>, N, <span class=\"number\">0</span>, K); </span><br><span class=\"line\"># 按照上述第<span class=\"number\">4</span>步对矩阵进行重排</span><br></pre></td></tr></table></figure>\n</li>\n</ul>\n</li>\n<li>\n<p><strong>矩阵计算</strong></p>\n<p>矩阵的计算是逐 Block 进行的, M8N12K4 的计算方式中,每一个块的大小为 8x12x4。</p>\n <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">for</span> (; m + m_block <= M; m += m_block) {</span><br><span class=\"line\"> <span class=\"type\">float</span>* output = C + (m / pack_mk * LDC);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">size_t</span> n = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* cur_pack_b = pack_b;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; n + n_block <= N; n += n_block) {</span><br><span class=\"line\"> kern_8x12_bias_relu(pack_a, cur_pack_b, K, output, LDC, _bias_ptr); # 每一个小block的计算</span><br><span class=\"line\"> output += n_block * pack_mk;</span><br><span class=\"line\"> ;</span><br><span class=\"line\"> cur_pack_b += K12;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> # 当n不能被<span class=\"number\">12</span>整除时,剩下的n按照<span class=\"number\">4</span>分割计算。</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; n < N; n += <span class=\"number\">4</span>) {</span><br><span class=\"line\"> kern_8x4_bias_relu(</span><br><span class=\"line\"> pack_a, cur_pack_b, K, output, LDC, _bias_ptr,</span><br><span class=\"line\"> N - n > <span class=\"number\">4</span> ? <span class=\"number\">4</span> : N - n); </span><br><span class=\"line\"> # 即使剩下的不能被<span class=\"number\">4</span>整除也按照<span class=\"number\">4</span>向上对齐处理。</span><br><span class=\"line\"> output += <span class=\"number\">4</span> * pack_mk;</span><br><span class=\"line\"> ;</span><br><span class=\"line\"> cur_pack_b += K4;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> pack_a += K8;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> #当m不能被<span class=\"number\">8</span>整除时,剩下的m的维度按照<span class=\"number\">4</span>整除计算。</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; m < M; m += m_block_4) {</span><br><span class=\"line\"> <span class=\"type\">float</span>* output = C + (m / pack_mk * LDC);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">size_t</span> n = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* cur_pack_b = pack_b;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; n + n_block - <span class=\"number\">1</span> < N; n += n_block) {</span><br><span class=\"line\"> kern_4x12_bias_relu(pack_a, cur_pack_b, K, output, LDC, _bias_ptr);</span><br><span class=\"line\"> output += n_block * pack_mk;</span><br><span class=\"line\"> ;</span><br><span class=\"line\"> cur_pack_b += K12;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> #同上</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; n < N; n += <span class=\"number\">4</span>) {</span><br><span class=\"line\"> kern_4x4_bias_relu(</span><br><span class=\"line\"> pack_a, cur_pack_b, K, output, LDC, _bias_ptr,</span><br><span class=\"line\"> N - n > <span class=\"number\">4</span> ? <span class=\"number\">4</span> : N - n);</span><br><span class=\"line\"> output += <span class=\"number\">4</span> * pack_mk;</span><br><span class=\"line\"> ;</span><br><span class=\"line\"> cur_pack_b += K4;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> pack_a += K4;</span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n</li>\n<li>\n<p><strong>汇编实现:内存重排</strong></p>\n<p>对 A 进行内存重排的程序入口如下,矩阵 A 的形状为 [M/4, K/4, 4, 4],如下图所示,A 矩阵在内存中首先以块顺序 0-7 存储,在每一块内按照 0-F 的顺序存储。对 A 进行内存重排后的形状为 [M/8, K, 8],在图中为了方便理解,箭头方向为数据存储的方向,假设 M=16,K=8。</p>\n <center>\n <img src=\"/2024/07/19/%E5%A6%82%E4%BD%95%E4%BC%98%E5%8C%96gemm%E7%AE%97%E5%AD%90/1.svg\" style=\"width:99%\">\n </center>\n<p>以下程序描述了如何进行内存重排的过程。首先需要两个指针 <code>inptr0</code> 和 <code>inptr1</code> 定位原矩阵的内存,其中 <code>inptr0</code> 定位的是第 0 矩阵块(以下都称为块,描述的是上图中矩阵的分块情况)内存起点, <code>inptr1</code> 定位的是第 2 块内存起点, <code>prefetch_2x</code> 函数的作用是读取 32 个 fp32 数据,即 2 块,该函数将 0、1 和 2、3 块数据加载到缓存中, <code>interleave_2x4_4_s</code> 是重排函数,作用是将载入缓存的块数据重排,具体如何展开请看后续。注意,若 m 不被 8 整除,需要在下一个循环代码中处理尾部数据。</p>\n <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"type\">void</span> <span class=\"title function_\">Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS_packa_n</span><span class=\"params\">(</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"type\">float</span>* outptr, <span class=\"type\">const</span> <span class=\"type\">float</span>* inptr, <span class=\"type\">int</span> ldin, <span class=\"type\">int</span> y0, <span class=\"type\">int</span> ymax, <span class=\"type\">int</span> k0,</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"type\">int</span> kmax)</span> {</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> pack_mk = <span class=\"number\">4</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> pack_m = <span class=\"number\">8</span>;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> m_stride = pack_m * pack_mk;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">int</span> min_m_stride = pack_mk * pack_mk;</span><br><span class=\"line\"> <span class=\"type\">int</span> y = <span class=\"number\">0</span>;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; y + <span class=\"number\">7</span> < ymax; y += pack_m) {</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* inptr0 = inptr + y / pack_mk * ldin;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* inptr1 = inptr0 + ldin;</span><br><span class=\"line\"> prefetch_2x(inptr0);</span><br><span class=\"line\"> prefetch_2x(inptr1);</span><br><span class=\"line\"> <span class=\"type\">int</span> k = (kmax);</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; k > <span class=\"number\">3</span>; k -= pack_mk) {</span><br><span class=\"line\"> interleave_2x4_4_s(inptr0, inptr1, outptr);</span><br><span class=\"line\"> outptr += m_stride;</span><br><span class=\"line\"> inptr0 += min_m_stride;</span><br><span class=\"line\"> inptr1 += min_m_stride;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"meta\"># m不被8整除</span></span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; y < ymax; y += pack_mk) {</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* inptr0 = inptr + y / pack_mk * ldin;</span><br><span class=\"line\"> prefetch_2x(inptr0);</span><br><span class=\"line\"> <span class=\"type\">int</span> K = (kmax);</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; K > <span class=\"number\">3</span>; K -= pack_mk) {</span><br><span class=\"line\"> interleave_1x4_4_s(inptr0, outptr);</span><br><span class=\"line\"> outptr += min_m_stride;</span><br><span class=\"line\"> inptr0 += min_m_stride;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br><span class=\"line\"></span><br></pre></td></tr></table></figure>\n<p>重排函数实现的重点是函数 <code>interleave_2x4_4_s</code> ,下图描述了矩阵 A 内存重排的实现过程。其中 v0-v7 为寄存器。程序首先将数据加载到寄存器后,重排顺序后再输出到矩阵 A 的输出位置指针。</p>\n <center>\n <img src=\"/2024/07/19/%E5%A6%82%E4%BD%95%E4%BC%98%E5%8C%96gemm%E7%AE%97%E5%AD%90/2.svg\" style=\"width:99%\">\n </center>\n<p>对 B 实现内存重排的原理类似,其原始形状为 [K/4, N, 4],重排后形状为 [N/12, K, 12],其形状变化和内存排序如下图所示,和 A 相比,需要多进行一个类似转置的操作。如下图所示,该重排把一个 4x12 的矩阵块(第一块绿色,紫色,黄色的三块)重排成了一个 12x4 的矩阵块。</p>\n <center>\n <img src=\"/2024/07/19/%E5%A6%82%E4%BD%95%E4%BC%98%E5%8C%96gemm%E7%AE%97%E5%AD%90/3.svg\" style=\"width:99%\">\n </center>\n <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"type\">void</span> <span class=\"title function_\">Arm64_fp32_m8_n12_mk4_matmul_NO_BIAS_packb_n</span><span class=\"params\">(</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"type\">float</span>* outptr, <span class=\"type\">const</span> <span class=\"type\">float</span>* inptr, <span class=\"type\">int</span> ldin, <span class=\"type\">int</span> x0, <span class=\"type\">int</span> xmax, <span class=\"type\">int</span> k0,</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"type\">int</span> kmax)</span> {</span><br><span class=\"line\"> <span class=\"type\">float</span> tmpbuff[<span class=\"number\">16</span>] = {<span class=\"number\">0.0f</span>};</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">int</span> PACK_C_SIZE = <span class=\"number\">4</span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> ksize = kmax - k0;</span><br><span class=\"line\"> <span class=\"type\">int</span> ksize12 = ksize * <span class=\"number\">12</span>;</span><br><span class=\"line\"> <span class=\"type\">int</span> ksize4 = (ksize << <span class=\"number\">2</span>);</span><br><span class=\"line\"> <span class=\"type\">float</span>* outptr_base = outptr;</span><br><span class=\"line\"> <span class=\"type\">float</span>* outptr_base4 = outptr_base + (xmax - x0) / <span class=\"number\">12</span> * ksize12;</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">int</span> k = k0;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; k + <span class=\"number\">3</span> < kmax; k += <span class=\"number\">4</span>) {</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* temp_inptr = inptr + k / PACK_C_SIZE * ldin + x0 * PACK_C_SIZE;</span><br><span class=\"line\"> prefetch_3x(temp_inptr);</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"type\">int</span> x = x0;</span><br><span class=\"line\"> <span class=\"type\">float</span>* temp_outptr = outptr_base;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; x + <span class=\"number\">12</span> <= xmax; x += <span class=\"number\">12</span>) {</span><br><span class=\"line\"> <span class=\"type\">float</span>* outptr_interleave = temp_outptr;</span><br><span class=\"line\"> transpose_1x12_4_s(temp_inptr, outptr_interleave);</span><br><span class=\"line\"> temp_outptr += ksize12;</span><br><span class=\"line\"> temp_inptr += <span class=\"number\">4</span> * <span class=\"number\">12</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> temp_outptr = outptr_base4;</span><br><span class=\"line\"> <span class=\"keyword\">for</span> (; x + <span class=\"number\">4</span> <= xmax; x += <span class=\"number\">4</span>) {</span><br><span class=\"line\"> <span class=\"type\">float</span>* outptr_interleave = temp_outptr;</span><br><span class=\"line\"> <span class=\"keyword\">asm</span> <span class=\"title function_\">volatile</span><span class=\"params\">(</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"string\">\"ld4 {v0.4s, v1.4s, v2.4s, v3.4s}, [%[inptr0]], #64\\n\"</span></span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"string\">\"st1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%[outptr0]]\\n\"</span></span></span><br><span class=\"line\"><span class=\"params\"> : [inptr0] <span class=\"string\">\"+r\"</span>(temp_inptr), [outptr0] <span class=\"string\">\"+r\"</span>(outptr_interleave)</span></span><br><span class=\"line\"><span class=\"params\"> :</span></span><br><span class=\"line\"><span class=\"params\"> : <span class=\"string\">\"v0\"</span>, <span class=\"string\">\"v1\"</span>, <span class=\"string\">\"v2\"</span>, <span class=\"string\">\"v3\"</span>, <span class=\"string\">\"memory\"</span>)</span>;</span><br><span class=\"line\"> temp_outptr += ksize4;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> <span class=\"keyword\">if</span> (x < xmax) {</span><br><span class=\"line\"> <span class=\"built_in\">memcpy</span>(tmpbuff, temp_inptr, <span class=\"keyword\">sizeof</span>(<span class=\"type\">float</span>) * (xmax - x) * PACK_C_SIZE);</span><br><span class=\"line\"> <span class=\"type\">float</span>* outptr_interleave = temp_outptr;</span><br><span class=\"line\"> <span class=\"type\">const</span> <span class=\"type\">float</span>* tmp_ptr = &tmpbuff[<span class=\"number\">0</span>];</span><br><span class=\"line\"> <span class=\"keyword\">asm</span> <span class=\"title function_\">volatile</span><span class=\"params\">(</span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"string\">\"ld4 {v0.4s, v1.4s, v2.4s, v3.4s}, [%[inptr0]], #64\\n\"</span></span></span><br><span class=\"line\"><span class=\"params\"> <span class=\"string\">\"st1 {v0.4s, v1.4s, v2.4s, v3.4s}, [%[outptr0]]\\n\"</span></span></span><br><span class=\"line\"><span class=\"params\"> : [inptr0] <span class=\"string\">\"+r\"</span>(tmp_ptr), [outptr0] <span class=\"string\">\"+r\"</span>(outptr_interleave)</span></span><br><span class=\"line\"><span class=\"params\"> :</span></span><br><span class=\"line\"><span class=\"params\"> : <span class=\"string\">\"v0\"</span>, <span class=\"string\">\"v1\"</span>, <span class=\"string\">\"v2\"</span>, <span class=\"string\">\"v3\"</span>, <span class=\"string\">\"memory\"</span>)</span>;</span><br><span class=\"line\"> temp_outptr += ksize4;</span><br><span class=\"line\"> }</span><br><span class=\"line\"> outptr_base += <span class=\"number\">12</span> * <span class=\"number\">4</span>;</span><br><span class=\"line\"> outptr_base4 += <span class=\"number\">4</span> * <span class=\"number\">4</span>;</span><br><span class=\"line\"> }</span><br><span class=\"line\">}</span><br></pre></td></tr></table></figure>\n</li>\n<li>\n<p><strong>汇编实现: kernel func</strong></p>\n<p>根据实现细节,实现一个 M8N12K4 的算子需要以下几个分层运算函数: <code>kern_8x12_bias_relu</code> , <code>kern_8x4_bias_relu</code> , <code>kern_4x12_bias_relu</code> , <code>kern_4x4_bias_relu</code> , 这些都是基于汇编语言实现的。以主要的 <code>kern_8x12_bias_relu</code> 为例子,来看一下这个函数是如何实现分层计算的。<br>\n需要理解的汇编语言操作如下表</p>\n<ol>\n<li>eor 异或操作</li>\n<li>ld1 从内存中加载数据</li>\n<li>prfm 预取内存到缓存</li>\n<li>cmp 比较操作符</li>\n<li>fmla 向量乘加操作</li>\n<li>bne 比较结果不相等时跳转</li>\n<li>st1 将寄存器的数据写入内存</li>\n</ol>\n<p>根据优化思路的第 2 步,首先你需要加载 A 的 8 个元素(2 个寄存器)和 B 的 12 个元素(3 个寄存器)到 cache 中,再为中间结果矩阵准备 24 个寄存器。<br>\n在以下这段汇编代码中,首先通过异或操作 <code>eor</code> 清空了 8-31 寄存器的所有字节(x.16b),一共 24 个,这些寄存器是为了存储中间结果准备的。用 output0 和 output1 两个指针作为输出,并通过 <code>prfm</code> 把他们预取到缓存中。以下是汇编代码的主体实现,实际使用时,arm 架构有 32 个 128 位的寄存器,除去以上的 29 个,另外空闲的 3 个处理器分给 B 做数据的预取。</p>\n<ul>\n<li>\n<p>Code</p>\n <figure class=\"highlight c\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br><span class=\"line\">49</span><br><span class=\"line\">50</span><br><span class=\"line\">51</span><br><span class=\"line\">52</span><br><span class=\"line\">53</span><br><span class=\"line\">54</span><br><span class=\"line\">55</span><br><span class=\"line\">56</span><br><span class=\"line\">57</span><br><span class=\"line\">58</span><br><span class=\"line\">59</span><br><span class=\"line\">60</span><br><span class=\"line\">61</span><br><span class=\"line\">62</span><br><span class=\"line\">63</span><br><span class=\"line\">64</span><br><span class=\"line\">65</span><br><span class=\"line\">66</span><br><span class=\"line\">67</span><br><span class=\"line\">68</span><br><span class=\"line\">69</span><br><span class=\"line\">70</span><br><span class=\"line\">71</span><br><span class=\"line\">72</span><br><span class=\"line\">73</span><br><span class=\"line\">74</span><br><span class=\"line\">75</span><br><span class=\"line\">76</span><br><span class=\"line\">77</span><br><span class=\"line\">78</span><br><span class=\"line\">79</span><br><span class=\"line\">80</span><br><span class=\"line\">81</span><br><span class=\"line\">82</span><br><span class=\"line\">83</span><br><span class=\"line\">84</span><br><span class=\"line\">85</span><br><span class=\"line\">86</span><br><span class=\"line\">87</span><br><span class=\"line\">88</span><br><span class=\"line\">89</span><br><span class=\"line\">90</span><br><span class=\"line\">91</span><br><span class=\"line\">92</span><br><span class=\"line\">93</span><br><span class=\"line\">94</span><br><span class=\"line\">95</span><br><span class=\"line\">96</span><br><span class=\"line\">97</span><br><span class=\"line\">98</span><br><span class=\"line\">99</span><br><span class=\"line\">100</span><br><span class=\"line\">101</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"string\">\"eor v8.16b, v8.16b, v8.16b \\n\"</span> # 清空v8寄存器,下同</span><br><span class=\"line\"><span class=\"string\">\"eor v9.16b, v9.16b, v9.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v10.16b, v10.16b, v10.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"prfm pstl1keep, [%[output0]] \\n\"</span> # 预取</span><br><span class=\"line\"><span class=\"string\">\"eor v11.16b, v11.16b, v11.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v12.16b, v12.16b, v12.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v13.16b, v13.16b, v13.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"prfm pstl1keep, [%[output1]] \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v14.16b, v14.16b, v14.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v15.16b, v15.16b, v15.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v2.4s}, [%[b_ptr]], #16 \\n\"</span> # v2加载B的四个字节,同时将指针向后移<span class=\"number\">16</span>个字节</span><br><span class=\"line\"><span class=\"string\">\"eor v16.16b, v16.16b, v16.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v17.16b, v17.16b, v17.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v18.16b, v18.16b, v18.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v19.16b, v19.16b, v19.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v20.16b, v20.16b, v20.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v3.4s}, [%[b_ptr]], #16 \\n\"</span> # v3加载B的四个字节,同时将指针向后移<span class=\"number\">16</span>个字节</span><br><span class=\"line\"><span class=\"string\">\"eor v21.16b, v21.16b, v21.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v22.16b, v22.16b, v22.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v23.16b, v23.16b, v23.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v4.4s}, [%[b_ptr]], #16 \\n\"</span> # v4加载B的四个字节,同时将指针向后移<span class=\"number\">16</span>个字节</span><br><span class=\"line\"><span class=\"string\">\"eor v24.16b, v24.16b, v24.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v25.16b, v25.16b, v25.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v26.16b, v26.16b, v26.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v27.16b, v27.16b, v27.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v28.16b, v28.16b, v28.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v0.4s}, [%[a_ptr]], #16 \\n\"</span># v0加载A的四个字节,同时将指针向后移<span class=\"number\">16</span>个字节</span><br><span class=\"line\"><span class=\"string\">\"eor v29.16b, v29.16b, v29.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v30.16b, v30.16b, v30.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"eor v31.16b, v31.16b, v31.16b \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"2: \\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"cmp %w[K], #0\\n\"</span> #如果k=<span class=\"number\">0</span> 此时k=<span class=\"number\">1</span></span><br><span class=\"line\"><span class=\"string\">\"beq 4f\\n\"</span> </span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"string\">\"3:\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v8.4s, v0.4s, v2.s[0]\\n\"</span> # A的前四个元素和B的第一个元素相乘</span><br><span class=\"line\"><span class=\"string\">\"fmla v9.4s, v0.4s, v2.s[1]\\n\"</span> # A的前四个元素和B的第二个元素相乘</span><br><span class=\"line\"><span class=\"string\">\"ld1 {v1.4s}, [%[a_ptr]], 16\\n\"</span> # v1加载A的四个字节,同时指针偏移</span><br><span class=\"line\"><span class=\"string\">\"fmla v10.4s, v0.4s, v2.s[2]\\n\"</span> # A的前四个元素和B的第三个元素相乘</span><br><span class=\"line\"><span class=\"string\">\"fmla v11.4s, v0.4s, v2.s[3]\\n\"</span> # A的前四个元素和B的第四个元素相乘</span><br><span class=\"line\"><span class=\"string\">\"ld1 {v5.4s}, [%[b_ptr]], #16\\n\"</span> # v5加载B的四个字节,同时指针偏移</span><br><span class=\"line\"><span class=\"string\">\"fmla v12.4s, v0.4s, v3.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v13.4s, v0.4s, v3.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v6.4s}, [%[b_ptr]], #16\\n\"</span> # v6加载B的四个字节,同时指针偏移</span><br><span class=\"line\"><span class=\"string\">\"fmla v14.4s, v0.4s, v3.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v15.4s, v0.4s, v3.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v7.4s}, [%[b_ptr]], #16\\n\"</span> # v7加载B的四个字节,同时指针偏移</span><br><span class=\"line\"><span class=\"string\">\"fmla v16.4s, v0.4s, v4.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v17.4s, v0.4s, v4.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v18.4s, v0.4s, v4.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v19.4s, v0.4s, v4.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v0.4s}, [%[a_ptr]], 16\\n\"</span> # 此时A的前四个元素的计算完成,向后加载<span class=\"number\">4</span>个字节</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"string\">\"fmla v20.4s, v1.4s, v2.s[0]\\n\"</span> </span><br><span class=\"line\"><span class=\"string\">\"fmla v21.4s, v1.4s, v2.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v22.4s, v1.4s, v2.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v23.4s, v1.4s, v2.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v24.4s, v1.4s, v3.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v25.4s, v1.4s, v3.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v26.4s, v1.4s, v3.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v27.4s, v1.4s, v3.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v28.4s, v1.4s, v4.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v29.4s, v1.4s, v4.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v30.4s, v1.4s, v4.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v31.4s, v1.4s, v4.s[3]\\n\"</span> </span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"string\">\"fmla v8.4s, v0.4s, v5.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v9.4s, v0.4s, v5.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v1.4s}, [%[a_ptr]], 16\\n\"</span> # 此时A的第一个<span class=\"number\">8</span>x1的矩阵计算完毕,向后加载<span class=\"number\">4</span>个字节</span><br><span class=\"line\"><span class=\"string\">\"fmla v10.4s, v0.4s, v5.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v11.4s, v0.4s, v5.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v2.4s}, [%[b_ptr]], 16\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v12.4s, v0.4s, v6.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v13.4s, v0.4s, v6.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v3.4s}, [%[b_ptr]], 16\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v14.4s, v0.4s, v6.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v15.4s, v0.4s, v6.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v4.4s}, [%[b_ptr]], 16\\n\"</span> # B也向后加载一个<span class=\"number\">1</span>x12的矩阵分块</span><br><span class=\"line\"><span class=\"string\">\"fmla v16.4s, v0.4s, v7.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v17.4s, v0.4s, v7.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v18.4s, v0.4s, v7.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v19.4s, v0.4s, v7.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"ld1 {v0.4s}, [%[a_ptr]], 16\\n\"</span> # 同上</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"string\">\"fmla v20.4s, v1.4s, v5.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v21.4s, v1.4s, v5.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v22.4s, v1.4s, v5.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v23.4s, v1.4s, v5.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v24.4s, v1.4s, v6.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"subs %w[K], %w[K], #1\\n\"</span> #处理K的大小</span><br><span class=\"line\"><span class=\"string\">\"fmla v25.4s, v1.4s, v6.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v26.4s, v1.4s, v6.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v27.4s, v1.4s, v6.s[3]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v28.4s, v1.4s, v7.s[0]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v29.4s, v1.4s, v7.s[1]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v30.4s, v1.4s, v7.s[2]\\n\"</span></span><br><span class=\"line\"><span class=\"string\">\"fmla v31.4s, v1.4s, v7.s[3]\\n\"</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"string\">\"bne 3b\\n\"</span></span><br><span class=\"line\"></span><br><span class=\"line\"># 后面是一些处理尾部的代码块,此处略</span><br></pre></td></tr></table></figure>\n</li>\n</ul>\n</li>\n</ol>\n",
"tags": [
"ospp"
]
},
{
"id": "http://example.com/2023/04/24/2023-04-reading-record/",
"url": "http://example.com/2023/04/24/2023-04-reading-record/",
"title": "2023-04-reading-record",
"date_published": "2023-04-24T04:54:29.000Z",
"content_html": "<p>“也许她以自己的方式在爱着安德蕾,问题在于:以哪种方式?各人有各人的方式,我们人人都爱着她。”</p>\n<span id=\"more\"></span>\n<h3 id=\"形影不离-波伏娃\"><a class=\"markdownIt-Anchor\" href=\"#形影不离-波伏娃\">#</a> 《形影不离》 波伏娃 √</h3>\n<p>⭐⭐⭐⭐</p>\n<p>波伏娃用来纪念最好的朋友扎扎的作品。<em>什么叫初恋!什么叫青梅青梅两小无猜!什么叫白月光!QAQ</em> 书中的安德蕾指波伏娃的好朋友扎扎,而希尔微指的是波伏娃。</p>\n<blockquote>\n<p>她们的直发和黑眼睛让我想起大腿被灼烧的那个小女孩,那个在十年前拿走了我的心的小女孩。</p>\n</blockquote>\n<p>书里的 “我 “看起来是和安德蕾一起长大的小女孩,但其实是几十年后的波伏娃去怀念过去的扎扎。几十年后,波伏娃明白了当年杀死扎扎的是什么。从文字中能感觉到波伏娃对扎扎无限的爱,一想到这些文字写于扎扎去世的几十年后,我也感觉到同样的心痛。安德蕾身上那种与众不同的天赋,狡黠的性格,求知和求善的本能让人毫不怀疑如果长大的话,她会成为非常杰出的人。而世界总是会首先毁灭那些善良和勇敢的人。</p>\n<p>安德蕾的死让我觉得人活在这个世界上太富于感情最终不会过的太好,她说 “玫瑰是一种讲究礼节的花,死时依然鲜活,枝头弯曲如行屈膝礼”,但真相是死了就什么都没有了,火化之后只剩下一抔尘土而已。无论是天主教,还是中国文化,实际上对女性都是一样的束缚和控制,本质上你不能为自己的利益而活。</p>\n<blockquote>\n<p>"仁慈的上帝啊,他是处于怎样的想法给了我这样一个女儿!" 卡拉尔夫人说。她本来是笑着的,突然又严肃地说:“立刻回去,你没有完成任何你应做的事。”</p>\n</blockquote>\n<p>安德蕾就是死于那些她 “应做的事”,整个世界都在利用她,波伏娃意识到了这一点,而她无法提醒安德蕾,因为安德蕾是一位富有感情的、虔诚的基督徒,用自己满足所有人。因为信仰施加给自己的不快乐而死是殉道吗?人的生命是如此珍贵的东西,而宗教不过是游戏而已。如果扎扎出生在今天,以她的智慧,就不会因为这些无意义的东西去死了。</p>\n<h3 id=\"爸妈我们需要谈谈钱\"><a class=\"markdownIt-Anchor\" href=\"#爸妈我们需要谈谈钱\">#</a> 《爸妈,我们需要谈谈钱》 √</h3>\n<p>⭐⭐⭐⭐</p>\n<p>详细的说明了美国的养老体系,以及作为孩子你能为逐渐衰老的父母所做的经济保障。可借鉴的部分是 1. 收集信息。2. 长期沟通。最近在帮爸爸戒酒,深感到这两点的重要,必要的信息都应该去做电子化。包括身份证号、社保账号、银行卡号和对应余额、贷款情况,身体不好的老人的基础数据和用药历史、检测报告等等,对于我家是流动资金比较大的家庭来说,应该建立系统再写上各个生意的总价、已付和未到账的清单,只靠文字账本和微信聊天记录实在是太危险了。</p>\n<h3 id=\"一个规矩女孩的回忆-波伏娃\"><a class=\"markdownIt-Anchor\" href=\"#一个规矩女孩的回忆-波伏娃\">#</a> 《一个规矩女孩的回忆》 波伏娃</h3>\n<p>⭐⭐⭐⭐⭐</p>\n<p>看了一半,详细描述了波伏娃十八岁左右以前的记忆,从父母、妹妹和保姆路易斯开始,到初步的重要的社会关系扎扎(包括了形影不离的若干内容)。其中很有趣的部分是波伏娃从小到大默认接受的权威(包括保姆路易斯、老师、牧师乃至神)崩塌,从这些崩塌中波伏娃逐渐建立自己的世界。波伏娃写东西的目的不在于艺术创造,而是希望通过总结自己的人生从而给后来者一些启示,非常典型的 N 人。波伏娃唤起了我小时候的一些记忆,我们都从很小的时候开始观察世界,都很叛逆,我感觉原本有一些应该在小时候点亮的火光,因为无人关注以及无书可看的原因最终沉默了。</p>\n<blockquote>\n<p>较之于永恒,这个世界算不了什么;这个世界之所以重要,是因为我爱它。</p>\n</blockquote>\n<blockquote>\n<p>我这样决定:她们将找到丈夫,而我找不到。我不会因此而难过。别人喜欢她们甚于喜欢我是对的。但是将发生某种事情,比任何偏爱更能激励我:我不知道将以什么方式,通过什么人,但我肯定会成名。</p>\n</blockquote>\n",
"tags": [
"reading record"
]
},
{
"id": "http://example.com/2023/03/30/%E5%86%99%E5%9C%A8%E4%B8%89%E6%9C%88%E6%9C%AB/",
"url": "http://example.com/2023/03/30/%E5%86%99%E5%9C%A8%E4%B8%89%E6%9C%88%E6%9C%AB/",
"title": "写在三月末",
"date_published": "2023-03-30T03:59:19.000Z",
"content_html": "<div class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"Oh, this is an invalid password. Check and try again, please.\" data-whm=\"OOPS, these decrypted content may changed, but you can still have a look.\">\n <script id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"c2c356ec5731e8ce7a659c489e6cb527bf703e892df89b2a349d8b97e239115b\">4f9de7028b481e695d9f95a34c356ed9a25ef61f6ad56b320af81e3f21c495dad97f8b720df3147f284ee582860f718e9e524dc3ce212f2886e8cde950788ed441b2368fc1ed248cecb33b87813e875e4b13252ecd0829da8002231c99fb48cd1a3b9038a84c674ffdcd8eb772434866c7adc49f07a62cc33ca06af02fada6f1ae936fd34cc3b47f3ee8fe9747b4ce28517c407cdf97a2ed812e181d6e79de91cf337a9715db123292e9b3d86553813245d8dc468b9b7e54d20708d11bd6a4b7e622a00f07671256ee36a42d40ccb64cc624c5b1c5238d753a1c6c48ab062ec7ec43d729d4b1892d15b337ac9eb8ac2f27e9f0aeda00fc677923af4a05726ebd5f59c775d0bf2abacb3f826e13b35490b908934bbfb20ddd895a404b05c8e93f558358aff741ab0aaa50260da2182e5aed25c064ed4bd60d5f78a1930306d08b90fa96918fea25872e5b665bc13f4ce56f44e2f449fed0376f468c5b4501b79e29713a2a7d55a2994edf1af80075cec125ff0af385d64a4a587182db4bc227c94be8b30be830f42b49da20ef78b1d560b6feb575c426d13c4cb8f21bf66d4ebaeb508d56a50bedde59fd49882cc5923260a173cad05242d33b4fabefe1993015c69ae5bce794b96c42a22c7f2d4d21622809258d35f1077bd7b18e65d03fcc3954331a34c81476cec8fa6069f063374fa98442e85229fbf68c2f5a0f91dfccc7289ef6b2ec858e901963d09353b2c2b1e4c1901093c61d60e56ed4c150026fe92eb4518e90edd2a7b72f75b11f69bbf4417bd6236dca7c6ed5cf790893f621dbb242985070a5d235d79d7b61d4355a5d21e240e7168c4182e7066c6cc36d8696e68a6a3fe77ab979c350a202a59cd07d5f1b67cb4c09409a5845568e25a0b1f65ba7904c99e3c0218aab98a3e7699c78ba4dea19ff9cd54c39bb6301bdae5b302bb243ad27325e72c064a1009d03ef62c8c52cee08f50c38de69b64c5589428553c3f6f001b58e5a91478976706354002773be453fa8293a901f6fa135c444e47027ab35b954bca7a04d48bbebbbeb615562047155c4a3ccd08bd295040620cd241ea0e1e52ae63cdbde4892d0bc2e09985654d7c66c2ffe87e04fe6b4f9b4e2928cd836fb550bfcf9d0debff58a90c1c3546760a13c2cdddf0d5c02c8371a630afcbe58001efd54980ba312ac0f1257db2e62fff7ab2f23c97e92031a838d2dd97d12d4465436c58e0fddeb797914c50447d6475bb818fbcf622867265b4ba54dc37298150c8f96e81086e46d4cc04ac89a0c9eac38eab336269c3277b015f5ad3f756905b6d41840c91e07aa2770ae48a2aaf9766d77005d8045d0f38f755d7d2d812064d70fa97837987fe990eecae5c6f8ef31efee97341ab869e1a6540ebac714734ed5002cb2d19c0fbc46f3344b673f474961ff0be44a2731ceae27096d88468fb2fba86f3fc1df399b8401076e23842a74cdee4560bcda3bc97349c151889c9a3cd50668761e425d35f8922a1ec5c37041f026374df0b5b1fc1aefd4ee748dc5883dc578aaaea72f5dc769614a76a2cc8d88009baea5cc0c367fecdab3a947a37281f60f100695055e78e488644739fb6f8b2a797b4b693376dc06f3e1b2f83c0022e3f6a61a1cc58c48154d35666719a55d23830ff2ee9f307576f1b6a28fb95fce0b55a278be65b237d77e1f3c92371f2654fd59504b555f272052cba47c84c274c47b7743c7d3f8eb4d938bab9fce5c2bc253a077bcdb64e6f81c4918f1072619a22aea5a91d166f66a34101fd3a72cb5e3f9bd117656c096dd01dec326c2ed322d9678a070a51700cc3b31fa46108180e2d893e336f423a9225222e9dd3c0fbddf1cf9f5473c27c78175e4a978130ab302c44b7c5cea0c0d76fa840c7be8864389af5ca84c72a1736ff18d078a5bffd8720d076079a769b916193002cc9dcbfa528779d8bd5573fc7d5d5bca41098d7c4d538af89cf8eea83d0cbd04b74a8b18b4446be55b93083d4c289f0b0c0d9c5254d1f78549c96bb6731a5ffe5490ab6fcc3b563ac6570525cbe8fbfa81bb2f44b36fd6e88c56e1ff8c6c0a6c8e4ac31008a7d6340609090ee8015e72aa9a5d5f3142090888783be9fb0c34c575863f4b374e015b4d258dac915c222e8e1a9cbd0a242b09f8484678baf91578e13da9717c69e07e1eb546bf4c8d9ca757e48662c0aa2ffcdc75679144ac9c892c7c47ad5ca7e3a21ef98345a329dd5434cb6a5ef2eceb609b1d013e5f928d7ca518435e2d3ceaa3ceb770da698ff164d7c03d3474d2817d134d6c64287109291395b9e5346b421e4f0412557054fd78112a5646d1b2a085aee96ac6279342ef09a3159625c880c9edb09afb765abfb66ac4646f2724b35aea12ccbbf1b4b414830d874bf0dd43019b7175dca7480011ccd73d5ae3350cad17eb777f673827e73e28c7e6c07499385ff19a493b19f0c429ffbdc34f2e8c706d9ceb91a403ee1eff9e00c7c476da1c2e420fde3fbf78141c40263ffde9caffb89cfea21946bda2f137809a1c46c6123ec8534a700bf59c13de4e5e84e29fb18e2c307cfc94ad7e7479ca1fc181c1c8306bacb7ff28a8e510faefc7b8f48aa401a3462af4afb5cec1ed8f447865bdecf0377df04b2ef58ee051fd5c50b2c8fafdaca43ddf1e5411b39f9b26963160b20ee7dae1668619abe710f6e1af26e622a9928fc54566a6bb6b021d65c15a102856f90124fcdbae1ffe4f1c2b284e5186bab483fcfc4006384cb469820e0e45db00ab2d2709cbdc00b793ffac87d25fcd1d5c57b06de7b8c32daf4a40f84c33978d15e54a2216ea32286b530f14dfa35c0ded5103ae9c895e0ae86af22357c14c2b1dc3431ce9430f176ce76a45219db941a264c5354d05f98a2c887afad3f841f9f8a2ee8b4446f2ad1c7611cf157d768d94ac5d3b57f738d614b0253a307dcb86ac57bea9a7339a4daf70e5f11c53651ed2341f66e632396155434377eb653d105ec7213c63e7e8f4e80789fc7bae074cf8c776fa46846a586a01ef31556c8d4b877ba4938f9426a9992ac65f89a5933ecdfc4451591b821148e6897688338284f3d0daf5220682e8eddf12a5a9d64cbd7911fd6713939da05ff5e691f707c0004790f48f02f712f8aa1ebe310a568e91a1b387a1f547683f84fd18539b2a1b5f574681fb346978bde7a2bb871e5def2afad95fe0baa7c7ac494ed281d6e5148b654da888edcd7b2d9245dbb632859b6d1246c551a3f94bdbbedc5da17504925dac6d00fd2e5556b3646170dd917c85511e8a3de24f77c81d9c8cbd1bf45bc6bba32201e945dd1ae01c084511bc95d7fb2cea4ce049afba993b7c60258945685c9f29223b464084110af8d984c991bff90ad9dbe5806971e4f4e454181d0b144966e354b8e84d80db9d41c1f29d7d35be049e4f4ede72363b0595a0c56a989e370f466a134d9cf653123ba2c385a5799d1f8e20acbcb75b4d992d6388c48430556ef7b5b8530fefbdb4a6fa917ea818833c589e4f181c5014706ba8ba388a2cece674e6564ea92961567afe60c2d0b6a5271ff1950aa586a7588f301e1e4d44e7196872d32167e3462e188772ba579efcb67113f8bedc8ae41a86bacf29ad9771ab5e7f21c199551f0006de3f9ba2546914ea05ae93cf6bcdda7d57dfdc3d1d34dc81f2636fc1a461135cb2ffd2304ab1a504b7bd029ede0275e229c78739f8f0feac15cde7f3e49acc176b82768897d56a85859540bbea64e0dcf25e0fbef4c87c6019d604b6ddf97372af5fe51d0623235c29cb61d52a8ed26eae5f62b387d7f78f09a5f0ef046c231d678285c434a471fcc8713ee7067e968d6ec27da6780965acc5ab2d8db4dc2d7ad3b4c1e817177e8f42e2d552a2110e48d827d6740d8327ff3a0f075094b5d53febaaecec13e802c5614fa598c633c43e7dc7ae734edaf63e2f0cafe5876f033cf53c28396dd9cf4a45551c2ad6d17df30ff1d44fa07cb7fb34ee93257b56bb595544d07e16ee4a1b52e5fe8e6c04d4eb764632f0a228bf180d28f387c08cad01bcd67a6307d63e943175fd73f6f73190214f84101b57ad1dcd9753732a3bd02e7b56ed9944ad4cd965453b50935aaf81a75aab2e0f701eb9ac059c87d4f1cb4626ead6e2358845374f3298c0b61da8e217bb2c84214bb840649e64f4e79f222e4b8fe7b22c8a8e290f7eb5e3b48f827635b2b6d5890b73dd10f05f5c2600ada96c72596bd2e82ff7b4d15e306adb74dffcdc7bf89d935ff2187d3683a43f61b407ce46380cbd8f9507f3fe88d585e6bebf69867344e8da0066a09632f90a00589d92ba682fd8263ade85f25edcdea372602510a4f9c8f3224440a16d4a403b463471adef367cec0e9dfec17e93f3ced3e4355461999397b2825ad81f5d6ffcf0766853afdd1116e33654e0f592691b3d2728a1bcb24f2fff772101f085db985b841980b97cb355fbb89818d1241add3d6be5da386c6d0b65e121f67805bb356d7b04bab89fbe39d8a17fef52854500e3333af8703f47ca3639a9d2fc0d80e84802737fa8b2edda77a7b08546899144e7e26fe193424a90cc3b38c6432fa9d4d9460282cfe1b199933439d0b6675ddb20a6b8a34c5e8a8abc4959f7dff8bc52904b32ecc65216045f947b2a6a88469992dcd30ff50948a85a15b44ff394ec3d27f5c2e0997a23a5016ea44bcb676c77f8b673bf96b0c76b571e406b4ec1133fa6aa1e6269cd8f726808570f9ff4d98301a3c15170b8bbc2d0b4798b0cd2724eb60890ecb51685cbc625a6430a1b0a44f2396c525f6e880bd8c4279e2553e905d335329e926c725535b8dd14f76b12b0a5c361c0c28fa521d0144f5e39db5f4186e6ae58dd4d469e93ec7c21ff363bab7de7f804f638a9ac0d131283b3c52511ee3b22994842234bb67dddffa1a4f682b17e88de29f23ae5f1d52f237dded5821e04dfd6322364b44a044a766f234d4bc74ca52ce2c63572095d5e7632a822ea9cc110d5b202a67ee1bb1ed6a4ca1e1d1ac7c9621cca4ebf31df8d7fb9505e7063d4af77045d6ddcb3ae89293bd4bee6d30deda1391a0cd0af86658f907491137119ba448a4a2eb5773fc77b52619a5d3bad459690d5adec4f5f444c240abcfe2edc6e5d4dcd48ef52ee16b8a1dac320f97b079aeb64e55c0838ba1d6d5301419484b5c79dbd32e71485978cbff402c7f7b1977ed17a96638dc94a709749f4b5379ef24cc7166737689f6d4fde22d42fcdadd88a9b426e39d899c44a26aff98a32fb285325df201e44d858d7da92516514d5112f5d72d7a48c21010d4a2068f2e5242a69f53007d0798466801bd58f8e97c44c557aa9efd4854ac8e4dbe7991016eb3ae49d56ca4aea68e88e64d7e38b11ed753ecf924b631bad9044b2c080a574f17344bb4a41a911161905ee45b684a2fbaa858567f251ad589c8547570bf6b43d6a56ef3fda18bcfb9d9fc4005441474bb73bc2a3c2fcb089a1193b9151a019e1c283de11b25b0cbf6b8095c1dec21fc4bb5a6e1fac5df71314a66a9a9d5d06bafdd905fc2c18ab9b3eba66be5dac9393ee50dee2ab97ced41c369ce60fbb6d70cca800b3a953e7687ba03bb0cc06be647ea80fe5b3228fe60f6fcf032ecf202b42313ae8e8ea23f51d26340dca66c665364d6e9b29315a6d36a3f5136a86624f9f83166b358b1107a3287bb3be43b644730d4f39c261aaacd89cf1bfac3aba9836f805259a58ad66d304aab57bc00238e976bc8c005b4aed97cc5d55f8b761d2aa4fad2e7ed10a7fdd300dd02486ceedb7d25a3ea84d16f7e6c94cba625f5b9d0854b07cdbd0e28cb08f52252ac4b424eb43dec8f848bc1ecf11e2fe2ea82442fa3424b8c023954efef29522c91ace325c5ca749c5eb3815d40e610bf97db94fa76835317100e4b776c570f24b7aec1c00d47deef0f7313d5623f4778b7d33dd0826f800c5d3df106c31bf2ab584cb360a9d7fd257fb4c40de3833dde52e7e2ee38574ae9613e9627f65d7895c3f0c778530099a9a6a1e4e757c2832e0c3d6f0e595e10e4a5c28c343fe1070812009ba5c968cf4530b67f3b13402b4773544e44b827b3824fb49e17f4e932367cf1cc00f504879cc427a164b944c0d95a8ab942734339f72d0c7215af8fe81f3606c6e20bf093112de094b3649a78af7d488a8277b92bd76b3e3a52605b026fd4e4620fa0e9d437004ccca1ce9faaf47b49a15cfd6e087b2d5c2981cbf71924acbd9e852cf35410da3e89ab372308a274334bde1f6bec4e457d7843c70e710c22eaeb600eff50c7408bb1213526ff3b6c37b9756d02b90f8f1aabec7927ca59f3768250aac00ca52c331e956511d68a7d5ea4deed95af3d2e44a7879c2567305b14f6fe971336c2338f255ddf53f9c980c1d18cdb4513ef4199e941fbb04eaca71f78f08ca30233eee34cc14a76aa3b8925f5d4317035c8803e1a883a6834894a9f3687832e0a02c7d93d8b04f0887059f6156b2408cf455bdef8c5fbf3542f6e79999ac8841de26da200dbf865cf47fe99f0d097022683552e8fa2ea9f4195a8ee4be1b1388619ed35144104d2e681e2b42e3dd72cc3affa2e37b2f31fccc428a6d22cfa092326dfd8008a2a3746989a9f688541ec8cc9a5c4a3843e31d22b78fc2dd2beb8ccc9bd1feaaa9d5bc6ca0ca6f6cfea100ba7ae9be0b399e3c778835b5571568835827ee45ee758228bf30d7577ff3b5668437acb7006bca</script>\n <div class=\"hbe hbe-content\">\n <div class=\"hbe hbe-input hbe-input-default\">\n <input class=\"hbe hbe-input-field hbe-input-field-default\" type=\"password\" id=\"hbePass\">\n <label class=\"hbe hbe-input-label hbe-input-label-default\" for=\"hbePass\">\n <span class=\"hbe hbe-input-label-content hbe-input-label-content-default\">Hey, password is required here.</span>\n </label>\n </div>\n </div>\n</div>\n<script data-pjax src=\"/lib/hbe.js\"></script><link href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\">",
"tags": [
"life"
]
},
{
"id": "http://example.com/2023/03/28/2023-03-reading-record/",
"url": "http://example.com/2023/03/28/2023-03-reading-record/",
"title": "2023-03-reading-record",
"date_published": "2023-03-28T12:01:18.000Z",
"content_html": "<p>“人是由上百层皮组成的洋葱,是由许多线构成的织物”</p>\n<span id=\"more\"></span>\n<h3 id=\"大师和玛格丽特没看完不看了\"><a class=\"markdownIt-Anchor\" href=\"#大师和玛格丽特没看完不看了\">#</a> 《大师和玛格丽特》(没看完,不看了)</h3>\n<p>四星</p>\n<ul>\n<li>精彩的 trick!可读性很好,作者爱咏叹调式地描述场景,很调皮可爱,我很喜欢这种故弄玄虚地博君一笑的感觉。</li>\n<li>咋说呢,这有点像起点文,写到其他的一切都很好,写到大师和玛格丽特的爱情就开始不太好了…… 整本书最精彩的部分是前半本,撒旦与黑猫在莫斯科横行霸道做各种恶作剧,到后半本其实都有些无聊了。</li>\n</ul>\n<h3 id=\"暮色将近戴安娜阿西尔\"><a class=\"markdownIt-Anchor\" href=\"#暮色将近戴安娜阿西尔\">#</a> 《暮色将近》戴安娜・阿西尔 √</h3>\n<p>四星</p>\n<ul>\n<li>《暮色将近》和《一百年,很多人,很多事》都是时代相近的两位年长的女性来讲述人生故事的书。《暮色将近》的视角更加深入作者自己的人生,也许是因为同一时代东方教育始终强调美而不是逻辑,以及东方毕竟相对保守的原因,杨苡(《一百年许多人许多事》的作者,上月阅读)写书的方式总让人觉得有一层阴影蒙在上面 —— 事情为什么变成了这样?她为什么会走向这样的人生道路?我很想知道她对于这些问题的答案,也觉得如果她在年轻的时候思考这些问题,也许她的人生会很不一样。</li>\n<li>我们对于当代和我们共处的老年人,由于成长的时代导致的巨大差异,年轻人很少会把自己和老年人看成是同样的人,毕竟中国这近一百年来的变化太大了。而戴安娜出生的背景,她所受的教育已经称得上是现代教育,因此看她写的记录,就像是我八九十岁的时候会写下的东西。</li>\n</ul>\n<h3 id=\"荒原狼-黑塞\"><a class=\"markdownIt-Anchor\" href=\"#荒原狼-黑塞\">#</a> 《荒原狼》 黑塞 √</h3>\n<p>五星</p>\n<ul>\n<li>\n<p>说来真的很好笑,《德米安・彷徨少年时》长年累月地放在我的衣柜里,《悉达多》长年累月地放在我的床头柜上,但我甚至没有翻开过它们,黑塞的书作为我家的装饰物,不知道出于什么原因我一直和它们处于一种互不打扰的室友关系。因为黑塞在语文课本上出现过,我在之前甚至以为荒原狼是一种语文课本式的作品(中学的语文教育真的狠狠阻碍了我的阅读之路,没想到是 i 人发大疯。</p>\n</li>\n<li>\n<p>极致的阅读体验,我很少说 “极致” 这样的词语,但《荒原狼》它的确就是这样的…… 我说过陀思妥耶夫斯基是图书馆吧,他至少还是完全 “人类” 的范畴里的,而黑塞就是万花筒,每一章、每一段都在人类社会和野兽社会之间跳跃,黑塞是拥有理智的绝对的疯子,德国人我真是被你狠狠 shock 到了。。感觉像是被车创了,但是创的很爽,嗯上帝也是偶尔会创造一些这样的东西出现在这个世界上的!</p>\n</li>\n<li>\n<p>在故事进入到最后一部分的时候,也就是哈里(主角)进入狂人剧场的时候,黑塞开始无所顾忌、无忧无虑、超级中二、超级古典地发了一个超级大的疯…… 在进入魔术剧场以前,哈里至少披了一张人皮在社会边缘行走,在温水中和赫米娜、帕布洛、玛丽亚交流,然而一切准备都是为了魔术剧场的预热,在踏入剧场的时刻,哈里身上的人皮掉了,无数的哈里如同洋葱无数的皮一层层被剥掉、重组,在魔术剧场里杀戮、表演、演绎无数种可能性,这什么克苏鲁行为。。</p>\n</li>\n<li>\n<blockquote>\n<p>在这场战争中,每个因空间狭小而感到窒息的人,每个觉得生活枯燥无味的人,都在用激烈的方式宣泄他们的烦恼,力图将这个细弱无力的文明世界全面摧毁。我看见,每个人的眼中都坦诚地露出强烈的破坏欲和谋杀欲。我自己的双眼也像红色的野花,开的又高又大。我也哈哈大笑起来,兴高采烈地加入了战斗的行列。</p>\n</blockquote>\n<blockquote>\n<p>所有我曾爱过的姑娘,现在都属于我。每个人都给予我一些仅有她才能给予的东西,我也给她们每个人仅有她才懂获取的东西。我体验到了许多的爱、幸福与快感,当然也包括许多的困惑与痛苦。在这个梦幻的时刻,我人生中所有错失的爱情都在我的花园里神奇地绽放美丽的花朵,有的纯洁娇嫩,有的耀眼绚丽,有的神秘但很快凋零,这是跃动的快感,热忱的幻想,强烈的忧郁,可怕的死亡和光芒四射的重生。</p>\n</blockquote>\n<blockquote>\n<p>哦,我领悟了一切,理解了帕布罗,理解了莫扎特,听见他在我身后的某处可怕地大笑。我知道口袋里有成百上千颗生活游戏的棋子,因了解这场游戏的意义而感到激动万分。我愿意再次开始这场游戏,再次体验它的痛苦,再次因它的荒诞不经而战栗,再次并时常穿行于我内心的地狱。终有一天,我会更好地玩这场人生游戏。终有一天,我会学会笑。帕布罗在等着我,莫扎特在等着我。</p>\n</blockquote>\n</li>\n</ul>\n<h3 id=\"黑塞童话-黑塞\"><a class=\"markdownIt-Anchor\" href=\"#黑塞童话-黑塞\">#</a> 《黑塞童话》 黑塞 √</h3>\n<p>六星</p>\n<ul>\n<li>\n<p>当你需要一些宁静隽永美好的东西的时候,看《黑塞童话》。我和黑塞童话的调谐真真是一种命中注定…… 特别是当我看黑塞的第一本书是 1927 年写的《荒原狼》,完成体黑塞在中间呈现出来那种嗑嗨了淋漓尽致发了一个大疯的印象和《黑塞童话》里温柔如水的感性,就,形成了一种非常微妙的对比。</p>\n</li>\n<li>\n<p>童话是写给小孩看的东西,本质上是告诉小孩这个世界是什么样的一种途径,关于人类公认的正义、真理(智慧)、爱等正面的情感,当然也关于死亡、战争、负面的内容,从这个视角来看《黑塞童话》会觉得非常非常感动,因为黑塞呈现真理的那种方式是非常感性善良的,并且非常美和隽永。和别的给小孩子看的东西不同,黑塞的童话里特别描绘了” 永恒 “和” 自由 “(当然小孩子可能理解不了这些),故事的主人公往往有一个梦幻般的伊甸园内的童年、在善与恶 / 理想与现实 / 成功与失败之间挣扎的成年,最后往往会得到启示,达到没有善恶存在的彼世。</p>\n<blockquote>\n<p>“没有可以折返的路了,” 他认真又亲切地说到,“人啊,如果想要探究这个世界的奥秘,就必须一直向前进。那个有着棕色眼眸的女孩就是你一生中最美好的存在,而且,你离她越远,她就会变得越美好。不过话说回来,毕竟开船的是你,那就去你想去的地方吧。如果你愿意的话,我就把自己掌舵的位置让给你!”</p>\n</blockquote>\n<blockquote>\n<p>爱之存在,就跟死亡一样,是在履行作为人类的一种义务,是一个不允许再有任何后继变化的傍晚时分。</p>\n</blockquote>\n<blockquote>\n<p>曾经令他痛心的一切转眼之间便烟消云散。高山轰然倒下,这片土地陷落了,曾经是法尔多的地方如今已经是无边无际的大海,波涛汹涌,雷鸣电闪,绵延不绝。在这片海洋上方,太阳与繁星永恒更替。</p>\n</blockquote>\n</li>\n<li>\n<p>以下是本人非常喜欢的篇章(排名分先后)</p>\n<ul>\n<li>《法尔多》</li>\n<li>《笛梦》</li>\n<li>《小矮人》</li>\n<li>《来自另一个星球的奇异信息》</li>\n<li>《奥古斯都》</li>\n<li>《影子游戏》</li>\n<li>《伊里斯》</li>\n</ul>\n</li>\n</ul>\n",
"tags": [
"reading record"
]
},
{
"id": "http://example.com/2023/02/26/2023-02-reading-record/",
"url": "http://example.com/2023/02/26/2023-02-reading-record/",
"title": "2023-02-reading-record",
"date_published": "2023-02-26T06:19:38.000Z",
"content_html": "<p>二月阅读记录,关于过去的时代,两位女性:杨苡和波伏娃;关于心理学。</p>\n<span id=\"more\"></span>\n<h3 id=\"在西伯利亚森林中-西尔万泰松\"><a class=\"markdownIt-Anchor\" href=\"#在西伯利亚森林中-西尔万泰松\">#</a> 《在西伯利亚森林中》 - 西尔万・泰松 √</h3>\n<p>三星</p>\n<ul>\n<li>\n<p>来看镶黄旗法兰西贵族在西伯利亚冰原上的快乐生活(不是。西尔万是法国人,就是很尖酸刻薄又带一丝幽默这样,又很胆小,面对野蛮的俄罗斯人只有心里唯唯诺诺在日记里狂说坏话,在聚会的时候是回嘴都不敢的,毕竟是真的打不过嘛。</p>\n</li>\n<li>\n<p>本书是以日记的形式记录的,作者想到什么写什么,看起来很轻松,虽然给了三星但是作为消遣阅读很适合。</p>\n</li>\n<li>\n<blockquote>\n<p>我终于会知道,我是否具有内心生活。</p>\n</blockquote>\n</li>\n</ul>\n<h3 id=\"一百年许多人许多事-杨\"><a class=\"markdownIt-Anchor\" href=\"#一百年许多人许多事-杨\">#</a> 《一百年,许多人,许多事》 - 杨 √</h3>\n<p>五星</p>\n<ul>\n<li>\n<p>上面那位是假的天龙人,这位是真的天龙人啊,父是中国银行行长那种天龙人小姐,在饿殍遍地的时代可以上一学期的学费是家里用人一辈子的工资的女子学校,和政要财阀以及军阀的女儿们从小一起长大。旧时代天龙人讲述随着时代变迁家族发迹、衰落的历史,往前追溯到慈禧发迹,到天龙人小姐之父这一代开始衰落,父亲死后频频搬家,实在是有末代皇帝的既视感,天龙人小姐的哥小时候在家里的情景简直和末代皇帝一毛一样。</p>\n</li>\n<li>\n<p>让人难以忍受的是大家族的生活竟然如此无聊如此样板戏,大太太的生活只有整天麻将,大姨太被当作生育机器被杨家买入,生下天龙人小姐和其哥哥、姐姐;二姨太是不知道是谁送的丫头;大太太生育的女儿整天把 “我不和姨太太生的小孩一起玩” 挂在嘴边;而大姨太生育的儿子一出生就是属于大太太的,连照片也没法和儿子拍一张…… 这一切和晋江人(还是三流晋江人)的想象也太吻合了,这嫡庶长幼父父子子知否知否(不是)的一套,果然只有女儿们是可爱的,然而下场也最凄惨,红楼梦诚不欺我。</p>\n</li>\n<li>\n<p>本来是四星的,看完变成五星了。5555 我天真烂漫的天龙人小小姐,,,初恋也太好磕了。</p>\n</li>\n<li>\n<p>我想说:活着就是一种胜利!等我活过了所有人我就是最有发言权的!(虽然对于长寿也没有很多渴望。)</p>\n</li>\n</ul>\n<h3 id=\"女性与权力一份宣言\"><a class=\"markdownIt-Anchor\" href=\"#女性与权力一份宣言\">#</a> 《女性与权力:一份宣言》 √</h3>\n<p>四星</p>\n<ul>\n<li>一份政治小册子,很巧的是最近在看荷马史诗,作者刚好从荷马史诗开始引入,从人类结构上来说,古老的就是厌女的,像罗马啊希腊啊就是单纯把女的当作客体一样的人形的不具有理性、智慧和权力的群体。</li>\n<li>人类已知文明的政治结构几乎和性别权力都是紧密结合的,女权所呼吁的一个世界是理想的世界,这本册子里也提到了,重点其实不是把更多的女性放到男性的位置上去(like 武则天),而是创造一种新的权力结构(当然这份蓝图几乎是不可能会实现的),只能说理想很好但是可行性为 0 吧,做个女的就基本上先把自己当成一个人看就是很不错的修行了,但是看看还是可以的,作者思路很清晰。</li>\n</ul>\n<h3 id=\"中年之路-詹姆斯霍利斯-人终有一死\"><a class=\"markdownIt-Anchor\" href=\"#中年之路-詹姆斯霍利斯-人终有一死\">#</a> 《中年之路》 詹姆斯・霍利斯 - “人终有一死” √</h3>\n<p>五星</p>\n<ul>\n<li>\n<p>微博上看到的书的推荐,基本上就是荣格的一些理论糅杂作者的一些观点。中年之路和我脑子里一直以来的想法 “成人” 大概是一个意思。想要成为大人,但是不想做主流社会的大人,想要寻求自我边界的拓展,想要过有意义的生活。中年之路把人的一生分割成四个部分,童年、(按照外部要求工作结婚生子的)成年,(寻求真正自我的)中年,(等待死亡的)老年。很明显现在的我就是不用承担任何意义上的家庭责任所以一直在思考自我实现的事情,然而一个人没有收入和工作,又怎么谈自我实现呢。</p>\n</li>\n<li>\n<blockquote>\n<p>荣格曾经说过,除非我们能够将父母视为其他成年人,否则我们无法长大;父母在我们的生命中肯定是特别的,也许还曾受过伤,但最重要的是,他们只是那些踏上或者没踏上自己心灵旅程的人。</p>\n</blockquote>\n</li>\n<li>\n<blockquote>\n<p>但也许没有哪种社会结构像婚姻那样,承担了如此多无意识的包袱。在婚礼圣坛上,很少有人意识到自己的期望有多么巨大。没有人会大声说出那些巨大的期望:“我希望你让我的生活有意义。”“我希望你永远在我身边。”“我希望你能读懂我的心思,预知我所有的需要。”“我希望你能包扎我的伤口,填补我生命中的缺憾。”“我希望你能包扎我的伤口,填补我生命中的缺憾。”“我希望你能让我成为一个完整的人,治愈我受伤的灵魂。” 爱情以距离、想象和投射为食,婚姻则以邻近、在场和共通为饮。</p>\n</blockquote>\n</li>\n<li>\n<blockquote>\n<p>在痛苦中也许可以找到前进的道路。因为生命不是一种疾病,死亡也不是一种惩罚,因此不存在所谓的治愈。但确实有一条道路,可以通往更有意义,更丰富的生活。</p>\n</blockquote>\n</li>\n<li>\n<p>这本书很神奇的一点是,很多我在片段中模模糊糊思考的东西,在这本书中反复得到了印证,并且书里讲的东西比我片段思考(基于微博的碎碎念)条理清晰很多。很有意思的一本书。但是这本书的内容几乎就是再说:每个人都有成为神的义务。(这里的神指的是全面治愈过去的自己,并从这其中延伸出新的自己)</p>\n</li>\n</ul>\n<h3 id=\"成为波伏娃\"><a class=\"markdownIt-Anchor\" href=\"#成为波伏娃\">#</a> 《成为波伏娃》 √</h3>\n<p>五星</p>\n<ul>\n<li>\n<p>二月最佳!《成为波伏娃》讲了波伏娃从小到大的经历,从幼年时受到启示到成年时通过哲学教师考试、盛年研究存在主义和女性哲学,波伏娃的人生线性地集中在哲学事业上,真是羡慕这种从小就知道以后要干什么的人 QAQ。</p>\n</li>\n<li>\n<p>从这本书能看到,波伏娃的哲学理论和她的人生经历完完全全是贴合的。</p>\n</li>\n<li>\n<blockquote>\n<p>我有一种很确定的感觉,这种感觉很奇特,我感到自己内心极其丰富,而且这种丰富会留下痕迹,我将会说出被别人倾听的话,我的生活将会是一孔供他人不断汲取的泉水,我很确定这是我的使命。</p>\n</blockquote>\n<p>事实正如她所说的那样,尤其是在此地,每个对自身的位置有所犹疑的人都能从波伏娃向外展露的人生中寻找很多私人的体验共振,对于我们共同的困惑、共同的愤懑、共同的命题,波伏娃提供了一个精彩的演绎版本。</p>\n</li>\n<li>\n<blockquote>\n<p>真正的问题是:大千世界里,到底什么是我们应该去在意和有所为的呢?波伏瓦对于这个问题的答案是:我们的行动。因为只有行动是唯一属于你,且仅属于你一个人的,这是你成为你自己的方式。只有你能创造和维持连接你和他人的关系,不管那是好的还是坏的。[插图] 你和他人的关系并不是先天存在的,必须由你和他人一天一天地去创造以及再创造,有时候能够很好地发展下去,有的时候会被忽视,也有的时候会被滥用消亡。</p>\n</blockquote>\n<blockquote>\n<p>我们在生活中主要缺的就是这样的人,他们能驱使我们去做自己能做的事</p>\n</blockquote>\n<blockquote>\n<p>需要的不仅仅是理性的推理,还要有一颗渴望征服的心灵。因此我仍然想要做一个女性,也许我的头脑更男性化,但是我的情感仍然是女性化的</p>\n</blockquote>\n<blockquote>\n<p>很明显,波伏瓦看待爱、人生和幸福的方式和她父母截然不同。她拒绝不加思考地过活,不想在别人安排下做所谓正确的事情,读别人认为适合她读的书。1926 年,波伏瓦终于得出结论,她尊敬那些思考自己人生的人,既不是那些只思考的人,也不是那些只生活不思考的人。</p>\n</blockquote>\n</li>\n</ul>\n<h3 id=\"the-design-of-everyday-things\"><a class=\"markdownIt-Anchor\" href=\"#the-design-of-everyday-things\">#</a> 《The Design of Everyday Things》 √</h3>\n<p>四星</p>\n<ul>\n<li>古老的书,重点侧重在人机交互,但是很多的部分可以应用到写论文和设计自己的系统里。前半部分是通用的设计思路,后半部分是对当时一些产品的思考,尽管这本书已经有了一些历史,前四章还是很值得去借鉴思考的。</li>\n</ul>\n",
"tags": [
"reading record"
]
},
{
"id": "http://example.com/2023/01/18/2023-01-reading-record/",
"url": "http://example.com/2023/01/18/2023-01-reading-record/",
"title": "2023-01-reading-record",
"date_published": "2023-01-18T13:36:54.000Z",
"content_html": "<p>23 年的阅读主题是女性主义、工具书,比如妇科和写作,今年比起美和真的感受,想获取更多的知识。如果在阅读上述书以外还有精力,读陀思妥耶夫斯基和现代政治哲学的书。今年要阅读更多的英文资料,读关于写作的书并且积极写作业。</p>\n<p>一月的阅读计划没有看完蚂蚁之美,感觉错过了看它的年纪……</p>\n<span id=\"more\"></span>\n<h3 id=\"身体由我关于了不起的女性身体的一切\"><a class=\"markdownIt-Anchor\" href=\"#身体由我关于了不起的女性身体的一切\">#</a> 《身体由我:关于了不起的女性身体的一切》 √</h3>\n<p>四星,不给五星是因为作者的用药建议太过随便,以及里面太多过于传统的视角观点。</p>\n<ul>\n<li>知识即权力。</li>\n<li>希望我永远不会用到产程和产后修复的知识。</li>\n<li>* 我写这本书的目的之一是让更多人了解女性生殖系统知识,不过,他(丈夫)持相反的意见,认为还是保持女性的神秘感为好。* 笑死,好地狱的笑话。</li>\n<li>造成子宫肌瘤变大的原因:1. 肥胖 2. 使用避孕药,雌激素异常 ,针对 2,女性绝经之后子宫肌瘤会变少。</li>\n</ul>\n<h3 id=\"妇科圣经-伊丽莎白g斯图尔特\"><a class=\"markdownIt-Anchor\" href=\"#妇科圣经-伊丽莎白g斯图尔特\">#</a> 《妇科圣经》 伊丽莎白・G・斯图尔特 √</h3>\n<p>五星</p>\n<ul>\n<li>看了身体由我之后从零开始学习妇科知识,以便于以后妈妈或者我会用到。</li>\n<li>相比《身体由我》,这本书用词和建议都更加书面化,妇科圣经的前半本主要是科普阴部的构成、阴道的形状,后半本每一章详细说一种疾病。没有涉及到妊娠的部分,对于更年期和绝经的科普也比《身体由我》更加详细。</li>\n<li>什么叫知识越多越反动,看的妇科知识越多就越觉得…… 生理上养育小孩对女性的身体完全是伤害。</li>\n<li>由于众所周知的审查原因,很多图片没有放在中文书里面。</li>\n</ul>\n<h3 id=\"蚂蚁之美-冉浩\"><a class=\"markdownIt-Anchor\" href=\"#蚂蚁之美-冉浩\">#</a> 《蚂蚁之美》 冉浩</h3>\n<ul>\n<li>只有丁家桥有,但是买了实体的!和佛罗伦萨的神女配合食用,感觉是轻松的饭后甜点,可以对世界增加一些其他方面的了解!</li>\n</ul>\n<h3 id=\"十一月的此刻\"><a class=\"markdownIt-Anchor\" href=\"#十一月的此刻\">#</a> 《十一月的此刻》 √</h3>\n<p>三星</p>\n<ul>\n<li>作者描述的那种阴郁的农场非常像英格兰的氛围,翻到腰封上果然看到有人说像是美国的勃朗特三姐妹,蛮好笑的。 从笔力上来说太像太像太像十七八岁的中学生写的了,无聊的景物描写、极度浅显的人物张力、大量自怨自艾的青春期情绪,难道真的是作者年少的时候留下来的日记吗……</li>\n<li>美国人过的好幸福,看了下作者的困境只是来自农场有贷款。不太想看完了,不想看美国农村的恩怨情仇。</li>\n</ul>\n<h3 id=\"死屋手记\"><a class=\"markdownIt-Anchor\" href=\"#死屋手记\">#</a> 《死屋手记》√</h3>\n<ul>\n<li>感觉我现在到了最适合读陀的心智,也是一月读的最好的书,陀被称之为 “描绘人内心的全部深度” 真是名副其实,我像参观博物馆一样读陀,在一年半以前看卡拉马佐夫兄弟的时候被陀繁复的语言和巨大的精神洪流冲垮,完全没 get 到其中魅力(太贫弱了!),但是现在看死屋手记觉得体验非常非常好,冥冥之中从《地下室手记》到《死屋手记》,感觉还是一条合适我的阅读之路。死屋手记讲的是在西伯利亚流放的各种苦役犯、杀人犯的故事,各种神经病粉墨登场,乍一看甚至还蛮欢乐的,陀真的是从小到大我看到的对人性洞察最深的作者,可能另外老舍算一个,但陀…… 哎,太好了,反复品味,很值得购买一本实体书看。</li>\n</ul>\n<h3 id=\"佛罗伦萨的神女\"><a class=\"markdownIt-Anchor\" href=\"#佛罗伦萨的神女\">#</a> 《佛罗伦萨的神女》√</h3>\n<ul>\n<li>\n<p>透过翻译能看出如果是英语应该会很精妙,独裁的君王以为自己是万物的化身,自恋到极致以至于幻想出不存在的皇后,用复数的 “我” 称呼自己,目前的故事很有趣,这本很适合睡前看。但是我还是要说,翻译除了名字翻得不错以外就是一坨屎。。。</p>\n</li>\n<li>\n<p>好神奇的阅读体验,人可以创造成真的幻想,反过来也可以将自己送入梦中。</p>\n</li>\n<li>\n<blockquote>\n<p>当你被你生命中的悲惨事件麻醉时,你到能够活下来。但你意识清醒过后,当你千辛万苦地认识到那一切时,它可以逼得你发疯。你那觉醒的记忆可以使你失去理智,那种屈辱的受到这么多折磨、这么多侵犯的记忆,也就是对男人的记忆。那不是记忆之宫,那是记忆的妓院,在这些记忆后面的是,你还知道疼爱你的那些人已经不在人世,你无法逃脱这一切。知道这些事可以使你站起身,振作起来跑掉。假如你跑的够快,你有可能逃脱你的过去,以及对别人加之于你的往事的回忆,还能够逃脱未来那无法摆脱的凄惨命运。有没有兄弟来救你呢?没有,你的兄弟都死去了。也许,这个世界本身也死去了把。是的,是死去了。作为死去的世界的一部分,你也必须死去。你必须尽量快跑,抵达生死两个世界的交界处,你没有停下脚步,空气就是玻璃,在你落下去时,空气在你身边像玻璃一样破碎了。空气像利刃一样把你割成碎片。落下去很好。很好。</p>\n</blockquote>\n</li>\n<li>\n<p>一个神秘宏大的谜面,一个乏味可陈的谜底。作者讲述故事的技巧很精巧,一切的开始是一切的结束之后,骗子向国王讲述从铁木真王国辗转到波斯、土耳其和佛罗伦萨的神女,能够征服任何帝王的神女当然也借骗子之口被当今的帝王所爱。可惜最后的谜底还挺无聊的,而且,“记忆之宫” 之于神女,白骨精床垫之于安吉莉卡和影子姑娘,焦哈特和佛罗伦萨的 top 妓女(忘记什么名字了),太多雕琢的地方反而损失了这本书的魅力。鲁西迪和马尔克斯终究还是不一样的。鲁西迪在去年遇刺,联系他的政治背景,大概明白为什么佛罗伦萨的神女会以那样的结局收尾。</p>\n</li>\n</ul>\n<h3 id=\"你的夏天还好吗-金爱烂\"><a class=\"markdownIt-Anchor\" href=\"#你的夏天还好吗-金爱烂\">#</a> 《你的夏天还好吗》 金爱烂 √</h3>\n<p>五星</p>\n<ul>\n<li>\n<p>这是我看的第一本韩国的小说,由八个短篇小说组成,在去水果市场的路上随意打开第一个故事,立刻明白为什么金爱烂会被称之为天才作家(我之前一直觉得韩国没什么文学),每一个都看的我起鸡皮疙瘩。以我个人的体验来说,敏感的心对于当代生活是一种负累,成倍地感受到爱的同时也会成倍地感受到痛苦,而金爱烂的敏感简直让我觉得同情,不做作家的话一定会生活的非常痛苦。从生活中提纯出痛苦、贫穷、失望、窘迫,用梦幻的语言描述灰暗的人生,每一个主人公就像在没有方向的救生艇上,在茫茫大海中越走越远,不知该往何处,手里握着的与其说是未来不如说是仅有的希望,而那希望多半也是假的。</p>\n</li>\n<li>\n<p>《水中的歌利亚》,最具神性的一篇。</p>\n<blockquote>\n<p>母亲像广告气球似的沿着水波流向远方。我感觉一张缠满绿色胶带的脸久久地注视着我。大树似乎让我不用担心,化作多臂的神灵,用树根托起母亲,消失在尽头。</p>\n</blockquote>\n<blockquote>\n<p>圆中的圆中的圆…… 很久以前,比这更久以前,以和现在相同的形状落下的圆;允许我们的受动性,命令我们的被动性,在我们的主语上掀起美丽波纹的圆;非常吵闹的圆。描画着雨点弥漫开去的样子,奇怪的是,我内心的某种东西也随之翻滚,感觉好像可以理解世界了。</p>\n</blockquote>\n</li>\n<li>\n<p>《角质层》,金爱烂太会写东亚女的缺爱了,因为对爱的渴望而进行消费,尽管只能获得很短暂的慰藉,但就像癌症的靶向药一样,尽管吃了有很多的副作用,但是不吃会死。很多人终其一生追求的其实是母爱。看完觉得很寂寞。</p>\n<blockquote>\n<p>淡淡的困意袭来,某个瞬间,我忽然心生冲动:“我想做护理,我想做保养,我希望有人永远像现在这样照顾我。” 有人长时间耐心地摆弄我,装饰我,爱惜我,我感觉自己似乎变小了许多,好像蜷缩起来,谁在这个安乐的世界里。</p>\n</blockquote>\n<blockquote>\n<p>尽管这只是老板娘为了讨顾客欢心而随口说说,然而我的脑海里还是浮现出一群女人,像站在河边的小鹿一样虔诚地互相舔舐对方的鹿角,以及从指尖无限延伸的十个美丽的长角。</p>\n</blockquote>\n</li>\n</ul>\n<h3 id=\"the-phd-grind\"><a class=\"markdownIt-Anchor\" href=\"#the-phd-grind\">#</a> 《The phd grind》</h3>\n<ul>\n<li>记录了作者在斯坦福读博的六年,作者是二代移民来着,硕士在 MIT 念的,可能是真心热爱学术吧,如果我是阿美二代移民妈妈还有终身教职以及 MIT 的硕士我肯定不会再继续读博了…… 斯坦福的科研氛围和待遇好好啊,但是独自去开拓一个方向还是非常艰辛,印象很深的是作者说做科研最重要的还是和老师、同门多交流合作(目前看到第三年),科研没法在真空之中诞生。</li>\n</ul>\n",
"tags": [
"reading record"
]
},
{
"id": "http://example.com/2023/01/14/Paper-ATC-2022-GPULet/",
"url": "http://example.com/2023/01/14/Paper-ATC-2022-GPULet/",
"title": "Paper-ATC'2022-GPULet",
"date_published": "2023-01-14T13:16:46.000Z",
"content_html": "<p>link: <a href=\"https://www.usenix.org/conference/atc22/presentation/choi-seungbeom\">Serving Heterogeneous Machine Learning Models on Multi-GPU Servers with Spatio-Temporal Sharing | USENIX</a></p>\n<span id=\"more\"></span>\n<center>\n<img src=\"/2023/01/14/Paper-ATC-2022-GPULet/system-overview.jpg\" style=\"padding:5px; display:inline;\" width=\"90%\">\n</center>\n<h3 id=\"abstract\"><a class=\"markdownIt-Anchor\" href=\"#abstract\">#</a> Abstract</h3>\n<p>本文以<strong>最大化资源利用率</strong>和<strong>任务吞吐量</strong>为目标,为多模型推断的 GPU 集群实现了一个在线推断请求调度框架,在物理 GPU 与在线的请求之间设计了 GPULet Scheduler 工具来将 GPU 的计算资源分割成 GPULet,在分割计算资源时,本文综合考虑了<strong>时间</strong>、<strong>空间</strong>上的 GPU 资源,以及每次处理请求的<strong>批次</strong>大小,并且将搜索成本降低到了实际的在线系统可接受的范围。该系统在处理多 DNN 场景时能够<strong>自发调节使用的 GPU 个数</strong>以节约资源,另外,该系统额外考虑到了不同的 DNN Model 在 GPU 上的并行推断产生的冲突问题,建立了干扰预测模型。</p>\n<h3 id=\"introduction\"><a class=\"markdownIt-Anchor\" href=\"#introduction\">#</a> Introduction</h3>\n<p>CPU 上下文切换的速度是微秒级别,而 GPU 是毫秒的级别。</p>\n<h3 id=\"background\"><a class=\"markdownIt-Anchor\" href=\"#background\">#</a> Background</h3>\n<p>在 Background 章节,作者从三个维度阐述了提高 GPU 利用率的方法。</p>\n<ul>\n<li>\n<p>Batching-Aware ML Inference Serving</p>\n<p>与预先加载好数据的模型训练相比,模型推断不能实现 GPU 资源的高利用率的原因是在在线推断场景中,推断请求是在线产生的。人为地设置 GPU 处理推断任务时的批次大小,可以提高 GPU 内核的利用率。</p>\n</li>\n<li>\n<p>Temporal Scheduling for ML on GPUs</p>\n<p>作者介绍了<strong> Nexus</strong>,通过将 GPU 资源在时间上分片提供给不同批大小的模型来提高 GPU 的利用效率。</p>\n<p><strong>Nexus</strong> 采用<strong> SBP</strong> 算法。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/temporal-sharing.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Spatial Sharing on GPU</p>\n<p>作者介绍了<strong> GSLICE</strong>,它的逻辑是根据推断结果的反馈来调整各个分区的资源占比,确定资源占比后启发式地调整批处理的大小,但 GSLICE 只针对单个 GPU。</p>\n</li>\n</ul>\n<p>本文的目标是在<strong>空间</strong>、<strong>时间</strong>以及<strong>批次大小</strong>三维的基础分割 GPU 资源实现<strong>最大化资源利用率</strong>和<strong>最小化使用 GPU</strong>。作者在 background 章节另外提出了本文的两个 baseline,分别是时间 baseline 的<strong> SBP</strong> 算法和空间 baseline 的<strong> Greedy best-fit</strong> 算法。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/t-s.jpg\" width=\"80%\">\n</center>\n<h3 id=\"motivation\"><a class=\"markdownIt-Anchor\" href=\"#motivation\">#</a> Motivation</h3>\n<ul>\n<li>\n<p>Pre-Experiment-1:推断任务的最佳<strong>批</strong>大小与 GPU 的<strong>空间分区</strong>之间存在紧密的联系。</p>\n<p>作者选取不同的模型</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig4.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Pre-Experiment-2:<strong>时 / 空 / 批</strong>三维的搜索空间得到的推断任务调度最优解比<strong>时 / 批</strong>二维的搜索空间得到的推断任务调度最优解更优。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/3d-search.jpg\" width=\"80%\">\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig5.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Pre-Experiment-3:在<strong>有效分割</strong>的前提下,时空 GPU 资源调度可以有效提高 GPU 的资源利用率,提高系统的吞吐量。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig6.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Pre-Experiment-4:<strong>不同</strong>的 Model 同时在一个 GPU 上进行推断任务时,由于存在<strong>资源争用</strong>问题,并行执行可能会存在额外的<strong>干扰</strong>开销。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig7.jpg\" width=\"80%\">\n</center>\n</li>\n</ul>\n<h3 id=\"design\"><a class=\"markdownIt-Anchor\" href=\"#design\">#</a> Design</h3>\n<ul>\n<li>\n<p>GPULet</p>\n<p>为了给不同的模型分配的 GPU 资源,作者引入了<strong> Gpulet</strong>,Gpulet 是建立在物理 GPU 上的一个虚拟的 GPU,它是 GPU 在<strong>空间</strong>和<strong>时间</strong>上分配的计算资源的集成。</p>\n<blockquote>\n<p>For each trained ML model, a minimal performance profile is collected offline.</p>\n</blockquote>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/gpulet.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Overview</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig8.jpg\" width=\"80%\">\n</center>\n<p><strong>Request Monitor:<strong>监视不同 Model 的 Request 频率,作为调度器调度的</strong>参考变量</strong>之一。</p>\n<p>**Gpulet Scheduler:** 综合配置文件中不同 Model 的时延、SLO 要求、Request 的到达频率,决定</p>\n<ul>\n<li>该 Model 的 Request 以何种<strong>批次大小</strong>执行。</li>\n<li>该 Model 的 Request 在<strong>哪块 GPU</strong> 上执行。</li>\n<li>该 Model 的 Request 在 GPU 的<strong>空间分区、时间分区</strong>的资源占用情况。</li>\n</ul>\n<p>**Partition Manager:** 实现 GPU 的分区,并且周期性的根据 Request 的 Rate 进行调整。</p>\n<p>**Executor:** 实现 Scheduler 的决策,将 Request 分配到不同的 Gpulet 上执行。</p>\n</li>\n<li>\n<p>Challenge-1: Achieve Cost-effective scheduling</p>\n<p>本文实现的核心调度算法,目标是<strong>最大化系统的吞吐量</strong>的同时<strong>最小化资源消耗</strong>。相比二维的情况,三维显著增加了调度的搜索空间,因此作者引入了配置文件,记录了 Model 在不同的 batch size 下不同的<strong> Gpu 空间分区</strong>的时延大小。</p>\n</li>\n<li>\n<p>Challenge-2: Dynamic reorganization</p>\n<p>当 Model 的 Request Rate 发生变化时,触发 GPULet 的<strong>重新调度</strong>。在 Gpu 上实现新的分区需要一定的代价开销,原文引用如下。解决的方法是周期性地</p>\n<blockquote>\n<p>Preparing a new partition includes spawning a new process, loading kernels used by PyTorch, loading required models, and warming up.</p>\n</blockquote>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig11.jpg\" width=\"80%\">\n</center>\n</li>\n<li>\n<p>Challenge-3: Interference prediction</p>\n<p>量化不同的模型在同一个物理的 GPU 上并行处理时的<strong>时延干扰损失</strong>,作者在衡量多个因素后选取了两个重要因素,通过<strong>线性回归</strong>判定 Model A 和 Model B 在同一块物理 GPU 上并行执行时的时延的<strong>额外开销</strong>,实验证明该错误率在 10% 左右。</p>\n<center>\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/interference.jpg\" width=\"80%\">\n <img src=\"/2023/01/14/Paper-ATC-2022-GPULet/fig10.jpg\" width=\"80%\">\n</center>\n</li>\n</ul>\n<h3 id=\"evaluation\"><a class=\"markdownIt-Anchor\" href=\"#evaluation\">#</a> Evaluation</h3>\n<h3 id=\"conclusion\"><a class=\"markdownIt-Anchor\" href=\"#conclusion\">#</a> Conclusion</h3>\n",
"tags": [
"paper"
]
},
{
"id": "http://example.com/2023/01/14/reading-list/",
"url": "http://example.com/2023/01/14/reading-list/",
"title": "reading list",
"date_published": "2023-01-14T12:14:36.000Z",
"content_html": "<p>[摘自网络]</p>\n<span id=\"more\"></span>\n<h3 id=\"frameworks\"><a class=\"markdownIt-Anchor\" href=\"#frameworks\">#</a> <strong>Frameworks</strong></h3>\n<ul>\n<li>[VLDB '20] PyTorch Distributed: Experiences on Accelerating Data Parallel Training</li>\n<li>[NeurIPS '19] PyTorch: An Imperative Style, High-Performance Deep Learning Library</li>\n<li>[OSDI '18] Ray: A Distributed Framework for Emerging AI Applications</li>\n<li>[OSDI '16] TensorFlow: A System for Large-Scale Machine Learning</li>\n</ul>\n<h3 id=\"parallelism-distributed-systems\"><a class=\"markdownIt-Anchor\" href=\"#parallelism-distributed-systems\">#</a> <strong>Parallelism & Distributed Systems</strong></h3>\n<ul>\n<li>[OSDI '22] Unity: Accelerating DNN Training Through Joint Optimization of Algebraic Transformations and Parallelization</li>\n<li>[EuroSys '22] Varuna: Scalable, Low-cost Training of Massive Deep Learning Models</li>\n<li>[SC ‘21’] Chimera: Efficiently Training Large-Scale Neural Networks with Bidirectional Pipelines</li>\n<li>[ICML '21] PipeTransformer: Automated Elastic Pipelining for Distributed Training of Large-scale Models</li>\n<li>[OSDI '20] A Unified Architecture for Accelerating Distributed DNN Training in Heterogeneous GPU/CPU Clusters</li>\n<li>[ATC '20] HetPipe: Enabling Large DNN Training on (Whimpy) Heterogeneous GPU Clusters through Integration of Pipelined Model Parallelism and Data Parallelism</li>\n<li>[NeurIPS '19] GPipe: Efficient Training of Giant Neural Networks using Pipeline Parallelism</li>\n<li>[SOSP '19] A Generic Communication Scheduler for Distributed DNN Training Acceleration</li>\n<li>[SOSP '19] PipeDream: Generalized Pipeline Parallelism for DNN Training</li>\n<li>[EuroSys '19] Parallax: Sparsity-aware Data Parallel Training of Deep Neural Networks</li>\n<li>[arXiv '18] Horovod: fast and easy distributed deep learning in TensorFlow</li>\n<li>[ATC '17] Poseidon: An Efficient Communication Architecture for Distributed Deep Learning on GPU Clusters</li>\n<li>[EuroSys '16] STRADS: A Distributed Framework for Scheduled Model Parallel Machine Learning</li>\n<li>[EuroSys '16] GeePS: Scalable Deep Learning on Distributed GPUs with a GPU-specialized Parameter Server</li>\n<li>[OSDI '14] Scaling Distributed Machine Learning with the Parameter Server</li>\n<li>[NIPS '12] Large Scale Distributed Deep Networks</li>\n</ul>\n<h3 id=\"gpu-cluster-management\"><a class=\"markdownIt-Anchor\" href=\"#gpu-cluster-management\">#</a> <strong>GPU Cluster Management</strong></h3>\n<ul>\n<li>[OSDI '22] Looking Beyond GPUs for DNN Scheduling on Multi-Tenant Clusters</li>\n<li>[NSDI '22] MLaaS in the Wild: Workload Analysis and Scheduling in Large-Scale Heterogeneous GPU Clusters</li>\n<li>[OSDI '21] Pollux: Co-adaptive Cluster Scheduling for Goodput-Optimized Deep Learning</li>\n<li>[NSDI '21] Elastic Resource Sharing for Distributed Deep Learning</li>\n<li>[OSDI '20] Heterogeneity-Aware Cluster Scheduling Policies for Deep Learning Workloads</li>\n<li>[OSDI '20] AntMan: Dynamic Scaling on GPU Clusters for Deep Learning</li>\n<li>[NSDI '20] Themis: Fair and Efficient GPU Cluster Scheduling</li>\n<li>[EuroSys '20] Balancing Efficiency and Fairness in Heterogeneous GPU Clusters for Deep Learning</li>\n<li>[NSDI '19] Tiresias: A GPU Cluster Manager for Distributed Deep Learning</li>\n<li>[ATC '19] Analysis of Large-Scale Multi-Tenant GPU Clusters for DNN Training Workloads</li>\n<li>[OSDI '18] Gandiva: Introspective cluster scheduling for deep learning</li>\n</ul>\n<h3 id=\"memory-management-for-machine-learning\"><a class=\"markdownIt-Anchor\" href=\"#memory-management-for-machine-learning\">#</a> <strong>Memory Management for Machine Learning</strong></h3>\n<ul>\n<li>[ATC '22] Memory Harvesting in Multi-GPU Systems with Hierarchical Unified Virtual Memory</li>\n<li>[MobiSys '22] Memory-efficient DNN Training on Mobile Devices</li>\n<li>[HPCA '22] Enabling Efficient Large-Scale Deep Learning Training with Cache Coherent Disaggregated Memory Systems</li>\n<li>[ASPLOS '20] Capuchin: Tensor-based GPU Memory Management for Deep Learning</li>\n<li>[ASPLOS '20] SwapAdvisor: Push Deep Learning Beyond the GPU Memory Limit via Smart Swapping</li>\n<li>[ISCA '19] Interplay between Hardware Prefetcher and Page Eviction Policy in CPU-GPU Unified Virtual Memory</li>\n<li>[ISCA '18] Gist: Efficient Data Encoding for Deep Neural Network Training</li>\n<li>[PPoPP '18] SuperNeurons: Dynamic GPU Memory Management for Training Deep Neural Networks</li>\n<li>[MICRO '16] vDNN: Virtualized Deep Neural Networks for Scalable, Memory-Efficient Neural Network Design</li>\n</ul>\n<h3 id=\"scheduling-resource-management\"><a class=\"markdownIt-Anchor\" href=\"#scheduling-resource-management\">#</a> <strong>Scheduling & Resource Management</strong></h3>\n<ul>\n<li>[arXiv '22] EasyScale: Accuracy-consistent Elastic Training for Deep Learning</li>\n<li>[MLSys '22] VirtualFlow: Decoupling Deep Learning Models from the Underlying Hardware</li>\n<li>[SIGCOMM '22] Multi-resource interleaving for deep learning training</li>\n<li>[EuroSys '22] Out-Of-Order BackProp: An Effective Scheduling Technique for Deep Learning</li>\n<li>[ATC '21] Zico: Efficient GPU Memory Sharing for Concurrent DNN Training</li>\n<li>[NeurIPS '20] Nimble: Lightweight and Parallel GPU Task Scheduling for Deep Learning</li>\n<li>[OSDI’ 20] KungFu: Making Training in Distributed Machine Learning Adaptive</li>\n<li>[OSDI '20] PipeSwitch: Fast Pipelined Context Switching for Deep Learning Applications</li>\n<li>[MLSys '20] Salus: Fine-Grained GPU Sharing Primitives for Deep Learning Applications</li>\n<li>[SOSP '19] Generic Communication Scheduler for Distributed DNN Training Acceleration</li>\n<li>[EuroSys '18] Optimus: An Efficient Dynamic Resource Scheduler for Deep Learning Clusters</li>\n<li>[HPCA '18] Applied Machine Learning at Facebook: A Datacenter Infrastructure Perspective</li>\n</ul>\n<h3 id=\"serving-systems-inference-acceleration\"><a class=\"markdownIt-Anchor\" href=\"#serving-systems-inference-acceleration\">#</a> <strong>Serving Systems (& inference acceleration)</strong></h3>\n<ul>\n<li>[EuroSys '23] Fast and Efficient Model Serving Using Multi-GPUs with Direct-Host-Access</li>\n<li>[MICRO '22] DFX: A Low-latency Multi-FPGA Appliance for Accelerating Transformer-based Text Generation</li>\n<li>[ATC '22] Serving Heterogeneous Machine Learning Models on Multi-GPU Servers with Spatio-Temporal Sharing</li>\n<li>[OSDI '22] Orca: A Distributed Serving System for Transformer-Based Language Generation Tasks</li>\n<li>[OSDI '22] Achieving μs-scale Preemption for Concurrent GPU-accelerated DNN Inferences</li>\n<li>[ATC '21] INFaaS: Automated Model-less Inference Serving</li>\n<li>[OSDI '20] Serving DNNs like Clockwork: Performance Predictability from the Bottom Up</li>\n<li>[ISCA '20] MLPerf Inference Benchmark</li>\n<li>[SOSP '19] Nexus: A GPU Cluster Engine for Accelerating DNN-Based Video Analysis</li>\n<li>[ISCA '19] MnnFast: a fast and scalable system architecture for memory-augmented neural networks</li>\n<li>[EuroSys '19] μLayer: Low Latency On-Device Inference Using Cooperative Single-Layer Acceleration and Processor-Friendly Quantization</li>\n<li>[EuroSys '19] GrandSLAm: Guaranteeing SLAs for Jobs in Microservices Execution Frameworks</li>\n<li>[OSDI '18] Pretzel: Opening the Black Box of Machine Learning Prediction Serving Systems</li>\n<li>[NSDI '17] Clipper: A Low-Latency Online Prediction Serving System</li>\n</ul>\n<h3 id=\"deep-learning-compiler\"><a class=\"markdownIt-Anchor\" href=\"#deep-learning-compiler\">#</a> <strong>Deep Learning Compiler</strong></h3>\n<ul>\n<li>[PLDI '21] DeepCuts: A Deep Learning Optimization Framework for Versatile GPU Workloads</li>\n<li>[OSDI '18] TVM: An Automated End-to-End Optimizing Compiler for Deep Learning</li>\n</ul>\n<h3 id=\"very-large-models\"><a class=\"markdownIt-Anchor\" href=\"#very-large-models\">#</a> <strong>Very Large Models</strong></h3>\n<ul>\n<li>[arxiv '21] ZeRO-Infinity: Breaking the GPU Memory Wall for Extreme Scale Deep Learning</li>\n<li>[ATC '21] ZeRO-Offload: Democratizing Billion-Scale Model Training</li>\n<li>[FAST '21] Behemoth: A Flash-centric Training Accelerator for Extreme-scale DNNs</li>\n</ul>\n<h3 id=\"deep-learning-recommendation-models\"><a class=\"markdownIt-Anchor\" href=\"#deep-learning-recommendation-models\">#</a> <strong>Deep Learning Recommendation Models</strong></h3>\n<ul>\n<li>[OSDI '22] FAERY: An FPGA-accelerated Embedding-based Retrieval System</li>\n<li>[OSDI '22] Ekko: A Large-Scale Deep Learning Recommender System with Low-Latency Model Update</li>\n<li>[EuroSys '22] Fleche: An Efficient GPU Embedding Cache for Personalized Recommendations</li>\n<li>[ASPLOS '22] RecShard: statistical feature-based memory optimization for industry-scale neural recommendation</li>\n<li>[HPCA '22] Hercules: Heterogeneity-Aware Inference Serving for At-Scale Personalized Recommendation</li>\n<li>[MLSys '21] TT-Rec: Tensor Train Compression for Deep Learning Recommendation Model Embeddings</li>\n<li>[HPCA '21] Tensor Casting: Co-Designing Algorithm-Architecture for Personalized Recommendation Training</li>\n<li>[HPCA '21] Understanding Training Efficiency of Deep Learning Recommendation Models at Scale</li>\n<li>[ISCA '20] DeepRecSys: A System for Optimizing End-To-End At-scale Neural Recommendation Inference</li>\n<li>[HPCA '20] The Architectural Implications of Facebook’s DNN-based Personalized Recommendation</li>\n<li>[MICRO '19] TensorDIMM: A Practical Near-Memory Processing Architecture for Embeddings and Tensor Operations in Deep Learning</li>\n</ul>\n<h3 id=\"hardware-support-for-ml\"><a class=\"markdownIt-Anchor\" href=\"#hardware-support-for-ml\">#</a> <strong>Hardware Support for ML</strong></h3>\n<ul>\n<li>[ISCA '18] A Configurable Cloud-Scale DNN Processor for Real-Time AI</li>\n<li>[ISCA '17] In-Datacenter Performance Analysis of a Tensor Processing Unit</li>\n</ul>\n<h3 id=\"ml-at-mobile-embedded-systems\"><a class=\"markdownIt-Anchor\" href=\"#ml-at-mobile-embedded-systems\">#</a> <strong>ML at Mobile & Embedded Systems</strong></h3>\n<ul>\n<li>[MobiCom '20] SPINN: Synergistic Progressive Inference of Neural Networks over Device and Cloud</li>\n<li>[RTSS '19] Pipelined Data-Parallel CPU/GPU Scheduling for Multi-DNN Real-Time Inference</li>\n<li>[ASPLOS '17] Neurosurgeon: Collaborative Intelligence Between the Cloud and Mobile Edge</li>\n</ul>\n<h3 id=\"ml-techniques-for-systems\"><a class=\"markdownIt-Anchor\" href=\"#ml-techniques-for-systems\">#</a> <strong>ML Techniques for Systems</strong></h3>\n<ul>\n<li>[ICML '20] An Imitation Learning Approach for Cache Replacement</li>\n<li>[ICML '18] Learning Memory Access Patterns</li>\n</ul>\n",
"tags": [
"MLsys"
]
},
{
"id": "http://example.com/2023/01/01/my-2022/",
"url": "http://example.com/2023/01/01/my-2022/",
"title": "my-2022",
"date_published": "2023-01-01T08:50:13.000Z",
"content_html": "<div class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"Oh, this is an invalid password. Check and try again, please.\" data-whm=\"OOPS, these decrypted content may changed, but you can still have a look.\">\n <script id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"6a4b5f8fe3a0c5526c664d2c58670532869037695f241a48c24502bc8abcc746\">4f9de7028b481e695d9f95a34c356ed9629bb1f222233ae7c7fdf8fa65bdf715f762df2474dadb8a6111178d3ec15446f0211cfb8d5a53e6be89117877ade3f2beb54b40fe52a11f9369c527f430cb03cbed8387d00b5eb91ae31e963222456aaf52845d6eb6bf386379dc41a5f879f852c777d4cd9ff51816866fd2ed39b809ee06127665391b5df2438836a53edfc4e8ab6ad733e3e8cf2107ad63906a06245ddde2ef4eb650a298e161ba79dd8f6c7787fa306c5a7fbcf2a69d41fcea62b894ea74bb25d60b57856b5fce0cf2b51cd3501e8a74f674e2d3ea0e1b387dc8028c7b4794009cf5f40647d87cbafb962cc764dc382745d5bf55b5bad4f057acfab569bf3d2e28da533242ee89289bbad9605283fd3c55ca5b06f27f077fc2f984edd3e64148cdcff61283857d517452feaca5918f4a7017284f29347f47c3404696b0540cbbc8abaa944df85f47414854dd2a862fa5bbb3ee3fd249d185fa3c098707c09f92d3875f0716b71af50d99375ca23f1bbae4475a50f7210183d530740c2c3a0da1412d57f962144066e4c1cb7647d53aec67bd14896aae1b0f887582a3af2fbf919acbc8939aadf76a98032d6d246b68590555496e82b2f8e44f123938994a14a7146d08625f0bffe65a50448de71516430f63c55d158f8a2226add76cc656177069eb09960cc1f0ae24a7095b4f1c6902a868388f041705b8b3d2d27136f7640562295d87135c549a0a468a5c29764954b16c2c6a7122b1c65179c8df70b9e16290a40d4d3af3220c02579469173c508297f60b5dbfe68cbc5467f5e91738cacc419dc86f1ffae8db625531aaaa41cbcd1a5aafc0c2afcbe00078dbe12af1a9d9d65ebaf3f0e5c93217a46174f418f4c5c9c905141d7e51d39867fe78a2f3fa972556571d86ff2b6df98ffa757b99b10d98ec2393e368c498cf79bde18da02c1b1aaba958d074c6beefe5e24a320881dd00b0762a47d5993ff40dca25661e72c85ff470a117c5fc2d423a32155a5ea5b0941c259712fe4203231f0ec774a1a865591b4fa00f657cb872c5657964f3082e903f018bbe188f5d736a5ffc1d6aa205a139d82912eb53ffac876cf4ab391f462a3ab7efc96b2057400a4f89389d05057687d7fa20fb020b441652a04ebfbb11ef1f6e9cc520e48c0bf75e9ce48fbbf38755a80813293f87c358b92114168b6aa7b476af96e95c78f64b8a3d83764903559e302c902c77d0c8a4ecdcaf86f8743790e04ca5dde6e34edec45cf84d26b7219d9f0ae3b4c0000dc3adf559f09c331e2a0d7d9f7260e5fcbba7bcdb12d5936c537846cbe639cc2bf338b8508e57e53f050aefc97bf7bed4f9ae21b427b1f87d126b8ddcb7a2dbdac8fc15103f102b50dd146af83a7099a87e5cdcac76254eac309ed18c9fb6d1ddbdfcd56b2a73090eb0752c3025d25872c54a7b5c499180914080d18470c91e1f8b5605180dd5a78ead7a53350d95cccf34e1cc5baac0ccd6f1e3102d4f64494af212986d278cf5226a81a442150d8b8b0889bb08e6e778d6726faf6663ec342590204dc11b621f09f654b833e085c428336a26eb49006d75bbcbdaeb86bf8c5323a95307461df70fff4c600e9950ba53c1b53d23531d180ffa4a33dff7ca383b0eac344a933eca543a66af321f90acbc564ab930e0640b3cbeeffc1d66d2fdeb69ffd2c6dd90e46d3fd549076a205c9468589adb47e9245b7c2cd4f40961c53cf78d319fb3d9871d747ba85ab7c75293aebf0c920dfce48a935c17ecbad069021451c285fa38a246c6fee66900f6e34d266790bafd40519c31dfa115367ff86d755cc177992050de47661ead5beba12883f12514896a5a91206419ca43b7ccd5f8f899ce174a20ea53b1718fe003eec2a39031f691e177a8bb157e6409f98c80445f1e78eb5054d4fb740ef09b7ca94479af65da31da40b77ff19ae2657596fbdbf0f7d3b13e9bc71aaecc0da9ed7524336e39d2adb084db83bb8f96c54b19d932eb72d60f86591fb4049c78e6bfaeab52aba7f1fc5a0a87f2e5d8cccb259b43f46952c6864305faed6c68aee142bd7246155379bf9f27f85f194d5d5c4a640fa24c1de8b630c9a0ce748ccc0e5277a4d7b42f50a7588836b79598c2069f9889b78f94af6e6d05ca296ebbe6cb67f17e745a8e58840aac892ceed96406e9428bcbe1a16d1582e59ba71a82942185dc064c4cd0b2db174dc3a5bc562105bc9868ce7375cd37fe8c15c1dc3997d7266e725847fb45fad7b644b4565f4fedd6812dd11bde3b6c0dfd524d5f002b5967c31531a4f1baa4536843c1cddf853f5a9043dd38fdd8e3e1b9480fdf3c4d08283b13e57fa02366479948a58ff345d7e56ba5fc624b1f0871aeec8e8fb5d0350ed0d514ef2e370563bbb8c8591cc870ce6d6251673d3329bd25925ba12524b8e0b7f9f03750de5fd6a70f5c42afa071abc7815072db304b6bfe6488186d25321cf1f8cda7a9d044dc04e9158b80200be7da459e5f9423fb8c9756e2fbac0271444f47db16a2db3e69cfd24c7356aa95601c2f899f18c0c1d7b502b7dba3e913ec1388e56048188fbfd8455c27433e88cce52c8e576c62f3242c78e84510ab4b239a35abd23323ab9b2184e7bacc69b325e71763bc3a6922e00a70c4f6636a2523fc70451c01d2f0db4694c591bad2e4ce29892445bd05b5bf39b2d150a1c628b153d67fdba66dbac01eaadbbcdc81d810e53050e606010fecff3d2e4dacc3e26931390e0aadfbddf34722875446ade44a58d0194731c9d8aeca79a655deabbfef49b7b8b2da689dca6099e46668e3b87cdf23678eac99cde5c5f0ca6969012cad87ccbf3231641145cb0d2127b841ef334a2c67e250f0363712d179c2a44529408f2de1fcd6a281ed992a2fa8021248e7743f3b684b42ef6430a99fb449213f4b58cf8073e8477c97794d0711856044fa4125b251a5bc2d268ffd2852d33847d4d32048652a0fdd56fc0fbaeae46b8b6ca6e8630c1f76367a1c93dae1fed230f3f05965e370990863df593dc531e010a5149affb626bdb767c0b776674f27ac4634dd495eec6201df30adc398d9d4bde16e9ba79fa55f5053ec1f4453c1f4dda1ccaf49a64df7706f3228ebe97d6dae3d717888e7b6542f10961b92ae3c2ad8c0bb1076f690a668276b9cc063a6a15ae78c00ef92bc4b1c134863b857331881b1d5c2adb67ee96419a01004bec5cec0939c7cdc41b99ca46335e7df7a2c9bfec33402611c46a6c048a7a91af7cf2dd06e10ff7e757c65fc4dd01f4f8573fe7d94a72c506240942cabf6f5b09b226c1b5c28d8bcf2c767fad522bbae736d5154bfefa4e9381926aac2e83c3232d0c54f331bfcee92abb7c16eac4273c4dcd193c022661a4c7f3a7a59451b0ccb0b9702860b5a20c101aeb6f26d6fc47b59211f3add43e0465804081dc4eb795554358053567b8e807b17b8e49d0b5071da0aa89a6170d3437045871f0f3247d4314ebbad0015bfc9ffd9385e5a45d9b53a00652937df98dfd70429a64154997dfe6b2cdbb875da9d258c6476dd300279a697459b5b290f67e223db8f09e582523fd114335933f572dec3bb9d7d02be95e7dd0069c98b331a76594a8f4a771a7259e8dc74c22500eee7f9d849ba434b35a2674e177873e5292e9dc87b5b0c9e9d06fea1779f4d9b3f98b38759e99af2bbb9d3eb682c4ae049b4c59f70c5de47c647cc64a692dccced6a75c6f7f9c291dff1479935c793af0874bb69725244deac8ccac17a0a4ec09f688b2a02cac7a8413666964113907bb3fd4472ff780395ad1009eb894d7001ae66901fb57a14bca4da197f7d7b600bf0e182b7c2eb91239161110bbd5f2e4fd16df7df029d87e65a41b5502c2121fca6432784b2a05020387a9b4bfff2910cbd82902882a2648e31dd447c2e35669b2b3d913124d9d8a1e7a134ec7891c5d4b7cc35d439f495076ece8054ad7c8a5cd454c607ffe24a3f3ec61086e6e56fcb42e40561709ca5404f18481038043f3b03a1b5a36291aab47c3165cbfd832a55dde82ced14f51ef0c8d9ffe8a13489a498af3aa43a3eb25e87df747cb7c87d343c232f98208ef7d3e62e54204620107fbe58838b736b170242f1905e37cf7f0818a55c905474a7c6128961d10b25f6effb8a16e3c41e6df0a895686eebb0269cd4146a6310b8b6889f34617cba10c3ee8c31391d1d7e0899de3703b14f6c39a9cd8b5eb901db118b535e200f613c2e6b0d0dbe1260d51b29fa87018935927c1b65f4eef19153fc441337f33371119e56b70fd45f868ac3aba1df51f3aee30cd3dcb79457b989774c7977f81674a6c3fd97b72edc5625a7693da0adc0a4b05d5b07092dce852e1cfbc3f7eaf25c203f7916f7df5f3c466bb28f4baf32d58d6611a17b1b0d941b1461674a777e95a46a3f3e735893cd621c7aa32838637b19c01f58fc8f49867d2fcd06bcb912a0fbd25db41b8171ff96bac454fcc4f2329ecd8b7a5b540f1723219b50b8393e1d501d0484b833a243f75cc8e515f7852273727456eb8cca488a67fa311aef16d00d74a762da93621ff63d3c4d02faaf806a89c3207635990430e7f7d07c41eb99d131dc629fde09aabe39228f8106181f207aebdc25d15ec6ad212e66a3fda581a1f71766a74024e8995911cdc72620f20c2da42ff8450afa2fa563dd1ab53c9c5bb2005a88140b2da28c76717dc2f2360a31c397b7bf1318a3f0c585342393fa4a884c23a7b78f7b859a2bbbec683040b242957f160d2f903fb2e355eea93897cbe0cdf5aad82e705a17c905f68252b0ef8eaed33aa980c18e24cdb7fbed0b0e0acc1bbf0535417e861f76463acbff7534392de4832f662bc8787695ea7010590248a749ebae938cefffb5bb60b89cc5bae72f26a189a74b547417b3dba994801b94dcf59a734f748562ad92ffaa254215b5bb374959b9335d541bd0cb1f13963abff2db43e72d4d0dfb147b99522306227c98c9af9909e6f0d60fa81cead182231167824adae9cee6eef409d68df1d3d1828860dbafaea763d6820c731e7dd8a1bf811b50a8a4fbeac0f357edb56ac3c5f3456b1533f9c20b7a7f7a0f685431fdf13a4250037dec87a05d82062b6c5debd221055829db737d50f5609d5e76fd42d55e1c8a8008676befc3fdfa155f6c2607ba0f6d87dedd803d789f547dbff2a341e3fb9948708cd23e6d2f79578210d9938f54dc26029aef6a3d79912a197d5508785e555135faca5c2411cc93bcbd6ea4d6e82deaad5689a48cb7bfaad72ff71303b64f53274fe484ee2d0e43f0cc7f5ad1d3e8c1a2e27a1aa38f9230c1e560b69992b0874c4613c60ded71a2763fde300aef175f04cfadbb503b15a2b229122ea9ac865ebdb69e4e00f83c4b8daefd5dd42436cb59ec4ff298ed21a0d65b53602b8ab893f64444380a936f229b0e7dbf7b6a448ae36eaaae627057d980afb6d879004ffa1cfbf59fe1df5cefce795b751680ab8f54bcd382ef161c2396efc99b40a524cca38e3713d7fc8ede3fcd364739b5bc37cb5b663a2073c28af6e6819290a244f9d4532c6efde3af5bc9290d8d4770517bb5a1d613b68156439757ad0ad1d02fa8e29fa959d3e72a93d972a13f37ae505d0f96d20c17270ae0414052b3ffc948c50975c3f8d22003c49f4a8397ad7dc06b43c52e583378693969b921c12f3858557fe33f7875e9aacaa574badff1fadafc56f24fdf9e42fde8517b3c933a2c24c9a133c2f6f8651d77f31154ca4ddb34fee9ee07f250943c969f361c5eebd40018bb9c88d046fe9b13b506480a41b72203ebe8d0a370d8330cab9f521dcf0df3ecd6b633f9d6258a1154cba4979bb46a42acefd71229a1b3e63e028d9ab77d13d47f079741de3f9da8f93bc029fc7381cbb7ce21fe24dc94b1d1b82204c7049a0eb99937adbea266ea96fd603795613f78ccca1e82e2200c63f4388be55ab0e66f1bf3846eba7d73e1d3a1588de3ae3ae0b6cbf4508ba025112c39629167dc5ec5b61c19dac893aecd32d8b3b72ebb14fe378de28a48fa4ca08de17d8e6fde14f9569b4fcb1e59004055c1ab4de0a0bba8e92e9c3d8d4c106878185d11c85afdbf092aee4ca32818b2a5a81fb5eb633eda16bc0a6c937796be5fd9b120c5b84ece2a4ae9f41c3958fd0b9c6d9e0d45bdfecd04359314b1a39a7c0f4eb1a1907a5eec5c72b4a164ec20b8c8a4ddace11395662118a6471a789cec3e1d68b14eaf55de5b365b53abb416d98b30f5ed58b6f1bf44936b1d351688b0b74532ab090a048f519cd3c41799de761283463b4ae69b4440087462349a573cfd9ebf393693869f53cdafd353947a96f224885574d54db9d78822e864fea729716e448ab959422aa27e91ae8be50317453c49a3e3cd84896c742a3f26d21c4a690fd02a9eb44c2a6fac6b747693de4f66c13577b768fd2c91cde4eca015e19b5d8df6b3e1ee8d71ac3b0c148e47ddbd042220fae8574c7a9c61b2e210736f3d40cd6bd022043f5144c5e74848285199a88dfc66b74b0a66bcc48544b4162404a8cafec14469d5d354a1f1e90ae179d7855f36995d5e241ef903d0285dc212bd1b945db713a9a387ef915aa7dd3ada18a814f3bb8bd46d6166c8cab57b867d512a3a8bdc7110520e7dff6087fcaed80c76142b0ae79b3a4f3ac27019a1dbae77c1de3aaa89d5b5a2c09482f4633be4b792bf777b48ffd3ede97457715d53384b7edc1a0942d99c04613b95f7721c9116233dcdf9ebbf5d5489377903f2c2bdfe0c0739c2f9c718e36f61ca2f3f7208443f6cd9989cce35cef6416a1a57373857d88b45719b8fbcb14dc759a46a20bec001ccbcb1cdb0ce8e410abf96b42f457dbb37fc85d150614273f275dcadc7cadd78eaea51453b7b8e4e435bcf16a6d2b4d974e91acf26d8bedccfea501a903c6a0be853d224012e346ecc44a5c0353f4981dfb815062314815f4e7f1861c7c29c70913ccda54dd61ce3ae1f59382c124e8a572e9a04c8979852c438005063d2a1700dbdd2e450c09e02d2e6df54fdb9e05b2e941ca3c35fe4ab6f934f9b5fc8899c5fca9af0d7a2cbd4c0bfae98df5d9c15b5e247d62f8c378f0ee3e7b55767fddfa28ef793413a33524e3cc1b366f000b09cdf343e4ae56b3ab8caba747bb2372cecf7277d694928bf219202203ffc31d74a182d0f4fd6d526c76b75fdccfde98a1f2570c13439a3a0c7d6d3bb8de7763e36f7fcc1efbb9504187d02fc93a12bad5a14669a78b2eaeb2b96eb706d1b0221298379da2cd57036473edfa1231521a49632f310c76d0e581374eafc68d0c68b3080370c931a9bdaeea543eddf5bd8fee425046ca2a0629f2e6e17bfb512e557a948c6dbd98ca3d29c83ea6d333a4dbbb7279cc7890c03b477876453c1d5a816ec47f1d0f9db7dd0f69f8c97cc84e3888efe8fc7e15019fcc4b5b4a89f0b85fe2aaf2f255d30bdaf91a5f1aa5399941c441108ee389552c1bdd96efbcea24884acb006a129a924d1c4d0755cb9528b4b74d44f803dfc7e1416b732dabbff94f07571e9c54754ca84513df613055caa2a7030e8ccd890741bf7451346a1326d51426f077540e2b47880a6725ac750c8cd71b89144286147f05d933e45047c37ab38165e8badb82b8b78fff567fe53817fd96dc0a000cd0131c9978f37aa455a26ab2087fce115bd333de076c6b440b99718339fb71ec8a2769f29fb3946f06ec99b23d5c3b5c5ba7fa724a83b609c9e1742d237d3de0ed9a607329174b0d5c525f5716d1b03659201ed93f9ffc7b6a0c416e8c4a5403d14a8a160c17cfbacabb9fd3505a7e315dc01deac5211d80fa365958b6116eab7581f8690715b34b70c68e9f5e4371d1e8a5c18bc33e39a985c58e0a392b8ea277d06ad11c7ba0279aedad0cec0b5e75f31e80aa63a0ec112cea4c6033daed725335066163ca44cfda8ac604da9d889d0390c21f803252bfccff823f40c6a03048105e4a57b7aada2690581493436de9643ceac981a39586eeef0a36f106380e77ac6f8374f710dc6bfbdc395172e86d85ab8b9336ede32d620a44493bcbc75ef13adce9b8945aa1fd0e2ce674421255ec1cca6b6ad52206ac2a2a1ad91bb6ce44b54a8854112514d2b2ea9cd8a0bf82615954a01e90709623482f69317722918360150ca3409565416cdf1b60fe501135a095c85dc33ee07099fa0d9880c927e40f8d3a0df60f74d6ff48400dae3682f30664372bba2a6d9bd4b10d96567dd0d387b93a13804c1bf780f12f5dc8ae46ad5af438c0f92d0e1d68364836f3682bce5a5477934cdba400132396f14beba9e124a11dd768e99a9933d5e29b7d164d7dcbf2719d67dc9178a84e0ddec3f5498cab233d142edf255478158c9ceec5f6567842844eb1ddc8a868c4c6ee40fbf7f534801944d0074b61811699fc6f3a6d82007b14503eaf808800c77cdda3f39ac6ddcd2ca7f5f7e6f473a0cb236924df082b065a2e041929e87bd5d552c7efb65dbe145228d952eff5c12a95c588c3218199a2b1d11b38e66a19be5eaf85dc9be720f7a6d3aa66b59dc58f4f4c14ca8d9345f448d3c0c080bbdd183689fcb92f8948b001d3f567a0436306813a9aa7c94d07172f7c2973b56bf444e563c29433db4a65c1ebe8e2024dd378fe59f28f2ed507c605b7dd7c464aa3ab05855f26266ab8b891e011865bb81618a9740a32dddf95a3e70d828c5c2e78984a64104932b41934b5f5c8fe2cecf9de9434addddd3a08d91beb5f62eab3cb834fbb052634515fa5491297235806f74ac553d8b1aff62edd65d3f546627333a2230d0bcc065ad68bdce04db7e5076cc64ed7c1bd4a62a1983aef31fd1cb986a050dc5756edc646240b6ffe0dc36e3bf2456620d4a27967d4f5bf185ca3d273500d801a6c58e0e31d72e6fe14403beee6de81999e56cd0ab1d917fa4ab42d56f725e5a5bc9b8c066784c0e3f4bb95a74a4ba2d169268e510eb9269b8fd39620a0c8bf18fe970953584c2cc3745a83c51fecc69d3cc6ba5b9a2549b4123910c2e079c3c218377a3e0bc8d02f5d7094c2b4db6cdce1ca7ba71b60cfa53a49ce527198d7baabacfac5f6d2baa8ea1b9ea69ddd156b3097e80dca69058450c7ba1b04f8df364ea8cb2b705b54072e3e51e8f7ae9037e0231470e39d86026a683e785e75728caf0127fb3f0c8f841a142ad875e6323a273310bda3542d3ff2626649619723be79003358f02e58b132e2d2beaf7bfdfd6059fc10c9af834a6fb2b72dc827987cc3e53a2d6700aea7dcc4b3b413d0e955ce41f0ae8582030b87fde68ff0168b8279bdd37363c24b893a1abe1dc075c27231fadd96c19d26d8ec6c45abb18fc2e7cfbdc2b1e6c029556d3d84c105b9bf25594bda1ca638f493d2e495e543d04123d781fedd90698bb875a18653ff495d07b0aa2ced7955a6bac88dd2ded8309b27a6bb2fa8848778a947e4d1674fb9ac18060e0f4ed3429e11f52558a77cbeeb6b404d9574c1955a426bdf29e49ea8fcf3aaab365a129dddd05a0e39e36d56ed5472b6fc360a62a38ac4d270d5b414b5b6335c23bede78a08968ffe93c1bfd6e75bf29f02bd082b787ed20869dcb424afcbc2e5a7b79777768941b148d9d9e252f55d8b3356b82b3bf7b685b905078d9c5c6c623fba044e832201a1c41927c6b60ccd6e9070ad147945370c4d9469f985d0fd8224317cbbdca8c9c4c193063f865e6d18f8bad6f43cccd178aee034e427da890f0bf7ab860873c30fb0e966e3639a3390495241b4ba0dc2135329aa486a58a3cd87087d5d79a9b077076142a7fa7b4a5ce863b535f69342dc58e2f95c44065f7f3c06293312fff14c5315a885163d4de3947af8e32c4e67e6afd3b59020bf3eb6c295aae9db5293c4dff82f7a7837447f91eac78974cc957681f49e72c23189eb1cbe80b93bec66761dcefa20548a6abfe186138bb3e042a09bac9a3fdc4db80e2776b8f0e42c1b6579fdabb82d4e3e797751c4aa03606197211bdb8da10cedcc385e254bbef6e283ae9e0e0efcff7851d2a4974fd828142ec7dee4b085401afd3c96aa56d5053549551d5e2b885802bc585172b0f28fbc739041320c2f9dd9aa57386fcd451cde6cd081effd7dd9ce337651a8a7cbfe8957fe2b367538238c352c9d37ebc9e8c7f5d35ed21a8b396d2aacd4700f2e2788ca769f5e6630cb3ee1e197afd93d297e3fb37ad2be5c05296fcb7aa4a829236def1a594c355564b503ae91944ced3ca07a5a9b02f062b5833a45932194448ac8e5f4ec75895f94caca3397ca8c19aeb00bbe2e337c0e9fa7dc5aa94eaf0f4f8f1f94dc0ef19b42a231b1ad6ee3f87da501c974447c2822b8418a77d72987d5e2c2f543b8ce7a91c8496f304a3e31fd4283bb7f2b0c82f532edcccf2ddd140ce5e54caab17ce1ee6df59ae8d5842b13dcdfa082111306a656812f8aaedb6bcef108087796ccd5343b6e568e00d422945487322317c0d38c2ef9956f15c61b59ace29bd372154f3e96e809a803f4b7b94f2c2b30d4d7241184de2327c42f2f0cba78d2433b690b1338c866db213d70c232dea10eb14bab625cd2e647a9b82b3fd7aa56ad43ddcf9b23b1322b2e95ffada3a3e2cd49d58b1ab0971765ae3af0d96c2bedb947da4569d350a81ce5d129b09ca6fa5db49c7f966c62102ffc90630150d6b4cba03f3d3140d0705d91cd940c2014166848227af846793252109519faca5a27d2402c84791d69234fc6e83eb2ae8215268c2a3a564dcab8ce5c79748a1d7f12ce2c3e4997baf58b972bcd4c0919afd78990311499fe21d80efc103592f821e453b3db65c41829e77f029375f3bbd016599f726c7687ffce7c547283ea22a8c96e8857de24f5a08b4297b4d0f02548d829667e3ae6e532fa01f12f92741265fb10453f6cf8b775115438812d435fbf0fbff0fcdd6eef746485d3019713e28af728f91a3e5d0ed91bc89996e7ef2558790d91e2467cfcb677012d57d85ca555bbab88ae15dc57f7e4edf66594ac50556b4d6983f120ec6af0e4f0dc2ca7c0560fc855b8a07f94a37a76dceb60a5a0fcc118a75512d1a04ea439466e20343e3d16aec48965e2cc8b5abf63dceb9117e6ed19e9eee72e8781070e4af26aa806cc518a3aab47dd5f6afbfe9de28ffe2fee281bdc9829722776b3d694730613a40b0c8386f6ac8e03a05cbed9a660782ca04ad3bd4fce360f56a36068cb1a1a9306c236a5c4a6785bce61581586f629d6ef6ddd9c3709aabff920cc3f90ac1457986303ebccdce22c152190be48b80c6b49a335dc0d947e657c85e6d4c6b94d1819b498d4d8ea442e1a9188b900359ce4044a91f84282c4120809f45554c81bfa9eaf481637c8ae9ff90397082bfa3c478a02651a43be9b2a0df0ae5c7efbdca6631f3e923e6ee4e0be778f6a276d0a19c7b5a94a02bb150680f85e1a426e9894e4c6a76d6b18b74082dbf5ef4737ad032553f9ba5240425d80e685031742136d25907532ba7aae1991d7a728f31b805dde4d604fad5da8adfd8ec6dc8a92735cdd5a4699e96259a924a4de5665580949373f62204a12423e9d6e9a24f35982f0d5b8831b911d2b5bf2e8ec99a0ad82122977b9771dea39acfb002a6243a70ac49ed8b76bbec194f369f39f9044382014c0ae14f12178b252012732b2685cc68f9fa969d859e2479151bb255826734cb34f337cc2ae72bb2fb23ff2058060d51d93373e7b081dce1fa1f6dc198af3fe884d8d230442a6f80e73704cad8e2dac47666dbbe634982622163968d4aaaeaa459cd42310ea54f2bc59ca0912d91ecc65728455e7ce14f203bd33019be3c19e6d9f6f74b8cc11e045424a0e08ec0adf1e384331b729f6e41a0dae7501279fa23f69bd0cd57ce0e947b8b5b3819b09e1d28de02c89babd42b12ca3cd57f2b091813b00ac478f0f7cd9248c1b846752bcfd66c093c3154c65d46ae5b99eca763bd579953de716c18d26f15fa3420c04caa6718f8cda8c4ef80b3b85fec907f31aefae76674ddc1a4f9e42e5a302be6decf0380ed03d9e116f104faed726a291884b853df822ccee80c00ca07cfeb17232e8f8c472a0e63b50bd357683eb83c27ef78166bd4d05d63efb5d9784c9a62029409e1b3ff6238770393a4a9ee593ab627e4988c4195c5517830a29b452f9403f09caadabeb574771628d225039e4294f39bbd6bc9485060723d439a683dd8c5e64a0a2e67ef68c46fbcb6e407df2203fb765ae769759ef431cc80e3511f83482492800c8efc4d3e61e7d85b1fa098cd2b87b3478dca35c4c75803e5436189f5eb4a5e6eba95fd2a4c661387736e9b6caee36c9bb9e8e30d6491a92c32a96a9a0bdb129de541139ccc651de19c599dc41f69ae582d3f7ccb69a3d8f0bc4e6e9f73249ba7e871959c4165af71eac9fca618cd239cd84a2f4d51bb68bcc74995c37132371a9befc30b72b72d20c8871e82d8a1f3716710bccba73bdf57ff64b645c3074b6318af1017ac5293d68a53ef0c16307b75d79b1bfe0cc0ed93d15f17fc9148cfe536c86a4dc533ea687805a51c723db846a182f1dae219ae6b68ca774dffaa3c958b6bce31583596383a10b90a60de24285b5dbaf63d6e1eeb9132ce9e2f501522ecfd1726cdf6360a2eebd5613d25c16710e2e9d077ea9593cec425f054dccffbe4fe0f5f8ddb674a3482910134e6a7536e8626538d0f87c18bb23bac686abf642d9f508939779de4ceb1807f91e5eb37bbe81ae0e4e6b96c8b886fd4618aba911f5a5c76dc34bb035d1e79f37f0a8acbf35ced5265b38f742889cb5b8cb0f776d8eb97ba65e4cea6ffc3bcb00fae2a3138379f562cce1187577a68a114971aa3dd582f05c75bbf35614713198ecec7483f6db1bed1a2c9f38126258cb7e3bb079f394dcacab853c59ab487f754bdc56086ccf05648f4d2e3e1831a195b4aa35cd9aaafa4747c040943eee319ba4648b239a8ce5c43c577ebf65a9bff3500eecee79a136e305b72b333f02159b1afef2a4d72ebc3a43ffbe775166cdd4de1fa578246bc6a1029cda637d62f3f174420fb59a3ee51e41f1546eb6d11336ba39160843b0dac459ec7ffd8441b67218f597c3c5526e7fd9dbff4366c41c08bba5de78e8733e4a4d2b8cf526f19f0cd0ccef5bd14942570a2fac7b9a8ec0bfd175e0d8a703302fef649de87c43f2518fe98873e3f0e48a9f6ad413fdcc09b40c5d140503b5f5fcd166fe9654f108bcfe7463fb54cf1b6a89196415c5b749bd303b918bdb491febad5e5f68ad4c097ad1c3e6c9005dd3843ea660e9f94de23d855527cf50b63aed1ce1116ba15f2a3f8692301f487626be54de1e3acad9734bb6eda6149758eccd5de13e3c872a043ee4c79700e1b62a9629c2121c6236d8c711c2f2c0671c2a2f22fc2ef4c6ab0632c1f23620dcbd6583a8d167ed33541b17e86e9311f219989927873cf5e973c7320b5ae1b6c1e3939f45d8f1bdf0feaf8fd1a9d4ed6ef0b5858fd1dc606945ed86477222e4df2e2725f054285656e889ed42ab0a83b32ece2c86406647a3148766fa2581a6612d9bbe5bab25c623d845a19da9d74ca45706c860a3bd3d535644f4bef1cefad3ca60c22f938386ee48b1866bd9c798625429a95fe532bd623f4686b861fc8ffe5eb8a5ad969cb787456a1cfdc69f4deafc98a6d8d3128aca48baa70293ccb0c75491542d2888b5a75cbba8303e2203386ce194a7a46df399441150e968937cc39aa6331d86c61dccbd163fdac2f409bc9457f21a110887f3cfc8e7e09f31628908ecdb717e2011ee791aced113cbda09fb3307e82be285a8ab57884d99f4f95928f5cdc23cfd6cbf3e75da34e4c3fae8dff15d413fae97509b5585fdf31f917faa979bdc084ae55acadacb049f8087929e140c8ca0d8b23523670e8a41465523114493b3cd394932e06f5f3c3d227fbcef511ab670369937a6b2710c3c868065b5a9f9d02626fbbed2373288d7638f289a3b590dfb75e721a0ca8ecfdc08d34f3b1f22e8ecfde3b1c9f38df6772061bfbcdb2c8f38647f0962f884ae26619ba05fd01380ad749e6be5940ea95fdfc65e68acc3bc268700223928bb8bc04fd9e34fb13581c7df8792daf7f69c6e53b61cb5b61c5df09d19e697225165555c36a36e7532cc41bc783d26cc395158bec3bf6c1ea3d424059013a5b5d402759a667022c005b016060ac2fa9da88045fde31289dd1baa0dcc2b8c124fd843e40e5812b8ce608a1c5727b335a32f45319162c079d50a28109352478bbe3d5ac8b2e9ced0625ac7beb9627d3aa56750f2556ff38d2284b6590cc6e193be33c4430f733fcbf8b795eb1d5a4cc5d47bda5bae84dcf91d4c055e1f2c7abf839b0dc2897f1f354b35d14b33b8a63eb1701ae16e5394cd82cd055d7702622c66fce8298b9cdea682cc37ae27a9790f1647bc502bc8cf3eb077d3d3286b16e5bb105df0de21d9e3878862641353cf7906a5b1d4f2c398b9f83e3c5fb026e9e68ca83e35006c08f302cb80dd67340590f7ef1686195323e04690733db93fbf99148bae4f7aecf170f8ae86fea1d2a03839015f6e0a27b8e0ce1337e1323c2f6d1ac210f59418fd702119218b8be18a79bbc5ce660ae16a953b2d8e7a4aad6bb9af9481f713ebe5458b0ebfa852d5aacc37a041f139e5696f4ea72d37de67559b8c0945ed2712a5c2ace7738bd430f8cb85baf4d20dddac4594bd2dbc13ac35520ac075fdc835b2ab760f05cd6b25a539ee3e233ff964b88c36ea3ac5f6971e1584798aa36f66c04ae9296e367b7643ba998b74f46b4f93220bb066d15046baf140436b87e6c5cb97d936e3e1f0288ef9166c074f2d2cc58c3fa326fa2d39995717cb5723f1535be65a5f09c073197ba6390a23ded2ed5543b4fb54a8c4c04c42b384906bba8e7f584c9c1ed7b2b07c35d4e68e4afd538e59c20f139ce986fda98adbbed4d7325ce5158354f4072d63dcaf414df16504954be5551faddcd14674415a71c1599e0f948689634722d99ef37fba42d8e82b2e68e4d618d1e2e3ecf6d9843da80067d89d51351750be93e3e2ebb0bed6a57e278c07c182e9ba4fb52f2422edcc5ea6d43ed296f636399877c5424ec41c18cc24c631b241b6be2d3750f28a87b2c97620530cde809988fee4069f39a412ec05cf552bd4c5bdd081785d7d23c52922ff14a2d428d5d111d93a899be82f6dfaf81ee73c8424ad6953d2df04162e0cb2094eb1f66c3f6c5bf8b7462156579d77895e6fe91d9f8f9038de7f9f9fc74ded2173cdde1b812c8fce93a83e4308934933a11fdba7223c3184e4818a92ef8390855c235bb1397f947f86fafd90312b6e4bf70072a464567081c57e3ce77b2cb5bb9ca51734ffe9d15585f85ad7a0c1dab553a17ca894c846a60dbad6fe709a77c4d8c4a03885711cb8e9738c33d2c216cfe3afe6216561dab1986eb2ea4d538f37f8306d3674a13c04b0cb81e1f45431874f24f98030e1209db24f737343e751f40c3c385ecc71085c43f6be644f4f92ad16c285b0c6739381cdd9f6eadcf38c039f7f795d7cc5a6d4b11754fde8bb295591f87db95d35de05df0dd7031c449bbe5e7fa993e07cbb9a9c9c1b05f4037c8532bfc87ef1e17a110b5e753fcce8de57fb26bf350cf5c0bc58b41c980f14bdf8f956696a8613e471f36225f73f33e3b32663d48c0e0edcc2a147ec9f8814c8666a8fd5df00b1eb7ac6e15ca110b186728460afffaf786b5af96b3cc8204246607fcd5d295ff43e217c2e22178912fd44b4647c67ded80b3370825e8933a31c8ca4d294424d2e1f70a018d36be5477077f1796c7a72a6b6d4ad7349e239290bc846faf8e0d8f541a80133603a03d1392b16a9d28c6e76c066b3b17d3c8267cc7c128ccc44684fd0bb0f9b66d19de58b8dea3183b22627bd7c29929c7c8d219a93707ba72a00066ed5fe0a8fc9e956463a8d46df885a3b27f808641815dc996cf94feb5592d6ab959be5ed74c54c3ccc531e4564c014ccc59d42b000c1a4221eedc012af954246d7885ee7a2c8a31d54ae4f8ead0fa2f549b509662ba0e3f58364e470ea00f421f4c1081f09bb7fc85069ed8c7db76b7f625ac60b3d62096e89cc79ab38f55e8f01471cd807594d8921672a162fd6738d2bad4d9578ad39e10dd65c0c9ff90f09fa8224de397a03b95a66468c73fc6397c2cd6dd44e7bad697efd62f1363de5d6bf77559a6b903d60c9b62325c864fa8a1a650d19190499c01915d472667b76b0852204961e2e18551fcfc8678d15205ba7caaac518ae24b145eb13bfdb6c97ce8322262cbad412a9de729efaf82f5abe4c176e2b2d196da8c4737aa230818427e65e1dbd8b33d2f9ac7b4b7b3b7a982807dc98392ea39815fd93d4d1a3781a074b3ba684bee849068ff6dd7e37fd0b271e0dad7f0787ae0df73b0fcd417754944c04dd5a0e0468822b211087bad84be0408e3dd45a2eeb0120f500839bb85d02ce9daf537bf70d800f3fe90b6de8545ffcad899564cd635310f269201e0c933d1adf3a943dfcd5839ef9a159907e0b365bb265469521ea8d5808178f1139611bac2b63d4299d647b4336c0d251f40afa6263f98a0cc5c34905fc46ac5e818061286174ad1b1f2e979c8872ba6a2699c2262908ecf77955a212047aa1d61a409e64e1aea0cb0eb904fbb9e41e9036e5c839904b45abd257797e54b03e638c5b8091c398dd3af9264f6d8c48acf5d15b15eff4218c4e27eabe87901b6ce84a96ddca50f21eb8d84b29eaf7d5e7fecb062e75d31b64a9e19790dc6a22566f00faf9e257d5dfadb9a26b3bccbfd0ecdb6f2cb101118e490721ad5ca3106f032dbd1cc8fa9cf284d465894327d2f26ea7d0493edabc38b621092636fb43ca76f6a1064cd2d0aff96eeb0ef6d1fcece3f0636cb66a5b0794afada58fddfb75f8e3b35a377d653c5a707c46b8706636fc66b8688880b473fcd98faa6a2bdd75619b9e0dd02d330f0485c0a8ae7ed13ea6d8416613fd5bdfe53bc6afabd44d9afd6035813a0f1312a55dbac309d7f4f9d3107159fdeb3fd9cf7b9e724ada4e6f6615838eb9c91728c07873872f76b0ed54bc1a3cc0d9b9bf488e540a7c73128b332b0b510d0dc28097932006e869991fbb285de8e12a60d82ceec732464b8b1bbd985a9653b0f1bf49736264862179a094ad06610e0546a5eb0f61f88b13d8ffb91a22cc80f9531e08780963e96aa961f18c24497dbc99f763323814a1a0bc50858fd77700d9fda43d93c54caa50ee0a7771c5222df4d8dd4debbb02cfb6cfdf4e9cea4e87e5e96ee580d9fe2b02396a6a54969b55b360c4893d600a856099f85aede465e63dac6156eb1e83e5ea5f5b9c179beae50b0974b09987e201123244da01949e3396d686c548aa6de8b2c16313248211f8ce9b2c7f9af749d451d283f0b8b9b094f650cf29e8c63deb28917854d12423f78cb1f572d173bf025a644ea1b1ffad73e0a344c0a69fc511bddb32edb928c74a847deed4cdf085381a7cfccf5a398c62a807e123d3e02c7fd22583485acc35439ff565b8b00cb6082c6729bbbd5012c117bfdee422515e103af9ce5f405a68fa06e91abbc6fe37285527e174fa0f092a22a95a3f1275ff26ce406683bfe1dbccc0873ec9414c57b68d4a002e44da8f0e92b9a077bc021cc45f9c2c63aabd0273629dcffbd88922cac0ec8a71af9d49aa2befdbacb8e02c246b37c92cf95a3c267e4d7ab6d9077aaee75a196980bc183169d61f44eafcc0cbc0d26695b54e4d73088ee47c5be9999a1609538df706ad4cfc647e8a91e498808fbddddc2221bfcd5280939bbba0a36ff550c9bf2ed250d9439a329b55f71c1cac2689be548d129325f2c99b84d5764b0c94bb256c9746039f5022d0b0f34d14f908eb97d9da883a91f1d9a90b8e2a97f669bc686bc0fcbac8b0990668ada45fbeb43022e514408b1183ac42c61ac76c73833bee19eea1faafa5aea1408e2370959bd1138e1e82abe1d828f08667f9012164ed3b733bf43279e1b6fe5f53cbbc03a53d6219e0e21a2017dd17856cca69c1433f56a6e605aa8da3b02f7a91cb73085d64e61ea320b975ce49a90150c7b4f38c37da0d644d8eb73209d9e0ba11e25f31036cc0dd28f36f968a046fe801a89288877a0eae183d276fe7c0d217242c89bc1145bcdeda60660617134a92861e0e005a2f9a117d588108e40a0054b381cc9669bf5f5fff2d482edf261f531ab121f58e7c3555874ab163b8c40984ce33e052d3c2b46343d729eef2e76ec8d94ed392f983e0bbe11f6ed8fc30cfcba3a7e0436ed1f6c5abe72a1109e586a4f5b38a07427f5d347584a371d759587201c4bd4507fef59f13768562e24ed3205d3dd6cfd5003f56f2165deb881763c63d2deb76fe70b18d98ea50b4a374befd25e2e28410519536df9b58b0e5ae9fd7652e94688245045b3cbe174a54c34527f3185086d7a008f702c8ea23998a2d6d91bc7547e1eb3607600126c58beb69d51cf4021d8c3d14c4c5fe298bba7de8445da22cff2fb5dfef1ac3cd9d01ad6e28d6653922263c111dc07dfc96db09103799b01d263c52aecfc6173e65cae3937b96cb368ade0312a6189f7c24f57c9fc8263185b5d3666fa8f7a573dd1af4c5bf44c6f9719834ad6f4209642640a4f4b75f68bcf640e2f5071c9e7276e5871cd67946979c123c2d3da47ec7b0e811f58a4eca94d01a6079c3d9308140a292183a4cf8792cc5cc07c1a07e0a579293629a3372b4fddb41d9ec111b93cbdfe03c67c3cd7c748573d648c030526321f05467bb1d191864cdb8415392331d67cf6b75a3beb6f544054718d4629ff10d8640254ff23aab3e78c671953fc7faa02bc6d17705850325a9d030316346e0f96b5d0aafc6d29af42a76530154963e047e48a68f9457f4256bd7c3c11b5a871fed05d4e2e88e5d9f7cb6654a3d3044dab4ddb97fc7504e59261fa018ae3bef653c333044e549b71be7149c3d82779497aa47a6bddf7a3ff82c12253caea2348d70e7cf63bccd0c77b3690f883aa4a6a50b4a756985f25201c7763cd6eb0db70404fdfdb92b0ebe6785c3777d97b41261c1b781b5d06f375e4b9ab21fecc643f98d42ea5af759c2618c95bfe841d3772024c6aa2de99c3d069a63bfd20b6bf960b253af803ef8da3878e06e55f7a80d77c8f53154e809d3281c91f57b40215b5391e33aad1021edc30b19a927be727b742b8dcb2ec795dd29c2db6e273a9a6fa0435d3696053be84337eb931780cf236a60a33fa8e3fbbcb25b43ebcb5e4b83ceb023bd21480dc57fb53c7da31ee675ed2f54d79bed92bc399cf92cb01084a2a80dc016085414fce95408ec7998ac05ae34b52b11c60a91058d0b2bd48b6fe132bdb22d68d6e4c8d9afb515f84bde285976e88d3aeaf9cccc207df6da98cd1d1ce6a24f829d570c00febe5f863b06d434f38ecc1b8583221a4f629ff32b992282962cddd28068166b452c5f5f8c1d3d8a4d592d4646b7e85b6b580d36ac87a43aa5550a116cb1375b11f3ff25ca754453e9422b41e85a8393696a69bd1c5bb6d8e6ae116626831467aa76cbb30cbe5801df801c10ec47a4731a389c488fe0591874b2d7054f22fa04e7ec4cfade565013ffc37b934efcdc6fb8ecd5e7fbde30e0a136d9195a5f228b68c7d70e5b7bbc4edc811f5edc35374267546b7188d4e36f91647a83fcd58aafc23cc43a20af9e3c5f93e0d7be8a89a196e72cc8f25103eee8c6467c6188eaee83cd0e0384a3b6c3a90aec6033ecd90b8b7f028cd57253548719b18560713627b5b3c219ba7ce7408a8d10535793e4fa7f2ada94923a3541f6f441240dcb70424e85a71a2fd7fa1cea92a0271d843b647fb2708bd507f2e62cce8299ef710838b0618cc8dce38b4ab9ffaf0a1d77e8814facb4a3e06fba7de33b4da20a4b2bf7c2579e7803f03656045ed231c7e429188f9ee964dc067fd13f2eca8474d287e44159facda4977d55be20eeddafc4ec45aece3a64a05c29f0dd8df7053dc43197b6d10d267e6f2309eee5cbfdd7456951ad5bd9bfa1d8aa146d83a29a047c35c438c6eb6202afd32e0e41222ce322bb40011cae5d66c05014a0c0ec0a71b58939e0ccf70d6494c2763fa6b67f4a780dc377523c863ac183273fb74ef58bc5e711f07466c42f114ce6ad1dfe752aa4ed84a690ac39f6585596c407e88108c6a3d80cfea41256a143d52b2054a1ac3b8e296da40488d975380d2ddb33dbad9917e8140aacd222138763fbd66db8a9d974f0122e84888d9c7d0e1178860881cde95058eef8d893c7fa459d3a90d83ec04b224a98909789effc3b7e2a3ed1e62877cab64a8ca1789fab05b87fcaa0aa64a9eb9e39f540ab7b7c31f93e3b6d14018c131701ae600cf66fdeeb9f2dc6c2b37bcfb9833e4b17c64d41831e53623be5cd4b0b3ea2c8e4dbb263df5f09dc35bfdb96f2cd9bf3abd675d05223c51508f0cf8dc5843a95f731c3e860ab5121e817036fd214496f77ab605e8ed413afe19ffbd366a3c8f474831f0e97fe1b39be3c102c3c5790884499a6828fb892154f7583e6f81a761555def73b6fe529d936fd34ef2942769afbf7894fb4d8ebcb5d894957f9fb2c436d497655d39c1005d81cbf02eb8ad74355e289c3c631f52bc5124b9b6e2bd2c93aeb936ab2178095f82db982346a852eee2b991996a2fc6dda0d507655b16380fb475811cea531b9a32ccd4496c711e5cd2e6afb46670e156304f9317720664b602d469b5bd5951fffffcbf72da384604e40da29dbc00e71ed530f86f2fa104c574b57140f006066e40abf64f978d3e2f04b154abe9d78ef455c4b7ef2a6a3e3e5001a2515441eaece870a88404bd60d455671649a083e30f635bc31213f3ad04f220f2ddb79e0fe5eefd802fe86059b95b3e09cd835a7edf26169ba27762b4a5b60a8bfe7f0a8e776aadc099101b84dc140701978a79be3272fb18acdee7ad5fe6d3069a4321459aa7ba8d5867e79eacfffd19f11b48f076073884bf5df555dbfb2893f4d5a01c91e0126471da1cbd6c619754723756ebf09eeff624a01a6d1242bca58362a18ffb82d5c169eeb5b861a692f5f4758ab905d3fd7dd2a89865d84f046490a55b22f6fe87e2555d6259e2abd5e61ae88a04aba3385ad0b30e1b2523a61a40ce5a8847b6a1c229def32bd6def1c4e8d329a5af02855fbc14cd9b671736b2f986f4469e4e37e76d652508cca1a0890e89548a61332c7b0775cc9142a7272ed1933e51e2f32aa6273fd20f7c55793a47383b43e31196602d8073a649453223222f89e5373bf790f5d19e1ebcac05f5745d8ee3ff3ce45ea91d7b26d2f738bc236311d8fcae672efa652a3e6f01de370fbdc2c10d9ce578b6cf41e4d6a9fa199cc3dadba3a23b073b75758bc9dee597a235722adbea2a12f805930d39d1932045970e19b1ec99935b1f2dc783e1a00c319941add5d6fbdae3ab6af9610bd6f8637f0e6e0a8981f7f493ac1f31535ea4711cc7929239a751b1e987007c1ccb618fde3c660c9c92fff5ea1f29fda8aae587a6e34ebd7c38018b3cbe00d1e54b582f9f28809ba770b9e874d5aca9942754954092972b7a526ee75bf25eade00431e380324b9495ad2e51e54a1be9d7e21f4e4a8b5bb7bbbe89d5f8dff55507f6105e174b4de69e8cd988bc95b673dd79977d688c5e1c858581e4107f9d039905d0abaa0ce28a7705f15be1686e10aa5f858a9c0c0b7c6d92715a3a8944f18be13463d120c8b742deceb701ad44015a411b56d18d276e1314ce79674335e382cb0f7047a9bb81edb53272c004371ae1c51c1d01e3fcf6cca026f61b187f5ab91f8d4f77aec38ee7f4a2775c4ca864fcdffdc52db6e1d7c2db08c38a57f3a5565403a60a2907b5a9d747a0caab807f10803465560d0f5292b5e7dd2afd26570b445015833261b24141857f9e2f8a5d5acc4aea4df9dd177fcb47dec19265d7681e9fb9163cade2ceb3ccb920e2be2a6385719ba30c16ec9f607bf6edc8c0fcd2c97df8bc9f3d65cd86e82d6f361e0f956033dd93b83226ed05687796a197d6eb4b494846c28d05d2144b9933eee2911eae3884402ec109fbe4eebf9a98a25534b1b162d32e94106ee11c7f550c71f86bc8a91b500b7a4e33c5d7f2e74b4f45d94405a76975b0744a600e6c13b77aaef655ac77c17549304d458e769d4775d91a9421114285aa7fdbfba1351fdf8918326400690a118fe39aaffb74164d9719912b56295150ca48570aefb628506e43d1a459e7a82a9f80624e98cdb349c30eee8c0c10b810c566da16468fffa2a7694f0d6d11c4707a9fab537b31616d893d7548dad2520462f1dda0d0655930fa255295f2eb108f8fa4ae53ab90d1c8019fa8b4601ffe509c1405385450c4f7634a2dab584b3c971be2ec12503224e3687eeb5a0004b7c811aa644f1685d1efa3648674987cd18ba4787a3cdad05672032f75b1355523acf900bfdfb6f681ae379a202d913cb00c94fc1d66802af55abfa5c77ea81774b766ad826b95648fe75c12779f12d79f4f0e8ab53c0ec640391fbaf04ab47877604ee78619b1af7f373021b4a0ba0786cb3ec09805974ad8857414ac375a1f112810afb0bc31e3fe3674669cb4abde3af64ca3c5836711192a15320f8aa9dbce6ec5e317525456b707d402d83d3b6ba2916ce82420c8aa3341283cd6cffe7012a8f0750370868a737002e68424a5e5231e10ce3d5b025f5a6db5ad616530cee56170afd5fdc05acbcf394413d28d635eef0de3ab32b880466608900f0c70a721a0779a801a2acb241bea8c12545c66057150fea0bd739fd232978412d86f65eb0a9218cc7109bb9754790a8225c6995a195c6eb333f4bca38d0a12796446606f43cd8a17c78d4db41b497f7d7e73e34d6780a6e9dc360e4cd90381b04964e691e1aa9705a67f90d952c1fb5a811337310a918f057956c67d26fdd84b30173507ee50740c5f50a0be0420aa7f96f0482ee65e7a4e1b8f9fde76750c01c8885f9af639241971adb55a4470402caceae2dcf530fb9e27f3753dd58b77b0e3419a0eecc1251d6642a25df0b9eb951d96f1f5f98023fb2cd5cf8d6a511e23881449681a4ef5dc3a05926a9e24b16a98d74fb44fb96fc7d00e48736401b09417df536d570d0a5a84fb1ea69c7ed7e554a8cc1b75aa627047f7c44d50df13b8cd04a9c3908ebedebe224040536a6dd4c4da3a39999ddba776464afdaf542affea19500f84c929e5e8bbd8d5e6a04dd320cd8d47032abbf6d541d1e89de5e542e35d76e2cadb547e0717ab5a82ff84780c6dd35fee7c852bf790cf76cbc64601d3a459f37278cefea278d3c2d45c1609c67cfd7df2a9dacab57836e66acf5b646ca7a813f591254956b307bc9fe9c849cd5c8ef09c107078e4f3e3903494387d15d2c58897f40abd7cd59ce4879ab522d0a76bd534adfcbc7303789dbe8a5270b3860ca92a6c2d33a3d1e57b21f319568ac80ae5324bfae2bd4defd91c22d1d4addef144a9280636a28a92b50a7de842a02c4a642f915ca44394b0e5ece1f5c2ba3113858bb801de14535164a9e94b36cea5aa90bc9491234e9b2425cbd2629ce4225d343e8769f4b45269bdef65007b449bd6fde498114d176395dae85f3da9e795f1102ebc5bef8144f188d8e57fb0cfb2445020772274076c6787969a77e28a1dadfc2fc2ad64ab7ce5a652f67daead3ff997bb764cc67adc148e333c06252d323c9920cf7b526b56a1b1113cc7bcafd0ade5ef7a46c0934cd8c59cda663353258cd3e4eeaec85808149d41360d48db9086f396f80db86dec6ae9e931b138fde05db5a17552ea68c68427f5e5622519ef6c598a5bdf65246e584c0decef8015f4f863b14f2add62fae62ba9757f224c103b6af4fd505148c33f931e16ed4290795eddced3cf97efdf1f6e9d41db7e190e424fba274cd93716e702d852ac2bc6a142fc0be7c5b05a77904564931c1ba9ba446b904ce0a0f9cde077f5e8990e70e209e470d00601ac22b6c69cac0fdc0e84d933ee1668a53fb8e2ef4c970f34583259b87434055c80877cbe4d228890356af0b3024b43444b411876f0e2905657301c2c157099198f8e54b8fd73f0abdab7c15fef25d6b3c004f09a47102ad255c8facc14b7f5dc9f3d870760ab18a42b6eb1b40f1bd893bd89927c0db7b32f82af0dfe17766530cb67bf6b3375df74ac456fe19909015473da3bb4fc8938cc15675bb7a765891a17e40ae8b3a8cb2dff0a17628f44293e61d0433ec053fe0ed95ef9dd724c34e37c914031b7bc5af47437c4a2b65b4cd019e5bf6c2e1c8c819b93b8d78901abfffb0c9270464b52780cfcb5ab30e14474cb38f18cddc2f0eab75e132a8570aeb3bbe58dc5968827f92e5a849c131ebc1b7a35c993673eef8b32769663f0ba6c1d15be148396439ac193f6604f86657b2df2df69d7ff35423e9f7584125d3d6a36fab7f7bb9ead2c5e7a0cdfd71826af5b68c1f2be952c968a9438a22e92873d65fa42596f09a1a1084692157c787bd2378220f018d34d0378d831b316fd593db7206a4fa51dac158c33e483cc2554229e4e6617f07c82056041caf53fe82090a1467150bf27f8ea8cce2c38842f54df4a87c6af22c800b53db555eb7dc59544fadde4d8633238f29c000d1ad7e6da85d10ffa9d0a44efe9fe22856f833111c59180b13ead4155ec3ddeef3a6757984fc6345c63a817fa94e409f73570d7c77cab440385b8be9db18adc5be4cdc7213562b225cfadc3383ac9834cca49b3457922c7c98eb2ef003eb1a3898169667fe08d69ce8d54aa43aa77dc6d1b7c976f018b9c9e7cb1dbd260272bbeb2d2dd0a327a3a185cc5b1bc33eb144d9cba17c24bdb22f0431c9cb31618ae122655993fcef068031cb0ae2f2d08ee09e67654524e8b7b0b28611fab315d778a5614a166ca2d638eac90f360734bba3da6928cbdfe37ec73d5e69dc4c3dee2a84afbdb4e8f11d897a4a16610057d85e4fa6cd4ba183d9a9f89cb633f32e32d5af2f739ef475750dcc6769dca5d5dc075b650b9397f6bad3297a8486c63fd33246d636b2f0254c98dcd7dca6071099802513136d597cd759090480787fc662b51ea29cb7ca387c235c7577a22d0062cc40574bdeab42a32b24eab6c76d0253362917eb9f492a7596e9d9ad16a04da8877621a937f81de17d477cae2c2fb09b70bbb2553d481a05cf8784fe31e82c754ed2c06e0565429c39af92b7a4c8df01446090fe92639600da019f22b4f285021e35a9c6073adaaaace733d6472c107b6820a12436dc31477628ace9fd53868a0138bd1fe5a0ed819a6bfccdf24bff38a11e1090acb3d7ee3ca17085863ab341c8fa3444c1159b23c327c8e7613d39e36c4bf7e508e1eeb29adbeb700dd0ac2ba4805eccb61f80d59bc9693986b5c74c08f0057761df1208f77861fb10733d34241c26306f8fb3b04b6d8002ed4058a9d76809bfdf9eb197065237de43c4e4f1b67ca63e57136848b66e4d16bd9c0bca0ac3ef92821ce072e8a84fe074b1c6a4fd2bfc0f031e05fa78d1df593b4b54b6fd650a773b4c57ec8fb48d5cbec6440d2263f3c591be2a9d89e55c7bf079a12e6650c3c5ee7333638c0ba83c6532ce0567cf45e0707c3d9ef7628ced1feeb32c03b5c368f0acfce3f8a3352720fbea716f8b7b1698cce64afdc3aaac9cf2b5324d67e7b8df629f60fc977daebb558de7721c88324f31abf681f085bbaea27134e28b494934030f7bbd917d7233928c8d94b02371aefdcc9a200db104068b10f4ec47995faf3845a96eb26d8030d9bacafdf8ceac135e4c37e401ebdfa96741ffc0a0c0812e8c9aa4c02418a28b7913c8b840e28e40f3afc69555372665bbdbee0f5862898e048918eff698cb943e8be701fa3bca4c5dd7faded7a30bcc14882d282ee1cbb5b893eb3924be1a18f38ac6768bd50a9a0af5a75231fda46533739db88732e690828ad51d5022dffb926c932cc40f6a1e9f0b0657e73f48913630e33b26606143f9e4db512c8ac3e09d990239489e4323802726bb1e2e06ca28888bce05de05ecbf760d032648f4d288458c98ebc200d9f7a7ef591353ee79d738ef282dcf70c7c8264e4bba20d9e819d9576d8332cd84bfa72e5455fdfafbf94075b14aca2680dcde35f6f5aa1ea35e6e85e3e62fe4fa4c056acb07f5e5abfac8e654f43631db54b71886b0f95283fe0951731ce9e6024ab66d06929703d0c3b2646f63d86fa64861c040713982927b70b3ef0d4917fc6b52d58ea41ae4c0ffb60b8a02ef5e8ded1b2d09bed644c65d268021c832a27f6fb132cefb427b850014f0ae2002ee44e1c48035872f385595f6845b4233fd26a867236206cfb387f73b31cfe4c2169b76fb0f35700bb61bb1b741446db2a521cb1b1422e6249da7a24e717b40ff9ba29db3eeb7d010cc1218867a76d7d980fa7f6c83bdc8cdb29f72027785def33e97fc72370c061e8ad703746b6a12540f730b64af7daca6db8a232032b55c1e9a79c01369df764667f8f549c572a72668816cdb4d4766b3e5c7cda4d68ec63875308344dbe38e125eb2c66f1723948db87aed8494e04d1ac67a2c2df870331770415249787b09370aafc7676a0a7dab7f37672f12c912aef3b4c4ddd819c1898379eb76bd6fb638e537685466e0d35e54c3ce3f7bc591f51c3e34f8b9eac472d42b13a5db0b899a6f60d5ae76eb1e59fbf7cbc603469f00a0db9d25faa90c422056c403bbb1a4ae59171c21a19cbfb3c7ed22d0156819a7dc1e4651e4af85806ae58082f4d196681f36a5a310fedfab99301f61e0840b04ac9f8172dd74a571237ce054599bf88462d66469bc9e9e6112028f2a6d9ea081880cf8df33e1575bbbbd41d03be11f4be15d108566a556a3c97f74b42762c22738894977c9698c805bdff97b3eee9974ea1bcd0f8f6d8b94c3a7ebeec8cedd969ad73d23ae033f9751617c3aef92a7d3f549aa30f20dbd64d224ff43c9c79aa7091c9b902f40fee2be0270970ab0bcb5094e73b31bc85a6fa84ec5bde1eb713db98f8a8171bf71b2a7fcb8fdbc8fc6fe4b06a07a32d7c90637beeebe9907cad70282a0a10468617a5161fe04a925ec84d996a7ab8f74f2678416c20bc76d9dcab72316fe40eac16a375ae310936f560aa216deace1f52664372e187f004db5707a3c8e088127e9db4cb0548c4507c381f860808e7f36a5b92ff0a5961455e18378a264eb12944b069f9067e3633b9dd0ddd89488e3e1cc132dadee424328c73b8f556123cebd1195a4fb7d81576ca373f741a4dfc9d7c4646d39b3240d035f46a206026581cb9425493a94dda146bbe4bac4580d3004251b0d6b592d612d8910323e25a269c884c11d9ac89bf94d4079607f1ca0c811998cdb712a383b0d0b9dafddc3004425e96b65d82e6db8fed9ea0ef19da0d36fe0855e59587cadb05af2f07c8c89baad1cadcebde2ac1a5629c60086820743c01c9bcf4157da3bd0be9a956741424bc38373aa15f63cbe2ec276d072e0851e8e97a29a403288eced7d0cb3fe58f4807da25122b3ebbc12a489eb3c4923cae3b08886a8c24ee474974164483b02351727fbb9e98581dcfbf068e32e9ecf5e1a63ad0a07c4133e26cb10d4b0360840a4198a50ef955b831cf8e74f47d4a12c856c35fdd318b2e454214c7c6a475a4cf2769a03452b543887619adbe7d7b43dc83b6149cabf1db8349516d6df1262c47d421a3a85783e597e965232eae64abcd3244e1bc0b646efb445fb4df050d4b67f229213b19b29d2a8255f5896da6ab94a0667a6f4ba176d3afc6128db0da4beeeb4cc4d23094c2e102c3639941900e50b05aecb33769cc4a1d28e68a1c3e94f28614a22acf412ea5f46fd22c8ab40e4bb58bc8472c3bfa83d4290b64bfa36a598a3b60c7ea2ef617f28d6d6a2868f38679e1a2731ae1fbf1e421596fafd74afa78b6c870e3521bcfb934c01db233cf984773584918358430f84c62594f679b11b73b527628c143208606d270e2a677752f08c12d1b2bce354c675ef0acd6fef920da78c2c57a6535937a595f64ccc60f404bf80084a2db03a0d8838352448ff20a8a81a2db796b844f8ecb783c73ab4b7571cdbf82c93a9b8502e4af409405fdeefea342718c3bef554baa295e509dac5320b19b707afc0242a02586a7592b2772bcb19c44afe2d1001e925e51e343c5ef971ed04f629dea14a6d8a28bb5a854a8c71305402456877d2a84656b669ff7a93168b0a23bcc54b73583d7d28cfa83c62082b7662992dfe3c1f4a3df1c7fc54813c754a618fa5a0b557c0cea0856b78ae365b392969897f7425837439ab5ad689abd1920de80aa60ba9ee35c21a5fb7b0babdcdaaf11e57dc1db3af880bd45b3e27d4d7944c0271f7d610eb85f51fc91ecc708ccb3af8be2cd6dc737096a5e221c4edc77beb4a3929e6ceb69b61d8c771757ff57c4dae8b619dfeda250027e4c296a38f4488753b0111be053fd1866f3f3ba51f8daa73e87a32aea9942085e6d452ea95cd3e6a30a518f556378a141dc112b3a8fdb2ef38f00592f26b9385e5e726a99364710d3e1a2bfd7c4321fc8956c37b5fce6dfa9beecdf87148a2e02ffed08733eac97596871368532524556d2f7e7c1c6478f4a5e99c4d5122f0f9549d130934b2c1e744de1bbaaf729c817a19b94f20b8ca25a1fc70415725a7bbab5485efe6f12e9a57872b228b69033e84bf4a0b0498c3171b1f452f465cdd02628acceeacad42f1450c17ccec4560e628054c316c98c0d256556e3deacf68b8527634f70e59903cce9e439a7265dfb8841b37cfcdd38457226b3e92cec0bdb592997d60e45a1e4450e5bf3e33a94f825133d13c099f188bee0b34ff4cd503acf55fb2bcb61f421af6b2bf60402386d7b4aaa46ef7d82ef232fee28c479c5f8be3fc78f88dd81da314ab06f0024af160f4fb14ecf1cf48614edb6ed0c5c1af3550a167ce44746496a5f98f322af820d2d0c0594b40944c39ae700c9c6c51935850fa29b2440d71a31f35b4c1ba9328e3f9e2f9516ff4c7d89774aa540769a1b64510403a425853fb5235b99c8c97284fb9c285b48d160e7e394e14ecc37de3107be010c6db14bb1c4ceb23ca46d2f9f6358c4c03787d90e257d29f741c4c25ca63db7e3ef55ce3174b4f8fdd730701c43cb4ffebe889acc982d23b95482deb9adecd616c6a1e14edc257d9feefb06caf56ffe5a1c6fa531a1c30222b027863e220df6d36c373491c98686d49f6af33ab8609a0c17b7c49de1da132b64c576d4685e5db74bc8f8d8cf9f32991cd089f239a3448942ae824aa25ff1839ec010730259af07b96b768bd9937d6c6023f82ac6740faefe5797240f829e83b0f3e46c554ce1321ef6fbdeaad7e9b7826f335c983778e214699db6943c71f952dfb59afa82e220ca3f7a28083f408296cd2aa2f10f9dda289b300835dd3e4cd2378cda4c579fcc25551f8ce62623a08987af61ef241ba07f2606985a4decbf58f22a9577c1ab746839882c0d8051cdcdde330e9365bad1099212cdec689fe1c930dd47894ae1fcf8b08a9a0057a095d5c493d26b5af1a259e16f04897dbde813aa531f0ce8cf3154972c83d276548d6e825eed9c29264f2476a6f379370d4939ba84574d5c5c1498cd39904cb4b4432b74295a55cdba046eab40bec45880ae6af37faca0123b6c63f4c65a6157dfec46bab25b3976f254b92f3ecb3f4c42fbcf1d2ee7271b8c3781b0787726e6d66b489a37db56f5580e3fa96f6152158106ccb4a04180e1c9503c272a50cb73c8beab0d9825c19f811507d74e05a6829b30ae5da0573c45a3e9f678c82501f7893b97651fc5b5d7b1e30fde136ca1912e816986d23bb67ca622a6d9a14a0687cd97deeb27bd556454247b45f4057c289524ab7a100ad177ff27cb666b81121a498a0a104154d5599ab6ccc9351ee272878b566cb7b0348bdac781dfe883f3f0242d9c7171785f3b51571e32c6dc8daba724e7db5a156005286c575e337a5854b24c23338fcebb00d82f6e2ed50d1f99cd95c2eac995e609e5652a3c26ab9dc46a754853d670deac5a1ae7387e8ea0f68add19716b43405ab7abf59b9589d4a1cd1267fc2a5cf6dcd94b5b9deb1d194ab483216c74f19e4e7672881c8364ca56735e1da4d9fcac73d6e739ebbac019887d7ba4c3d00c465f0696fb22bcab4c53e49996de6662efc43753a9a64c859e32d317b71c4072c68511dcfdce4e0dda6ab2dda34f84b722c180b75875c9751f28a69db957d51f782a40b0270ddc9818f905c6da4161cfa751564f7bc68978349ca5177e3ac2cbb4bd7ba8526f583064fe6587ad9a2f292b591451499f2dbb1262c10806c4514c002b64753e81de3dceae6201b493556b806e4907cfe3f655d91f21e7adb656b5f246716055cfe5882291cdc66ca8782b9ae676cd4a56d587817a4c0b302f78e6748a01c7c084bf426b34df91000e00de235a118773e94a208e199d157b55712df41d4d3d1d0a2acf71d36fcc4b6b1f37d5338e6051d705d747fc7ea1ffa4a6708ef31f3d2ab61bda10e95549c42434063ca72ae14ce8d370c6ac0ad31ae1fa80cd3ed9af9c14b0db600daef8c0ad069d23835519afe2419d635a7a59cbb8333dcf63ed2542a34d3d824376ab09ba9b091312073671ecc1562d75509d1cca53096cdeaa38a32b2489295e685b443129643b03fcdc0cd218a9a1b13309b8b75551a08071e812941f1a9e6ba503a5f8aa653719f37f905f57aea6668deff45468d224a39ae1d0e5ecb41e01250dacac3e07a667cd0a0148ab8c836c477f335a23badbb5ac6501f4dfd350bf54dafc80231aefc5ec124a2b6310c9b41ec581ff6b55832933e8e35f8e732523cb4d06649ff017bf37495cad1ae40f6a33c73ca4aaf4a313a76404eac10138010069e39953137cee764109a0f9e65ef27541883d4eb197a6f487da1300fdf9a5d8f0055da40edfaf7018fb86415926c7ef9fbd53e11712a6ca38e74d3c7eb3b15981a848f14d09ef63ce61f58074fc386705b8f4264d460fae5b13f2eadf5f70878d8edf1a30297a4d1a1f8a6eceaa6ae877619e8e87d903a7f30059f40bf75792bdddd48e851cfa0fa9f6e501350f2c596d61eb7bd0cdab34b561d0e77e19d224b623931f6bfd7f28a4af1352880718eb7398dbf0d6a383b8389b8ff332f0c0d507b5b7d83bcef63b7d11e52c64645eb22300053252611343db87a2b36659fcee5d41ccbcaa0a49e9e0324bfa95656ea44acb52d1d466689393ef900ac7cafb6b64f43642f9ac87ef01fceae56e229bc9f05c260f7db14b17eeb33c2f4c088135a9ec74923a1612346be5c4fd2a91d8150c2fbe7c7425517b6c712848c1b4d28753733c5f38f0d16dc50a112162571a5830b34da357699b260e4868890302a328a702ca50835d3b48313dd48497d3eac9b71f4d55aa55af7de4cdc245cbaed58f9c2e830f1a5d358c619e3887f6746bab1ffe6b1a8eaee7bc36daf01b4c2cc350af8300dee2aed19154dc6f15270b497a2f02bf8f7421a37e86c5aaee61a27cfe26568ff7c0d9fe88cf026191a3ed7e893506ec7a245c6c55de82bbccf287996c46387a76f18558882fd0e8bc52a6eadd1ea834b729a41e5f4191de148771a52664960088cfdf917041d01e203148837c1637b60a1cf0a773e3b158b2431415a546400c592eabf2b04552931cafba6352d398ec25bb4346424f996324a22863c320f26a76218010170f6ee8f086558dd667d508d164751bbbe67eec8d85a27558d84b28fb0de624f9c3710c046b7a5e4dfebcc810d62582d53fb9ea23dcb65793ecaaeb52f90ff26511c2a9b7a01de0936874e5e806ccdebac0088614bdd510afc58419690857deb6a3a87458bd21b67cc81fc809ae1ff3b6a71680d2722aa7c342db277dd06f47dfda83eca0e16130688ff81cb85c43c812262b1dd21a82e2929c17b678e650f9c94750dbd3b1694bf1acc7824c162af49be04918dafa1be6edc220702da88d98763e9d68b021021cfc21636dc1f3914c2b5468f04b21ac2a8e5acce2c13990cb21a31006ffcae2316377b13ad321ce3e200c1eb108cdcd2251ea2d9a2caca95dd66ff87ca4b4993422d6e7f06f1830ffb31c2536e70d216790b944d9650b981d5991fbccf3120958b5ad3411a90f2cd541ab3a5f29b547840fbdf0fd18b3be9201d0ef1c9d206443f8cecff3cf27eabe1e7307f141659f3ac21262ea65f3ca97091f7285b4fdaec99db9a90c7f2aa079cf22ec0bccd97f1a3485edb69926cc2d3fef2e836826598058c02093417bbda612d6520c2a772cdb56bee418380866196d4cade0b840138b881f7f6a14a88d74fe946a03512bc5c674ad089b226d19bff65d546150b958a22a59f74f12a1bc6542071cf855dca3736195eee51d4ae924d9d20263c9b7ff81626281968aaf9a5c0d6c77141749fff7e237e4689af56d1bb4aacf4ddd1b9b8200e9afda9866763278100c2d348f131a480d011caccce4dc2ed30ae6f085d6d8efd28d6e110e0e1a29d56026acdb9e4941ad6a01171370be81b54c90be7d861ff4a4701f76fc541993565638b54293ab3b9199c8a31be299d4c4bdafad73e494e3ede26a397bbdff8f782f48c1a7e91a629e8b2a2581c24a9a4eb442ad2373cde6195bff09e5e77e4a47744c93b1921e174cd53d7fd4088321d7bf2e938040e99246696e188571bd040b29cb210a1c4219925802828eb42a2587018a506a56723ed6b0166964e10c934a8c51b6711ba1747ed97b4fb076cb29bd98e07cab72f2d2373bd8d7a184dea88b48db2cec8ec6ffceb81aa1eb31c43534c727fd7dfddfd07b5612724d77105333d0ba75b0b8c1187aa34b706235ef7f2620314f6ddf8af788a46a2e50f0cac3fe94d1848ed6e4319165db7ff66117f2d1883b1448c699979dce733b2670934aba04b988792ed3a7c8e8d091f4f0a79d2c20b8d86f138b57e35851573498483e0cfa70e68a1df4389769c9e84707d36f42ac7b61563d3be0e32bc2e3f03d77f7ded1d8e73d95f290f2ffe3ca676bfe7e0b6da56f804ddecad910cf102e27f996b90e2b79c6f53ae55d2f639cbf1524fbb8d1a4c274214277a3bad6293d1622ab119f8d5f0c06e5a74367dfc5064d98528fd0a63c3aa540ce84b61f6ae8de72f16f71cf5509bf2439eb5634abd2606457bea9b72d841bd71dc159230c9754caa5d1f99dcff2e51abaa39fbd2f8ca947da8b9c6565aaee8023292554cdb922c77fc503c852b127cf6128788f4dc4c6e4f484938a88bd9075aaad5c9a35a6f99c49031f7953babc38949a2fc65cec1ba9869739101942183bb7fda5ca1f70c2944fc3af851d70a52a30124fb</script>\n <div class=\"hbe hbe-content\">\n <div class=\"hbe hbe-input hbe-input-default\">\n <input class=\"hbe hbe-input-field hbe-input-field-default\" type=\"password\" id=\"hbePass\">\n <label class=\"hbe hbe-input-label hbe-input-label-default\" for=\"hbePass\">\n <span class=\"hbe hbe-input-label-content hbe-input-label-content-default\">Hey, password is required here.</span>\n </label>\n </div>\n </div>\n</div>\n<script data-pjax src=\"/lib/hbe.js\"></script><link href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\">",
"tags": [
"life"
]
},
{
"id": "http://example.com/2022/12/28/2019-2022%E6%A2%A6%E5%A2%83%E8%AE%B0%E5%BD%95/",
"url": "http://example.com/2022/12/28/2019-2022%E6%A2%A6%E5%A2%83%E8%AE%B0%E5%BD%95/",
"title": "2019-2022 dream record",
"date_published": "2022-12-28T14:10:22.000Z",
"content_html": "<div class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"Oh, this is an invalid password. Check and try again, please.\" data-whm=\"OOPS, these decrypted content may changed, but you can still have a look.\">\n <script id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"d13ca3ae6ee378c7d3a77c01a45099397b90b4fe62d6ebb817387c4e8e092893\">a7f6cc7f088b73fa346a4b9d957bdfd9324e66270a2ce054ea576980c9cda0173286f4a3696778e7d27b856aafa861f529e130a470a7a4d4a5329f8266ad94931487bf91a92208230ad0236c561347c9c6462d82b53cc27d6531377303b112af0c95833be98b83d274e661b70cfe8511024cf1ecd5313f2ff38b7aad8fb6d007cb9bd7bdfe7ca31ad193ba73c7f6f65373ec273b691812c0b4df2835380ddc919c3ad61df75c7ccd38f88732a422c5631c3c12e9118a1af5186d53a49bb9b95c95d05abe978c4fc56d309beacf99603086dd686bf798a59105dbe3b71ff9e5d3d2215b8ecd2eff29f3bcdef21df97fb511418e21ca646aafcb664f85f224318a2e2057a7841d255f98e96588cddfb1152fa3ad00d63849d23dbeb1e4b1c2d78f6f7881376941f371389efe7186e1b0462d4c53f3bc1644e147934f909e2abab0b54b840bf3bc6e83508abec226de0953ef8acc9de1c21a431eba0c052efbdf5595d2d78874ce50c35e381cf69c9ab92432563ed6f2e27bb06a5871bbce0c147e0bcd9d9eb8a8d5cfd5fd9059f4d04ef06126ae8938e95d125321bc1bab1c43d1bb0caa6bd6e9f961b7f131a27694c3412d0b1e7b6fce79584031db0060b78d3b12553c3c316422508be21a191ee8ed5498cb6fb3f3376f35ba5edad4a140378adfeb1a6ade552eba092372f597f97c2d9993dcda95822be6eb085ffe37ba4164bf98bffa3658b93e430ea3a9ea68cb1a09496985666d1b2b9329f8ada0014670c29aee9e7077024a47dff454b068de2d031ae49e12b479f83a2a32bc5a14e9f15ef926e08ef161bcc3473b7ddd66c2070bb5df8ea53bfcbe465dba4e91cbafb4421bd66549b4486d3670c196f48d1ed39180a38da6a032949c84c778847786a4014f31d69d57a2a67d4bb8f70194c427def15c8625045c66292d3444e1bf48e59351add575fd36d146ab71d29e90cccda895d324d6c237b3167a7d0f0f635badbe7794b8d222783afb3b227eb4afefdb0f3f79d5fe511bfa3aade3ff925b1c62d96bad08b6d81358e26304aeb184acc7452447c401f351da08dbf8aefacd155ff60437971f1d050cfdd491bb21ceafa50b96cde49f81dd6c81745c10c77658209d331308cb65dab09f4747ae380e7161930f4d32572a4432f127a5ff0f281449640f6200ed06c1db52efb7a4e678cc7b5909906ea6d12fe7ed63ca38780384be8f4511e21ce2b30b9e29e82b0676b7c6d7405a4cca02308245c9c2ad06e60a30c5e8956df7ea05fb1e909b66357dd69fea549ea2ed48b60fb76acab352a8f1f5392c1242478b0b9fdf3c5eec91b2809fef5c3ea2fff203e0cd59ddd6c803e9aad7e86a8e6332d4f76956139328a02758551b830d89dad9ec79904930565878d0dbc6daed9f0abb5d11484ed77dbd5155a8f53c631754228282b3b44d342103be7b88488f7847e9cf6037a73705997280e2704a799482f5bcc7c12e0dbb5fb489398b6904dd42ff27628d508c572c8d429a49d47779f689fb4eedfc4967c0d2e9641e980f8c5088eeeab04bfa0aa0c69602c1e413ff7f35d02efd585e6f0b5a702c6d0b96f48171fd228824dcec0deca5f8ad1a628d7e18a41040c1b017564b86da77b4db33341a0825f163e0ef085c5f060eba7c9980b9bf2360217389bbc19262e8b071e9a0bc6472718886ddf62fce77951a4701815ea2751f9c85edc3687701b8265d19b231ccb00144f2e2a1d5fb2dd8983b1b71c920fef6443d3298e340ad99fb2452c5e2cac73a622373cfbd3d70dd930ebc39f349473ed1d291adb142ba0941a3147fec487fa7ed2ab970b2113d84d7157df60a4442ac5970cbc6ce8577ab1fb304cd1c457074b3d34af81e869d1f5ac271199dd9c9586cc5f22888508ead64e0b25c1d5a14ea6922e571b39ab04df09a1a36cfed0cfdb44f30f2337db7ae789101256e6cd7cc9343635a7e0b399c44e77adb4af1e043b15a799d208b63d5914b32fcecee755c3b6146beb9643a045cc9f65262e4cbfa88a4867bf737f15aac984063ec4c883f6d8b1b616b07aa20c53539f363490ffc9343593f2f6319ffc77203ae63626790204cc415a7b1f9a3bec0a54a5a6ddb44457091f6354a844e75a3d4698d37cdf3c1e07d5de954a82952006edfcc50c14dcb7bde29584dff66128b0c26b91fb2997a7c8af54ecd252664b7ef59f6cf6a2e9f187102468017d19cbbbe35f34df697444dbe2e461689a1092effdb347ccb6c905e84814667efa3bdc8e37f769d4dcb867473098f95695167bd5f56b313be5e921c9d898b65fea745e72cefaaf41fa6fa1ea8bd5c638b3258f4d1e81007f4d4fad4adeed4f008939e102b234747fa6971df866069ad38921c5b8ec8a4517af5003dca0a1556996fade9f9b0bba25010262365da9b5e11b78b0f05ae3e5d6fecb831f845a6353a793125d17326edf0c7ac75a05521942bcc5bac21e33c2f44900d4c4245a89d64b1a47180e1d91f901590a0bbb2c8df9c665459d68e465286f75f43fdb29f50f841cf4f12832267f56f23f50070072f75daf8426b39fc519fc92fd3ae9c90371382ea96115f985f64fff9c601338548ef68f7f0fc2dc13c382c6a113e2a7d68aec1a0a51460c58f9e30ac68a788daea26d3a76d25abd3035fa305a0cc89041434d257914621e13841b5fcd42d419c78db4319b2ac45a521ccd4f1586ea44a75aeccc5a0c31c97e8b1decc8a0ccf786026fca7153b1117753965a19254dea943355764b5b9a659bd75d0231c054c163d4dc01f25b50dcf837f9127264080e7943f886cd0a499b97a7b69ed9085d1196c7c0656136be1195ba862d9315948c64747d6fdc844c36e1f5a9594cace92ea350676140ea4844e2f75d4bc19b7a6d2c3de9aaf5d4a302f7ea8ed8a38cb0ce919ae916e9da93fa5c27213fc74ec2d7fc7ce52970411c4cfc3aa31935310c9afe9076b0a3953c056aded46c2fda272260cf97f6835e77c7ddaa4588f48d9d586412f77603885b9940bbd1ea6ecd1742da4fb105698be62aa59087da9b38dd2154c3a23ff9fd2bc06f74a08037ba929d6d678a964b757ebcdcb3e46e8bb7764ad0a390c88567af66ddfe7c901acf17194d023102dc2de743d92d7d3261224c4fa015153fedddbc364fa4d1be8da25c53f7447a1714705746c40cde4a1f33007943254d27a9ecbb628e7d15bd3b450bf6ad6c52ef9da0971bdb0d98eca546ce10d51583ef7a11f8d7ab769a270493a3c85fb52f3a8bdd88d0e9f9181c84c34ad81cb7747f9683c59bff2615d350e30cfcc37e138a99745c358c73db84ffd4450f56347da4f006f1acac7bbede2a12d3c1e78b3a72319bdde72a0cfac738d678baea2efd6ede43e14b7fa1b1a2f860d57455a3a81bef8974508ee7d38589cff6ac7e750086055be7d7cff5440f885f35a935787fced98b2aac58f4a5de8d26d861dbc0a8d14d2ae59aec8c5a0eff9d4015d5f26818e2d03b2e7e03d270b8403f3a8b45d03af4f8b099b3fe16a849208836a6645ef1b2b6491338be3edc848d512cebf4addc57358cf3cdd76d71ec0311839667e4733494c2a6273013a681d7c29d207b0a6f9412e677b20848d9637b2621befe23e180ab887bba179bc753c7a57445b85dcd3350904e9479bab25a6e61c4115aff24ba0ea3123cdb2261d0eaff6a798b76c8503a8ceddba1ae4168e6f8613d58ea680f65a60929b72252bed7973ac302a0459f384d128c232a48e697580ececf86280adb9d05aceca0bbf43b136dd4f502ce92037ba28035245d1276a9acf9e1f98ce9e9b9b1d6e0785ea6aaa014a53ab3c26db2561114e2f52fd33274e11ab17f272860306d4320dea75832703c387d5b83725ad0e877edd4250d4f1dac922b789171b8728672558f358fd1bbc6a74630a882c78f3441aeba745ebd9da8647c7769f70951e9119904d67a7fb7cfa688320e824ab555075892a8f99b68e3da68ce62d64f250a52cbcfb9383079190190074379d5087de7f4abf2e7cd6a6c5e31b9ff69b805b79b9fdee7d5fd459fbf393f86020366663f2d89e75bf667c2350231015d5f0a6e914af0c71313abe72b67aa9a9a3fafd84dfccde03a9c5fae8519ccff6fecf38d6422a185b53a6ac7d7ccb1f81788c41300b9b57db78083aff938d40a1846aaa2213d6a9b0c815af33d78caecf18f2c79b52943e27c109087479d9580ffe7fb2e991ba4d4edf2737e0b513b7503571bd53065c2081e6dab7393761da38ace1a95db02aea1cc597a9d7106ccbefff92a430cf9e5a825f8a88b092893be732905fe9e3dee09a62d603adef27ec28cb961f77aab1a2fdc2304fe437b37b6eb181d04c8b7340ea5c278a0dd9da0192db67294b59d334c7d60fd7590edcd8fde9cab7644c8ce2e4a69308840a3d04242c3ecb7d71b7e68dd31e9fb1ff1415a9d80b4e88e03b2e57c6eb7766b056cddcb732e37415b897615681d3899bd5a83e7d0bc4612a815bccc05dcbe49cd56ca3a7a7e2cebe512f61b3c905c17f5342383fde5f8f9605333b35e9f977799eecf64caa9bdf3733e7a30463241bb75ca91c866c1abb1f8468e953b3f5e39cd5f0eb46d0dd886ab30342fe00d6aa50a94f812f74267533da645a60b304c522b0eaae35c44d51c8a6247851b196dd33878db9c80757bad79712d840980745a6ae666131b33eddc091f6d28934f5727fed0ccdc8d6a9dc08695498567e9527f032d3743ecaa11ff2d79b033c34ea0733c4f4291ae46788a962c3d7d569f460264d224fc7f9c84957fb1bf75e50a2c1cadd09202cc79ee4d4655332110f91edb59bced8bcfcb35bf45a5697249d6aa99cee1e277fd93ccf61dbafa2b4cd675d4efa23f362df7440af6c39c8c07be2c82581a267b33dd97900a6bd3edb4c5c7b0d8bfe3b039db184d351ea984e6ffd00f195a7dbcfb1c1d2e19161f4031060af0b625e5af1a2104ea6e615529be54443e78b2a0acf8b4bde46e5728341c2984776e95453d1098a9d4889ac35598b784b7bbce370ae71041918298eed09ca0d7bcfd5f38a75c44bd407fd72d0107f692fefc790eb55f56c77d1dfd191061e953663d59d0f80e56dd50bb51c1a0c4cb34aadd722c44ad787dcc2532ebf93eee645ce843515647c70319fba02dae90cf6ae4c0dc3e3991c0876adb66f3182dcada383bb48ad58ad1c8a5f6e2f04cdc9c6cd961df5814e19d334f79cd78afa3e92797eebc77feb7a7ee8647e0bbcc5307605906f1f0cb8306de6a6b8d777c3865a1a7b974bc16b82d7438ba966da0ce215cd5c603dbcb5f17fb7be72e2e27e4d83d6c87b549c1c40de2be6cbe8bf5cfde0c3a6a3928ad8b346f33ed152053c77e4147344f77cac2d7e1836619a40849f238de373412e53d71562bdf8cf02f652fc01c4910cbeb9c77a312fb4f70bfdfc353f29c1e7f7ebf38f1c575726d4b02f90991c83ca11dcae69d8ad2fd804c4739e3549ccd34b76af601254444c6a7669c7d50ec5bec3fbc2ff8d25caca1fa0598b1a66b62362b2cca17e00f1e284fc39814bc65cbb7e119511a9acd0155ccb670d9cf9f0dd77910e9f35dbc1dfb5078025073c73e86ee2fbeae5109f8b424299104a12693a393c66f192f07cf1c3d025beaaacb0d7664f02f81b0bab0d085a989016cc10d2dc1268f9a66c75b471b8a5264a93e25d3f023eb62a0dedbf8689a807b70b4f7fae40efcd28b7115e9888b10ca89bab97777a45b19051abb44510d75e57b8415eca3792b84c3b0eae545eb27e6373247e6c278ac14b6ad01023317bca5ddbccb9e790d74633a08e486dcd3ff150cfcb3252070d1ee4f98bd0039f06d47ee330191862f74c017d1b9356591c62739f733c2a8f796bf7590c1413c2ed55fe3dd3f7bf028b5f10026b03779232c910d6cc9a14957715b9bfb34638205575647eb13fecafb1c0213847b79065926bc58fca4dca63fb8927307d692e549cf05022c15cb50a165242c77ae6a6c9cc73ec9408c372433233c5cefc71c93b0d5042353e198b657f5eb7ec8ffd971da78c1872287cc02cda889097d9d784f3cbc89885b3fbe7ce69a6739f655e5656db6384defae2db24b271764965250f064181f5c55eef130f70682ad062681abd5485b5540428283aadab495debfb52f747cd64e7f04f29fc488a8335b9325f21d8f1a19ac80336adec9fae1c6b6ef95443fe5e8558491242189298778637432e3c8b62a85bd378466a459b93c35e684696a958cfe9fa754a05055336d23d9bd5eb0b9bdcf77bed8205bb8d1c1ee76121efda1e64c3e86ceeb98f2c4dd655040ba90921dd11cf0cfcfe87606ef0e0dea348849ddd7f5181aee9b164cd89feb5d7b1365e6e8fd2151739744bcd1d6648d2717236387df33fc61b0da7dcf6e5650714634e5bd3de78abd5d70df2b250051940e677a144c333d82735d589213e7f5d8cb2208d4daa5645646fc99722d5ba332a5391eac267c9a896df7c1011d14a1878073a78bb63f043fec57ab39cccf1da7d60398af296da8969b3c67e4d2b41a18667a313cdd5859cf1632c1608c8a382219c8f94a658a1fc54b8155e40ecfb71708cbd6777cd29118ac4099dbaf559e1bd2006242561fdaffd916f7c9e4f15f712aa36591ad8f6e29c246202a8acfcb435ce610e02cd6267590e4a6e31153818747adaf51d5b24b3ffc1b4190e51001b9dc4fd6265fbf002028c692ee934e833c0b7333f308e872dfe5ffef51bde36d3fd8711f25c58ec7cd560e1a792452d3f82e6e8f28ba8666fd9429e99274d88964dc195574130f26ef7f04a253d2bb7229bfd4f3e1f57dde0a5a0be1ec9366500c37cece0212494ae8e8d05210623945ae0908ec61795402868b313e41a3209d5eab149af3a3f07ff5887deafcde85a8ed4fe173778a0f264d2b2654c6524ef1c81e1b94e2aba257063f1c668dbf3b67a51d33a1a542080df9627a1af09f3a2cb332ba49fb0a31f980e84f6396d4556ccf2658369c0a9bc9bff3763ec5467952170e4bd632ec4943a753d2e7855624a9952010fb878ffa4464d6af5fe37c561c69eba502fc336e86af1e3eeee05aa2ba1c88b19a357fa355e3f981f547b54e81edf4ca1ce173b4d1c8c08f1a256343fd99bfab62b2704f09a846028ff77d9dceee8d4df44582002b210138c3797095fef9fcc9bfcc6048d6fbd07a3756ccaa89b7d5c62d9068dd405a5814983d9258b33c08bcb7e1f441d2bdb7e0d059f688f06891c7fe9bdaba19b67ffda1de70a62a60478f7fa92467a3a5971e752af9785fd093922ca03890fc5c5508f4bcf91afb06225712dd112c487e031f5a586d62801edf26779106af3506ac46ec852e2f94d2989dd1468b174a4881aad46982519dd75c8969fe7d2ab37cdba3f0663e3d3b7d767bb78e8348d525bd28821372f10c29c81ce34d864214094a8f3d4ee416745184920500e076d8dd12ea95857c4192f953d43c9baf37c79e6c68c3d10e24c97c9df35d36f4b53fe10d3f62634d08d8b3fa1d01dd00fa0415a34c2dc85fa78a5d8053004a42559b00eaf80e4996992544257b100add83586f200535bd704ab6370b4d8528a8535c2b3a7c79a15693b1120486aa0c09b211bbffefa65bf6bb0b1f11be3eab3adc22921361c85b31dda3d6ffbae78ed19851f06eafa7762f2a7f6992f99e565ed8c7dd53f0d2dd2e5e3ab388529094a873eda5bd7910ff0d18e7920a17a211eda069e2fce94e156234e14288b5cd25185a5a1ca197d6e8a425e04829efc3665ea4ef007882cad419223a055df42b71d73d44a48bc1292c5e0f7bc67ca6f08c016c9c8ef938af141026d6f528169d122a964de69da3a1815bfdca3ada0efc9e4143905c059b384e51181a074768dd7af91a9100b47589825f9152f4ad57637476c71b31c19752ed480bfd4526cbabd829e508748fd815639eb9c10d8220a3c958de8cd0a3818c49df30770d698896c78e6186e52780e37bf669cd0afc91d2d08a706ad3850984141ecdf300c9c7a5749ddf8cee2da2921c6101a8842791f47d8a19f198d69cfb6e9a3f61f31130c14d0b2a97f6a6b5f872f432ec12273e28260cc198a247d9d7560ffc35854fb4f9a87749a78c2397312593556e0b0fbe1d52bb60ae5fe1dd4f88d962ff7ea5e7ea9c479f1b7917e150b14901f63d31573dec70d2d59501e5da267056ef51f72a6e36c9d1349fb6b1e0744c8e41c48218eed033ee86fe352f4c9314a0a48a4987f2fad80445857c7fb6cd0fc4871faa3f58a85eda97fd794f6d7d3de7d4e99a22667670cd954fb4a1e4accba052f93778dc127b8f8a2705383e47ae4873b6ddf64fda2c9cdfb5214679f6beed47dac2e6c8f76f59e4af77420442b8974a767c131581b0fd05437a8ff911a3ad8e1cc24bb4e338c1385e80e2d40f81733280d8b4faf6e69abdb44b2c49c7de3cbce8e3eeef47ef8b35761948a6af3240bc19c1f60f637d811110e726ad8ee7386a39b69cb5f50d88192f568925e6b1719af6261eca5c8a246f803876fdd7fa6e6aa19d3c3fa906e26f3a88ae1ed4a157bc291d35228f15bb36b2605f0bdab71093f43dd9f3cf34581396f57c305fbf95321f8d7585762f0e6823015406388477280d17207108268513c3da1419a53a31a96adb3f0378d6fb159e28d2d2bd9c55190bcf8d53e53b386895f601764faddd8e86c8c717116a9bc645faac62acd84692f75e3ddae3c25d30ae95398a6e4497cd110c6bdcf5a6d0b29df2c6e4d6802acea319cd57d072934b8aa82d1022ed9cae368782add623642f936984cb1938851c5903d5967c5ee47996c6a0bda850e2c0c73fa466f164f2dfd012c0245e59ac704392fdb8a4091439b7815b45a3d06252c3c603b0c6ad0bf5a250dcc8fe335cb3e645aae8f9bbc08058c104f6a7171870136866ace21a2bef96daecf2cf5b0f89a51bd96beb97f67c7532b1453e23aad60d8518945e28efd632a9f3dd9d2d9ec8e69e7ab7539c3697861502d4d3e87f53a8a8084f775a16933b5541c3c93caf9b18895cf0e9a2bd5bcef11850c69912bf0a9d42621eaf6f49672f57c89f761ed6365c6d4852770e80dcfea75cb5c6246ff427c6a9273070ce861b4ddcc4bf8b78c99217b701f1de2568222c47f629dc2374f5f556377d825260031296fc88b2ebad5eebf403885c104c6a872680ab29643259276ceed1a7c7d9c2f059c21d19d45290a3fd5c9a79d1d13508b773a987c6144b8147caa2495d5302ed43b877525cc5adff40aaa2d1c5d2db6896c45e0ca2cab2bb146ba070c8f6b4bfbf86d2ae88fc75a38fdfa226410c37e06b8552da06104591a4b45c6f8be6e27d3da5e487427d407a6c3c2882756b0df315bd619ddcca58a9b08589ef5f1224c377856a6ffdde85d1a6118f9c96ac905f5aac1360366c4f03521bbbb86195d77f6a113ac299a2fa0317d2a7f63a128e3ab247b4213e30fd2f45f418fa778b6d7eb234b03c5be8af1289a26eb914cb4964a512bb86dacf5d28c6374b11625f3cd194d6b637333c63762d45f5a8e705b5228a1399283d5922f2ef3b059adaa01d615537a8153cf7af31f0e4485f002d2999f7e452936b39aac608f0d146e42580bbf49c059d3b2454d9031f7ebe613b90bd0d3c0ec475e013f6be535df8c613f8f68d1ef784c559f4f500f1f4e65d5e70221d665dec27f957dba3c9ea336d8b02d977e689aaf632b13361f2a43209dbce4152c87a321a194bdc7269c0ed81f37b3f430189347683ba66e26e20142b80a736c4feb646174a754f93193c33422c6fd4d2040bd397cd285d780f44dcaddd2e16f8c293a119beaaa31dc6c4fb067b04102f0b31d3949ae3e22e38504431224261907293f686496ff7623e32cf3549e8c32a664ebd9bbfdbeedbe6ce1eda1505b6b38cc76949a0b7e08290988e5d91f11e9693609dd12d24464823072dc3d9314025f60726f4c30fda59d400ed853e3a68c20a7ad60ac8d3705e6a6c0568dc3d4485ae8ecea84faa5edbbb5def2c0a383c315fbc073fbd1a0de8b75edb3537eed1823641894e0febff447cddd2f1664c1a846002ead4034cd2d8898a0c21722ecfc2317207325c61f9a3a63df05b9d9c20783827caebd7255734528020a81aea6aaf57c1de0d369d61187c6f17e2d74067cc3988cd2088e4ebbfcf7615bf50aeaca19ce3b2163bfd475e2f4a14c0079dab32b5fd5c2115403335597a8c6401cb19825bcbb2850a702b7fe6711dec7caeb85d5815b1a1ef6da74cc931bed3c21d652911a6604bb0cf891fd4c720364b7384e43eac9a3cad0991459fd8eb3e95e90c16b1484932e7488b180b30c8e768ff1242d2e9772dc08e21a063c6ca6897969f95da46aed6645b260b0b8dc6d7c08fd3bb044b58f6c8719a3b13b8216749ef5a3ac9211ea947c29ac007d27ed7cacb5073d5c33c236fcf0f194f890c78f00b636bc3310f7f5cea46e236dd75ebcebb184c5e4025000ba34ed65d15a20d3d60b8d69de91641da5e44e2df69517c3a305711209ce150e4df85f70fc74f4b17488047d6bf2255bddad15086d6bfc011b5e3ce93c7db5ae7de52439d496e1caa677cc06e69b92625d91bfbacd00507bb6972f56a985efcfa33b5e257eef8e3676413dd6ff87e05a5cff888d9cee8382613e2811420d55708a8809a29af713eec8131d51f9cde97e1afbf7b786a7a47a48b815b8a8b21bdbc3372f248f1b1ffa8066d156a98dcba5015aa8b42686d119aa933398cbe3dd3f986f7575ed42914057801cfc24856f743f701bd1ff9c34539b2297405d45930c97f310ff5f6131890e964db47d769b695a225f8d52b050c75763416e872d334fca084457c7d6b0ad253da6c892fce362ff015b3b2127092aa07c28d4d7ec5e20f5e6590c5858d710274942eaa94e46c1a738ba908188d690f12c0a18320fa4606921a8476c02d4d59d42c2485d3ce63cd7ee6a59443242a83e21fbfe7794431e17ce60a792aa85d89b6760a4d8d3057d2a1b1ceba4cff16c2b7e3c9b9e4b19e59f7699a738d5a500826fb2367b2e2b95cec7284f8cb8deaceaff6615310f0d8dbafcd2b46bf78615c243a97c15f12c41702891d82b73be2d031133292072205ae6f8cd22b628721468cb348f555ed4fd6df44bd241d1489c639448150773ff9af3b19538da7880d865753926c822b3530de882910e51bbc93bfa9c415d9b6aca58f849e7c377123fe55c77111728854fd40967678fe84d317b5b2fa83122d6d30b7e0e36c30ef6dadf2d77d3f0236e6d3070abd9e75ca1420c5d6feb9715c909ac60a4310f0bd2d8e2ba8eaa430f53cfe0a64b79827a65a8a7472e510c89bf8ebce6af208ebdd14a282a367a88feef83a69022bae51133eba2567d16a8c000d05dc9dc272914a1034d7a005f879b34c49ba86f1428ee5e3b701fb282e52cd7347ee9fb7e885704c2512e5adf0a8cf52d1bec9c5f761ce48d0bd6ccb405dfb5494aafd2361775bdcbcec3809c55699bc9e355c24c5674dbb4fbbb6d14a1bfa7add5fda718439b063f32a16c40aab70ebe9c98774ec3771633828b6f08b3137097fe1ccba916f13c6b5f791920b3688c0c23b8b9e9d7260bd12b4a1c347a5573944ea96412f100d637738f3533370cf6c291a01bfa132f8a02dc5dbeefb26ba17c5eb250d8abcff68be483861bde71d789d8f5b1cebd8ea49c466cd98709da66bfb8dbf9295d725007df3b08fc0b6f25e1ad2d1485bb98f940df8c8476adb7bf281f18dedd62ad4aed401ad1c1d4e87ab2549c4955e5f61c3aa77e43201a6a829e1e9d6c2e18f3f489527cd93d6c7ed57726405bdb4f3baf8ba127c74237d564d624c5b380a61098123dba2b275297d0e360bb3a43f62519e8d09adbfaee187bbe813d0a1b6614a20041610cf18e4b11958ed8dcef379b855409a9ad4890e2b269f343dd0b438c3de7ab91605bdb57a67848027d5d3a9227a0f8507c646d061cf89013cea054ad41cd4b59f22e4e2b770880965109a519d0e93fc1328bcca46edf26a98e671dfa838a407f317d8724f299c53986f3f0ce1b4b6f4226b33170900c980b59de873bceafc1cb80c172e47f219de24b86cc19098afb6edd501127e21f2dc9dc98d394f4e830e7850099d361b990680fb4e9c88f250313aa03ddb7d112d30e7e6e360f7a0981eeec15214ef575b145b99a8b9e51038052ad7c8eae0b2af85c3de316f7dcdd08b1686cf9a5651e1ebd0c1790b06eac931fac54c7b583949002892e10ed44f3007b276b696f5dcd1f097401b90abed12214ff2b6844eda75c54d7e9d6bc6aecf50bfbfb6fb4cde237cf5aa82a4c3f5dcdaa206ce2f4e0eb13ab891994742e12373d272752a447c78f7750f7f5cf1adbf96eb40b8abd57a58895f2204bbc46ec6e10758b12f7cc39c22b7c28d0e7ab15bd0954d9e9864315f5d75e008548b7b2a88f6c35f78a3c4c5a2e985f31bcc4f7cb35db95a68f19fdfc66bd8cf803e835cac96954c2e757221b81db3834fcba5502b90994e353b26717be5db82c6c7f224662a15990e9e9d12d558bdb8ec98f9bbb8c98ef1e7794a2cc748887637f389b280b2fcb83a6bf1905bf76ddac0a3f8157b887883851f4a19145a8392dc5625a364ef844c2d41031bdea976b82fd976dbdeb3cfa385e08c7e5d5a36acefe48a67338788f769ad1c65fb8b3b84b757ac4197c9156d3d7d5f41d30c98ad296d327ab7ee6706db66b04753353019f10175f2f1ef03087457e9d2cf8cb7dbb3c7f8b420da9c59e92a4b9eb6441664e621db1ee2c179bb6cf2103dbdd7d58afd016d16b96b197462133cfcc1665a8468a1dd57508b1b56353c95ed2a010901f5cae40db6b0cd80ec7726ba1e2cb8027c74b86b301bcfea077f87b9b1d645bd74ab49f408afc65c1622807d7dae97fb90d5d964daf59ee2b27c5c7367d391295cfd4cfb2b31f1c94ec137ce593f2f7fda119041b72b2ea91a2f1b601fc6b248985b5c6c386b1a0e6515493c55ac004a44b89454a755056bb63e696df99b8f08ed6d957bc1ff48296787f6295f851006250ed32768cdfd0a4d286274b1a9b2facc1ebac9a6000ac157cefe26dabb511cd33fe0f46ee60578cf6ee28b1e44cd7d2324a92c524cf492bbbee49d0f645e0df49cf69b439db970fcf472d074231d02fa66b00fa23a0c697ad354f67d9b55e3227f09cc6fda1dbcbad4566a6c41afdb9cc8569670c2866f9a6573015eef4c68b2f602aae2e7b699447869515559f9bba074546efde4593435a4ff5403b5535334412ca0ad42717f3a28d30824a3ae1de46133ea132ff1c91361d7f35adb0af1d29106fff25d7dec6644e57959cfdb2c5f4af3e52e1097edbec01d24a70e32fedf484ab67d4a0fa2de5b3562f9057ddc03e0f2310127d54e4950e78965379ad8231bc327466a3d59332ebe3b2d3806e0f8c267df5dc213a84af3b953c6b29bc8e96c7a8aae1ff5b969c5bd0430aeadfc7b9bcee824a2c8635883aade2458978398201208faa5145a48f906ef214f2e9d7009128e5160d3b5aa1b660bfc96a76960c0aa7be719b023d98e56b6471bc854f757318726d39dc6801bd8827510c1638d1d2602b9df3b92bae837e0d2afb21f465a3fa422f12532d3fdb8896eee22f98c77ee08e3c64249e57e6987f3d9b63c2871d2294b32408aa3c4cbba1f724e93bcaa5694cb5f5560b223030fdaa89ce8739e3bd03d468893b860317ee94139cfbceceef2d12e05dd768755aea46aaf869fc20306d93e4fd54ea50a986fa8cefa67bcb5d96bd0756854a5a08e1a169ba4c13ec8878a8b86758969dd5d7a1f65a66bebd1af1447db2765e3dab14e60ad42149e092567b7225bb8ca2f61efe745a9e1c30b6e785f7fd0d9de53dc21f8a596c9bdfc823ac3af487321c2db88460a3c4d3d14fbf2a0ec88254513b26d5082812c26e146ef4f4803dcda20aec90850ca444625ddb40e168b33bcd98047c1f02178996e304b63d483ed1b561374393d0cdf3157aaf0c83983f85ad55023834a9b1e2575185577fecbe4576cfd5360d46b3ec0aee22f73eb9a27a381c90dfd14cf97483cbf82fa1f5d7e7a5ea78ebc86a06aff6fabd21202384545b1e5a750d348ae9b80196dca496caa0d49479e6f47bc30dbb8a064fc961cff68334f289a4e863f5d909015614ab5028d55b1529f0ea0dc8efffc048f1e7425482fce84f05750241985bdd18d53e6b0e68c3540f0ec7ea640ec1e09bd432c7bcdaca51ed86389bf40bb53549bd7a2cd4a17fcd07f1bef04286ae664297318086762b9efc31f0cb1c9e6428f583ab6545781bc0146573516b5e05c32fd34ba49f6feedeb348ace3d24849df54616c27b1ed82347ab2c3b7fe8ac3f70a3bede59ca99bc21208b668667c66f81ce2f0068867dcfed134fcce2364c813ce95dda6dc3a66e6bbb330f7c99e99986baf35ba8448f62fec05e8bf76b6bb29f54507a35aabcca95b63c08b7f8369307b4c7a2e7bcb3bb73819492e29b45bb5a13404fbae3477308696695afe87cce4e1c2884fcc7ae9950c7bc75c3922a3c6f42bc0ded41145b4e9cf7bfe27cf48d1a002ca7e02e90a084a5a3ff13d99af210c6e6869438d9237df2cdd8451c871924ed1fff3e5ab7bab6558486387ae48151847b9723d83c8717a54b116da378b34835b4ee4fe0ebb9ce16b4ffaf103f7404dc0654aff01fa90ebde05d43854d4250852af8fe2cc1169c235b7af8f74641caf0461303bc8afb85c71f6b6dd9bba6d1f16004f9b5e9ee097ae6478ac051ae2092fc82ebbc10751289b25cca0b86a6ab0395773dc39e0c2fce377fa8cad28580998076d7422436c709add41238dad2c00f8cd007b3e4210d19770af1811e200d2fa2a1904b10e0de81d5581b9c27572c0304789ee6b239037b496b4fb87a14253c1d82cf307fc2679abbe374208575bdc159b28d5efeaa3ddc7ca00a24c2a1c608bbdd5dc968484d18322ea965da05b660feceafd920dcd1e4a186677a764a90842454542341595f9fba12701a5d8a8d404172e001acfef42932957c812cb34a661ace2c058b2fe643d73fef92ad78b915fc4f840415043c6051d480a295c4e0a55ea271205d32a1e36b05b390c942027e54a2c68633665920af86a07bd4bdeae88d556ddc5e003dc02da54c103601a698f8765b24dba61a8e8a0ac6b30c1547c97be3d9fda6f150b85c47e7853854c29f2a009622015910d979ed7c06d19a398ca58de3022eb87b7a16cb607383c0ec71c4638f39f6a57f52b9a623c60bb4fda26a54c7d592fb6ac0b855e2a4d9c13b4f5cea2f9c7fe15a9454cf69e65d481d6712c05f04fba7380fb21e560828c0d8f865640160b94a5cac11301b955b9a595c83bf420b83d4b78a707ca30ad19a90b420d912110defae731cbcf94f1270db50004088cccdee4b8ba58833d4bbda8450e63ed0228ba5a52e14c31a525a13e788f3fffc9e1136b72377685109d830d689a33b35dc7d04ee00f080f875c235164dbc14bf324c627c06f1f322aff374a26ff747709b12b34943b3fdcef4d18c71a446633495be08716f35b82387a0f4e1f85e45ebf2bcf7dbbec4d85e2386a66935e78028b60cd78f796bab392d3257c3a581b6a60cc0aa8ed14913e57fb28ab8eadbf4ad2fc00a5a792a03b620815be0a7f355e6e516f0f6983a77fe6b46356b72e347c3a92df3ab6140f1ef39b823d29bfa942ee102f70c73bd410eed627f4ecd4e56f0c2452939812afe8551220073aef567bc8ae1d5638333861e3bdc6f078fcc5a746ea73687191e4ff9e0902c763835e3a52e36cd2b3222e1d005b87b5f409aaf4eeebe1fa2f31cf1b228a62b630c66a1a901fd2db6fe7056479ac40ca3814fe42963e80d08563cb657c76978fa36a20818bc4a86789f9cd9a4cf7846238d3e595e188bffc29b173564280d87d688ea637a3d3a735b9aef0e0fbd84600636a4d71f0a8b5ccdc768fd3ab0fd587779440e4a8fbbca2f6c386d2b2d7b48015c5c7b8048f965de20740097d273a2b03d6426c995a8811bc4bb8c35ad065e2cdc61b0bcac1a34746adae60e098e2b4abea6327554ff2d3ef7906138ef6d0a0adb58b7cfcfc091ad7f25630119e91e90531a3ee88d1d7088c1bb91bf49258461fed1036d6cbde3e34b02529fbed9df4e654f8d61cfb0ee20ba3321a3ff7d89421eb782609f66dda953166a12dcb6ba5a0f0546e241b5701cabd3715492300d529bf940c934b0a1220b01700e0308ed6aafcb1a16b7bca87428ba73fd8474a79e269bb4f15ae49628a75483fe07d872bc27b7bf19e3bf88b9e54d4095fb12e73863d453c416f016e197c9e302f09a2f0445ad18145c1be8240e5cca7cb0a4ab78161073d2914ce88dfd4a8393266ccfb945031a8a6443b227422726a8abe7c12aaf9e4e24fcef91c91f2ed0d99b485e39c96a18dc463954067633b3c938cdf5f3ae11fbf04db4b92f0c32f95adf39cfbc71c72674e6d312837ef4d131a6ee9c0db7b17e33137f578dd2b021d64bd7ce7a6682465a79b72e8cc6ca9e78b3d13c8385c1e3568c3b24d3bd48347c39842c6d8ba56b68b5070796444fc9f70c5160349e4a1dfc020dcd9b2447b1f4a91ab51f18b4be1ab779061f51e732bacbd891389c3deb863047eb05803fe225a33968911bf75d77abd3473bc52aaa51d7260db5ff3f8ab6236ac2d9d0cc2f697d57aec3e4519104bf8b1445a4f7fded418cced31474123d30f622137ef5fefbb6b675e4764702cb0a49dc0a03aee65ebb9471b1a0e59d0829b548fde4819a713b3673ea7c83943d66e3a5d0f7c81da57a400f5e73208a050ad2c9ff76c25256ea2f3edb5b279c1088fdc877f8e0380bc0d390cc23ac5452a801cc8044feb11c8b0a5b77989f82948b2d72f2b508a475cb3864c5437f1ca575969cc11389fa41810c54eb06908c4e81b1bf22c2a86e6754c83841689402dded16b1d9e45052659d807349a143d4f7d484ab6d42f632bd3d09fb033be8fe92a9753d8aa876a0e4778034890382d0f1cbfd55936795ad39cadf78d5765d4728f99ae1ed31e8eddcfc365f2c08638bd59129fdf6c805418ebff537107f9029d71b6519f5569dd03c09770ed403e24a234a30599104f285704b9c6b249838ce412046711f48e700c0316ff4617811098434126d05a056df20f55fcd130b55d253ca1d1f3d1ca1234829b4944bc532224118d67c39b3fbb2502e29f526b9cb511abbfbaa6e727dee78cc8692fa190e8012517a04ea0d2bb300438630d7a28eb03f11b9b4cd54b4ebde7c625c7e4943a573d90364c40e4d449cba5016bc08be8e14c20a1be108cbb125087de80bdf9aa44dc3052992798808bde23edc0dce177b56339aed2cf6db112c35b30b37be4eeaaffb3e109a343435e38a4c330395d682de736f424c53275c3eb7ccf798ec9c39ab18676aeea45f7b3f78659e579e92453d3d6a20f25dc2ed910de78b7dfa1165c47eb48c7379ce98bcc4d5cf1cee6ff529dd04eac5238659eeccff34fcee7bab1fe4770dc88abbdc1260d04a3b08efd0ee31f72c7898e056dc572b478ea85a6d643bc2957f9860ed498416e3d8e232ecde2295d2fbb6b1534028df16aaf3fa615e33edc4c8256d15b0cdba308b1ec34b0d35da8758b26617b8821ef858e93980688915a92597715f4a3f260d2f77ce28bcf38e5356e170a150e71f913df83c5b4eb406114a3da4255b88d251b83f35068d9f0eb3674aae5ab7e7e6d5a73a62bc3f85e9e0936665f87216725ee262e9285393b844841bd7a65ba539264e866e384c8a36d7758cf654cda2f9022013d95905c11a4785924265b781b8d955e417494abd5d916dcb8d52540bc233a62591703e172568c2d51a5486c09ee1b6d3fbd00de78b3af1628fe987432ac3e74912af7baa2c7a9a6a41b425fa702102192656bef59885aa8a74469985edc23e04b691c0b4f24162d668f0c7e4f24589d3fd3d745be10e314acb17c7bbab9c0c67549ac108e00adddd9155a073857ee0875a91585d0881eb1f7b9a27f9e36291f0773918533b4f821f06adde74f0e89d35085eeb7f9ccadc22cf38e043a630ccc670d71da19743da94c9b9186fd5415f5d3e06fec4bff1aa40ee3de758c50b90a93a5b2db266ed34a4f7a14ba84b6be762c4e964f14f3bb4d05314aa27ff81666282a99e05b570adce86e4a65766e74d9b201ca9ee21c37609e4e91ac059e84c9375c1f8827214498246ca6a64fbba6e960e7039ef9ff5f32b32b407222e3b5361e7c52ed917d849d62cc880d3daef30c0c3e54710837732f94231a09a5dd84159eff637adc88737ced47d627aaeabeb3427990dc5d9979d45f14b5ef07e7d9918728b59cf38031901fc006a23c3de571b568a6414b212438c899a85acaec8c5449f2768421b19e6de8b79baf199a051797ff218180236487216e11dc3f1650dca7593cf3696787089c4feb265e96c9fa7f1e2eea1adbd29009359da64fb7aeec1087904c6abd46ab3793545ae521141f292ba6c93722cc2e45632f447675d31d94d3e765575511be359d7c2b3361000988eb987f642aba9886f31a632711ddd0e1b99571d3d8450c08cc7fe82b12b2361c5d118e096fe04ec7aae42f18c7f7445b515774dffb4a118cf053ecfedc5e1372583ba359a704c70e2c135b4aa42e21275463d636772efaa114d05fcc03c49fc53a6f3f0aa422504961983bdba2a37fa1c4528a0f452fabf9a72d52851c38a74c5edc5d4d27306bcc39e9c75460a67dc9a5b2aae63998b9035ae4c1979bc75c7b1c72df8e43deace1aff94f3c8d14ceac16bc120c8e8152579ade59230ae72412e8fcb0f8c7cae81f05e18d3188372b1b3a68f530e4c08cd839a4e104c538eb3cd932e1a60941f9ef0d0537c4c4685488f361efe1f78ea578bf31f19eb35c21b41fb4b9aadec179f55dacc52a1595a7b428986207533c0a3717ca58a9a055c641e2a1813dd3b17e1ced177193621dde5cd59da263a932207b02695f79773b6c61468c656aa438369cf6f028f29326e783a467cc5b09a8f4e695383e21ecf931e88b64a9ea0f217dcde937538231eaba4d2c947204db020990cd559ce1d9ae3a458d759e62a3c8f7d1ab6bd60422fe92bcc2ca9e84f5ed2f02da02846747040cea006be522f6a307154f4147d6b6fc3ee4139a91cad42f1fce63cf5461daa0c68f6245c8b62c8f46944ce7f3afcc45a0fe319021c19ed18b793f5742b4ee9ab94d4979623f3d1c39ebac2ff24517b40e9ad0f4d88730e68b0c8d438cd34cce721ae0dc1284294242bdb4ebae152fdd02b4db34774d75570f49cc70c28b09ab5584c5c515aa5a530797bd62d05a6ae2798035289eac17569f494ac8efee6412bafba3805edbfe25e6a9f3b47112cd55dc53cc9ee6b5e53ed57471b488fa6ccfd15c5a37919156691983cab6cd7401fc5bf61c7ab8a67d390393dae291162b281a0ce5efde75d94eca02f1204ad6099f5b177072f4ced760b0dad23103da7e3ebaee14268f8776b5318b847e2e535e41c3c7dea6c0c5af52bc20e5f443cfe748e9e60764915dd413a7d2af98551ff5858db66af1aab38a4f4169820721a2725c6913e2384047e00f2b630cde271bb010605cd193c11c80e42ea99400a9703f7860bf624fef9c819c9760aad87239b703311a8fd4b68338648b8ed279aff36e7f3a9e525acaa32911c7cae67cdbc04b5b49b98c64e13519656dfd34d701b7e9c47c2d9aee401ac53aa3f0f27d566bb6c9e6605807c222c8aadb53d67ecda073f9777e01379b90bdf54980af7d24afe9d2ef07feeb0a799f877b50674e0f27cfe8f842cfb717db874e589a27380a403e08f35ba3a6f59bbfaeb9ae10a0cb7af3afb8de733595ccd15e2444c6c1ca6970eca701301bceaa09c378f9e412bdd482a28fd8692edc5b9ab681d9553f01fd03f14c9bd57f90943c9527cb870a7abe938463164175345358522556873de03feaedab0a065f54cde4ca65fc7e05a9c0d9a6ecd10fcf4ac06392920a68ef570c7ae995dafa9be181737b60c28b86edd972afd6a45f4c13943ae8e5f13d88d53129c45ed968e2181bad1434ccac084ec7855302ff95f09890a76ac2616f88d81fdbae47c6371724ab8d69d89545c448749951ed28d29f536544e49523202fd7ed77f83da38318ed17b2ac739e51061a3ca2f2fa06267a8ea2686b03984c0c3422f52800dd3c3b778f99d8f9618fb993df0e7a343fdae35f88f5916fd45db228f34907bdabe3c29cc9e1ddd9e38cd1bf0760a4ce2c0d8cd0932483913d8601b3a11c24b173949c16e9f486336d365c0ad8e347ba73c5b0e7ae5b26c3ace28ec412e212c0bee226502e3e31a8416bc6b19b239c7eee15511cf134b356438f1a871c09a4812e74e563e38548b9e615161c4a92f0bec9910acb26755122192c20b906e56f0bb1e9e0ac156c14d31c314126c326d9dab2207b6e5b452f4ac04a0a531d7304d4aec0065ff3c0835016bc0d21d72af3dcc11abfed64fa69a98a0a100032e5f8c6a49fbaf746647ac5ae0939a9f6e04629552a798739d904365a263aee98a211498ce3a5e44bb4746516bc20f64cda1fe701c1e43748b93d5bbc8a072b100f7d214d7d4bade7d6288ad2cfb7ce298787e18ae4a9dae7ee2eff3dc076c762d6535e5f177ade32291b74a0540010a8a7f9fd1e63202276e911b2403377606d895fb997770e83746011f56b42567448ef7e78fd821405f55b41b6d6054671ff509967aa068e9efb431a8ab7603a84a51d12e38bc5ee3b99f25fa2dfa818b76a90d48a8245937a38a87bbdb6484eba0cac48e58e79299ef961f7df6603c43e57d3fb4702fee35cadca106c4f9d2da62a8838e4ccfef083b9c538103c9e089343e426f9ba9af589110ecf8e54c844c23fa9b9a21ab87dfa199fb6252f31e5d52afa82a22e944d6e5e3f99507fc119688f81ce5806d150b831f4e3cd624afdc6f4c364178cb2a90c7723891c9c8663d7bdb720e4ca546bac44c95983600fcc0c612191038fb69021622089f4ebfc5e153d390b72ea2a8027385e21bd563d021b01e61f2c13b854d67c210b48827abbeebd33d829f42f216d1eaef2925f24c24116bc61343ffaba52e19d7eaffca2e937ddc7c6db71a558f9d376d0e59ed0900e1b3b6b28813b2ac1ddeb0ec89d1d62c5fbdd9a0ccd638b6957c0689949ba4c1fad612d3a358966cd0265e9d21626f0b06ecde9902927f172c12a54a6915d886e4992a1159caf116f0282ce49770d2502fe82b88825e99620186a3c0f27a5702a565717a6bbfd068d196d3ac1db73d79b384b4a2a1eaf2b9e8c86305594d73dae0f4567b0cbde604aa699d0c66ce804d4495a6f662fc020410a55ce7ace85bc3658a34463cca75e4598d8369c29e65bc4779d868b00a93a3e5b04b315ea0056ecb5a123c0f351d77fb71d6b0b9348d456dc167fb8c0e0741614aeb7d94dd3991a531ba4c456a8d5ed4c5acb1069d68ba77e6de5c7e53f4f82079171b642598984ac3b11d0be77811da82f9d4a299a8ea9b8720fe626299909e61b104a82a5817d4da231985ef18c0172d71213cc363113e3b13b19fb4c5633e21ab3c80b9ebf904116df42ba51b3a83d3af02a51abeeac70d20ccd76ac7c1a091de7a4dc72ecfcc7499a55efd250309ea827874d001773af8f0942d6ec3d71596da0a60d61c5e012462a0e72b4a27416804d00ecc72d92c84a7c7c54494a6733947115a839c6f386eabb6b08c17a249e01e5e36a0831170840ad04377ab31168fa3b469eb3b0081cd83a807a0eb1d5145c42d088c7a5ff60d964a6bff35cf78cefc76bfd45f846c79ec06d54410acc70d048ebd60596ebd41b91a8ba1c9d6317db9826a53525a9ce3b2f8678f416fce1c10b7ccf2c19124f72c586d82edfadaf43efcda17a8ef331794f4a42c1d160a9e3a5e5d61b17338ad601cec3026a5eba304826313014444c43efe0451f2949946a7751283affb5d824393e19acc1c9aaca2180e6835b1ddc809f0746cb7eab93b995c85c596f82cf46fa2c35b11c19f8a657289b5538804f056742a362801f7eff6f6cf93fb0585e12ffbccafdf2a5e4d87b4085f0fa8de1ff9da688684578e4b6951eeee72f2d229f7f36be4318d1de3cb6540937c512734cee0e7408237bc6489e2da1ed1ff1dfacfed250fadd496530a78d0e839e0a18c60930639203e72b4cc65d4544cf38837297b012096f1ce74d12cf00868d4a5c8f292ba3021a39d389970e49824b3db9ad91c7e0fe6272fbedcf72f45d8427adfe0a0dbc54223bd111af2751fe6780ab4d8d6cb65c19a00a20f50198da7495f7fae002f685cce7b9d4fb7eb9757ca4ac7fc664820f09f25786a3851d14233e91ec61929b04bed0af6046af9780c25e4b10edf61f1bee51f00dfe1adfe42bc57211787eb701ed1278d157c588a1b2b611bfa7ca978707e7099f60c9a84fc55a91f88b0832501d42d260386c300b703036c115c01e9bb262c24bdd228fcf156ecd9ee6d42e6a14fac0e095f0e13cc05f8f4b18903e701f1a1db1c071ed379d426073e1dfbd290fbe0b8f78a51533dae18e64bd2b50646571da62c10e498bb6d2895e9ddc3f3d2137f884b47d85b93ae9d986a628580741a3da678cfa92fc76a1eefd1f2330ea79cbd1866b97cc560d54fc9faf96ccb1d6362b7d5caf1dc7710d152fd5a9f8472abd9ccfc0afe3a155af6ab1686d8a7fe10ff8e088b8fe869f257b835a17faaede6ccf3f4c179f12c0103d497722fbf01eba289bcd6d60051893a7dbaf877adccfab7575de2759677576ed2f30dc6a8a369df1b01e57399089f2a442a06bf0315d8e5a32ecf359cfec0d6b7bc0adf5e589b19e5b4a50d5ff77638f9fab07d2d66c45e9c7d6d9f607f60cd88f7ce412d2a2bb630d70463dddc288d0bab284c2d9b3116fd516e9ab66afc55ee0539392d359d0d1fad244ad45f79bc881f63ab45627dae38193339b33babf0436d2149f28770cf932c819293688b32e020697094f2e8833ed58e5da8bd15f1484b907a59116f28921154b35335f10926aaeaa89e9f9d4b67bbfb1fc9ac741ba01a05cdf702098de8386697d67367287e5f9122b5cd502a82fed2829be4799de0f77a7bc873cb0b7f9d37442b68db395f17f99149e83db9258e389729ef7acff0f986aa7e378b7442614d5da906171d6a9ee546df0316e5864e34d0ed4c561b5d788898fef0a990b2aac1c7b12e61de004bff3b665519dbedb9068e6492b309db098c00d365851a37676f5e3680daacda5ce087b0cbf05bd244323926be4fd96d2de18e75bed6db6189f216a2185aa116d214f76d133d3e6a3c4df6eb637c844b90e528c4aa44998eea3b2aa9c3feeaa4feb4264be19ef0312760a1e708ff2097edc4a70fd8fd4925dfd1a50da0b23559b4e392ea9c581203a48428d0a7842cb2edbddef7c63d99c1689b6449c242f8c917f2e0f372caa31ccdaaea372835d1bb837a0e4929e4b1cc986444ef14e3e2f8c10a47a9f65073a779c668c3cd7d04d49d6ea3d29bb5db4bb73928b60e2dbc8dd5960fa6ebcb262962379437d7dabd1af0c1cdd442ba72ff69c2a0495cad9d6112919c4d5a8afdcbdf8a5e5aa60481e0e0f3dbf102ec015b11c5fdcf2b4672a97f69da4de24113b1ef49bcf2e75e8dfb52721662a15a6137c987cc883d566f114a9b912427e409af6934a9ac9f907dfb2e06bae4c1d93db1d9491afd8086f2bd6f0351dc61eef073f279ee92f61c21fbbd80744e45f5b94059f05b6de7f3ee1e6a50ce11b492dc60f9a1ac0b1c375db782938d458ca154609355cbd9ca37c6c588d8e7d1cf19bb3310f34e86544b4927a1a5768b56f7e89936e493415b34e7268f087c4c46efbe3b97c4cee5db213e5d5e1280bfacd9589e2980a48e860de2eeda93b73347a3255a7e781cf8ca6fc02cb883db8225b39c741a85a6db6dcd000e65ecac5c107b1c1dd5bc2447f0ec2e09a8d4d6be594c0deebd0c4430b7c4e940a178dda26694db0d0d86881dc7b31eae063ccec81cdf8c8eabc5822fc5a8f81e397c1903288d92aa68c2b21378fa67d2a4ad6cbd9b7cb275685dc21ba50e5ddfe6af88920eb2ea99dabd9eaf18842767076d8a16b6c809365707b07a52796d000952cc3bae951e3c610b4bf85748a5e4f60531aee20c87a225c606bb26a483c6cf390f7deaf9a1fe2c1baadbac2b814d0bfc05b990dd7aaf95edf1f17ea9c94fba07deb6cb4ed8d8d1fdeb5be6ce71287b1dfee124c36919fab381a5fec381ddfded7a90fe9edbd5184f6b1ec1c8066ba5f892e4f29a1a8b8c4f82c5a817b5a43038e9e3a2ec76c6cccde22c937644687044b39ef24e93a116c86dda1fedb094fdb5569f9a3f370e5242e95dbef0119fa66bcb5c9086592b6a6e73c78ee5f9fa3e5b898b9c6223e8030f4cab6290870a2f8edf392e150b0042fc4263962c9a73bf60e5f4f0a1cbc67f40740968a0e071592080b1b958acd98b94a8e53bebabca6c13f97e37920dec8d6ecd1f2ee0f86a731c7abeed161cc3e7a2f3f734d97b6df5840bb07eef66cc25e51c17d6089372d715730c926ec8d070d81d9f747fbcc14f902efd087757f1b372c5decef8f36f141e96e40c2f3c3af9539cba8a4f2f286da17bd5333c37c7e927b27993dc508bf1a5708eb704f1f6c043b8f60851c3999041c2fef819054a2c2f65b0a16ffe9227b9c184f878fbcba0c6c46b9637cf3e5688e59eb82f3533eaddf40693b46457ae30feff35f071de1591cabaa934ef1e696e72069a29680dd9ddfdcfeb90f7dad53ca896ee8bb9bb060ac2e9edc18812fa57c6fcdbd64c7a24a583b75fa313febb6d2dedf0ca88b95ab4c9a59b9f2f253224583a845616f993cfd5ab44720e66d876dece7b83faca87b486b51dd95d5ea2f3ea80dfd647dbe518335f546db2274ca3031460b71e5a3006090a14114c907752182650ac583f85a37b91e2c8576f055ab0463dc2d5d7c4534087444bd7f632bb2b2d09d2ba4f5171c6232f716f2cd4b75001c59cfcdfd94165e2ea022a4757e933a40244eb925bcb9e9e310fa0c9843cd5e557ba9bab901929350c4801ce57a92c7c228167544319fb0e9badd4f4b784031c093d8ec0d599b55f67830e53ed401b70b8d68ee5557387bab0ce295c0a55dcf76ed923e96632cda0406baaaec5c6c9d27731cd16e6d2ee0fec8ea7a5ec7a77af99dc1cd6a8a8fc34bdf12b0c2cc2b22f4bac5ec060cf38f9a53604bf5609075ff42fde641f6f8b7a1fdd0e165a69fda03da77669b229de60c1862cfc7167959046817a444b0032465b70df2a3eb684c3d9406f709c567b190fc502351247801ee032af3701932675979b2311f903d781f2e031a52a979f1c90702f3e612ca2bbb587764a0667feee9e8ccba2fb0d99847a84185426617779374945619d418e81887ad21658cb8bc0a92adeeb4cd17f56f88ba7a7e7ed328061400d2fb85c7272d66d885ce709e376e77a3caf03e773c1663c6079e84effc367759de712ee5999f4c629d2086b3a468129b38a074c22913f742a11d5124b9ed3a7ac0a7444a134b31293c138f69e3c74a5888516f738dbb1842cbf4a52ab66c67758a6f3e3adf1d0001437aeabf1ff134a5c0f80d63d6863a3c42ed77d62c2411ab8f282247c4ccf7c3046a16de63bbad110a41664ac0bfa151b9c76584f7e53ddbb1016d4aa2a1fb3251a42f034d3bf4658c4c8f75bcffda63570c3761b7f6beeb3a6f34dd1eb3877cb12a4090b59a3b4ddcdcbcfa07024d102a3ca0a60466715511517e2c0d95193ea590abb0598fae69e4961e14553596bf21bfa45e1418a6e7cd1484090b4c9cd69a5b2976edbcc4010b6a5182dc5f2dda19ef9165713482f9ab1e07fd2f98656151abc61bf04e81fbb536c71cdb9ae8a45ba9ef769f3881e8c0838b88d2398fe7d89d96866eda751dc8ce1a4272e5d704576534f04efdd176edc58757c61342b2edfa7f15692bf723a4f68bdcae90e166a930ae2941c6f27e93de8079026982787aac40f076be221279c71419d4d25a061a515c4184a66127583f554a7f6beb67aa95f4377dda14e05706f04015b297eeded20c9c8a845af94299c24093a92704458a6466e90e90a3fe911460c780c0617148f51f95a2abac892855196da17de5525bfa7e0a1ae741322a4cd378f54af9d6aad241d6aa38df770b197866e211510871d10a4708bec571575955ca62046f37f93010881d35140a880e7b77a5e3fff706502d4af07b2c6bb2187068d9dbc0c2bb4b7c4d33011e18c3352756119858f5de03886b91fa18213a06c1e260ad27d9a6f8859289fd3b1d57574c9d5cf21ce5eb0880158d1fe175fe380ecf1099e97343463897ff9006c85e1854fae63753acc5bdfcb80df08c8979d3ef7fc9818923d57999073f6b1ab98fd96cc420be4921704f7737d1dbafd49a60e41caf1fec22a06f6ad48eb7c953367ba152ad1109aee15ca3ed3bf5e017e99015c62f1e7eacb2c4d557400c5c12b3d2eaf5230c96ecbe0516b814e94ee34e65613a5d34475003580a3dbc43a7114eb029af1e713be18a2cf6c134084697982e3608463ea9c8c1c5c1619f69469c69a21bef4bfe34b3aa70b8c0fda33f793ebc95b955345ca8529bbbab00d7caecb20cdac827e1ae1d0051756118f3efd556d724ed3a032af0f14aef96826b1d7924739c599d7f8dd310ff2e179daa9f4d6d705d7c0975a0d67e93db16299add0b2b80c96ce466c3d3b8caa5b5e86f038c8e75c5905a6e203a7a3b4409c20f046fe90f2581033ffcb4fa1e6b00de09e5061e180c0f6865d6e1890f31b010c391a0940641784a2234a12e58bed77344f56e5e270f2df0de5bef6d261fec30c33c35e0bed560df794594c54825b06d221db7e4674c328b2d2f38bff94895d55d25be5696d8b0d8897dbaddf0e07f24b0c2c635d599035d3727d4930f0190cac7fd2f88100ad24a544ae09b313b1019557bcedf74dbc396043c041bdb0d7026c6968d0624c78fc3017e3a686179524ad861db1f2bac726041d200588837a6cd97101a93c27a7d895a1621bbf4139d54bc485abe6029daf93a780e3dfea67f2b466ac28397f24e9b2ba53f35bc0199e1762ef99763f7347dcda91c5f33888e9993da5c6125d6dd0f3a6588f590d982a3f8745e2914c679f3572aa89315d7be4a33a052c349194da1a32e6365ca8dbc8cd003e2935b6b26b4a5ea9436e3baaf32fa316bad8589e6b27f33eb8bb5b5c4999738b67f39e980f8f3993c6b0d2ba6482a8573c93ea088e734a42f96e5d634f2bcf5644f2d8b9071d95c311a88e77a8efb76163a23651b8973748779a61978c325e0976faf968f015c682b5ad7fe119116667690aeaa5eaebc1e336c5edc2c4b552bdb758757176ee182eb3b8d09c806034892216995850edd3479297bd73a4cc16a020670d7e254793b17c4d4a9b38c0f47ff35c17fb8952e9ee5a4ec5f53f12c4e3e6eea005b4108982244c755c415f406e3a6df1e1c08861662574610abb9b3e411509a015f11a43d3aa7664cfbe99d006383f78ff64c17b800d3d74f15c97564e9a33e748583869f53c312be4645990693919ac5952412ea498a8232996ee2330a65e56049862e2ced0a542393d2f171aecdc050cd5b16f00a3528a1fc922d1b2135adab975d1b0fb4f1024f17aaaa7086d64cf12ff1a43805576706d8e011fd7c2f6ff0a61f7df40fe41b7a16e958379f492f01b339f78c5506bf24e4c97803cea85696c6389a65ea0bfe9339a5deed491d8fd0a155243336b01b8174e6261d9d769d07f7f16ecaacb2e8562f7a3da390bea295544b1c84ecc623b2ff980da3f519540bbabd191b79cf2a6bf9df42024a4bcc23d3a64bbbe1e6b688c98c99977756d30c7ec27bec4d237f1b7c4505377ef516bae3134f9a4f91093e30b6007394635759f328d497597eb694d9e40c6f1fe942bd6efcea8e38fd12ce48d1139ff9e18b78b75e71fc59731e297ff306238145d4f0136759244c4dad84993c620ac9a4718b5f909780e77fc9c1e5d8816ac86ce505ea80a6de8979724139fa3f851fa2506fb6c6e2b066ba68d1448d94e01e35668af9427ac5de75381fc1639ca6304cd3b13948c5dcb30b7a6102ef925ca4817ed830767f858723ae00d9b2ba07fef4988baa8dc6fe31cd61fa2cee56cfecaf15a52b65ab93408e69348c5b6bf23f6fa76a3e4b32dc18fd14ac2e1e49499e87e24d8e6cd13f5cfd974c6b5a98206518684865fbab0b5f76bdbc432dfc068bce9421043cf6a149fbc0c89f8c69a461336756d47ba0da4caedf76164408bd0d58f8971b60506cdeb0b2d8e0549027a006e5c59351b5d96e57882fee4d6fed829064474347cca76657df0d748ec15a51f280cd72f362071f3cc29a12ac84864d133318420a1457ec1cd03eff38c6ad9c7e67d2c43c7ebf73cb3ef5105f84097bccda25bf536619708dc033200a1e94e9be723fe681a4d58f41276ceb69890226959740a256d1731e25fb204fc4df7d3ded346b3d6173b3530e79d56a31473a818776ce9773ed34e3640c9fcbcd387b6278874c689a8820b3f393db797c157664fa30e3060116ed411eb09b55a4fb75251c048abfcf47a19a479d06a9f51edb3b3dbfa9906944fc24854f336b598aad691ff10020d4f441a8d979d537918bafe63bdde2718eadc42bd9a0dfe83e57209e4af6a5db8ce5cbc59fba9a8734f7db85f98b6a34f7e380a905cbed101ced761cb485d357fcc9c242f8708e0a9dbe31ca5f535350847867b0d6f9598dc122ae22fce728226e7d3122de0a42116d9036d353a52293228174fb02cc7eb6969f6e54012f7767edc668b2175afe22e8cfb106398c20f56cc4b67a194915b57972b7bc17aae31fb183aaa711818ab283d390680785eaa48aef5a206c8da1a2ed8f04c4052ef628157e1a3d935797d6ba29ef05c1d3a6229981db4d9937ab46486b4e9839ff1c8b81ce8e0430704c7e2776788721d96294505c990ba931c18a23947d4fdf3bddc332d56071c00212aac96d55f657208d21d34e207be723757e3511041cee882418a916907d0c4bc113adfb3ab84cef880c1c02115d26a0304e79cfe5e7d062166ae7072a477867ba115492eb4634590487ec4674856da596e283468d0c36ef6510bba339505309cc95c2e00cd7d401c6fd7a1f47de8b53f317678d3fac17535e66284001f5527262d81fcc884f76c7ae2b1bb42f76afd174a37508e07f85426ec389a3c2b4c7d394da5f99f73d22e35a2e3552bb2ab5aabec041fd9a611a327f1e4724cf587a15fb64a2904d2df2b40cfddd942e33bd7bcd788424231772fe28a12a17ccdd0cba564a936172ec12ec69449df6a82501ae7936cf7d196d267deec9c63a324f2668e7a8623357e4f73c704dcda3e13a6af112a8c9a5f8e6f78a40b21dede3938c4f90a1fd7d37b1eb657c18f30e5e4215314e3876b949d3a2d177d11a8f218ee36141df2b1421a137b4871fd5a74109b624c76ecdef1c9be4a93e0f1c7d066b2e3790d1df71225e6a3d2884142215349012756a0d726eea9d43d2a1214c103f55153c0664a36f5ead7d55743572899ba423d07aef46e9d36a2fd0a13747a14650425e9883131b7564931914edb7cd49d142b9cd3bed7868f4d51dfdbed7b293bbbfbbd8242ac9cd037ef06767e15153263e2d24e82693604490dcd609353f0e630dc206396eafd4feae50c12b932b606e29d841228af26b301a91bd4199e55001eb2b4a7c48e21daef2b72f1fef8809e5ea867b06a354a5327e2932b036e69ffc3666ce46db1d80889648beacab63f0ba456e9fbe7117aca3df538200bfc04560298190737eacfeef49207980d1b809be0821f92c1932632ea7abc60a17ddddd05b0a6b7c9c278ef43f3d676412e811eb151fcf69b4bcd7efe9f7dfeb1ff7dff9e2c19e9625005979e0b8b50e462eddd0ec9a600e31f006e652768e6de46c460e98e364ff8fc6fb231d97f6812d33ee2b45b7630f8d43cc4f1ca4a891cb29be39abe3083f43169522fbe97e6a8f8d652a9c4eb1930f871adeee25d8a12bb40c897b4562d4957e435b0c90ec968797870a6e39b2ab7bfe246b1d31bb2e5533b96902c613ba9397ec7fbdc13af5d7cd973f09419fee9be19dfc331b0b1b380a7f07fc22681a1e1a818174b2a8b54638dd2e704fe3768b4e45c9352232c06e5052884c65480b97cba1b1a63c9479c7b2f204f597e8540cda7fe4345a92fc47e68d1c929bdeeafbbe26b258fd324858e99031b20a9111fccfe36c47594328452ed2ccc22d208226e0ab5499e645a28cacb6ee876d3241cba4648282e87d26d0511df27cd2a8e40564317528da1b49ea32f2f5c92b1391d31c9d88fc4399a39cec92b5fc3cd7d7b56fd0538944bb20839aeaf916d0ca882d6373227e5118dc6468a8bd9896a34edaa1ae8a52ad01163f42c20ec9701c59920d887f266cc714a6492a49168c862b0bb28b914767c5b3dcf2c8c8bb9eed0ec3197a0522017d2f7a658a81ba084e9a19009bbe4b45a0d2f042dc7fe6a09d35e0df96471cc96a6f5f483799b3b509850213b2fdebb2268d737c0c04e31f75cb145a80f23382444897ed76998628604958e88a930427aed2439ed516a2f5ab2832a24faeaa164f7ad9c39db04aa45a044016435c5e13e8cf40d847f4f2789dfa1efa7dd81c855e1da47ccf12e2204e223cdd006c07f01f0d3adb454a2fa29ecb296cdae60ceca6b908dfef2817a65a91bcc23addfbf02b7b3581196d39795191f71a519b2976aa2a5902c929931ee0d3dfb75d0ea24a9c8c837bfab8c7633d8a70ee90358d6da9e758f759855cfe50e55d8bcffed731ca9a3aed69bb3485bdd5cfff9732fff22ec6aeb3ca41dff3d0e73473ead196a38aec7c7b49a52e2deaa069cc5add1aacdf3d413159e3b41d9d396122e082a052bb2b74a3df986c16ba132eead0a422e37d148bf8a7134774feb3292371f53c78f465656adc15a4b4fa7897b41aed03772e9287c519292b4f93fbcc0443bfb893a2480d2a7a824623d56a6cc4eeb73e2d4453f7fcbf588544e0a444dcf40ddc609f4a17156953e968a9e32cb4ae91c51690dc6033c25b4f0c80136ffdf4de9eb0fdc0e24439ec989674cf3235d3306a0e8df6d99aad071bc4567d9c5cd38790758c23ea9d9654456e1f8e2d84edb3f9bb907a384f778b526429694ab213f7bc3684fd15aa185cf1b3564879c5fb7dc3eacb340507dfab0f09330ee19d9f24f998f20758ef49d4b2c025b48c9ffb88226e3b179629def3c9cbe2e565ed0b7a33f4a9867956c6bce7e25844331ef139e727f055dbf1ebb229b431244784c3609c406054caa87526ea72fb8fbcefc2d375b58b33b57254336eab9c8751a6707833ac5086f1fad8719e31e918166d4cc074b21ac067e25705cdb3f635bec733544fea6cbd556c80b5b3d5373f5d2b8d5800edf7709dcc15a43dc5a3de84368daaaa7029d18a8cb8a997b54d065480532da6465f518a6eeea1fd47b1e003601b843704d417c415ac73f464fcb8378abdd4fc7b8229859eb8045f7dc230705e43e306706ac7953beff43312174e2d59a13db151b5b31c4b8b6b35258dcb1a6667a45982ca683ed8a670033ba154c714da88f1f1ac00aa8851e16e0e76b70731d71574c9eaaf0752da17e702d859f0975e7b618f049bbdd777fa66dfac1ed8e85112275f098689d6e5a338d1ae5afd6c2bbaa69ce1e93bbed371cea988b278155e380f20b779fd8217f1651469793018dd65491c0bd1eb794fe8fd48f91c3333be0fafd49668ae80213d123c372096e688d691e7531746e8b9aa1a2c72fb28e8df60dba6d6a8da5a07d9bfe94b42d9b0ae1b2933fa3e18ac1a265b50037c40db5a1285b4c7c24c8f51517886426e142ff104157a8b79373c33479c90dbde671fb1a19f641fc8dac05d4d8f22ba172b4d12d78ec2633c8bb79c07f15ffbf7f1950bfd6b4cb33310354bda26baddd13c619fcf01234a19ab93aff3ec573385df05eeaddf5f793ff2adc0e5d0615540a7b51457c8c802db85ddaaef02e87583358579117e992a2c5ac222f73b0ad386e12ee75f58b10e461bcd55702f20712ce15ed8c8611fd84d593ebcb3e343978022003fc85f8ccd90a74461da2dbef6e4349c06875b4fb20e4f5cbb7206cff4d0a34af5f23ae73f701aba7efd3ef6bbfa812e24e9f5ad00ea74f042ca101ae59c833903404d3bcf3c4e4fa9dac6f415eb782f95140df978d0a9c7d1ef4c921ae35f7f136e9f09ee908aecdc0da844ddbd2920666f0d802178b076d7f9e9fa325d5a4cc397b22ca57d4a46cf7605fb27bd82c9ae47c3f2f336a94c513f7fde2df69a3ec75bf0b8f49001bf3a7d6ce89064500d82e9cf254f2f0dc66b60a85166612ea4f76389797e1e0baf2d1fee7c1d629206509f155c94a99bdb1cda25c4ca03b77eb2792c3cd7c24e140855ce9c12620c9c14e9d0c5843199f7cff120d210e85cdf301d4047fba9cfd537262b768f75e2beb17b1ce8eb6bd11100dc72aeb2568cb619a12bd600141d87be4ad775129917dbbe13f4755a92bf0010866a47b587779ce36a8d38daa349d4526cfc242400d71f7f75adf77d2c042900fe7eb3057fd4f52ab7d6a26e9d4e360c5bd7119c6e689b591169430d79c4648ac75240019a60d4b30c95b1b39e45256b6761f8f1f59be6d9a8952d978fe983f2f6799819ed1ba021dc757e40e1d371b582d00ce56b19d40f92b0daa48b524daa6b13121607229960afb92db29bd818a9623857db6422db83ba487721127f28fcdede4a2818831dbe6a330a828c301dab3d62ae2e49c4c56347a6ffa263669cda536c5bc6847f5f60c83df8aacb7d0c10bcd9bda4b09567676b17c1ac73b70cd8c8f54d88d812eeb006d9b9dfa964e99e320bfd670fcdea855e00ad4eddc5a1f481715392d70a490427f07090c4ca571f9f1bb88e1bca3b722075fe5d6dbd6f5d051b5f935b690ff5f2976f1c22fa6196ed35eb6925927c2fb3c37e9c0c0f87cec3e1aeb1d33a111fb024bacc144bd15cd4009b86cb872e0293de3a21b62a32dfbbdc2306999ec9f9a8c2ab49c848e3f585255dc63b3d042270f85b8e136a5b016f5ff64090c39d9581ddffa3fb8e84fc9b51844391b0eb57710aec5af41941b7b28bee1dddebfcb2d8258f3346e2383a3811156137ffc7e2f973be2b40966a12f187a73700fc509944ab54365f29c5ac0b05b2b125074963c8916967a21b0d4f28a6d812d740f32dc24d701e59231f3e485fade729cbb3aa1106aa30ccd5f0988dfcdec03c129b32b340399cd76ce1d912807ab4efff33c582131d86832b9a09308616f14ccfca4fa9d6855a7b20ec1edeabdd4f8f6218e64e467c3bf8727208f222b9d0568a125f40544074164d8f08f0acd8866b7b5989415a47efabe537beb20f4cb9ce2b1f03f4dea641c67554a2c9c7ac83ce10c36c582090df95c6f39eb29876bb4549d3523a9451cefc3b1074227e4af71ab9d718832cc2d94ad420d2d1901693c4fb585f137a9029852babe5059cf4563ec973d4663daaa0524d6de93fd8fea76e9a16356850ba6df9ced876376a20b489d3638ce5a5f2525c2a13cda5a5287f0b2c0bcf598858cc073c1e59877b06be60f0dfe5239e8bb84079d17ae27783c75bc2aaec61b38efb2187e06949bfd659cfe68469e57a1e692d55896a770de0163c0c968d205467d11cb29d4c994b2aa123ca21f189658f118e49cc8130d82fe17666a4155a9a1396ac233aec46d818381b864cccdcc67ef3b3e05620f968f1e7d1b23c3489b66bd60e8132af806a34c809aa89ec9773ac5c18391b8955fb64582354684da702445021d911e545cc8585935065a1752c52642bf911a7d560cfcca6d9f690256b6a6e26821d9c6a5d1e69907386ed7e1e18c005bf7c0c8dd8ccc80fdd44086cbc8e1872aef9fe6e01e629725b95fee7434942c3e1575bf1da76f78b6639f054047e87596686dd9eb63997a922126c100c32ea14e7edc075ee4e5f024982b0e97c61e1388b3902d9a13dca81f35baf17b8a649c1d92dc51b6f25494cc8c3416a67153d91d60da69d543d2b9717b5d348229386110dc9f36ea27fe79b0842f8318cebda795f5165031d32a681878efeb534f6ffcc178b9e6943a55bc5fc42816af08f05f7bf6c3eab7215cce97a6ff8585eaef6386914255f4e9cdd159d90c54815688171c7ec4636e7f41b9bda743eaa9bf64e0a6c91b89c148aa8d1388ed73b7853a206ffed826fd93fe6ba3c59c71f9c0cbce97f42df04b7a93c9f7e87b659034ea32039c0368d63cb0b5a4fe117d9ed97b2621755fe07073727d19af8bf8bc280f134741e442652d1b4209f471538fa3aff6b8f429af9aff22ba2841f0d844705c76638d2d4728db10dbfc7c2ab396a0d2a183557d09769dae6af5ddeb71301cda5024b013ee4cb7e50b446b5b1bfa5f1938b0ef65edaaff3c17165b6ae60ed6812f8b7347c10e053414d6569375d56475f9f3f0d842f3cfd2cbcea7c08bd8f4f4cc257e9c26ad46bb1baf0c3e81c16e9f453a940d474cf97e7e27a4da5cef8da84d27a8b6a8de46f026628fe383cbc6dd800a2f56dbc159138f4a664f0c5325bf06e90807429ae66e4e7d21bf5b9ca03e7d6adc97b76c7b31c87fa041b40bff2fe14e75c371ff981fb64340ae9fbdd281dcbc802a6c2046918f55556f031e4653784a7149aa02a335926ec70a374ab3d292109929c71451f94bf65ac6576e77504e7f8597ab53156d44f0057bf9c763ae890ddf80c4ac3d1241a236bc118cad1fcc9fcecc3ce81f627c9ee7844b5100d61329f79174d41023b6bf3541622ffa9cd5332233df1f44820c31644a85cc7f9772bb526a0c868996bd857ababfae9c4e71d77b286b4b95179950f82a23c96cd9ab986ccb82a8eecdf49abcb9bb4703d6141390d8c501ee9ffa4efceb8eca67f2d3c0cb4da85f596897be47f542cc210398f5ccae430d7bf7e985ea7d23915d0df24d35366d6eb52d872950109922326c77c726c6ecce10ce12fdb01e79fe612c3f481b018ad67e5a4b66310351b485292a2d3038f466ffb52fb860fe1ea559b7a930e911e419ccfa5de7294aabacf52266fb4589b337a000a25eaad248f3c9ac09e7a121a2233bfb020f15c6600e7a5c08cf6090d4b77dec81d3087a556956663c5c70b25bffcb780f21bba7748ec64922cf4194f99cd3fdcb9f5d3c84771017eba1a9fcc8462638779d785a9560dcfbed3357a729ae08f33a2d1f259a958015215051a1e6d68f7a39cca9087b9ffc8e67480a2a5745e9731aca344ede4a98df8de458dd928ad168cc4329313609fec920884c650ad8417352e31fa4ddbf5c18969819256b8ba18906edf070fc0a6ce78f89dfcc01255104fc5f1e2b3d27827476b4ac6de3c852f1ef2bb23d6c92f602caed08e231de778beb15997eb6ca6bf285fde87ee5ecc09c836d2d89f386ccf8dccfa6c3c195e24ec2a4c3d21f31b10541ff5443832fcb40bc6c8074fef8ba426c243d204e894917bceba5f0bae3ced3c76e9e5dcba39d6c6e1509cb60c58beeeda52bd26bb88c9b54f183fd287cc379aee15b8ed5ce24215129b72066eac22e416f9144eed465b205dd8991ce2231b173acf0a45623b13cdb2a1caa26056ab23344ae5d006aab8dd8735f633a3537987872cde8baf458ec2c1e91fa01cc66b80d27e4f283976d25d5838a87c5a16628138d7d8fe091e2972a7024940f8cc42492af8b06204172c27fce468b8b3a2cff30f397e8fe8705b4f685b491a57e955dc7eba1953aae07c917bd1862d76b348de8e50a34271a8d5205cfc21b409da97df2cecd513bbf8e0c47c0ff562b830e160b0747cf3933f4c80e9496eb14217a71ef47217a63d97492ffe69cf393f75bc68b48000bdc6bc79969b9db8fcbd5d8488120ae41bb2c08486630529bff16be6f66f1e4fad0c6ca16f9f016947d124cecff6b815a13537a0d483837f4fd7e7c3c30bb4f3baa2c2f84b6199e9ea4246e5324358267c67322cb382fc3a08c4cf7ca53f79311deec99719127c29358b25be2786cea54d33e7902b8761234112d6ae0ce8f3e94f7720fe900a58812f4485c14671c04960326f482443d27026bf2b97f18cc91a8e3fdccb118e2866562cd6c0f085cf684183611e0db3f1812b3ca9043ecc2c73eb5ca5fc1a337f0362c2f7ed54d818413171752e9098ae679e2155408346568e14ceb9fa8f9c7eefde1d5189fddb3d817336b5db9437a1a17410d6711aedd45820ad47dda3b3e2ff403d82ca2805cb9697672dc95bb0a6a6c85684f589011464977938544603272aea3d669a9bb5a878e1c9d3a8fef66e98a2e7ad921bfacc403fd5ab95985a7d8e8d026e985eb1ec8f1ebdef0c3ff198997c49d9d3d35c359697b4ae24fab76ce9063f0070ec9e508d000937f53be2d857a6a53aa37fa85cb2dae27969e46e19bb81511693c7a2018ca0c0f0dbbf27051ea15f3997660e8845cca0220fe9043f502f9d0e8362c50af22ebdce374c35dc83414a652ba633113a9028003b44fd264cb6cf39168644390b225a403411635d7d719073582ff031ed4240c2711195092522a29043e049f518ead37e819d882d5bf6ee4ed9530e211c1f9535145993d147b59e88103bb9c6b9e58433c874bc85b23cf58974cbb4e9db6521d9ffb3a3a67b8f9e9cd6a0c7866e1412a380b6cacc956938b67d5dac30f8c3b2c25dcf5149ca8e50db2dae5976e45e005dab50167c9fc4a1b332bd85d18df96ad8ccecfa5eed9eb15414cdf8ec0bd8409c770e0ac5eb647999fed9d5386240e7d2591331ba93eb7ecface6a711a410e589a229e23cdbe209606664bddb7d52d0f7632b29670956619ea990e6e1492e12429a526910e8a133a94dbcb1c8f5e1b2f0d08bbb5c2015fa6d813fbe649b9ab6603bf4e146ef6008b69bc4263301b1ee790a1d323ffd55a943de1a1c151b3fabe31bbfe3123a4044912e4cafb6fa641fd0a876f5df3d720d90699073102adbb1924432645e7970f3b969880b8ef7022e3f3dad020efdb456da8f01c66e1cb03f078b17631b3cb25b59dbf6680ba55750db719af0fe6fcffc07b98af8f88ee92d2d463e7090623f358f170b6d152ff000599d6347db03f67f7c1b0197051265420bcb260b18624d51971c282d33a7c881048a180bfee39e3434b221a028ac82c2c2e57e7abbbe4ed9d9f0ae0e9cfc220b6cc98b907369d826ed9cc642d2c32822760ed719125dc060e72843caa575a173fca63efd80916650a95ce2812fe8fa5b4692473b3db0ce76b56ccbc6686dfd67369a48fd9ce05270e70f5dd751c4affda58199a85f5017b5a2d0ad1b6256d2a9171cf3299a2dd299894e5fcfe00e7f514baadb8b19d25608d7a7d6d8ec97abe62442303b6a7762d6062c2e17143cdbf3c78626c2ba06adf7c9a0ded3b7bfb914e6c7088780f73d5819ec461c48b2b66d5e595f69e2c33d0c0bde290befbddd8edd78f6a1ff5b944db9f37617d933e039b00cc2552364600c8f563dd259cf2c3253b57bff6d9d0be674aaf5bc47f6240ec0ff0c9ba424160ac1a0f84909f8bbcce5de10d4f0fa5e3a0df308ac0c4faf3a9bda954b224aa9e3dfc297391c4be2eed2356a19987058e87b25d4d2d7878b0e43e620595fb3fbd00b3bbf0dce111ca3a73500d95e246ed059bf6db9297d0121b11be5cf3a83a331c15605666b03a8e08f1a609ffd59251beb85eeacb90affea473f5e89868fb2af00c1261d49a6c9ee06a83a14f147d04ec22a58bbd82ddb38d36f6caca823c46261185221d79dc07940b097964a38aeabb928be8bdc830caea09a19a91381734b7d38b4f648fb6960e92d3dd1896c48e7291942ea8c0c6c17dec7d3d7e48e37f5002c48fc5021221a507c1feffdd4a58482cda7e5170ed1160878597aa856566fde44bde172d1477d6dffb97f3878ab2b234a642f7bfbde462a2e59b13a0ed6916cb139ec11e89ff922c757f166be6e611397be0cd4b19ca9eb5d1e669ebb6efc06dd665bb64a76f86a306542882b9f10f9e31b81ac49237a24c2ca5a9fe730056a93e3cd01e17b01fcf5afad16dc43e9dcaadedb6c0c11cd9c89159cb67f5012026b48d82ba065bdaf2959087dd52764993813bbfde72adb27e98b2a854339383b654ea789c063cc9fa13fc7b3ee82263821757474f74e112245dda552fbec486d721cc7aa6c687518eab01eedea55475f8e0098d62e39e2309278a66ce425257889a93f9e100fbce2c6221f6ccd74065df839e28fa102cfa3d463bfee4db4bab14f8d92cdbc58d9f531d35b13b8de99a511f9b6e11fa86b7f909b2627c3a222ac3ada23c1745d06ae212d59666df78f336a2f1bb582ed4bfd809eda2406cca62815f73b3dd624d30f59606823b97ae5128c805605bfa13a28e0776e713bf0c7e45e878a1dae2b3ebc7480a2b40c7e32b7e041b09cb1a889a8df617bdab9c4f48d8ac7ffe17bc98d72701d79954001c21730921ffada0a861e242484e63523d24268a115165693d5f9cab74bf3161e206b353410283dccc4110c6ad94bc18f853b2ba0f5d3fe39d8d42b54e60091b9a4a7b915f934e475225ac3ce9a0b739eb1ef5bfb2eac1f769b3dd8f8eba94e5fbd08f880fef5ffa712e7e6928aa583395c5056a31aa74e37c8363474258076c38a33e359861fba0f7defb1abfba3aebefb11a490dc144c29ba65117f7c2e24764a24e9c65e71230f446c2d46913e779c8f86f0aec11b8d77bd1e2b25f94604f1b85efc84bd47424d8ea857962defec88d73a9565a8827f1512b8eae694a54f4706a065f48d4dde242cc87721f6294025841057092b2107eb4d399adb5aef310eeff4dcca506f4eae81dc1cbeebfa1194f16e8cc3bfd5ad5207c35c4ec91e5902da80eda42429111b25db25b0fa46c6404ebe8e71fdfdbb22e2f60056e4b8e0d32cbf17bcb74a858168a65adc514e18fa023b7a786306b0946917ec165a5415ccabcb999ed90208c7c7588502701c12a7aaa3e1417a3a7517e6ff65497f3e8717131476b7494f1b296973b3a2f040cbea6cc230a4e6aa01ed424a9fc1cc3e1d5eb612f96a7125b86a1251af7702bd356454f85576c0ca0e3574c465b895f4f136ee0f67061d66749f504008a4c2b7aa1bd154f4cb96fa8c4e5715ce0f8cd93208dc98266a8817291d01a3793c087587604da10573e80222ceb664402f88df38b83fa54629f901afcdcd401fca40e3671f567089affc0825164f5c567a75734b919b6d9bee4ad75af9f32dda67e0ef9b92a033551f88ec1361bda1b712b4fa830e386442b67ec954883f08b67a2f73e937ed40fee57f6a9db802bccc2a36ab8eb8db4fe87e612f4c28db32bcf39674e4a45c02fc3160e92db1af34d385e4e9ce2e9266d49ff3c634b8c62fb5a7de06ed63412cfb5dad775d6b06f411c78dbc7affb9f7efefcafc34088bf3ca4b96839395b6de4b1d2ce78f639ccb274faee4e468c2de146d22b79e830eca1609cbd92195d0eeba49b31d158f4f545c98b734166966f721bff21e84eb883c64f369bb0abcf49e27bbe06371bb8f2bd5c42f204c2a28713930fcd24485fe8ac26ed7b2559f7f627f919a6e627ee54c4ca21b6a77d963908162d704f0086729662fd84180025f4af32e6bf57263de4ac9261f93413d1e4e6978461fdda1b8c8556b63682d13a6f017bd6010da468bc6468c5c7aa1ba7f44b6188fcb906b3dac36269e43242abc35203e104d1aa7bc9fd17b10d112c66a45b2435b79cc33700dba32ef58210c06b19f946083cd1d4ec9c834b4bd4f473e84b7066ced2eddcb7ee85c9b8fdc0b66033eb3fe632fb3967d1394e6aecf407ebae9bf28917ed426e228abb13b033d4a19aab88d5da03a76353ecc4bceaab859ef34789ba5ea701211ff1fed6a4d728ed09a77a2667d85b851b4c6fe3d3e35aa11567c6abf9591bc283bee7dbe8c0c695137c244f330095777d973dc6d9f7c371294dfdea36ad791342a862621d46e06f8927cd20553cf501fb42d25216030e1033bf5261a696f044750689d9ff5fe7233c98042416112019890a49ece903b451d4131c299f39b019e788e84876143e777f450a68f4bd1f4c3bc2b066328bf7c6020483d0fbba74fb6169b76d63bd345ea10f6fa86a750eee5815d5b82bb2e29edb08c6e7fd7e8d1e2eae8aaa7b69478685f2044d84dafb5cd86f4cbb6a8353f3b0f386f15cd1ace87eb0ddd69ed6aab48eb84b3fdc247f5d60431e7b52cea8918b1f2a4c10d5328643f5e2b89d741f1be40d3f88aef9403344b134242cd8e869b3c56d70cc4c372d9cc09c4a380b8f7b76973a7372ba8e2b6b1aacdc5f834ff5941f1982f66c91f8fafe2e36fb5d0cecf699aeeecb2468197c9d3db635c20b8255c54e768510dbe42c522ee38c20df7193b9405d2582036da0aa2983acd41133a307d19da82da7bd7b5ac71d4966cdbdabb9470773729c1f2d796d070cc79ef08d83613cf1ab11546a4a50b64f2282dd194fb270929af7099127db4f95265eea3cf9b16b09efd14e4efad9645d9464eab673346436c1547420a84b7aa5d74db0f69513e08cb58beba49f775d32024c5b5fac6584be8d2fd44637ef07f4ab1005ba8d71a2091190475152db48d5af060d326d02ccfb05c9baa2cd47ad55c5dbe594f1d17384ea1e4bfd176d4bed1f7ce95524049c99cb5794604b4ea3c5d4f3012956ace855920bcc414e8bd2dd39717a029d6512eac5e59f22c9b3b5f81bbf81822029f8e851187d90815175a1974aece59a93ba33cc11d832d1cd0c8ddd99025289b7c6076ec4df3f675a8dea20f36fb613dc0e42a5348096d18ff55734d2ace42da8a3648572d1bc11e9f550fc80411e2d129fc729e1b571d046bce921d6bc3fcf13ca53236cf28804c9542e904769ecace9a91a890a2e5315e54be5e0aa1042537227ea24e34b0f0bc135c924b3e3a9c1f9eef98e194da08412dc871bd867cca7a2b6d4b8e0fe3e23343e4c972026bdfec7893bc8c5478ede808f46b9f20b5c7ddebf3119a83b312aefa1f0de0b8e60b9d3487c2cd7543b57fa24a341b5d37efe59367a9797593e0b9f4bd5fb42cf55233c6929959f389b58bbc961a001a28f17b03ac20438c5c1edb0eaedc07860e17c38362ff54ad1dd8d45fe4543a3599303879c060cc0952ceab493ead05fde0560d43a691a004260075ceec14a14c9c507ff3f491e8197b836c65b4aa787f3b04f0e14b22c3539a0f7d3002a51df11eaaa0fecfda90ebc5d1d651969b2aac13f71158da09d6b323348e859d0ab9878e39e86174a24b02c7177f09322caf9369da97e1c88a07d4846780865030667b3d7fe334927805f5c905fbb91b221cf6f95af9c666d11c25dbd822ab768969288cc2682b6c995d1ec886a985f8e76e7ba5ab0509426259e04c167023be9018f4574730445581e5f26aa77d71133158fdb4f80daf7700ae3c59edce76bac661eeecd4e267f8308e8afb107442ffae5c8f3825c63a10f07d387af979308cc594a651c05e50a61b488fc7c614e3a20f392b98c67ebc998b252c9477a30c91afef998d2c523d412e32dd45a8ab4af1bf0bb4816863f8313a4c3bd92c39fde948ad00d16101b834eb70054f019083446175ee10d3677b0aefd17c1a31337f535f3866d025eb909763de342edc0eb9646934edd0036477c16023f7250879066729527cc0146f8c7bba2641d5b1f81d521a1e049955a8e48376d272499fa2f14ada853c20034031f887977fc4acd0a42387bb5670139fba58658a40e2225a4bf7da8320aea1cec19e6f94d79269b0d9dae4df4e1458944eaf08a758348d4954d458b8747401e508d9d13063618813a557334726d886075e3e651f0d26eba621122cf8055e2e9fb38f31e4095a16cff4b27e460b131b6ffa623f2b036fcd5b030c638d49adefcb9caf8f3c70de178310ce32b8cb01c62e123014e3ff95b52bbbc459af0b3384b9b5ef09c16584e8b1b16876f34f47674b4a5fd8ee343e7e8d0dcea7c8e6c0fd40fee0eb2808fbcff735655dd4053ce2dc5a5ac17d200f3df6501025c5514f08322ecf95d7a7400ec220c333b56fcae2495b62b29ffb42885fd8ae30771f10e55f36982f8fec4e2f7e6e8417a57ca4feb5f9cdd3853e0c7dd43f829608408eee4fb8977df207b95f2b630247821292b8c1f8573a79962760cc1b51decc8bb589ce1c18a0d6bd9fa2592f99e2b03ad3dd8d1b36661b060e8c42ffdb699b13f15f4373d240fa5d70f5bd9a237c33d13d12d3a1b4bf765ef4d04f03f5c5d55fe968abfb86722904f2fc9cb46287b930d6986bfba2cab852171ac49f986a032c2c3b8e36a0e1d4188c0f82029abcdff7a1dd191c3f55285cf376fdd0df50f9be2f9bdf224e7dcdd776f4c5ac22bc26a12b9f37bc2951269db27dfba3ae4ed4da1821c425a492f086f6fffd681bb1c96e3cb62706574e0a42af91b09872d46bd77e9e975fef86e9a787cc73724d02ebd0d2ab4a263e0445369f768a04517887fff20c037067828a61838e88e91fd52074717d94015b21a40aa298a94ad67b8d8294535713079c1791074366e1a4e0e3971293b43df4467608b95640b83f78cc3e5a2965cd75059cc4f6dcd558568a565aaaaa49f769864e2427f3f2e81524dd0471a11356923e389df54a4f66debcb30bd5495e70fdb4d498f050c7a7410adaea7ee65018568ac5ba5940dd0bea98b457e642242959b23ff56683f22ccf1aeae856f0eb5b07b301f9ded834a6bb834d9b9bc89ba9ed2ed861c0cb30abe35feac6eed1f0c656116b30fbc974492d4a253686c1a9003cd635827f0a3cc735322ef4492cc5248337dbc6f904a8955550a6838e7a734d1a583aa617f7a573eb89247507e20da83fb49a0c2c42266e3cc072e70b583c73057d85d1e791b2b3a33bfe793e381856de799948b2d54dc31b9958a4d2ea411f713db4101312773be6ca33d1b5daecac4bf815bd8f9261decef90d468016f234e2908fb34a120af2ee81efdbbca136b4095e570421b8c1b8ba7829edd6355d1a7b446c736297ab3a2e6ddc9c7238491a0bef6ff265f1383b527968a6b7befa57869ec059b3176e3c665dd5879b49e146165417f493c14fe033f5717f21232a9aabc7af13a08e1b5cb22679de67d7d5efff76a2d47a1fda1f12086550fb00ac8a529bdc0ef3975673dc2f474d5589c66c48f0973cc4db3fa51343cae14efb80f367e08cd60b355fc1dde00443a3467aa1f5d0c42bf14d254633e1dc76228d2c44a82d0d280e9e115b17f9ac85f8cc1e9cd9d548657911d497962afb93890cb4f9424d54ff4bee47ec4e5e29d89212ca39155cb7fbe97878976cbd4fdfdd7b34b35a6dc1463eca194d77fcb1b7807ca1d7aa66c853fbd25aebff25d733cd5d80fe72fc8557a535e1e451a83ca10a2fd877f650543fd17a77162959f2262c091015d806d57fe244e1277b9b8c1869afd67586dbeba24731a2252850417aed7b72f2a7eed1b4e77899fc1558ab0d7ec18c64278f5bafefa13d919410052df5cde09cfeaa274c109ad11269770aa0e5ef5987bf73e6eeb60bdb383b8c531c5a344fc6f77fd1e26dc3ff4e17bd0dfbd26d2eaa303f4cda49302768beadbe7ac069c8b2ce604499f87436a82efb8eaf967d396c8bc8a8484763c092c17ade2a42fe9baea6db11a34fb9324b49fbcecde4515f32ff19817543ca18442384a65cbe3b5d1b5da92c56ad1478abf9e01ca5197c1e109a50d5ca77e658ba1106f284fd718026e7b9f8a8cb41700f21310a7b08f388032ba50e5437fcdde3d933abe2ab2f3915141b9dd91e84e645bde2c095d64cd5a3e406401ec2a8cd70d28473e204881917bb0cf218d3ecfce2147ad5a8bb2b84e81f60198aff551b155a57ce62cb146575af6848367dea5da2e0de39f2be33f08d7fdcacf722fd7673579bf84b74fd16a7c688f0aa8902bfa04972d86d4142c9e3b194a492d46ae17aac0e89a733994a12fd955ca3be352acb3db78577eea1f5a4c29474b81b9aab01042f5643e76f7ebd2a18a4bbb7dd787b6e3adf831575f5f3f8414c13e99fe4cd551b043405f96ee2b4fec9f05c8109a8fbd29d110904de81a6eab660f9942c57517c3884cf5e99c04c456ef9417a817ceca9ae35d741a62c15f617e28fd1cbcfb139c3d06ad7debc8ac998bbd5082d81870e6004ac6b946f6d92c6b9028a0fc6e324707b0c7e772bd1f45de7d5cb35892ce1aa4f4ff7e73ed640bf80afd27ab8fdfa854e4a2515292ffc8bb1808ff970e77c2e86f982fe43f7b12c25b02d69bfea5f6e049d3d4c68dd957772d735e5591f4787740aeee12c33c86789e2a6beccc4680bebbdfde3b55b9af36fda47480fcd4be9e00dcb0eff9ee8086141bdb0c546168d616feb87b6602f9d0e733025d7f8ba2680b3f16499d10a61b41c47f10e1b5a93323b842a1ea29e50ea76af809dabfd3905de0e6c5f822d27dc984d7abd01d4765502cf7ead6f1977f928af1e59167a7973239360864be92f24b2305a49aacd1d4e29c9b6b9756e384e312ecacecbb00522d81feb380b93244dadbe7dca61daad797a4448c58bb1f843aefa65278f0b84029f12fd3d8fcedfc0e4bc38265946dda4fd5701ee3282c3ca2374e11ce1d81271f00252e33ddad81c8a19d3796bc090b4c377f7d913328100cbc574f5c210abe04cc5abcd94194d755993f8cbdbb53c7885bb0a4279024bc2425e7f1e7a3b7cec05442805a51b1792fb7573dacb4f8fc6bee72354e7dd4303917b6e67b45d080b6bd9c32a71924386ee5da156b0527fb72044d33ce9e69992acc60923720657ca4dc98d5ffbe0e139d95d24504def200c4762dc79f63b982ed349302435de1875827296a831a7e71ca423b2971ab73306b93cdb01328969099926433c97be0ec803710e840b990ccb9d213bb272605d8da7889192492dee29a154251c01ea6e762b2b629d48a3893fff3b4ddaf8639db49b767eeb436fd0ed0d0465c9b1febb0f023616eba4c1b57020c99a11b4c5cf80d4016f9566ad85ef4e82d9f236c6d893dbde3ff873198711765da90a5eac68e242a9abae99c719bd84a4f04939387fcd4153d549f981fef231218b615ee82421ab31da3194ef7369afbeccc5d332ef3e5d20cbe0e7c0511eb9dc9b2e5dc5d3e8050f32866ed18b511069807bc3719fbe60271fb7fa1bef921d7eb87c90ad8999aba48d12ebd774dff99ed3ff4b5b8c83509bbc193a0069c9ac9c3755dacf0982482c90e74a37f1c99459f5837607e939003bb723beb989a24cc62db62e14f8b3ec41d545e6cbe8e2cbb1ccbca7489fdce28a17736f7f27c40c814e564eca862908cd86a32500fbbe76908d16aa661d0c5ecc05e8818a476d3e8ed5d9b7b2caf2ffe936451af4c24c48d5a8d6f97e8de6b3d2ffdce97e1935c46652d7c281639869a22c22761bc6a5255999fdac48ac7a5430b8c78f3e604ed1dcae38bfa8e5a849ba193cde6bbe86b9b1d972715924cb87b1ddc6c20284a0a2d0e67f237b17d827b8a4e550f7ca89e947d920c7884f1cd7b70eb0f855cb61d400bade992827dcb841f18a1842a28dfb81a1be387ec368dd2296bbdf0e722f87f293db8d0ed8ebc65ffcc61d09a42b13befb5dd113f65249616d1d16d0fa68c474d3ccbca220ac794154886fde6e15d1ec3ce319a1b9724598719b7073693f631b4cc7a26f23d33105d356a66b3970a5f415832d3c32918f803b9a61f464d8f87020701a838db05310549abdfca0d9c31061948ac97ada05663c747e06984ca0417cc52639acd61419709f648925b16a09d905d23ab3b5c538910203938ebe454a7cf705ee11f9366f2652629fb2ee022d45f3deeb3537bc91f5dede2ba8f83637796442ea58851b24dd31cc025943720568022cdba5ad7dd9ece70cbde42a1aaf312acdbe61c416f7a6a13f67a9f806c3251d250b1ebf401385b227aa3cd521f98ad913f9fd7dc50db09c3d47bf5acb98b2a7a86ae7fe4b3d924b4dfa78b51ed8745a54d55b58d8110cd5e8309e23cfc94b80d332f4d020ce66993c8ec0242e2c4e470b839959d6fa135ae8ba7d8140a3c54625bbb25f0038acde7eaf2b785a336ec7d630c989d9208616e15a9a973a791c5abe4ab850fee06aafede6242890556f99c51587464fd6ffe1990c957bbb864ce28cc9c47cd7a0c018325fc8a807be1679f83c83f60e8ce7dc21cc2389fc2a43667cb7f0a18a5b123ea794f4431c1c075933dbfa5856d2929d4de75b2f5fc82d92fa5934421bf339a823d6dc000588b7671a08828675547ec59bbb26fe3472325a17ead7cdc60fdb0f0108471a9ed54755633bb9554455c0f2b84aae08e3e13195c2dab2787a42d14283594016809030e74c44292e58093a64e087d958b92cc063c8ff0c33f2ac14290dd2348a80acf966a11ce4c9aa6ef401512ecfb1e42db8463f6761c6d134509e9b326fb215496d0c9b895a6534666af5e70ae4364df3978c892648e668537424ed02e2284f503a4e1092f3862a9a09aa62579ff8792769c33f4239e53658a498704cf1e19f50dfd0ccf422d42e242bd2c5c1881238ace732e3b01a202da8919507305204d5177eeab9a85517ffef1604c95d3dcb169142e492af1d95560aa80fc4978c2a497f882a6aa3df754a04ed0a5dbec0af6f2a10798ffc24fff7b0ced301306cca20dc034e2435bfed57b6c5bf7f5644a2386a0bb366e0e181bd2d9634a67ed40e1c5a353f2b9d7ea37ee19f5c29abdd3e3146df3ad0c5f64c4fbb22b9dcbe1efde3519db85be1babf515643cadcec44b978580988b849359681e36eb7425143d814fbdd855ca355d63ffdaf99efc21e6a0a6d880314322361496540cd5cba00f5c6d47de101f87e31964cec3e608a9ebb888d10f57dd7b462a09f2988141ad2b70c6284a16a5e5ca1e83dc1633e708ba6b9b8c943ee0be279714bb8c2df26cb348f4f9c3e7a43ec6ba5652a2193d114b706cabc5039f11d8521ff4916ccba3b758b786249030268a4606030d07b04dc14944fff8aa5aa11f9f9cbf5f8e15518bf1db834298b1e79cb37234869bfcfcd55abf60ef1ea94e904743bc3e9ea279a780b2fc67935da39fe7417d53959602ac5b430f72cdbe195bd55a182f7aca293f47f02a31d0eaa28585f216a95ec3ea22ee17533d9e918e35b1f714111d6ef8a792a40279b81ae6cd97f3233fc839af8269f4aa945fa15407eb1f8c25d6bdcd49c07003441ccfd406029ac3dc4195868772b2906046727a394390312f3220189ddebe0f1e665c81f36f816d26477c890940f8e9837bb9b9b0ed40c5d09f7b347da801ba8e73f234c003444b4271a176fc781e2f8f68c0df5ced607818fcbb0aa13f7b3deb118b0a0229dbb40c8b7c8507e34bd0629b9eba071d6d4e66ee7acbf1ee620e42ecf0156ff01f4febd28848f951f83ebe30a82418670e8cf0b4780b8329ad195fdb419d6afa4a3cc42ce14a6cba4cd97e7bddfa11c10ea827ab294d47a3781582978e3bb4e2073f637c8d8f51c36abcf8647b2a3591d1ceb9a2e17ca98ce6cee8589eb3f4651a8b9042f2467f391939c9ac3f40c65a520694fe4383998f2f455c5ecf471ce790a65f320d7eebe710d62cb0dfa625b12032161fccb21cfd45915be28548835e02cd434c6da22d277cc84a71ee5d96a043198bfcab22aeeb96ce28ec93802d3330209e2a1ff715f03ab9668967246275f97126c712c4cf8e52d88176141002cb6435cd4860f01272fa5211536eb4dd57a9faed9e5ef8c22147047288aad09ac2bf44527a2725c93996cb8c9698b5b3e15cc87b26ccdb409e137a05abedd4b1df92212228e8eb5d96cf4ce3d6940d02a1eec4407ed1f72b2c798183b3146d6dc6ce9ef7e4cb41c314886b7921f140dfa1ca238bc3c8a1121094daf2656ddf9d3ae895f6799aa8f3e3206628b5c627c82f89939d10f229a23a978d64f32b2011078dcbfa8df74c9b5ad47d38b4e954176da74fd6e0e2d529b9a21e781a49f0c147fdfa90ba02fb718b1e3c993f4e497483b91873801477f390d83abd29c4515141070ddd7f1641e43db519fb5d0a6ab5d89ad7d645a012802a509b1bfab463ae711f0d1acdd38cd42d49b5f120761094aaf31a553125f084a93cc6df825b938b2bc487e999a672049497418336ac5b2e1f5f9d6ce5a7bda4bbdcb43748859e1d20e5980c92a0b7c2cbce593a35a10b933bfb6405c0f30b8d81be77d4c47f98ec2cd11fad8ea8a5b1e378b5d5b006e820703e3e6cfb24931e542292136d94f54a87e32c41c33e565deb8d1bd29388f1b3b702387a3126cc458fd10b8591b6487a8fcd194f7eb7fb7a4484a52f37988d240b0d6a5819d8f9522157b62e12b0c2d9c32ac9734b33c31f4949bd37d76157ef50eaea05e96d8a1602dd2833305aecf2b6cf8fb8d65f36fb9d4f985f32ca642284feb643ffe007d887de6ef9e9df58ad4aba70365d2419dc04f43fd9e7707d72d4cb145f33436fd12f3393e35d5ea06877a10a89f98634ee577aecba6a2754286ed8cef3777f8e4d7fc64d427965f49e8b40e00814d92473c71acc57fe207cc0ba4b1b5a947c668ad089f351faa7418c890cdac3db10fbe5193bb83b555a62fecea786b2fe82006670e4e2612649c8a44d7bb631b6b0caab9897c860b8c5ac9e1f5f578b94959a3fa8b671ff8cfad15619770544e961354b4ba8395659c5c4ee227a60f66945d33fd3e39b9bbb4c80955f12c59c56a10d43f2aa620ab3cf130fa3938e157aef0e6071cd3cafbbd639a7febdbdaa8de79d468d7087066f4482977d085eabd8defb13a1750c2fd673656651c6608b25d0c8ef37a063139ef40041ccde2eeb96a7420efce27c15a0a4ad4bf5b870e6e4450f605257cd0dcbdcdc47ffd1608dd5edf0c4e0a199ef5dae7e7fb6d15ff4460b5d0aa4a2fc911f59a23dc035e588a7c584f11b282a2ac778619ec0b4832af534f637abd6aaf19427527fd09ccd2d59a8fc1d420639d63fdba42fa31467dd6ab060990f04f93e40ecbf754ac7e1a84a16f19047601e48726dace11b2671c7d9ad94e918a5dc136b1515e0e6dc60a1e623dfa7de900801d10bba281b50fc84639e2aae14740340cc2315e3cfb47f93b0cfa69e1de520a40a3eb9ddb0b02dd79f3522a950717fa813d4ef70b75288933330ca60c01f60b14f93ca09124e5ea4229f850571c2c66c3438299beb7e3df33a44721c5fac82401fc759c94edccfd535d9edb6c5ef19ea90a1638860cc7c2f4792a87b2e92e22ac8de643f9fe8684c8e0f722c6f1c4ccf6c96c05b3e2232b3f5c956eab5aca8160b559cc512b57dd99d99387b29fe73836dde76839b9134ac8bc3dff5ebf9d5c5da29463ed666dfaab970c3cf8609f1ba08b050e77947f0315ced23811ef1075ed091f844d591c4f6761623bdfe706de572b8e54b4a1cda0b46523daf037c5de0ba02108722fd9195de9db15ceb9c4c6a9e0c421e2b1e1692f2fbf7541a11eccfa526221524111677fb9c10048471da55e8b543c633923b2ad85fc47099501724eba45607d3add642f644bd1b767521d948cd354c8b0201911257e71f080b9ff4130fc94d10d431ac0f2ea3455bef09ce12714681b4ab9f341f6fb214a34a727f5bac1b7c6ed134e712e25e2f9f65f873fdf4f7ca8b5664aadbe3828bdbb3ca8e2de28ceb296ea1031c78783973e127f1fdc7bb9205dcf2afef3fdf666e0f312e0b9e29a1a99e96a3ce518983fd672c4af25e9cc95e872a78635f0983917345a2cfeb8098d94061ad26eaa62fbee4fbad594826fa51c1e37e16a2d6f92823e2af4d3c9d2b5af533c7faa85b64560acef44ecf45cc4414cd903342352dc583988ab8ddc570049ea1f8b61394a7f1405df5cb7d7423df5bd13d98901e075653f4af618ea78b1901822ac9d4c8987a2014da64dd4a05807f22362c53f0f6336c7bd4e4195ba490a01fa0ff2daf8b30f38cb9a5f3390baa070a80c3756810a616c7395dcc1631e9ef09ad8b87555850d5963a88b16305bf1cbe806fa59fa1bb6962ff3a9ad98e04a71ba41619329bf7cbc2aea3fb16cfa7022a1a9d4d4ff25cd82e3f8f7d41b16406ebe9d792a1877a32ca9ed40b2e58ccbf26042fb04e8312adfcea693fcd7ed0825759a4946c50e1c043967161fe9ad7ab77546e7b006095767a79290b44922e9d4c703cd91bf9e71cddf8e6c04febe4a6751017f47a9c2d426508f6fb0c42103f62b604ff956a704bba76f9da60c6c2ef1d2535ea9b2673839681eeaaf14e4ece9a6afe4af5de61512c5d3e96892a902625e3c04176daabc3d655ce0f33fe1c907a4b41e61c819b0dbe8cab692a5b42129975b9a8e7d2d5455219d3fbdfae747720583ad8d15120f4e8303f28681265b26dac0ef39768ef72d3dd9f6877fd9cece78f53ee5e42e2df5f079a94d7c76e347667740d20584275483f671b4d73f572201d7140a4df15faea2409a9c1481f58877f4ff6614ee97e361542c2eb0651a9a4f0e3e83e8e0f5e6a5e0bfe341dbbf9a39333c7ba7659c3ba1970106998a064465a284ff39b253ce6f12fd581e8c34360de86daaedd46071cc7edd88704ffa2b8ea9be96285daec43b8344204f1cf0cf451763f644aa104fee78d1444ee963e07299d0553e12833362d99a0808b0599b4fb7b2fe088ff45f4a2eac265f236f3e51a06ebfc8a0d12127875bbedbb95d5c70caec74470be6400f80e1056f76f72c9fc82b1a8107dc959c26655296df601132ec5a1d8e461ab28b89bf5058eeffb3e3f9163e6d9a921e52ab2ee6a5c456db0144315f40a07280667f8173aa97c72f99b49770ce192871dafcd1f955627cc78fb10b656eb7fc87990ca948f094a1e638cafdc599ff0c9d443a96662408ff844419079cd49a1c27b5e300d6bde356800a8296b972f6ab8f87896eddcbc714b10832b340d80944c6a0fdd3f83cdf446ed1bfe6f490c3bd0bd65ccaf899eb6ccb6607ea027998b81c267686a8d996ccc1ad43e4176d88ed760ad891b5abf4ff5fcbeb2d0a2168526f0a81ee0214d072073c3bb92dfa3a3756cd5ac7cfe99fbcae6a5619c6c1151e9c22b94e7f6b91cffa2a8d8304bdb13fe26151d6deefd459e10d0b56b30abf672efc719ee68ccdec27617b3ac69c94adbf4b7d9cacd3beddd2fc826f1e4b42e146f3ecf4096aeadf172cedefde720e24eee18c65c6b647051492f23bc7a1742252e02d348c53a6808acc8df0716409b1326d4f8e6a24731651c3f38265135f5d5aa53c39bf25029049a71026040d116d522a337226e5d356c610dbc0c97fc9304381ca9fde5a94132eb5e74191b7e3c661a491924da823063254fd177e6edd9709747cd73accf1b78ca5bc39e54e9b3e56ede7e306e5dc7cbfb6db5500926bfcdd4ba350d32bd76c78d00831397cb743affc562c044b3183655f8af3bbb9d12b0083362a70fd03b1c662fcb1b9757d701a736a24b63b9dba7d2e6865c746e702d11395b3892c293d9f004613b5309707b1749bd752922c314fb82b3e200dccf32cd86bf5bba85386f3f7a7099e77209df489f3f725e2f162d6435bf1df46aa960302060315db1b79606791d8cc3bc4faf8271d558e68134e73894a532d3bc108c1c043010a803c5fdafcbb3f0d51de2b51ae1d694fc086517ea9a8c29bcb54de69dd1deff4b3288c6a342db01713ec9b5362952dc56f735960a46c9597ff0d93fa637f0ea07f4252c624e9ef798fb01d806e3634bc7bace5b3e010cc1a039754675efedcc6710948cf4472619a206033c89fc6aa1207e33b39bec0f32f17a41494705af40a9c2c39974c8797eab86bbb0bec0ae137b59fe0c1009cd9a7297cece715a9e23d5f0df19b52c444d47b8fdb0caf6d8e06b95f015f2bbea23037075e0707b9e6289075adb0b37b5dafe16ed6ff3a0cf9f79314b816ab68ec0cc275fcb39388790fd9fd175b3d38807f5f9b09478b1768190d20343fe7320ed3c32992b0d066c9076fd5512ed527bb17b0ed86a2944e6637e39fca8c76ca329b485c84e88ad6316697a842420b146c08bb2e06f6eb4ffde2b0d7269f180b63653ab9e715ee8215e5242914c882002f4a5674edb497a8d7e83cafdee78879466f68b26f2c41a2f5a1a33424636ba83616d34a507277181a6dee31549271fb8145a5af86bb2b141fd6d5c318c4af584564cd1ffde6780f20604520f93fe377e92cb3594933fd72d65717f0afb4eec6b912e31a9ae3cad051916928d0403606090819f897c76b88fc71a6e6e33cb106f0e9a60fdcf1c5fa2091b8861335ca22166c292b12339ae558f63e275949d231afe8c287e758bcf53347700b22f0c368f134bda4614dcbe269f7a15ae29adf7540156a06a3d11894237c3c2fa58fa78450a34118ea3dd2b451107d41aa50351f8764ec419f299b6201f00b30afc407e16c6f708420a88566e3721c96c979b69988a921ee15ad4ab8aa2f295973704818694b534907366e71d8c59c40e3fc68f45c9f6f0c7c19a8592cbfbd57de34c1c9141303b9b48645440e3a87923dfceb8a0163b01093d54ce85ba3a861b76cfa40a042c23c090319a31f4b738da2a2d958bb698517d5190b5e37a341265c4ab5f42d9901186a968aac05e4f16abff16596d8671ad1630b7bd71163c7ba4fa48f3f26f4d224bc3614cc4b273533ba6ae0a4e32882b644d78e29d80eb0484c3cc982bbb3bd2600039210059e0ca4abd38aee884cb127d264fb7c3052710f9ed5cacbccea4c395ed7607f1c4aa7a4b2c107a0c189100d78082f4bc34d405b5145ed8a4223c65b2251b89718cdb407911f00eea7068adbebd12dd8da66caa5b75e4e5ac7a8ff4c958bdecced637726e4315157aacd278f9a4a2c1741bf8c89e87398a7f0e9a79f38a5b0fdb81a43b3a263f8a4a8fce08ab2c5f53fe957e5bdb62e4bc1b74671c922fd6362539a55308e00a43ffd7b60b64ab005173e3168ab5a183884238e0aaac7492b9ccacb1e896dc62f40ee7cfb5226cbd5da9e548a0fbff53a94a3135c6c5724b577211b7326f3df8398a2a5f6efdc7e4e37e29330d15ba56bda406c005b726919ff07bcd4b92240fa85ec7a9e06cc4d1e955ddf28191e0cb93b353118ae596ae6c219a510cf9d997a8ba2a13a14667bcc0e7350dcc7ac1e7e13d7d2de80c34f23c97e7f19b98db0f5a199d16d87621e463f477f52f3434aa20b60589c288186e1e5f2cd5786dbe6594f4e3e13192a49ea8e37d05f36c31b45bd218ca57ec90dc8ff3c22b0c88e87fdf2efef1287a7ee099c8434189cce3226883f3cb0af3bc41b9ad84e0c93959f978bf8b1cbf42fe93111ef99d99c7645a4b695dc32c26dc5f1495f75339420ba7fd11f6858ae1b945e7bb728a6a0527fcafd7a53d6414578a4fdf7ac7e9b1c99266fafb5891020285ebe3a289220de7f71f4f504322bb78a6f07a8d3564c0f7c1b5248887c10c8770f7009a26d49aefa631edeceed958333450a20c33294f376ae8802d2ba219c7d879c264e9cc32591c8d8e24ab3fde3f13988061abff14bf4444185243c64a1e1cd0bad11d542f582c2164d9d46ace553b317c6fd9d928af2f25720b70655cf0b9f3066aba3042d8f36f23b0003b47daeb8adcdb5a0e55d61829fe0875e1cfef5698c60fad5c19386f580c41ffd19ad6960087550feff48f82395a0861a25a11fbcb2ac3fc5ed3c14b38a07de13f2e851b357cd28f5ae0bdb570a2df59a075fcc351750f33297bada56c3d7d40a94aef51bb93fc356c761634bf44745da35d9b0ee76b2a6fed85243163621f24b607e177f54cfeffbfe447f788d03fa3f5807266b78a7547de6f57e5519a063246671d8d9d8870571a21838990afdd9606e45e13ea0b1fe6bcbe9d4ae85b0770baf8618288495184198848337d05fdcc83b136a26ed055e96c693d8bdc1f2989ed86d3c9250558988eec7a5d4470b756ea29c27cb30c8f267b2872ddc1cce2a91be0fbf0c11579632e6b9d2420d9ebea62cdc2ea9ff3e37474c156488a4f45c317b2295074835877897bd77e850a532d155e77d546bcaeada867430ebefa8157b6cf47642fcde2db33723ddae1b31a2514c945483b979566856105f63e4dfc327aef70563ec15ef79cb7fecba3bc6a1e7214f3d6b7eb89bcadf7064881af0e598515fe9540896dcb90d2d0c996869e8f6a1f9275ad4d98b631b50c04ede91facf54f80850d3817f137f8ac2781f0a327286c00a57f158f08ca1a22b3edab0a4378f70d1643033a625e621f904a4fc7d79ac7270dc2abe66265fffa99e3106c4fbf772ef99c88d811a4ebd4a61998fc87724ddccef592ef99cf0cc140814f68e34ea7ca66b2e92a8fb6b45c9f254905465a5f0caa391b26f5d2046e91ef663eceb07bd6331c9058e628a3bdc7ad9334740cbd9d4cfadce52436e356be5fdb54562363ba09a867ac43a32e1bb6a00e20642f5108da7542204ec5e9385f32661b96cfa595219a211da2493dc33cb6787b8004efb4feb7309eb12506d6cf43c7367cd5701488d2a3b00641eb63f7f91b7e66127eccc630d7930a55bb84df85320a91204c3390a798ee93d1cfe5c7b761c7708712d3891d3e1bcd052453b278d07ee4862a7d26914268f39a99941b6e63e253ba0a0ca1e71cbdf7811a97be0b4b47557f6187c4fb3c785f9a8622af66e22669243333148152968f7c72b5be92e15990172093f5ce30c16776b00f1bdb822be98cf1b9528e11b15b77b06fd969c3660cbd03b931ce19fd4bd364cc1b1b349f827ec94a41c4d5744cf0319ccd5eaa5821e4372681b3215c71b48c5a90e5177cb19bfbeac1977f404f37941115b881f3e66c30ab0071abb102882b28fa25fbe778a3346873426f21d84dec8685bca3307773b96180589c5c989d561d976ec9496f79df0a4e2b0359a12acb8f28a42f58fdae80325d98b11223f76a70b81ca927c59b04ece522619e1a040c24afc560a2fda43abfd8ed90bdb4522656ab786c49e855b64db38d19231f59fbe4c793d1d65b858a0454065be48fd99eeeeaafab30f53e34acd2b3242c317b7ac0ffa6fb31cb856e00939d7e9d737a51b80f864af1cee8b071d030d4f67301b7ee3764cf3024ddfcbcc89810b565faae620ea107776b291c6694091d0e9b5541af4a817cf902d18d3e730e5fd53eab0292124bb255dc7563fa64ec0d9a41d6e395fa81c5da99c74ba9a29bfb6f5ef1151b274f2589baac07eea300875bef7bd7003ce773d571bbb35c1f7b6</script>\n <div class=\"hbe hbe-content\">\n <div class=\"hbe hbe-input hbe-input-default\">\n <input class=\"hbe hbe-input-field hbe-input-field-default\" type=\"password\" id=\"hbePass\">\n <label class=\"hbe hbe-input-label hbe-input-label-default\" for=\"hbePass\">\n <span class=\"hbe hbe-input-label-content hbe-input-label-content-default\">Hey, password is required here.</span>\n </label>\n </div>\n </div>\n</div>\n<script data-pjax src=\"/lib/hbe.js\"></script><link href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\">",
"tags": [
"life"
]
},
{
"id": "http://example.com/2022/12/28/2022-read-record/",
"url": "http://example.com/2022/12/28/2022-read-record/",
"title": "2022-read-record",
"date_published": "2022-12-28T12:55:38.000Z",
"content_html": "<p>研一开学以来看过的书的记录。</p>\n<span id=\"more\"></span>\n<h3 id=\"202210\"><a class=\"markdownIt-Anchor\" href=\"#202210\">#</a> 2022.10</h3>\n<p>《圣母》 秋吉理香子</p>\n<ul>\n<li>不太喜欢。看完圣母之后决心今年一年不看日本的小说。这本书内描述的感情阴暗、粘稠,深入母女之间过于幽深的关系。最近的状态希望看到一些视野更加开阔的作品。</li>\n<li>圣母的核心是一个诡计,母亲为了保护女儿,帮忙隐瞒女儿的杀人事实,作者诱导读者认为被保护的女儿其实是真正的女儿被性侵生下的小孩。但是我认为这样的 trick 并不高明,至少作为读者我认为被愚弄了。</li>\n<li>另外作者的设定也很老套,比如硬汉警察(男)和飒爽新人警探(女),可能类似的设定我会更愿意看汉尼拔……</li>\n</ul>\n<h3 id=\"202211\"><a class=\"markdownIt-Anchor\" href=\"#202211\">#</a> 2022.11</h3>\n<p>《始于极限》 上野千鹤子</p>\n<ul>\n<li>\n<p>上野千鹤子和铃木凉美延续了一年、每个月一次的对话。作为年龄差可以作为母女的两个人,探讨的话题都很有意思。</p>\n</li>\n<li>\n<p>一个女性必定会被母亲塑造,根据母亲形成对性、自我、亲密关系的初步看法,上野在书中说到,女儿往往是母亲最尖锐的审判者,而强大的母亲对于女儿来说即是一种助力也是一种桎梏。</p>\n</li>\n</ul>\n<p>《从零开始的女性主义》 上野千鹤子</p>\n<ul>\n<li>通俗的女性主义读物,主要内容是 "接受自己的软弱"、"你想要什么" 和骂男的。</li>\n<li>因为是女性,因为是被社会塑造的性别,因为永远处于凝视之中,因为容易被太多东西牵绊而走向软弱,一个女性的成长之路势必会比男性复杂曲折很多,我恨自己的性别也爱自己的性别,如果我是男性我不会这么喜欢自己。</li>\n</ul>\n<p>《永别了,武器》 海明威</p>\n<ul>\n<li>宁静、隽永,我爱海明威但是我是女权所以对他的态度一直很矛盾。但是这本书写的很好,我认为他至少对文学很真诚。</li>\n</ul>\n<p>《奇想之年》琼・狄迪恩</p>\n<ul>\n<li>十一月看的最喜欢的书,在心碎和回忆中重拾自我。无法评价,个人色彩太过强烈的记录,流畅的可以一口气读完,很喜欢,应该以后会看很多遍。</li>\n<li>在书里体会到哀恸,但是那对我而言是安全的……</li>\n</ul>\n<p>《烦人的爱》 埃莱娜・费兰特</p>\n<ul>\n<li>总结到这本我发现了,我很愿意看一些探讨母女关系的小说。因为我对自己的母女关系很困惑,至少妈妈对我的爱绝不是无私的。</li>\n<li>埃莱娜的文学底色很灰暗。把母女关系和月经、童年、性串联在一起,母亲的一生,她的一生。作为女儿,在自己都不能保护自己的时候,能不能原谅母亲因为收到太多来自家庭的痛苦从而无法顾及她?作为女儿能不能接受母亲有别的情欲,而且那份情欲在衰老的身体上仍然鲜活地存在?这一切不是说和解两个字就能解决的。</li>\n<li>感觉男的弑父就行了,母女关系好 tm 复杂。。。。。。</li>\n</ul>\n<p>《地下室手记》 陀思妥耶夫斯基</p>\n<ul>\n<li>我喜欢陀思妥耶夫斯基疯狂澎湃的感情,永远不放过自己的自察,痛苦、敏锐。对于别的作者来说,语言可以是一种戏法或者是陷阱类似的东西,但是对于陀思妥耶夫斯基来说,堆彻的语言就是他本身。</li>\n<li>人的内心,对我们而言最重要的东西是什么呢?地下室手记认为是无法抑制的非理性瞬间。</li>\n</ul>\n",
"tags": [
"reading record"
]
},
{
"id": "http://example.com/2022/12/27/2022-12/",
"url": "http://example.com/2022/12/27/2022-12/",
"title": "2022-12",
"date_published": "2022-12-27T14:03:31.000Z",
"content_html": "<div class=\"hbe hbe-container\" id=\"hexo-blog-encrypt\" data-wpm=\"Oh, this is an invalid password. Check and try again, please.\" data-whm=\"OOPS, these decrypted content may changed, but you can still have a look.\">\n <script id=\"hbeData\" type=\"hbeData\" data-hmacdigest=\"3deeab3c996177c7122fa160a82b89293c4b1db4370b38fac387da0de0d1735f\">b8d495f296e442dab4f5c644a6122a6dfee46865e5824b1e71a4c9a72a34f41bccbe97619f7a25692d0a92e2ad63b7aac94144b5bf421f7346d75e0b4aae765c1625c8cc5c84ce13db318307744116c907bc05407704514a16227d4bf6bee7494b63a90265e42f472b127b7e471b6e1ccdaf4d12f3bae40b7673f94d981fda0c06ea6645a625c7324269811d950b6592e82794ed5fc7391e546d88f2718976a63e0b6f442af4c75676ee0b8f94271e45c5d5f7eec089fc6a0ff224365cd63efb3a6c338199d4c6a040d69e993395e7f6b88a0bf933c451e2f6a1c5f861e728c11cf8dfe398907bf9abe61015ac63540120b6e0ef347263bbe5963ad237ecaaffa3195d12e441c0a862e50b229c4fabc511354a79e318ac9ccd4b25b62ec0f9d2f4d5b4531fc2926d0ae305706bbcae020f8fa6aaf0bebd9071d778e583b247f01f77982f6abc9b103dcaf3aac4a023418df703f64f39b31e5c5da2cbd412cdceabd61a60176a94c20870e3c8f7f83752a1b9ef133497a9e8bf3810e68446e786f934204a79d94d74c74cce316cc3d52a3f42bd8aa87d28fa1d74334fd7bdaf56fc4f56b028060fd011fa3c418ac95ad4877a68123895d1e6eefba838cb04d529904b000de0939ab6b4f02b68940221ea8709237319a1dd55d5776f5e73b8306c50a5cf537440e57658c4c09ac96ad2ea1d4163e587cbb0824a7f95144449db46c033f80f3401d1562ab9b0ec26502d364aada1d71dd3d4202593b60bbfdf1b382806394a8ef7f8a366073d31eb305a0910468112ca07bc690f858d16919a977534f8fa4ad85d2757a662baa6f6a74ed8602f40eeb4615b2b606499921b720d845c3f36625199548730e161af83cead61aaf8e7adbc37bd2437308647e241e22f15f9a42821bd24e92a77825cf0d4dcbc593a45535fb35f3e1f5ab06b516a630d4959ad5c045085d1bee0567455e0e1fcb8e8cb0cc3dd771468406036fb3a865085d1d6ee4a567aeee98fdd0ea8f37652f892a973c5f2063cb7cee5e2f7aff5d8aac71ca1bea917601d73f9b9bae830ca4f954545a3271733ee75b80228c03e2b5f2596ed40b7ff63d0dae0ba556a913e9ba03d98455ff107e58d96f7d5baa9c69b2246104e930ec9d4ef42998d66b526a36e23d12479175f6ab3ba9fb24273cb32f6937ac7a3948a0c5f9280ace964dc28e5b5c7c3bf39ae895287bf672a8023ba3dd61372b825df58ca653fef7ce1a89fada8e4f29d85780e5cbd886273537b8391fb8352c945081978e60793517ebc059ad8c9d0eea9948a5e26b32446eff4fceeb2f5b406d2b0a419fdbe90a67aa9d430041c261af78b4b9d7791cbec6f85c1cebf61f0c47c032bb92d74f806240217b8cb1015ad8f2b82555b6cb8f28d9ff9de3c5c169ef835be42bf782e32b363cbbcc5c5c8aff6bf7dcff648e8bbc6481db1dc7dcfcc8e057a504404236d5d7123467376d57e1d55875048f079c0014a651786ed172da4306aa0302fe068c68f629bb980d9785f0603b8b69696576c5e14e545d782f0a4c51b58ba5b98c3118c5cae41820494e0b61722d3543da0947b9e920dafd1f060a19af7cf3dda92cbe304d845a0548484008ffcba6f348f2ac4f628adaae8161c896116a57eb2afb17e52be13aeb6a58a8db9d8b6b67fb729c89bdea1d0e8c45e46487bb5d07681ab3c93f1d9772fa34761cc947a25b975d616ffb68f089a0ea2cd72e81e57ebf2e076c3d9d9b3785a883b54f015af9f06ae4c52a5fe5165a48e9f3271a2262bf6d68e2a258392d12b76968c7a4b8029b816292272b792268ec9ff78761b095a6869eac2366a014a373591b6c99d999d341750080e5ce1eebcf9cb19955a9857064c41e11e5b3efb5093f9130479675504489498fd4f0738367811c31589fdc6f295fff8834e5032bca587ffa52dc321d893fde852f6b8905ae692456863f02e80233b00653309e13bbad87f5511be86d13d68db4025ac872bf355a0896717066ae97b2988f01dc8f03ac8cfe708368904448a2d1b32b59c012b77856b5de1dbe64b0cc22c559bd6b02be1fd70de216efd4f04c0e5b5f4fd9230662534d977907840937f2fdf97eb52f8ca0b5b8f4690eed55ba8a5d5b7d0cef7da3f93564925927db75ef901a185fbe90fb428d5258555ff57c0b844c307b134d4f60a66c64e3b1328030a8fcbd71d5f7e79c1266f2700028ee77096ad1c7e624759e6671b79f16ecd217b65086643fda5056e70f815e9c47cd5c5e13229e2751527a8b2b1af3fc727259b9677d17daaa7d537907b2f3f1a7efed7e3d057fb2c7fe2f3dc75fbf36a1c4c2825d38e1df844cc1bfb004aa4fbe5d7d138fb2e7d17e2b22baa405ac4dcd490046f0dec1999ac9074f13298e59bb4ff4db3adf0668b050c88766c7aac80d61eb5331635582c01879adad2812368d9963b531bacc07401e572ef6106d05916623b87b79fb77c049c32da1bb51badd29561b462aa71aad99e77ec89c1bf44392045aa449be70ea39b40e4a2c843356ffba543ef0c87b69a0f61d6a0428eb1f8fabf9ea502ec20cf5cbacd484f732f1f0e9faf96964650186c9936ef72b8a35ec9234210e09864b479dbc5dd1eeaa163c638689e257f83c2bb8859d3eeed5e6517ec0e1988f04bc444d94d789671ef9595909e96ecdd21ea8011e7798a5717bc6d94644edaf2fc4641ce76fd7418ceb5606fa298c633390b7e920bbe76cf43004d475ed32048b27802c770a3e7eba0ea199652047e63a67bf8b1875263ad5405ee021222c17abcce70f7fc9f78db4c32c61b4e7cd5ad7e9d237da4d1ce908dd8fb3fdfe86990ee630e078379338da817c50a1c92895499029e76ab5f8d89983b30b87e616de21d8903bb69c8c1c71bfa0c5510b0b669fb87d0775b0881cbfc808a0b7bafbf6325c25bdbc4b74e69b928b9dba3b2fc7a67d673ea85789d84b2b4983cf15dda9474af7334f2ed2cc05bdd038d3fcd2f39d1fa6f03b6dde0ba292adea90278aeb61a932738f85f07c4a6722c66e8c2f66171db7cfb4197c2afbd246207afe22a8396ecb422cb62f75696cc4595671e4f4ed0fd9b4615333e3336123474c647d7ddd27f730415218b6e43d661f55fbdeb483de269d3e330b81ea039f905f5e90832de11e86b688b485916ec13494f04c3a5daddad029cf7a72bb81b292c8b2dcf3e6b920a6ba82e36d849fb6a733669c741ee1c265d3d30ee8c786f25ede9edb50e7ab39a85d04fe60bc3a6f5b9bf571163de37b7e0b76706002bfbe80ded1949450edf86753cfa4201153aeec2e7d99bc7b8cf00a3cad43333d0a5f59bbbc95ec1186179da6a7646a4398e8bae772100f2c84fd4ea4e94431be3cd53afc64c8a0ec4c482db3c8be786abc480539cc1a2d82d23aca074e200f6af913154b26b460c0dadf2f9e5b968cbd96e1536c5b05a5d2ab82467fbc7bcfa483a19bf94b8c0cafec9238db8967d97ff5c05fd49b0009e69b05cb1c276cce7ffb1cc08b14a09ef642ba6c34034186dcab7bfe35fb1e1268b08e3b3378534cc2cf1ae5b1d35f7927917ec43baeeb3464abe8911e1dc3148a0a86dffa16ad3fd2ce51e4de3731e2152c20b24fbce3761390b3a22d3b9127df3a705f09a3627d06458e898090ceb14bdc349fb3770e8f90f510e4e64a0da7bd844de616e25cb441ef848b7e39d28df5df9a02948b70213afa5a20cc4a24b8d7212cf6409d67ee4f2f6193e9436021723f7f1b910a1532fa3200f5a1f990e9be8c682841e16e80fbe090a0713ef9b8ba342820ede237e00ac583e9c7e36f415dfcf068f8605c3d9c6c831883d56603be391e987f186b9749a308c1eed2d64701c2ebd17f8e5b238acce095763eae640336c9197f56cecb306bc1b2457832f636d2f79c006a8c9de9bfd5f896d7a08ca23326e12add9e9284b3ad2a79e4487698281a4c825b0f01978e8ec641b491c9bf9b4a54a752f5f6815ef9bf31e0d5134a8529cc6689d5af09cf955359c2d642650564b212dd8a3c2d9b8b5c13db99c07bb2b22b094d196b35403b61892c3b662a04ad57f78fc0f500d2033afbb9a2ef409f03d3dbdac1116aa3d447eb2c191b8d92c2fea0ee123a8547d790f02389b40bc0314662c5dc0b06511e90c66257371820d81c914690356a7226f3a1ce79862bb8b5c56c6448804089037e6fb8860004edfccaa267426e698f620a83a612f087d1bd31251f8c4cc6fd91a434c993fa87dedc8d22b2dcd23e3c6ad3cf54aba2a89211aa9dd47946623f445c1ec5abf2b7e4c22fb378bb173bcec2f56b39ba4caa3899b7e210a105827197c30af80956ab4582e5970937c8b34ce46927934045930718a3791f36c059712d8887394140625da9500376e63868a34c685a8f7f3087ef0c943f00b5f33ee0d23507f051de1c8804d5d3a9634c91b0fb7ea98b0d57e34c85044b189e7ecda1dfba994a4861632c6e0c8dd14531a6e99828acdac81b44650f0b908661e493df3460991538d8b8fe9edf78e35322ee2861aa10e53032350b38bc7bee671da199e0a6a664f63e4b760159f570b6d85f03d57a2562903919c99ec2e85c958db856fc458ccae6b2f40ba0077cf08da5e98041adcb6467372cfa3b80045ff682975830140175bf806815eb38b8ba525eb4e51d5676db4d36db1167a407df8be8a2b6ca68abe78e4d0d03796d9b25a793e68725bde44333a2c422c09f5268f969160029321fecd2bf69f90136d9d8f39d0d4a1e01f727c573b1cfcb122e4c868884f5101a9dc13d32544dbbf5eade518d046e98ac263d69beb1f41a106456df9d8463ca8c0d912caf5f9d85e0cb7a01405750b8b5e2adf584b868f5399267fd525868e333cfae2fcc9b55a9d0eb86f009a85e0f33b9c169affbbe9911b72ec5b9c3e5ae7d4155e397ec2f0d1a8f12aae1bd32814c34df3d3efea59bb7534f00336fd737e17879ad0e1fe0e5d8065cb81881d9caf5ea88e5b5f8408914fc0cf693b9335f077a8714c875adfab5eeb3880c669b9af263a59df45b47c69af2fd4bff3f9ec1b2a2bf91cc77abe78712cb9d883b7a9d557ecad30b1d602a7e049522daca92a124f340fbe2d53451f4459dfb58a1f9f950dd013489f6b91253643ded5c342a6cb8173c9e44e02b2a4435ee03b44d9493c015f749ca2a3e262daf17d0d8a030e3cc269ac8d79cb1eb146d0aa84eec65af79f9e8603f9c5ec245504ed2b3a8e07b3e68e47421c1d2756b18be904af4fc6d667965f1ad6ed1b27d1a4bdf06978d732c5f563c839d28848ef685e9ef1a4b61a5038e8a1c57625d26138f09fd126abe2a46fcce3d21a2b14d1bda7444b173b4c96f4a21628632fd3794ba781aba79256478649ddcd03deb7180d88232a63deb0e4992cae09a3d524b2090e6184691ba5caa325a980916f94f52c33e66b7644bc27ca608422bd416ec11d23869806faf7ac7e4acf28ab7c847760ba05a8a36a8f11ca7ad03fe58c3804c658e7c82e27d14d700102d78b4ab7e72ad9ecb1626899fd6b70ff7df593990dc48b173111be4c5615ef70441201d954c723eeabd15d7ed404b7c97364b917c4a52071ecf86f19aea9d85f111a8026067eece9ef5c1be2d2783afc027082dd8c86f4bed14a74b5adbba5b25096f49ba199ebe8d1527883d6264c210a12402db35897c7f3d00b93777dac0f3f1548b2949f598ed57a86b8fdba1e347ce8d1139555968f7fc6dfe15586a82fce1aa4a375d20caa21eab7535bb87e612e5d939ef2b3392b5d8f7e12e80ac5cf04068f9b2b9d6dd56fe1b205cba3fecc93acb969f488eef29469aead0a4421a16ad21b110104bad3f1aa46da6e89f04655ff0dd5b5dd7cee8197c8984a41c5daa601f737d1707f566b27dcfac2cf3572a0130598f469285cf13b91e05504eb3e8a6ac74c3b0e2c833ff04c8ae365a43df2b86a5d988b7bc3fdbdaf87803f1661dd6b67b3da52053ccf8f6f195bb61342f203454eb0c430176b744b234e710a6172c40272108e28c0cdaadd6e741f66bf74ce9cf71462ce8a878ef64ea974a517afbf62aab5f8c62f4505372f432b796469668c6b061dfe9f9b280a3666f8a7077ef6195ede39d7a0e8f7a717bea2773c22ea780d21f724a5de5bc4e4c75c790735f66bd252979feb51da44d6bcec752639362f704949989ed6b1cdeac8a5e1701ce8ea8b7da68a3d4fa937a4c272a5151c122ddb86428b0e64d4347f0286f4f924b56b6572dd4e1529f0a2e1e21c7e56d8c917e9c4927aad0c9a28f2aad6e472b30b049be3af8ca4a953de3440381cce616868a2faed6f9bbf04bb8d241cc3d0c9152b852d90c4f5ced718ebb610fd4bb8c6234099a1a46bd34182221eeb714690c6c5fb87afcec466fff7081a896264ff30c74f02e9bcb4a9c57c4b71c27a91eda1e414003537d98dd1ef04f06395333eeb9245b5bb7efc6959a6f3c30f23e22ef99f90391edccbeb55e9ccd0144fbc0e6fef295676bafc8570da0751890563ffbe672221580bbf3b00340e67f1474dc88286773639ad6d9187eb72a50e82158784ba6937b200f5db7b9f6ba89ed45c1ac105cecb1681b8421fc042e4e4744c26f901a4127481cc485a3911deecb049c7ddedcebdd656de16e2fd537065aa6d6dbca728c1ef35b1cc60368c896412e40e1ce49ad729d15fa9ff7d3a2c6f4f2d39b836de19afbedf0af815fcec662ce5d6ae7c23ed79b42be9253ef23bf706bbe09069e4b47a1d8a9aa2a9042adec54ce652872fe3b6d64492747849e9b5a28fb43eec0ebb5f2a0ef9f6d75ae1e5db2138a770016f092581d70ff317e362ba967a03f75c49efd7f352bac29d2876d2937eabcc75d36b02000f29bd072a3957b29a7c322a5cf0be49d6d83434c75cde9e8bb68e45c567b816da9fb1fa5f49fde798460a489d56bb23b7a971c3715f43f1028b1e8aebdcf47bcb8a397498fd609e00364a84290762c3c540bcee131e64343ad415325027e5cd2c378d08e74866f38f5151fb83740c3c5fa273891f00f41f811e5c190a14bfbeaceb0fa3d7250cef7c2e13d5b4fb0f2ee4f925c791a5eb8cb2ca9e29ee6184660e02741d87b39d249ebb0f18f655521abfe911e73457f8e552be851c25819e1f458322def2eefb54569c8932087955869048b80f88221a277c88ef35d065edbe4f780e45095d16171fcba8785430d2bcb75e7374620d51f9681013c953a9a07d0dab2a951d53c6b9f0c8c097a612404b65f44e167ff3948155f14550093ffecc026a7c115816ad1807520e94a1e86652b5705dbde2310942ed4d27e52859850ed53e7933dd1f6cb57b1812597baced1204d2a239c48dd4ee69c0d6864442f010f11351694b3e75f0427bd1a385289932ba5c7fcee6a637a84b88c5e3f4cce674f6db17f1200be3dc16522464bdc1eb1f73e8f6cb1c3e5364233f4bf68a42272b13711aa01ff1adfbf7399885d538490086c4e1914156cb1fdd8ec120f27191ae2270bb7909d439d5f13b64e368009b0dc85dadbe498f2ddd35958a4f6dcfca3f38597b1c0b5b5a188f33b4c8a491dfed90b2846e5ef1378ee9f79af39ed9fe4c021ab657588c23258a37820844091bc41774f7fc95029515d62fc81d9bd1aacaa38878eab2d43b5aace589741dad1a2c12f9b37ec02719127f0a4db53e6b3159d78ba90ed840abcc12d9ad842f5094006e7deae1bbe491dcb69a09d41e883a03188495539a5ffe503804dd90837f117f04bbf25bc69ff87035424a8101f4ac8d74883b03a52b76db26ddb4e026de8b0b6aef081c3684bab70be927e6579553bfec4f09a4bff0db205bb00f6ef0c5763fb2bb9d388f8b5146c983390db67d58f98cfa8152cb4a90b86825166331802b55492c78a18a830f84c8143d273c93673a4e60970d03b0e0ed7459dd66cbace1e5a69fd6383b2995a218fe64d643c53cad45c4d10e26c31af362a804bf55878407c9ec92cbd8029a33b7ab36a5a54768c23a62199d0f208a9dbbd15e30bd1fb5bb51a97f985b8e833afcd77c807ec66d200f46e7756113b403800829e7be5573261ef61428180b0990678dc8fea4fda63354620ee2fd1384fc37c4fd01856f786c08f183</script>\n <div class=\"hbe hbe-content\">\n <div class=\"hbe hbe-input hbe-input-default\">\n <input class=\"hbe hbe-input-field hbe-input-field-default\" type=\"password\" id=\"hbePass\">\n <label class=\"hbe hbe-input-label hbe-input-label-default\" for=\"hbePass\">\n <span class=\"hbe hbe-input-label-content hbe-input-label-content-default\">Hey, password is required here.</span>\n </label>\n </div>\n </div>\n</div>\n<script data-pjax src=\"/lib/hbe.js\"></script><link href=\"/css/hbe.style.css\" rel=\"stylesheet\" type=\"text/css\">",
"tags": [
"life"
]
},
{
"id": "http://example.com/2022/04/08/%E4%BD%BF%E7%94%A8kubernetes-API-Python-%E6%9D%A5%E6%8E%A7%E5%88%B6%E9%9B%86%E7%BE%A4%E5%86%85%E9%83%A8%E5%AF%B9%E8%B1%A1%E7%9A%84CURD/",
"url": "http://example.com/2022/04/08/%E4%BD%BF%E7%94%A8kubernetes-API-Python-%E6%9D%A5%E6%8E%A7%E5%88%B6%E9%9B%86%E7%BE%A4%E5%86%85%E9%83%A8%E5%AF%B9%E8%B1%A1%E7%9A%84CURD/",
"title": "使用kubernetes API(Python)来控制集群内部对象的CURD",
"date_published": "2022-04-08T14:07:45.000Z",
"content_html": "<p>写在前面:依旧是疫情远程实验室中,不知道为什么我的 kubernetes 集群突然集体更换了 ip 地址,真的很诡异 desu… 重新配集群的话我会想死,最后使用了一个基于 Go 语言的二进制一键离线部署安装工具 sealos,基本上只要指定三个节点的地址,不过不知道为啥似乎只能使用 root 用户来进行操作(可能是前置的一些设置没有设置)。</p>\n<span id=\"more\"></span>\n<p>sealos 地址:<a href=\"https://github.com/fanux/sealos\">https://github.com/fanux/sealos</a></p>\n<p>使用 sealos 时三台虚拟机上要开启 ssh 服务,通过以下命令安装并且开放权限(我的系统是 ubuntu20.04)</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">apt install ssh</span><br><span class=\"line\">vi /etc/ssh/sshd_config</span><br><span class=\"line\"><span class=\"meta prompt_\"># </span><span class=\"language-bash\">修改 PermitRootLogin = <span class=\"built_in\">yes</span></span></span><br><span class=\"line\"><span class=\"meta prompt_\"># </span><span class=\"language-bash\">restart ssh 服务</span></span><br></pre></td></tr></table></figure>\n<p>以下是新的系统配置</p>\n<table>\n<thead>\n<tr>\n<th>ip 地址</th>\n<th>节点类型</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>192.168.2.113</td>\n<td>master</td>\n</tr>\n<tr>\n<td>192.168.2.114</td>\n<td>node</td>\n</tr>\n<tr>\n<td>192.168.2.115</td>\n<td>node</td>\n</tr>\n</tbody>\n</table>\n<p>最近主要研究实现了怎么使用 kubernetes 的 api 接口来管理 kubernetes 集群,使用的语言是 python,python-kubernetes-client 的官方地址如下:<a href=\"https://github.com/kubernetes-client/python/tree/master/kubernetes\">https://github.com/kubernetes-client/python/tree/master/kubernetes</a></p>\n<h3 id=\"引入kubernetes包\"><a class=\"markdownIt-Anchor\" href=\"#引入kubernetes包\">#</a> 引入 kubernetes 包</h3>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"comment\"># pip install kubernetes</span></span><br><span class=\"line\"><span class=\"keyword\">import</span> kubernetes</span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"comment\"># 以下使用到了kubernetes官方库的config和client,因此可以这样写</span></span><br><span class=\"line\"><span class=\"keyword\">from</span> kubernetes <span class=\"keyword\">import</span> config, client</span><br></pre></td></tr></table></figure>\n<h3 id=\"集群内部控制\"><a class=\"markdownIt-Anchor\" href=\"#集群内部控制\">#</a> 集群内部控制</h3>\n<p>我搭建的系统是在 pod 内去修改 kubernetes 的资源,首先在对系统的修改之前,需要访问系统的配置文件,得到系统的相关配置</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">config.load_incluster_config()</span><br><span class=\"line\"><span class=\"comment\"># incluster表示在节点内</span></span><br></pre></td></tr></table></figure>\n<p>得到系统配置后,我们可以通过建立相关的 api 创建、更新、访问相关资源,以下以项目中用到的 Job 和 Server 为例,在实际创建过程中,可能会遇到 403 错误,该错误可以通过设置 rbac 解决,使用的 yaml 如下:</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"meta\">---</span></span><br><span class=\"line\"><span class=\"attr\">kind:</span> <span class=\"string\">ClusterRole</span></span><br><span class=\"line\"><span class=\"attr\">apiVersion:</span> <span class=\"string\">rbac.authorization.k8s.io/v1</span></span><br><span class=\"line\"><span class=\"attr\">metadata:</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">test</span></span><br><span class=\"line\"><span class=\"attr\">rules:</span> <span class=\"comment\"># 似乎是在这里添加权限</span></span><br><span class=\"line\"><span class=\"bullet\">-</span> <span class=\"attr\">apiGroups:</span> [<span class=\"string\">""</span>]</span><br><span class=\"line\"> <span class=\"attr\">resources:</span> [<span class=\"string\">"pods"</span>, <span class=\"string\">"services"</span>]</span><br><span class=\"line\"> <span class=\"attr\">verbs:</span> [<span class=\"string\">"list"</span>, <span class=\"string\">"create"</span>, <span class=\"string\">"get"</span>, <span class=\"string\">"delete"</span>]</span><br><span class=\"line\"><span class=\"bullet\">-</span> <span class=\"attr\">apiGroups:</span> [<span class=\"string\">"batch"</span>]</span><br><span class=\"line\"> <span class=\"attr\">resources:</span> [<span class=\"string\">"jobs"</span>, <span class=\"string\">"jobs/status"</span>]</span><br><span class=\"line\"> <span class=\"attr\">verbs:</span> [<span class=\"string\">"list"</span>, <span class=\"string\">"create"</span>, <span class=\"string\">"get"</span>, <span class=\"string\">"delete"</span>]</span><br><span class=\"line\"><span class=\"meta\">---</span></span><br><span class=\"line\"><span class=\"attr\">kind:</span> <span class=\"string\">ClusterRoleBinding</span></span><br><span class=\"line\"><span class=\"attr\">apiVersion:</span> <span class=\"string\">rbac.authorization.k8s.io/v1</span></span><br><span class=\"line\"><span class=\"attr\">metadata:</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">test-bind</span></span><br><span class=\"line\"><span class=\"attr\">subjects:</span></span><br><span class=\"line\"><span class=\"bullet\">-</span> <span class=\"attr\">kind:</span> <span class=\"string\">ServiceAccount</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">default</span></span><br><span class=\"line\"> <span class=\"attr\">namespace:</span> <span class=\"string\">default</span></span><br><span class=\"line\"><span class=\"attr\">roleRef:</span></span><br><span class=\"line\"> <span class=\"attr\">kind:</span> <span class=\"string\">ClusterRole</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">test</span></span><br><span class=\"line\"> <span class=\"attr\">apiGroup:</span> <span class=\"string\">rbac.authorization.k8s.io</span></span><br></pre></td></tr></table></figure>\n<h4 id=\"创建和管理job\"><a class=\"markdownIt-Anchor\" href=\"#创建和管理job\">#</a> 创建和管理 Job</h4>\n<p>job 的 api-group 是 batch,通过以下命令来创建相关的 api,成功创建后就可以管理 job 资源</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">batch_v1 = client.BatchV1Api()</span><br></pre></td></tr></table></figure>\n<p><strong>创建 job</strong></p>\n<p>删除 job 的逻辑写在创建 job 的时候,spec.ttlSecondsAfterFinished,代表 job 完工 30 秒后删除</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">def</span> <span class=\"title function_\">create_container</span>():</span><br><span class=\"line\"> port_list = [<span class=\"number\">8888</span>, <span class=\"number\">8889</span>]</span><br><span class=\"line\"> container_port_list = <span class=\"built_in\">list</span>()</span><br><span class=\"line\"> container_name = <span class=\"string\">"pi"</span> + <span class=\"built_in\">str</span>(uuid.uuid1())</span><br><span class=\"line\"> <span class=\"keyword\">for</span> port <span class=\"keyword\">in</span> port_list:</span><br><span class=\"line\"> container_port = <span class=\"built_in\">int</span>(port)</span><br><span class=\"line\"> c_port = client.V1ContainerPort(container_port=container_port)</span><br><span class=\"line\"> container_port_list.append(c_port)</span><br><span class=\"line\"> container = client.V1Container(</span><br><span class=\"line\"> name=container_name,</span><br><span class=\"line\"> image=<span class=\"string\">"lcy200077/exec:v1.1"</span>,</span><br><span class=\"line\"> ports=container_port_list</span><br><span class=\"line\"> )</span><br><span class=\"line\"> <span class=\"keyword\">return</span> container</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">def</span> <span class=\"title function_\">create_job_object</span>(<span class=\"params\">node</span>):</span><br><span class=\"line\"> <span class=\"comment\"># Configurate Pod template container</span></span><br><span class=\"line\"> container = create_container()</span><br><span class=\"line\"> <span class=\"comment\"># Create and configure a spec section</span></span><br><span class=\"line\"> job_name = <span class=\"string\">'pi'</span> + <span class=\"built_in\">str</span>(uuid.uuid1())</span><br><span class=\"line\"> template = client.V1PodTemplateSpec(</span><br><span class=\"line\"> metadata=client.V1ObjectMeta(labels={<span class=\"string\">"app"</span>: <span class=\"string\">"pi"</span>}),</span><br><span class=\"line\"> spec=client.V1PodSpec(restart_policy=<span class=\"string\">"Never"</span>, containers=[container], node_name=node))</span><br><span class=\"line\"> <span class=\"comment\"># Create the specification of deployment</span></span><br><span class=\"line\"> spec = client.V1JobSpec(</span><br><span class=\"line\"> template=template,</span><br><span class=\"line\"> ttl_seconds_after_finished=<span class=\"number\">30</span>,</span><br><span class=\"line\"> backoff_limit=<span class=\"number\">4</span>)</span><br><span class=\"line\"> <span class=\"comment\"># 三十秒后删除</span></span><br><span class=\"line\"> <span class=\"comment\"># Instantiate the job object</span></span><br><span class=\"line\"> job = client.V1Job(</span><br><span class=\"line\"> api_version=<span class=\"string\">"batch/v1"</span>,</span><br><span class=\"line\"> kind=<span class=\"string\">"Job"</span>,</span><br><span class=\"line\"> metadata=client.V1ObjectMeta(name=job_name),</span><br><span class=\"line\"> spec=spec)</span><br><span class=\"line\"></span><br><span class=\"line\"> <span class=\"keyword\">return</span> job, job_name</span><br><span class=\"line\"></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">def</span> <span class=\"title function_\">create_job</span>(<span class=\"params\">api_instance, job, job_name</span>):</span><br><span class=\"line\"> api_response = api_instance.create_namespaced_job(</span><br><span class=\"line\"> body=job,</span><br><span class=\"line\"> namespace=<span class=\"string\">"default"</span>)</span><br><span class=\"line\"> <span class=\"built_in\">print</span>(<span class=\"string\">"Job created. status='%s'"</span> % <span class=\"built_in\">str</span>(api_response.status))</span><br></pre></td></tr></table></figure>\n<p><strong>获取 Job 信息</strong></p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">def</span> <span class=\"title function_\">get_job_status</span>(<span class=\"params\">api_instance, job_name</span>):</span><br><span class=\"line\"> job_completed = <span class=\"literal\">False</span></span><br><span class=\"line\"> <span class=\"keyword\">while</span> <span class=\"keyword\">not</span> job_completed:</span><br><span class=\"line\"> api_response = api_instance.read_namespaced_job_status(</span><br><span class=\"line\"> name=job_name,</span><br><span class=\"line\"> namespace=<span class=\"string\">"default"</span>)</span><br><span class=\"line\"> <span class=\"keyword\">if</span> api_response.status.succeeded <span class=\"keyword\">is</span> <span class=\"keyword\">not</span> <span class=\"literal\">None</span> <span class=\"keyword\">or</span> \\</span><br><span class=\"line\"> api_response.status.failed <span class=\"keyword\">is</span> <span class=\"keyword\">not</span> <span class=\"literal\">None</span>:</span><br><span class=\"line\"> job_completed = <span class=\"literal\">True</span></span><br><span class=\"line\"> sleep(<span class=\"number\">1</span>)</span><br><span class=\"line\"> <span class=\"built_in\">print</span>(<span class=\"string\">"Job status='%s'"</span> % <span class=\"built_in\">str</span>(api_response.status))</span><br></pre></td></tr></table></figure>\n<h4 id=\"创建和管理service\"><a class=\"markdownIt-Anchor\" href=\"#创建和管理service\">#</a> 创建和管理 service</h4>\n<p>service 采用 manifest 的方法创建,其中将 service 对应的 job 作为依赖项,当 job 被删除的时候,kubernetes 的垃圾回收机制会自动回收掉依赖 job 的 Service</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br><span class=\"line\">44</span><br><span class=\"line\">45</span><br><span class=\"line\">46</span><br><span class=\"line\">47</span><br><span class=\"line\">48</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">def</span> <span class=\"title function_\">create_service</span>(<span class=\"params\">api, job_name</span>):</span><br><span class=\"line\"> batch_v1 = client.BatchV1Api()</span><br><span class=\"line\"> job_response = batch_v1.read_namespaced_job_status(</span><br><span class=\"line\"> name=job_name,</span><br><span class=\"line\"> namespace=<span class=\"string\">"default"</span></span><br><span class=\"line\"> )</span><br><span class=\"line\"> uid = job_response.metadata.uid</span><br><span class=\"line\"> <span class=\"keyword\">global</span> num</span><br><span class=\"line\"> service_name = <span class=\"string\">"pi"</span> + <span class=\"built_in\">str</span>(uuid.uuid1())</span><br><span class=\"line\"> node_p1 = <span class=\"number\">30030</span> + num * <span class=\"number\">2</span></span><br><span class=\"line\"> node_p2 = <span class=\"number\">30030</span> + num * <span class=\"number\">2</span> + <span class=\"number\">1</span></span><br><span class=\"line\"> service_manifest = {</span><br><span class=\"line\"> <span class=\"string\">"apiVersion"</span>: <span class=\"string\">"v1"</span>,</span><br><span class=\"line\"> <span class=\"string\">"kind"</span>: <span class=\"string\">"Service"</span>,</span><br><span class=\"line\"> <span class=\"string\">"metadata"</span>: {</span><br><span class=\"line\"> <span class=\"string\">"labels"</span>: {<span class=\"string\">"name"</span>: service_name},</span><br><span class=\"line\"> <span class=\"string\">"name"</span>: service_name,</span><br><span class=\"line\"> <span class=\"string\">"resourceversion"</span>: <span class=\"string\">"v1"</span>,</span><br><span class=\"line\"> <span class=\"string\">"ownerReferences"</span>: {</span><br><span class=\"line\"> <span class=\"string\">"kind"</span>: <span class=\"string\">"Job"</span>,</span><br><span class=\"line\"> <span class=\"string\">"name"</span>: job_name,</span><br><span class=\"line\"> <span class=\"string\">"apiVersion"</span>: <span class=\"string\">"batch/v1"</span>,</span><br><span class=\"line\"> <span class=\"string\">"uid"</span>: uid</span><br><span class=\"line\"> }</span><br><span class=\"line\"> },</span><br><span class=\"line\"> <span class=\"string\">"spec"</span>: {</span><br><span class=\"line\"> <span class=\"string\">"type"</span>: <span class=\"string\">"NodePort"</span>,</span><br><span class=\"line\"> <span class=\"string\">"ports"</span>: [</span><br><span class=\"line\"> {<span class=\"string\">"name"</span>: <span class=\"string\">"p1"</span>, </span><br><span class=\"line\"> <span class=\"string\">"port"</span>: <span class=\"number\">80</span>, </span><br><span class=\"line\"> <span class=\"string\">"protocol"</span>: <span class=\"string\">"TCP"</span>, </span><br><span class=\"line\"> <span class=\"string\">"targetPort"</span>: <span class=\"number\">8888</span>, </span><br><span class=\"line\"> <span class=\"string\">"nodePort"</span>: node_p1</span><br><span class=\"line\"> },</span><br><span class=\"line\"> {<span class=\"string\">"name"</span>: <span class=\"string\">"p2"</span>, </span><br><span class=\"line\"> <span class=\"string\">"port"</span>: <span class=\"number\">81</span>, </span><br><span class=\"line\"> <span class=\"string\">"protocol"</span>: <span class=\"string\">"TCP"</span>, </span><br><span class=\"line\"> <span class=\"string\">"targetPort"</span>: <span class=\"number\">8889</span>, </span><br><span class=\"line\"> <span class=\"string\">"nodePort"</span>: node_p2</span><br><span class=\"line\"> }</span><br><span class=\"line\"> ],</span><br><span class=\"line\"> <span class=\"string\">"selector"</span>: {<span class=\"string\">"job-name"</span>: job_name},</span><br><span class=\"line\"> },</span><br><span class=\"line\"> }</span><br><span class=\"line\"> service = api.create(body=service_manifest, namespace=<span class=\"string\">"default"</span>)</span><br><span class=\"line\"> <span class=\"built_in\">print</span>(<span class=\"string\">"Service "</span> + service_name + <span class=\"string\">"created"</span>)</span><br><span class=\"line\"> num += <span class=\"number\">1</span></span><br><span class=\"line\"> <span class=\"keyword\">return</span> node_p1, node_p2</span><br></pre></td></tr></table></figure>\n<p><strong>ownerReference</strong></p>\n<p>是依赖项,在 spec 中设置,一般来说 kubernetes 会自动配置,也可以手动配置,一个 ownerReference 需要以下几个参数,缺一不可</p>\n<figure class=\"highlight python\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"string\">"ownerReferences"</span>: {</span><br><span class=\"line\">\t<span class=\"string\">"kind"</span>: <span class=\"string\">"Job"</span>,</span><br><span class=\"line\"> <span class=\"string\">"name"</span>: job_name, </span><br><span class=\"line\"> <span class=\"string\">"apiVersion"</span>: <span class=\"string\">"batch/v1"</span>,</span><br><span class=\"line\"> <span class=\"string\">"uid"</span>: uid <span class=\"comment\">#可以通过api get来获取</span></span><br><span class=\"line\"> }</span><br></pre></td></tr></table></figure>\n",
"tags": [
"kubernetes"
]
},
{
"id": "http://example.com/2022/03/24/k8s-%E5%A6%82%E4%BD%95%E5%B0%86python%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2%E6%88%90service/",
"url": "http://example.com/2022/03/24/k8s-%E5%A6%82%E4%BD%95%E5%B0%86python%E9%A1%B9%E7%9B%AE%E9%83%A8%E7%BD%B2%E6%88%90service/",
"title": "k8s-如何将python项目部署成service",
"date_published": "2022-03-24T08:26:24.000Z",
"content_html": "<p>毕业设计需要设计一个 kubernetes 的系统,寒假前在实验室的电脑上搭建了 k8s 的集群,但是寒假后回来不知道为什么集群失效了。。重新配置又花了很久时间,正式开始推进毕设大概两周,主要做的工作是把图片识别的 python 项目部署到了 k8s 的集群上(顺便可视化了一下)。</p>\n<span id=\"more\"></span>\n<h3 id=\"实验环境\"><a class=\"markdownIt-Anchor\" href=\"#实验环境\">#</a> 实验环境</h3>\n<table>\n<thead>\n<tr>\n<th>主机 ip</th>\n<th>名称</th>\n<th>系统</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>192.168.1.129</td>\n<td>k8s-master01</td>\n<td>ubuntu</td>\n</tr>\n<tr>\n<td>192.168.1.130</td>\n<td>k8s-node01</td>\n<td>ubuntu</td>\n</tr>\n<tr>\n<td>192.168.1.131</td>\n<td>k8s-node02</td>\n<td>ubuntu</td>\n</tr>\n</tbody>\n</table>\n<h3 id=\"docker-image的创建\"><a class=\"markdownIt-Anchor\" href=\"#docker-image的创建\">#</a> Docker image 的创建</h3>\n<p>kubernetes 本质上来说还是一个管理 dokcer 的工具,因此首先需要制作 Dockerfile 把我们的 python 项目制作成镜像,我使用了 winscp 把 python 项目文件夹复制到了虚拟机上,进入该目录</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">vi Dockerfile # 创建Dockerfile</span><br></pre></td></tr></table></figure>\n<p>Dockerfile 的内容如下</p>\n<figure class=\"highlight dockerfile\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"keyword\">FROM</span> python:<span class=\"number\">3.8</span>-slim-buster <span class=\"comment\"># 拉取基础镜像</span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">WORKDIR</span><span class=\"language-bash\"> /app <span class=\"comment\"># 设置容器内的工作目录,和容器外无关</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">COPY</span><span class=\"language-bash\"> requirements.txt requirements.txt <span class=\"comment\"># 设置依赖包,由于实验环境用到了torch包,很大,创建第一个镜像的时候用了特别久</span></span></span><br><span class=\"line\"><span class=\"keyword\">RUN</span><span class=\"language-bash\"> pip3 install -r requirements.txt <span class=\"comment\"># 下载依赖包</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">COPY</span><span class=\"language-bash\"> . . <span class=\"comment\"># 把python项目内的所有文件复制到docker镜像中 </span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">CMD</span><span class=\"language-bash\"> [<span class=\"string\">"python"</span>,<span class=\"string\">"test.py"</span>] <span class=\"comment\"># 容器执行的命令,需要是一个不断执行的命令,不然容器会反复创建运行,并且报错</span></span></span><br><span class=\"line\"></span><br><span class=\"line\"><span class=\"keyword\">EXPOSE</span> <span class=\"number\">8888</span> <span class=\"comment\"># 暴露8888端口,我在后续的python代码中又暴露了一个端口,直接在yaml文件里设置了,也成功了,貌似这里不用设置</span></span><br></pre></td></tr></table></figure>\n<p>输入:wq 保存并且退出,输入以下命令,创建镜像</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">docker build -t lcy200077/app:v1 .</span><br></pre></td></tr></table></figure>\n<p>出现 successful 提示后,输入以下命令就可以看见多了一个名称为 <em>lcy200077/app</em> 的镜像,版本是 v1</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">docker images</span><br></pre></td></tr></table></figure>\n<h3 id=\"上传镜像至中央仓库\"><a class=\"markdownIt-Anchor\" href=\"#上传镜像至中央仓库\">#</a> 上传镜像至中央仓库</h3>\n<p>成功创建 <em>lcy200077/app</em> 镜像后,下一步是把 docker 镜像上传至中央仓库,这一步的前提是需要在<a href=\"https://registry.hub.docker.com/\"> DockerHub</a> 上注册账号,非常便捷,上传后就可以随时随地拉取</p>\n<p>注意在上传镜像时,dokcer 镜像的名称必须是 <em>username/xxx</em> ,其中 username 是个人在<a href=\"https://registry.hub.docker.com/\"> DockerHub</a> 上的用户名,xxx 是镜像的名字,可以任意</p>\n<p>第一步是在 ubuntu 虚拟机上登录 dockerhub 的账号,输入以下命令,出现对应提示后输入用户名和密码,若成功,会提示 success</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">docker login</span><br></pre></td></tr></table></figure>\n<p>在 build 该镜像的虚拟机上执行以下命令,将镜像 push 到中央仓库</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">docker push lcy200077/app:v1</span><br></pre></td></tr></table></figure>\n<h3 id=\"编写yaml文件与创建service服务\"><a class=\"markdownIt-Anchor\" href=\"#编写yaml文件与创建service服务\">#</a> 编写 YAML 文件与创建 service 服务</h3>\n<p>服务可以通过 yaml 文件在 master 节点上使用以下命令创建</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">kubectl apply -f xxx.yaml</span><br></pre></td></tr></table></figure>\n<p>我的实验环境中,每一个 node 节点跑一个指定的 docker 容器,master 节点的负责负载均衡的算法调配,以下 yaml 文件以 node01 节点上部署的服务为例子(实际上我对于 yaml 文件的写法只知道个大概)</p>\n<p>其中 replicas 指定了容器的数量,image 指定了拉取的镜像,nodeName 指定了跑在哪个节点上,如果不确定节点名称可以通过 <em>kubectl get nodes</em> 命令在 master 节点上查看,containerPort 指定了容器暴露的端口,我的两个端口一个用于收取信息一个用于发送信息,连接方式都是 TCP,service 部分的 type 指定了服务向外界暴露的方式,即通过端口 nodePort,指定端口 30026 对应容器端口 8888,指定端口 30027 对应端口 8889。</p>\n<figure class=\"highlight yaml\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br><span class=\"line\">3</span><br><span class=\"line\">4</span><br><span class=\"line\">5</span><br><span class=\"line\">6</span><br><span class=\"line\">7</span><br><span class=\"line\">8</span><br><span class=\"line\">9</span><br><span class=\"line\">10</span><br><span class=\"line\">11</span><br><span class=\"line\">12</span><br><span class=\"line\">13</span><br><span class=\"line\">14</span><br><span class=\"line\">15</span><br><span class=\"line\">16</span><br><span class=\"line\">17</span><br><span class=\"line\">18</span><br><span class=\"line\">19</span><br><span class=\"line\">20</span><br><span class=\"line\">21</span><br><span class=\"line\">22</span><br><span class=\"line\">23</span><br><span class=\"line\">24</span><br><span class=\"line\">25</span><br><span class=\"line\">26</span><br><span class=\"line\">27</span><br><span class=\"line\">28</span><br><span class=\"line\">29</span><br><span class=\"line\">30</span><br><span class=\"line\">31</span><br><span class=\"line\">32</span><br><span class=\"line\">33</span><br><span class=\"line\">34</span><br><span class=\"line\">35</span><br><span class=\"line\">36</span><br><span class=\"line\">37</span><br><span class=\"line\">38</span><br><span class=\"line\">39</span><br><span class=\"line\">40</span><br><span class=\"line\">41</span><br><span class=\"line\">42</span><br><span class=\"line\">43</span><br></pre></td><td class=\"code\"><pre><span class=\"line\"><span class=\"attr\">apiVersion:</span> <span class=\"string\">apps/v1</span></span><br><span class=\"line\"><span class=\"attr\">kind:</span> <span class=\"string\">Deployment</span></span><br><span class=\"line\"><span class=\"attr\">metadata:</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">my-python-app</span></span><br><span class=\"line\"> <span class=\"attr\">labels:</span></span><br><span class=\"line\"> <span class=\"attr\">app:</span> <span class=\"string\">my-python</span></span><br><span class=\"line\"><span class=\"attr\">spec:</span></span><br><span class=\"line\"> <span class=\"attr\">replicas:</span> <span class=\"number\">1</span></span><br><span class=\"line\"> <span class=\"attr\">selector:</span></span><br><span class=\"line\"> <span class=\"attr\">matchLabels:</span></span><br><span class=\"line\"> <span class=\"attr\">app:</span> <span class=\"string\">my-python</span></span><br><span class=\"line\"> <span class=\"attr\">template:</span></span><br><span class=\"line\"> <span class=\"attr\">metadata:</span></span><br><span class=\"line\"> <span class=\"attr\">labels:</span></span><br><span class=\"line\"> <span class=\"attr\">app:</span> <span class=\"string\">my-python</span></span><br><span class=\"line\"> <span class=\"attr\">spec:</span></span><br><span class=\"line\"> <span class=\"attr\">nodeName:</span> <span class=\"string\">k8s-node01</span></span><br><span class=\"line\"> <span class=\"attr\">containers:</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">name:</span> <span class=\"string\">my-python</span></span><br><span class=\"line\"> <span class=\"attr\">image:</span> <span class=\"string\">lcy200077/app:v1</span></span><br><span class=\"line\"> <span class=\"attr\">ports:</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">containerPort:</span> <span class=\"number\">8888</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">containerPort:</span> <span class=\"number\">8889</span></span><br><span class=\"line\"> </span><br><span class=\"line\"><span class=\"meta\">---</span></span><br><span class=\"line\"><span class=\"meta\"></span></span><br><span class=\"line\"><span class=\"attr\">apiVersion:</span> <span class=\"string\">v1</span></span><br><span class=\"line\"><span class=\"attr\">kind:</span> <span class=\"string\">Service</span></span><br><span class=\"line\"><span class=\"attr\">metadata:</span></span><br><span class=\"line\"> <span class=\"attr\">name:</span> <span class=\"string\">my-python-app</span></span><br><span class=\"line\"><span class=\"attr\">spec:</span></span><br><span class=\"line\"> <span class=\"attr\">type:</span> <span class=\"string\">NodePort</span></span><br><span class=\"line\"> <span class=\"attr\">selector:</span></span><br><span class=\"line\"> <span class=\"attr\">app:</span> <span class=\"string\">my-python</span></span><br><span class=\"line\"> <span class=\"attr\">ports:</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">protocol:</span> <span class=\"string\">TCP</span></span><br><span class=\"line\"> <span class=\"attr\">port:</span> <span class=\"number\">80</span></span><br><span class=\"line\"> <span class=\"attr\">targetPort:</span> <span class=\"number\">8888</span></span><br><span class=\"line\"> <span class=\"attr\">nodePort:</span> <span class=\"number\">30026</span></span><br><span class=\"line\"> <span class=\"bullet\">-</span> <span class=\"attr\">protocol:</span> <span class=\"string\">TCP</span></span><br><span class=\"line\"> <span class=\"attr\">port:</span> <span class=\"number\">81</span></span><br><span class=\"line\"> <span class=\"attr\">targetPort:</span> <span class=\"number\">8889</span></span><br><span class=\"line\"> <span class=\"attr\">nodePort:</span> <span class=\"number\">30027</span></span><br></pre></td></tr></table></figure>\n<p>使用以下命令部署服务</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">kubectl apply -f app.yaml</span><br></pre></td></tr></table></figure>\n<p>使用以下命令查看部署的服务,若状态是 running,就是运行成功,可以通信了~</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br><span class=\"line\">2</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">kubectl get service / kubectl get svc # 查看部署成功的服务,会显示my-python-xxxx,以及端口</span><br><span class=\"line\">kubectl get pod / kubectl get po # 查看部署的pod,一个pod内是一个容器</span><br></pre></td></tr></table></figure>\n<p>使用以下命令查看 pod 的状态</p>\n<figure class=\"highlight shell\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">kubectl describe po my-python-xxx #最后一个为pod的名字</span><br></pre></td></tr></table></figure>\n",
"tags": [
"kubernetes"
]
},
{
"id": "http://example.com/2022/03/24/hexo%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/",
"url": "http://example.com/2022/03/24/hexo%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4/",
"title": "hexo-command",
"date_published": "2022-03-24T06:34:13.000Z",
"content_html": "<hr>\n<h3 id=\"hexo部署博客常用命令记录\"><a class=\"markdownIt-Anchor\" href=\"#hexo部署博客常用命令记录\">#</a> Hexo 部署博客常用命令记录</h3>\n<ol>\n<li>\n<p>常用命令组件</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">hexo clean & hexo generate & hexo deploy</span><br></pre></td></tr></table></figure>\n<p>清除缓存 & 渲染界面 & 部署至 github</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">hexo server</span><br></pre></td></tr></table></figure>\n<p>部署在本地 4000 端口上,可以在 deploy 前先进行预览</p>\n</li>\n<li>\n<p>新增文章</p>\n<figure class=\"highlight plaintext\"><table><tr><td class=\"gutter\"><pre><span class=\"line\">1</span><br></pre></td><td class=\"code\"><pre><span class=\"line\">hexo n #title#</span><br></pre></td></tr></table></figure>\n<p>根据提示找到对应的 md 文件夹,修改内容,使用 hexo clean & hexo generate & hexo deploy 部署</p>\n</li>\n</ol>\n",
"tags": [
"hexo"
]
}
]
}