-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathatom.xml
More file actions
424 lines (231 loc) · 177 KB
/
atom.xml
File metadata and controls
424 lines (231 loc) · 177 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>oldmee</title>
<link href="https://oldmee.github.io/atom.xml" rel="self"/>
<link href="https://oldmee.github.io/"/>
<updated>2023-08-08T09:26:03.403Z</updated>
<id>https://oldmee.github.io/</id>
<author>
<name>oldmee</name>
</author>
<generator uri="https://hexo.io/">Hexo</generator>
<entry>
<title>quick-sort-again</title>
<link href="https://oldmee.github.io/2023/07/29/quick-sort-again/"/>
<id>https://oldmee.github.io/2023/07/29/quick-sort-again/</id>
<published>2023-07-29T00:46:32.000Z</published>
<updated>2023-08-08T09:26:03.403Z</updated>
<content type="html"><![CDATA[<p>“同学你是做什么的?”<br>“Java”<br>“你呢?”<br>“C#”<br>“那你呢?”<br>“我是GoLang”</p><p>为啥程序员要用语言来划分?</p><br><span id="more"></span><h3 id="起因"><a href="#起因" class="headerlink" title="起因"></a>起因</h3><p>最新在重温C语言,这玩意从学校出来后就没再用过了,重温的时候找算法题来练练手感,正好练习到了快速排序,就准备用C语言实现一下,但是在获取子数组引用的时候无从下手了,memcpy函数只是从内存地址拷贝一个新数组出来,跟原来的数组并没有引用关系了,这就很麻烦了,一时间断了思绪,第二天起来晨跑后,茅塞顿开,GoLang的切片不正好是子数组的引用么(改了子数组原始数组也会改变),然后迅速用GoLang实现了一下,果然,前辈们都说程序员不要限制在某种语言里,要打开思路,在适合的场景下用适合的语言才是王道。</p><p>贴一下GoLang的快排实现</p><figure class="highlight go"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> main</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> (</span><br><span class="line"><span class="string">"fmt"</span></span><br><span class="line">)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {</span><br><span class="line">array := []<span class="type">int</span>{<span class="number">8</span>, <span class="number">7</span>, <span class="number">6</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">9</span>, <span class="number">2</span>}</span><br><span class="line">sort(array)</span><br><span class="line"><span class="keyword">for</span> i, v := <span class="keyword">range</span> array {</span><br><span class="line">fmt.Printf(<span class="string">"i:%d,v:%d\n"</span>, i, v)</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sort</span><span class="params">(array []<span class="type">int</span>)</span></span> {</span><br><span class="line"><span class="built_in">len</span> := <span class="built_in">len</span>(array)</span><br><span class="line"><span class="keyword">if</span> (<span class="built_in">len</span> <= <span class="number">1</span>) {</span><br><span class="line"><span class="keyword">return</span></span><br><span class="line">}</span><br><span class="line">pivot := array[<span class="built_in">len</span><span class="number">-1</span>]</span><br><span class="line">pointer2 := <span class="number">-1</span></span><br><span class="line">flagMax := <span class="literal">true</span></span><br><span class="line"><span class="keyword">for</span> i := <span class="number">0</span>; i < <span class="built_in">len</span>; i++ {</span><br><span class="line"><span class="keyword">if</span> array[i] > pivot && flagMax {</span><br><span class="line">pointer2 = i</span><br><span class="line">flagMax = <span class="literal">false</span></span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> pointer2 >= <span class="number">0</span> && array[i] < pivot {</span><br><span class="line">swap(array, pointer2, i)</span><br><span class="line">flagMax = <span class="literal">true</span></span><br><span class="line">i = pointer2</span><br><span class="line">pointer2 = <span class="number">-1</span></span><br><span class="line"><span class="keyword">continue</span></span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 找到比pivot大的,但是没找到比pivot小的</span></span><br><span class="line"><span class="keyword">if</span> i >= <span class="built_in">len</span><span class="number">-2</span> && pointer2 >= <span class="number">0</span> {</span><br><span class="line">swap(array, pointer2, <span class="built_in">len</span><span class="number">-1</span>)</span><br><span class="line">flagMax = <span class="literal">true</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// subarray of left</span></span><br><span class="line">sort(array[<span class="number">0</span>:pointer2])</span><br><span class="line"></span><br><span class="line"><span class="comment">// subarray of right</span></span><br><span class="line">sort(array[pointer2+<span class="number">1</span> : <span class="built_in">len</span>])</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// 没找到比pivot大的,说明pivot是最大数,那么它的位置不变,递归subarray(0,len-1)的子数组</span></span><br><span class="line"><span class="keyword">if</span> i >= <span class="built_in">len</span><span class="number">-2</span> && pointer2 < <span class="number">0</span> {</span><br><span class="line">flagMax = <span class="literal">true</span></span><br><span class="line"><span class="keyword">if</span> <span class="built_in">len</span> > <span class="number">2</span> {</span><br><span class="line">sort(array[<span class="number">0</span> : <span class="built_in">len</span><span class="number">-1</span>])</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">swap</span><span class="params">(array []<span class="type">int</span>, first <span class="type">int</span>, secode <span class="type">int</span>)</span></span> {</span><br><span class="line">tmp := array[first]</span><br><span class="line">array[first] = array[secode]</span><br><span class="line">array[secode] = tmp</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2023/07/29/quick-sort-again/">https://oldmee.github.io/2023/07/29/quick-sort-again/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p>“同学你是做什么的?”<br>“Java”<br>“你呢?”<br>“C#”<br>“那你呢?”<br>“我是GoLang”</p>
<p>为啥程序员要用语言来划分?</p>
<br></summary>
</entry>
<entry>
<title>how to @Resource work in Spring</title>
<link href="https://oldmee.github.io/2023/07/16/how-to-resource-annotation-work-in-spring/"/>
<id>https://oldmee.github.io/2023/07/16/how-to-resource-annotation-work-in-spring/</id>
<published>2023-07-16T08:27:00.000Z</published>
<updated>2023-08-08T08:16:29.716Z</updated>
<content type="html"><![CDATA[<p><code>@Resource</code>根据<code>name</code>匹配不到就退回到用<code>type</code>去匹配,<code>@Autowire</code>默认根据<code>type</code>去匹配,匹配不到也会根据<code>name</code>匹配。</p><p><code>@Autowire</code>是因为有一个叫<code>AutowiredAnnotationBeanPostProcessor</code>的<code>BeanPostProcessor</code>,在<code>Spring</code>初始化的时候会去处理被<code>@Autowire</code>注解的类,对其进行注入,那<code>@Resource</code>呢,甚至在<code>Spring Frame</code>里都没有这个注解。</p><p>当然,这个注解是在<code>JSR250</code>(<a href="https://link.springer.com/chapter/10.1007/978-1-4842-5642-8_2">JSR:Java Specification Requests</a> 可以理解为JDK的需求,250是需求编号)中提出来的,这个注解在<code>jakarta.annotation-api</code>中,引入即可,是不是这样注解就生效了呢,并不是,注解只是标注,还是需要实现,那么<code>@resource</code>是谁来实现的呢?</p><p><code>CommonAnnotationBeanPostProcessor</code>,这个<code>BeanPostProcessor</code>专门负责处理<code>out-of-box</code>的注解,也就是非<code>Spring</code>体系的注解,<code>@Resource</code>也不例外,它会扫描被<code>@Resource</code>注解了的类,然后调用<code>inject</code>方法进行注入,因为<code>@Resource</code>并不局限于<code>Spring</code>生态,<code>JNDI</code>也会定义“资源”,也是<code>CommonAnnotationBeanPostProcessor</code>负责实现。</p><p>具体的实现过程最好去debug一下才好理解。</p><br><br><h3 id="先byName再byType解释"><a href="#先byName再byType解释" class="headerlink" title="先byName再byType解释"></a>先byName再byType解释</h3><p>@Resource没有参数时,会先byName,这个name是被@Resource修饰的成员变量的名称,如果找不到才会退回到byType,而且就如下面所说的,“自己的类中注入自己是不会被byType注入的”</p><figure> <img src="/images/pasted-11.png"> <center><figcaption>【成员变量的名称】</figcaption></center></figure><figure> <img src="/images/pasted-9.png"> <center><figcaption>【bean的名称】</figcaption></center></figure><br><br><p>在<code>CommonAnnotationBeanPostProcessor</code>中,有一个控制回退到byType匹配的字段<code>fallbackToDefaultTypeMatch</code>,默认值就是true,如下图所示:</p><p><img src="/images/pasted-12.png" alt="upload successful"></p><p><img src="/images/pasted-13.png" alt="upload successful"></p><br><br>果然是这样,自己的类中注入自己是不会被byType注入的(但是可以通过byName注入,容易死循环【就像一个没有出口的递归函数】,慎用)<p><img src="/images/pasted-14.png" alt="upload successful"></p><p><img src="/images/pasted-15.png" alt="upload successful"></p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2023/07/16/how-to-resource-annotation-work-in-spring/">https://oldmee.github.io/2023/07/16/how-to-resource-annotation-work-in-spring/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p><code>@Resource</code>根据<code>name</code>匹配不到就退回到用<code>type</code>去匹配,<code>@Autowire</code>默认根据<code>type</code>去匹配,匹配不到也会根据<code>name<</summary>
</entry>
<entry>
<title>parkinson's law</title>
<link href="https://oldmee.github.io/2023/06/27/parkinson-s-law/"/>
<id>https://oldmee.github.io/2023/06/27/parkinson-s-law/</id>
<published>2023-06-27T04:01:56.000Z</published>
<updated>2023-08-08T08:16:50.061Z</updated>
<content type="html"><![CDATA[<p>Elon Musk fired 6,500 employees at Twitter.</p><p>A little birdie told me it’s down to:</p><ul><li>2 designers</li><li>6 iOS developers</li><li>20 web developers</li><li>Around 1,400 sales and operations people</li></ul><p>How is it possible that we are still using this website?</p><p>Two words: </p><p><code>Parkinson's Law.</code></p><span id="more"></span><p>Have you ever wondered why seemingly simple tech companies have tens of thousands of employees?</p><p>Sometimes, it’s because they have huge sales forces or tech support/operations people. </p><p>But often it’s also due to Parkinson’s Law.</p><p>Parkinson’s law is like lighter fluid for bureaucracy.</p><p>It’s a business tapeworm that slowly eats away at companies, making them less and less efficient and innovative over time.</p><p>Parkinson’s Law is the idea that the work will generally expand to the amount of time, budget, and number of people allocated to it, and no matter how many people you allocate to it, those people will feel busy.</p><p>They’ll feel busy because, due to the excess time/slack in the system, they’ll start focusing on less and less important tasks.</p><p><code>Here's how it manifests on an individual level:</code></p><p>Let’s say you have a report due in a week. </p><p>The report might only take you around five hours to finish if you really focus and work efficiently. However, because you know you have a week to complete it, you might find yourself spending a lot more time on it than you need to. </p><p>You’ll be more prone to distractions, take longer breaks, or perhaps decide to add more details, tables, graphs, and so forth. </p><p>Essentially, the task becomes more complex and time-consuming purely because you have more time in which to do it.</p><p><code>And here's how it manifests across organizations:</code></p><p>Imagine a big tech company. A social media company with various departments. Each department has tasks that it must complete to contribute to the overall productivity of the company.</p><p>Now, suppose each department is given a budget and a set amount of time to complete its tasks for the year.</p><p>According to Parkinson’s Law, each department will use its entire budget and the entire allotted time, even if the tasks could have been completed more efficiently. </p><p>This is because as resources and time increase, departments tend to become more complex and less efficient.</p><p>For example, a department might add more steps to its procedures, requiring more approvals and creating more paperwork, which slows down the process. </p><p>Or it might use the full budget on additional personnel or equipment that doesn’t necessarily improve productivity.</p><p>The department might also use the full budget to justify the same or larger budget for the next year, since budgets in many organizations are often determined based on the previous year’s spending. </p><p>This is a phenomenon known as “budget padding” or “spend it or lose it” mentality.</p><p>Inefficiencies can also develop in staff allocation. If a department expands, it might add managerial positions that aren’t strictly necessary. </p><p>More employees are hired to manage, creating layers of bureaucracy that may not contribute to productivity and can even slow decision-making.</p><p>I have seen this occur over and over again in my career. The larger the team, the larger the budget, the longer the timeline, the less gets accomplished.</p><p>I’m very curious to see how many more tech companies come to this realization. </p><p>So often, good times + revenue growth = Parkinson’s Law.</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2023/06/27/parkinson-s-law/">https://oldmee.github.io/2023/06/27/parkinson-s-law/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p>Elon Musk fired 6,500 employees at Twitter.</p>
<p>A little birdie told me it’s down to:</p>
<ul>
<li>2 designers</li>
<li>6 iOS developers</li>
<li>20 web developers</li>
<li>Around 1,400 sales and operations people</li>
</ul>
<p>How is it possible that we are still using this website?</p>
<p>Two words: </p>
<p><code>Parkinson&#39;s Law.</code></p></summary>
</entry>
<entry>
<title>线程池运行逻辑</title>
<link href="https://oldmee.github.io/2023/06/01/thread-pool-executor/"/>
<id>https://oldmee.github.io/2023/06/01/thread-pool-executor/</id>
<published>2023-06-01T05:56:25.000Z</published>
<updated>2023-08-08T08:16:58.887Z</updated>
<content type="html"><![CDATA[<blockquote><p>线程池的设计思路,你真的了解么?</p></blockquote><span id="more"></span><br><h3 id="当有线程提交时,创建线程"><a href="#当有线程提交时,创建线程" class="headerlink" title="当有线程提交时,创建线程"></a>当有线程提交时,创建线程</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">execute</span><span class="params">(Runnable command)</span> {</span><br><span class="line"> <span class="keyword">if</span> (command == <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">NullPointerException</span>();</span><br><span class="line"> <span class="type">int</span> <span class="variable">c</span> <span class="operator">=</span> ctl.get();</span><br><span class="line"> <span class="keyword">if</span> (workerCountOf(c) < corePoolSize) {</span><br><span class="line"> <span class="keyword">if</span> (addWorker(command, <span class="literal">true</span>))</span><br><span class="line"> <span class="keyword">return</span>;</span><br><span class="line"> c = ctl.get();</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (isRunning(c) && workQueue.offer(command)) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">recheck</span> <span class="operator">=</span> ctl.get();</span><br><span class="line"> <span class="keyword">if</span> (! isRunning(recheck) && remove(command))</span><br><span class="line"> reject(command);</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (workerCountOf(recheck) == <span class="number">0</span>)</span><br><span class="line"> addWorker(<span class="literal">null</span>, <span class="literal">false</span>);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> <span class="keyword">if</span> (!addWorker(command, <span class="literal">false</span>))</span><br><span class="line"> reject(command);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>如果线程小于核心线程数则创建新的线程<code>addWorker</code>,借助于阻塞队列<code>workQueue</code>的功能,将任务放到队列里,线程运行时会从<code>getTask</code>方法中获取任务并执行。在上面的代码中也可以看出当阻塞队列放不下了也会去创建新的线程,因为<code>workQueue.offer(command)</code>为<code>false</code></p><h3 id="如何维护核心线程,超过核心线程数量的线程具体是什么时候销毁的"><a href="#如何维护核心线程,超过核心线程数量的线程具体是什么时候销毁的" class="headerlink" title="如何维护核心线程,超过核心线程数量的线程具体是什么时候销毁的"></a>如何维护核心线程,超过核心线程数量的线程具体是什么时候销毁的</h3><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Runnable <span class="title function_">getTask</span><span class="params">()</span> {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">timedOut</span> <span class="operator">=</span> <span class="literal">false</span>; <span class="comment">// Did the last poll() time out?</span></span><br><span class="line"></span><br><span class="line"> <span class="keyword">for</span> (;;) {</span><br><span class="line"> <span class="type">int</span> <span class="variable">c</span> <span class="operator">=</span> ctl.get();</span><br><span class="line"> <span class="type">int</span> <span class="variable">rs</span> <span class="operator">=</span> runStateOf(c);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Check if queue empty only if necessary.</span></span><br><span class="line"> <span class="keyword">if</span> (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {</span><br><span class="line"> decrementWorkerCount();</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> <span class="variable">wc</span> <span class="operator">=</span> workerCountOf(c);</span><br><span class="line"></span><br><span class="line"> <span class="comment">// Are workers subject to culling?</span></span><br><span class="line"> <span class="type">boolean</span> <span class="variable">timed</span> <span class="operator">=</span> allowCoreThreadTimeOut || wc > corePoolSize;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> ((wc > maximumPoolSize || (timed && timedOut))</span><br><span class="line"> && (wc > <span class="number">1</span> || workQueue.isEmpty())) {</span><br><span class="line"> <span class="keyword">if</span> (compareAndDecrementWorkerCount(c))</span><br><span class="line"> <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line"> <span class="keyword">continue</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="type">Runnable</span> <span class="variable">r</span> <span class="operator">=</span> timed ?</span><br><span class="line"> workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :</span><br><span class="line"> workQueue.take();</span><br><span class="line"> <span class="keyword">if</span> (r != <span class="literal">null</span>)</span><br><span class="line"> <span class="keyword">return</span> r;</span><br><span class="line"> timedOut = <span class="literal">true</span>;</span><br><span class="line"> } <span class="keyword">catch</span> (InterruptedException retry) {</span><br><span class="line"> timedOut = <span class="literal">false</span>;</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>首先明确一下,这个<code>getTask</code>方法是各个线程获取任务调用的方法。我们都知道正常结束的线程会自动销毁,那么如果我不想让线程销毁,让线程池一直维护核心数目的线程要怎么做呢?设计者还是借助了阻塞队列的能力,如果线程数目小于等于核心线程数那么这个线程会受到<code>workQueue.take</code>方法而阻塞,这样线程不就不会结束了么,当有新的任务放到阻塞队列里,take方法就会立马返回,这样线程就可以持续下去一直不被销毁,这也就是线程池维护核心线程数目的原理。<br><br><br>还有一种情况,如果线程数超过核心线程数呢?回想一下,<code>ThreadPoolExecutor</code>构造器中是不是有一个<code>keepAliveTime</code>参数,当创建的线程超过核心线程数后,超过的线程不会立即销毁,会等待一段时间,这个时间就是<code>keepAliveTime</code>,实现原理还是借助于阻塞队列,这次用的是它的<code>poll</code>方法,<code>poll</code>与<code>take</code>的区别就是<code>poll</code>不会一直阻塞,如果超过设置的时间还没有拿到任务则直接返回,这样就达到了释放线程的目的,线程也就被销毁了。</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2023/06/01/thread-pool-executor/">https://oldmee.github.io/2023/06/01/thread-pool-executor/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><blockquote>
<p>线程池的设计思路,你真的了解么?</p>
</blockquote></summary>
</entry>
<entry>
<title>治疗鼻炎最行之有效的方法</title>
<link href="https://oldmee.github.io/2023/05/26/treatment-of-rhinitis-method/"/>
<id>https://oldmee.github.io/2023/05/26/treatment-of-rhinitis-method/</id>
<published>2023-05-26T06:04:41.000Z</published>
<updated>2023-08-08T08:17:15.568Z</updated>
<content type="html"><![CDATA[<blockquote><p>从现在开始,像正常人一样呼吸</p></blockquote><br><h3 id="吃药"><a href="#吃药" class="headerlink" title="吃药"></a>吃药</h3><ol><li>抗组胺药物 </li><li>喷鼻腔的,类固醇喷雾</li></ol><h3 id="洗鼻子"><a href="#洗鼻子" class="headerlink" title="洗鼻子"></a>洗鼻子</h3><ol><li>生理盐水洗鼻子</li></ol><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2023/05/26/treatment-of-rhinitis-method/">https://oldmee.github.io/2023/05/26/treatment-of-rhinitis-method/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><blockquote>
<p>从现在开始,像正常人一样呼吸</p>
</blockquote>
<br>
<h3 id="吃药"><a href="#吃药" class="headerlink" title="吃药"></a>吃药</h3><ol>
<li>抗组胺药物 </</summary>
</entry>
<entry>
<title>Twelve home remedies (12个家庭偏方)</title>
<link href="https://oldmee.github.io/2023/05/19/Twelve-home-remedies/"/>
<id>https://oldmee.github.io/2023/05/19/Twelve-home-remedies/</id>
<published>2023-05-19T00:31:00.000Z</published>
<updated>2023-05-19T00:34:14.948Z</updated>
<content type="html"><![CDATA[<blockquote><p>There are several popular home remedies for indigestion. Some may also help ease stomach upset from other sources, such as irritable bowel syndrome.<br>有几种常见的治疗消化不良的家庭疗法。有些还可以帮助缓解其他原因引起的胃部不适,比如肠易激综合症。</p></blockquote><span id="more"></span><h3 id="1-Drinking-water-喝水"><a href="#1-Drinking-water-喝水" class="headerlink" title="1. Drinking water(喝水)"></a>1. Drinking water(喝水)</h3><p>The body needs water to efficiently digest and absorb nutrients from foods and beverages. Being dehydrated makes digestion more difficult and less effective, increasing the likelihood of an upset stomach.<br>身体需要水来有效地消化和吸收食物和饮料中的营养。脱水会使消化更加困难,效率降低,增加胃部不适的可能性。</p><p>Additionally, drinking water may help reduce heartburn.<br>此外,喝水可能有助于减少胃灼热。</p><h3 id="2-Avoiding-lying-down(避免躺下)"><a href="#2-Avoiding-lying-down(避免躺下)" class="headerlink" title="2. Avoiding lying down(避免躺下)"></a>2. Avoiding lying down(避免躺下)</h3><p>Avoiding lying down may prevent indigestion from becoming heartburn.<br>避免躺下可以防止消化不良变成胃灼热。 </p><p>When the body is horizontal, the acid in the stomach is more likely to travel backward and move upward, which can cause heartburn.<br>当身体处于水平状态时,胃酸更容易逆流而上,从而引起胃灼热。</p><p>Therefore, people with an upset stomach should avoid lying down or going to bed for at least a few hours until it passes.<br>因此,胃部不适的人应该避免躺下或上床睡觉至少几个小时,直到它过去。</p><h3 id="3-Ginger(生姜)"><a href="#3-Ginger(生姜)" class="headerlink" title="3. Ginger(生姜)"></a>3. Ginger(生姜)</h3><p>Ginger may help reduceTrusted Source nausea and vomiting in people who are pregnant or those who undergo chemotherapy.<br>生姜可能有助于减少孕妇或化疗患者的可信源性恶心和呕吐。 </p><p>Individuals with an upset stomach could try adding ginger to their food or drinking it as tea. Some all-natural ginger ales may also contain enough ginger to settle an upset stomach.<br>胃不舒服的人可以尝试在食物中加入生姜,或者把生姜当茶喝。一些纯天然的姜汁啤酒可能含有足够的姜汁来缓解胃部不适。</p><p>Ginger tea is widely available to buy in supermarkets and online.<br>姜茶在超市和网上随处可见。</p><h3 id="4-BRAT-diet(BRAT食谱)"><a href="#4-BRAT-diet(BRAT食谱)" class="headerlink" title="4. BRAT diet(BRAT食谱)"></a>4. BRAT diet(BRAT食谱)</h3><p>Doctors may recommend the bananas, rice, applesauce, and toast (BRAT) diet to people with diarrhea.<br>医生可能会向腹泻患者推荐香蕉、米饭、苹果酱和吐司(BRAT)饮食。 </p><p>BRATTrusted Source foods may decrease the number of stools a person passes and help ease their diarrhea.<br>可靠来源的食物可以减少一个人排便的次数,帮助缓解腹泻。 </p><p>As these foods are bland, they do not contain substances that irritate the stomach, throat, or intestines. Therefore, this diet can soothe the tissue irritation resulting from the acids in vomit.<br>由于这些食物是温和的,它们不含有刺激胃、喉咙或肠道的物质。因此,这种饮食可以缓解呕吐物中的酸对组织的刺激。 </p><p>Many of the foods in the BRAT diet are also high in nutrients, such as potassium and magnesium, and can replace those someone loses through diarrhea and vomiting.<br>BRAT饮食中的许多食物也富含营养,如钾和镁,可以补充因腹泻和呕吐而失去的营养。</p><h3 id="5-Avoiding-smoking-and-drinking-alcohol(避免吸烟和饮酒)"><a href="#5-Avoiding-smoking-and-drinking-alcohol(避免吸烟和饮酒)" class="headerlink" title="5. Avoiding smoking and drinking alcohol(避免吸烟和饮酒)"></a>5. Avoiding smoking and drinking alcohol(避免吸烟和饮酒)</h3><p>Smoking and alcohol may trigger indigestion and other gastrointestinal conditions, such as gastroesophageal reflux disease (GERD).<br>吸烟和饮酒可能引发消化不良和其他胃肠道疾病,如胃食管反流病(GERD)。</p><h3 id="6-Avoiding-difficult-to-digest-foods(避免难以消化的食物)"><a href="#6-Avoiding-difficult-to-digest-foods(避免难以消化的食物)" class="headerlink" title="6. Avoiding difficult-to-digest foods(避免难以消化的食物)"></a>6. Avoiding difficult-to-digest foods(避免难以消化的食物)</h3><p>ResearchTrusted Source suggests that the following foods may increase the risk of indigestion:<br>研究表明,以下食物可能会增加消化不良的风险: </p><ul><li>fatty or acidic foods<br>脂肪或酸性食物 </li><li>wheat products<br>小麦产品</li><li>fruit and fruit juices such as watermelon<br>水果和果汁,如西瓜</li><li>spicy foods<br>辛辣的食物 </li><li>greasy foods<br>油腻的食物</li></ul><h3 id="7-Baking-soda-小苏打"><a href="#7-Baking-soda-小苏打" class="headerlink" title="7. Baking soda(小苏打)"></a>7. Baking soda(小苏打)</h3><p>Some healthcare professionals suggest that baking soda can help relieve heartburn and indigestion by reducing stomach acidity.<br>一些医疗保健专业人士建议,小苏打可以通过减少胃酸来帮助缓解胃灼热和消化不良。</p><h3 id="8-Figs-无花果"><a href="#8-Figs-无花果" class="headerlink" title="8. Figs(无花果)"></a>8. Figs(无花果)</h3><p>Figs contain substances that act as laxatives to ease constipation and encourage healthy bowel movements. Figs also contain compounds that may help to ease indigestion.<br>无花果含有的物质可以起到泻药的作用,缓解便秘,促进健康的肠道运动。无花果还含有有助于缓解消化不良的化合物。</p><h3 id="9-Aloe-juice-芦荟汁"><a href="#9-Aloe-juice-芦荟汁" class="headerlink" title="9. Aloe juice(芦荟汁)"></a>9. Aloe juice(芦荟汁)</h3><p>Aloe vera may helpTrusted Source reduce symptoms of irritable bowel syndrome and colitis, although the evidence for these benefits is slight and needs further research.<br>芦荟可能有助于减轻肠易激综合征和结肠炎的症状,尽管这些益处的证据很少,需要进一步研究。</p><h3 id="10-Basil-罗勒"><a href="#10-Basil-罗勒" class="headerlink" title="10. Basil(罗勒)"></a>10. Basil(罗勒)</h3><p>Basil contains substances that may reduce gas. Its leaves also contain levels of high linoleic acid, which has anti-inflammatory properties.<br>罗勒含有可以减少气体的物质。它的叶子还含有高水平的亚油酸,具有抗炎作用。</p><h3 id="11-Licorice-甘草"><a href="#11-Licorice-甘草" class="headerlink" title="11. Licorice(甘草)"></a>11. Licorice(甘草)</h3><p>Products that contain licorice root may helpTrusted Source relieve digestive symptoms. However, experts are uncertain about the role of licorice in these products.<br>含有甘草根的产品可能有助于缓解消化系统症状。然而,专家们不确定甘草在这些产品中的作用。 </p><p>Someone with an upset stomach could try drinking licorice root tea several times daily until their symptoms improve.<br>胃不舒服的人可以尝试每天喝几次甘草根茶,直到症状好转。</p><h3 id="12-Rice-大米"><a href="#12-Rice-大米" class="headerlink" title="12. Rice(大米)"></a>12. Rice(大米)</h3><p>Plain rice may be beneficial for those with stomach pain due to irritable bowel syndrome, along with other low FODMAP food.<br>白米饭和其他低FODMAP食物可能对那些因肠易激综合症而胃痛的人有益。 </p><p>Rice is also part of the BRAT diet that doctors may recommend.<br>米饭也是医生推荐的BRAT饮食的一部分。</p>]]></content>
<summary type="html"><blockquote>
<p>There are several popular home remedies for indigestion. Some may also help ease stomach upset from other sources, such as irritable bowel syndrome.<br>有几种常见的治疗消化不良的家庭疗法。有些还可以帮助缓解其他原因引起的胃部不适,比如肠易激综合症。</p>
</blockquote></summary>
<category term="养生" scheme="https://oldmee.github.io/categories/%E5%85%BB%E7%94%9F/"/>
<category term="胃疼" scheme="https://oldmee.github.io/tags/%E8%83%83%E7%96%BC/"/>
</entry>
<entry>
<title>纪念左耳朵耗子 (转载)</title>
<link href="https://oldmee.github.io/2023/05/16/%E7%BA%AA%E5%BF%B5%E5%B7%A6%E8%80%B3%E6%9C%B5%E8%80%97%E5%AD%90/"/>
<id>https://oldmee.github.io/2023/05/16/%E7%BA%AA%E5%BF%B5%E5%B7%A6%E8%80%B3%E6%9C%B5%E8%80%97%E5%AD%90/</id>
<published>2023-05-16T07:01:04.000Z</published>
<updated>2023-05-17T04:11:58.723Z</updated>
<content type="html"><![CDATA[<blockquote><p>source link: <a href="https://blog.kevinzhow.com/posts/in-memory-of-haoel/zh">https://blog.kevinzhow.com/posts/in-memory-of-haoel/zh</a></p></blockquote><p>刚刚从半睡半醒中醒来,梦境的最后一刻是陈皓成为了 AI,而我刚想和“他”说说话。</p><p>我相信那一天终究会到来,但此刻看着 Discord 里甚至还没显示为离线的他,我也知道再也得不到回应。</p><p>在北京相识<br>我一直称他为皓哥,因此现在也还是皓哥吧,但这个名称其实让我纠结过,毕竟他那么显老,甚至让我一度也想过叫皓叔。但,为了不让陈皓同志觉得和我有年龄代沟,最终还是用哥这个辈分了,感觉他挺喜欢的 :)</p><p><img src="/images/pasted-1.png" alt="upload successful"></p><p>2015 年底的时候我因为公司被收购来到了北京,当时负责筹划名叫「字里行间」的写作产品,2016 年 3 月的时候,正值组建团队之际,公司有阿里背景的 HR 大姐说,有个技术大神从阿里出来了,约了吃个饭,问我能不能一起去。</p><p>我拿过来一看——陈皓,接着大姐说 “在 Amazon 干过,还有个技术博客非常有名,叫 Coolshell” 。</p><p>我当即就去网上 “人肉” 了一番,找到了他的博客,微博,Twitter,从那时候开始,我从皓哥的个人介绍里就总能看到这句 “芝兰生于深谷,不以无人而不芳” 。其实这个和我潜意识的技术人是有点不搭的,也太“老土”了吧,哈哈,但说真的,我是很喜欢这句话的。</p><p>皓哥是真的把座右铭当成信条来执行,使得这句话也就不再像是一句用来装饰自己的空话。</p><p>这张 Twitter 截图应该是见面前一天晚截下来的,为第二天的见面做准备。</p><p><img src="/images/pasted-2.png" alt="upload successful"><br>第二天中午,我在北京朝阳大悦城的望湘园见到了他,皓哥这个人很真实,他如果一开始觉得对公司没兴趣,就会略显疲态,言语间带着攻击性,上来先劈头盖脸的批判了一番我们金主的业务内容,直到上菜了,才让我得以在他嚼饭的空隙做一些自我介绍。</p><p>“这个是我之前的产品,Yep”</p><p>“Yep 是你做的?”</p><p>“是啊”</p><p>“这个我知道啊,太酷了,第一次见在国内这么玩开源的”</p><p>Yep 是我之前做的一款面向程序员和设计师的社交产品,当时走了客户端全开源的模式,因为这款产品,本来将要不欢而散的饭局,产生了 180 度的反转,皓哥说可以聊聊,然后特别的说 “我主要是对 Kevin 感兴趣”。</p><p>我没有想到他会这样想。</p><p>在尝试拉他入伙的时候,他反复追问当时的老板是 “相信技术,还是相信管理” ,而老板的太极回答没能让他满意。</p><p>再后来,他便成为了当时公司的技术顾问,而我们的友谊也是从那时开始的。</p><p>亦师亦友<br>我当时住在朝阳区的青年汇佳园,而皓哥在朝阳的远洋天地,地缘上的因素使得我们就像是邻居一样,经常能碰个面,吃个饭。</p><p>聊天时,皓哥的输出是非常持久的,通常开启一个话题后,我基本只剩下负责吃的份,而他都是一个小时起步,跟我讲很多他的经历,价值观,他喜欢对比 Amazon 和 阿里 的企业文化,一个是工程师文化的代表,一个是销售驱动的代表,一个相信技术,一个相信管理,以此为引子,就是那晚的下饭菜。</p><p>有一次我跟他吐槽说,公司昨天有人没关窗户,结果现在开始安排值日关窗了。</p><p>他说:“你看,这个就是相信管理,如果要是相信技术的公司,就会安装一个自动闭门器,相信什么是刻在公司基因里的。”</p><p>有一次我问他,Amazon 那么好,你为啥还愿意去阿里。</p><p>他说:“本来是没什么兴趣的,但他们的 HR 的诚意打动了我,我想去看看到底是什么样的企业文化能有这个样的 HR”</p><p>皓哥就一直是这样较真的一个人,如果感兴趣,就一定会去试试,他从来不会只停留在想的阶段,我也从没有见过他纠结的样子,总是会坚定的随着自己的价值观,行动,验证。</p><p>也正是他,逐渐影响了我价值观塑造的时期,做自己相信的事情,再把相信的事情做对。</p><p>2017 年底的时候,我决定离开当时的公司,谈完离职之后,我给皓哥发了信息,一起在管氏翅吧撸串。</p><p>那天,我一直在跟他倾诉,说着那些在公司里无法实现的抱负,说着自己后悔没有坚持下来的那些事情,以及最后我哭着说 “我只是想做自己想做的产品”</p><p>现在回想那些瞬间,我才意识到自己失去一个挚友所代表的是什么。</p><p>青岛<br>2018 年的时候我决定离开北京,在青岛以独立开发者的形式,去弥补那些自己过去的遗憾。</p><p>临走前,皓哥非要约我一起爬山,于是我带着老婆,他带着女儿,四个人一起去爬了怀柔的红螺寺,那天我被折磨的很惨,一路累的哭爹喊娘,第二天腿酸的厕所都上不了。</p><p>他说:“我就是故意搞你的,我要做点什么事情,让你记住我”。</p><p>说这句话的时候,他带着一种老男人的风情。</p><p>离别前,他说:“我以前有朋友从北京回到昆明后,失去了理想变得世俗了,但我不担心你,因为你知道自己想要什么。”</p><p>我觉得他还有点担心的,但所幸,我并没有改变。</p><p>因为皓哥在青岛也有亲人的原因,在随后 2019 - 2021 的那段时期,皓哥每年暑期都会带着家人来青岛和我聚一聚,带着一点点视察的性质。</p><p>他说,他很喜欢海的辽阔,在海边会觉得一切事情都会被包容。</p><p>而我却再也没去过一次北京,也没能赴约昆明。</p><p>记忆中,那天青岛下着小雨,他带着女儿坐在我家客厅的地垫上,电视播放着一个在日本旅行走路的 Youtube 频道,4K.</p><p>他说,感觉真的太放松了,我们一定要一起去一次日本。</p><p><img src="/images/pasted-3.png" alt="upload successful"></p><p><img src="/images/pasted-4.png" alt="upload successful"></p><p><img src="/images/pasted-5.png" alt="upload successful"><br>一起做点什么事情<br>皓哥一直说 “总觉得我们会在一起搞点事情”,但很多年来都没真的走在一起做点什么。</p><p>所幸,这件事没有成为遗憾。</p><p>2022 年的时候我开始给自己的产品加入服务器,公有云的服务太贵了,而皓哥的 MegaEase 正好可以解决这个问题,我成为了潜在用户。</p><p>那天他说想去海外推广这款产品,但是产品设计他不满意,他说: “这是我自己设计的,也是我能力范围内能做的到的极限了”。</p><p>我说: “要不我给你搞搞吧,反正我也想用这个系统,这样我用的可以更爽一些”。</p><p>于是我得以有机会,在那之后的 3 个月,利用每天一些闲暇的时间,给 MEGAEASE 做一些品牌和产品的设计,其实很多地方我也许可以做的更好,但再也没有如果。</p><p>2023 年的 4 月 27 号,是他最后一次跟我打电话</p><p><img src="/images/pasted-6.png" alt="upload successful"><br>那天他跟我聊了会 MegaEase,以及接下来想做的 AI 产品,说 “这可能是我最后一次能赶上的技术风口,再往后可能我也不懂了” 。</p><p>希望我能以合伙人的形式,跟他一起搞这款产品。</p><p>其实在此之前,皓哥都将我视作未来的合伙人。但我因为自己的产品还没有完成计划,不想再一次留下遗憾,也深知在兼顾的情况下,我无法符合一个合伙人所代表的期望,因此我总是有些抗拒的。</p><p>这一天我依旧有些抗拒,但和皓哥一起做点事总是我心底也期望的,在听他讲了 1 个小时后,我把心里关于不想留下产品遗憾的事情又提了一次,说 “我觉得这方向没有问题的,等到时候可以搞搞看,反正我也会用到”。</p><p>留下了一张空头支票。</p><p>最后一次对话<br>2023 年的 5 月 2 号的凌晨 3 点左右,我在睡觉前发现 Discord 好像上线了语音消息的功能,于是就给皓哥发了句语音 “测试一下 Discord 的语音功能”,第二天,他 7 点多回了句语音 “你晚上不睡觉啊”。</p><p>然后我也没有回复,这种没头没尾的对话,我们已经习以为常。</p><p>也从来未曾想到,如此稀松平常的对话,会是最后一次。</p><p>5 月 15 号凌晨,朋友给我个信息说,皓哥走了。</p><p>我一时错愕,问 “走了是啥意思,润了吗”</p><p>我没有能走入那个时间线。</p><p>直到现在,我都觉得非常不真实。</p><p>因为我可以轻易的想起他说话的音调,想像出他对一件事会有怎样的态度,会如何回应我的信息。</p><p>那些一起和朋友们玩 FIFA 的瞬间,和家人们在海边散步影像,以及我俩在烧烤店撸串时的对话,都能那么轻易的被回忆起来。</p><p>怎么,这些就都不再有后续了呢?</p><p>这个有时候爱称自己的是老家伙,知道我也听 AC/DC 后就兴奋的给我分享歌单的人</p><p>怎么能就没了呢?</p><p>没有遗忘,就没有离去<br>我一直以为,自己是一个可以看淡生死的人,甚至从初中开始,我就一直会以这种方式思考自己的人生:</p><p>“假如今天我已经 80 岁了,即将死去,我回想自己的一生,是否会觉得自己是个傻逼”</p><p>毫无疑问,皓哥的一生是值得他骄傲的。</p><p>每当想起他的时候,我总是能得到勇气把自己相信的事情坚持下去,让做和不做的事情都一样骄傲。</p><p>我希望自己能传承一点他的骄傲,继续创造,分享,更勇敢的面对未来,他已经留下了答卷,而我仍需要继续作答我的人生。</p><p>我想,只要我没有忘记他留给我的那些精神,他也就未曾离我而去。</p><p>愿他在另一个世界,依旧玩的开心。</p><p>以此纪念我的挚友,陈皓。</p>]]></content>
<summary type="html"><blockquote><p>source link: <a href="https://blog.kevinzhow.com/posts/in-memory-of-haoel/zh">https://blog.kevinzhow.com/posts/in-memory-of-h</summary>
</entry>
<entry>
<title>5 things I wish I heard at the graduation I never had (transpond)</title>
<link href="https://oldmee.github.io/2023/05/16/5-things-I-wish-I-heard-at-the-graduation-I-never-had/"/>
<id>https://oldmee.github.io/2023/05/16/5-things-I-wish-I-heard-at-the-graduation-I-never-had/</id>
<published>2023-05-16T00:29:00.000Z</published>
<updated>2023-08-08T08:17:39.963Z</updated>
<content type="html"><![CDATA[<blockquote><p><img src="/images/pasted-0.png"><br>The advice I shared with the class of 2023 is advice I could have used myself.</p></blockquote><span id="more"></span><p>Throughout my career, I’ve been lucky to give two commencement speeches: one to Harvard—the alma mater I never graduated from—in 2007, and another to Stanford in 2014. Today, I delivered my third to the forestry and engineering graduates of Northern Arizona University. (You can read more about what drew me to NAU here.)</p><p>The class of 2023 is no ordinary group of graduates. Before most of them completed their first year of college, a once-in-a-generation pandemic came along and changed life—and learning—as we knew it. It took resilience, grit, and a whole lot of ingenuity for them to cross this finish line. So I was excited to congratulate them before they begin the next stages of their lives, and share some wisdom I’ve picked up in the decades since I left my own college campus.</p><p>This is what I told them:</p><p>Remarks as prepared<br>May 13, 2023<br>Northern Arizona University Commencement Ceremony for the College of Engineering, Informatics, and Applied Sciences and the College of the Environment, Forestry, and Natural Sciences</p><p>Good afternoon! Thank you, President Cruz Rivera and the Arizona Board of Regents, for this tremendous honor. I am thrilled to be here with NAU’s esteemed faculty and staff.</p><p>Friends and family, the time has finally come to exhale. Today is your accomplishment, too—and I think that deserves a round of applause.</p><p>Graduates, you made it. You finished your capstones and your internships. You survived junior-level writing class and multiple Tequila Sunrises. You had your last Dimes Night at Museum Club, and you earned your rubber duck from Collins.</p><p>You might be happy to know that I have joined your ranks. I am now the proud recipient of an honorary doctorate and an honorary ducky.</p><p>I am honored to have the opportunity to address you today, because I believe more people should know about the tremendous value of an NAU education. You are graduating from an institution that creates opportunity, fosters innovation, and builds community, and it has prepared you to find solutions to some of the biggest problems facing us today. </p><p>NAU is also giving you something I never received: A real college degree.</p><p>Some of you might know that I never made it to my own graduation. I left after three semesters to start Microsoft. So, what does a college dropout know about graduation? Not much personally, to be honest.</p><p>As I prepared for today, I thought about how you, as new graduates, can have the biggest impact on the world with the education you received here. That led me to thinking about the graduation I never had, the commencement speech I never heard, and the advice I wasn’t given on a day just like this one.</p><p>That is what I want to share with you this afternoon: The five things I wish I was told at the graduation I never attended.</p><h3 id="The-first-thing-is-your-life-isn’t-a-one-act-play"><a href="#The-first-thing-is-your-life-isn’t-a-one-act-play" class="headerlink" title="The first thing is, your life isn’t a one-act play."></a>The first thing is, your life isn’t a one-act play.</h3><p>You probably feel a lot of pressure right now to make the right decisions about your career. It might feel like those decisions are permanent. They’re not. What you do tomorrow—or for the next ten years—does not have to be what you do forever.</p><p>When I left school, I thought I would work at Microsoft for the rest of my life.</p><p>Today, I still love my work on software, but philanthropy is my full-time job. I spend my days working to create innovations that fight climate change and reduce inequalities around the world—including in health and education.</p><p>I feel lucky that our foundation gets to support amazing institutions like NAU—even if it’s not what I imagined I’d be doing when I was 22. Not only is it okay to change your mind or have a second career… it can be a very good thing.</p><h3 id="The-second-piece-of-advice-I-wish-I-heard-at-my-graduation-is-that-you-are-never-too-smart-to-be-confused"><a href="#The-second-piece-of-advice-I-wish-I-heard-at-my-graduation-is-that-you-are-never-too-smart-to-be-confused" class="headerlink" title="The second piece of advice I wish I heard at my graduation is that you are never too smart to be confused."></a>The second piece of advice I wish I heard at my graduation is that you are never too smart to be confused.</h3><p>I thought I knew everything I needed to know when I left college. But the first step to learning something new is embracing what you don’t know, instead of focusing on what you do know.</p><p>At some point in your career, you will find yourself facing a problem you cannot solve on your own. When that happens, don’t panic. Take a breath. Force yourself to think things through. And then find smart people to learn from.</p><p>It could be a colleague with more experience. It could be one of your fellow graduates, who has a good perspective and will push you to think differently. It could be an expert in the field who is willing to reply to your questions over DM.</p><p>Just about everything I have accomplished came because I sought out others who knew more. People want to help you. The key is to not be afraid to ask.</p><p>You may be done with school. But you can—and should—see the rest of your life as an education. </p><h3 id="My-third-piece-of-advice-is-to-gravitate-toward-work-that-solves-an-important-problem"><a href="#My-third-piece-of-advice-is-to-gravitate-toward-work-that-solves-an-important-problem" class="headerlink" title="My third piece of advice is to gravitate toward work that solves an important problem."></a>My third piece of advice is to gravitate toward work that solves an important problem.</h3><p>The good news is, you are graduating at a time when there are many important problems to solve. New industries and companies are emerging every day that will allow you to make a living and make a difference, and advances in science and technology have made it easier than ever to make a big impact.</p><p>For example, many of you are becoming foresters. Your professors taught you about cutting-edge tools, like drones that use LIDAR to produce accurate maps of the forest floor. You could find new ways to use that technology to help fight climate change.</p><p>Some of you are heading off to start careers as programmers. You could use your talents to make sure all people can benefit from artificial intelligence—or to help eliminate biases in AI.</p><p>When you spend your days doing something that solves a big problem, it energizes you to do your best work. It forces you to be more creative, and it gives your life a strong sense of purpose.</p><h3 id="My-fourth-piece-of-advice-is-simple-Don’t-underestimate-the-power-of-friendship"><a href="#My-fourth-piece-of-advice-is-simple-Don’t-underestimate-the-power-of-friendship" class="headerlink" title="My fourth piece of advice is simple: Don’t underestimate the power of friendship."></a>My fourth piece of advice is simple: Don’t underestimate the power of friendship.</h3><p>When I was in school, I became friends with another student who shared a lot of my interests, like science fiction novels and computer magazines.</p><p>Little did I know how important that friendship would be. My friend’s name was Paul Allen—and we started Microsoft together.</p><p>Remember that people you’ve sat next to in lectures, skied Snowbowl with, and competed against on Wingo night are not just your classmates. They are your network. Your future co-founders and colleagues. A great future source of support, information, and advice. </p><p>The only thing more valuable than what you walk offstage with today is who you walk onstage with.</p><h3 id="My-last-piece-of-advice-is-the-one-I-could-have-used-the-most-It-took-me-a-long-time-to-learn-And-it-is-this-You-are-not-a-slacker-if-you-cut-yourself-some-slack"><a href="#My-last-piece-of-advice-is-the-one-I-could-have-used-the-most-It-took-me-a-long-time-to-learn-And-it-is-this-You-are-not-a-slacker-if-you-cut-yourself-some-slack" class="headerlink" title="My last piece of advice is the one I could have used the most. It took me a long time to learn. And it is this: You are not a slacker if you cut yourself some slack."></a>My last piece of advice is the one I could have used the most. It took me a long time to learn. And it is this: You are not a slacker if you cut yourself some slack.</h3><p>When I was your age, I didn’t believe in vacations. I didn’t believe in weekends. I pushed everyone around me to work very long hours. In the early days of Microsoft, my office overlooked the parking lot—and I would keep track of who was leaving early and staying late.</p><p>But as I got older—and especially once I became a father—I realized there is more to life than work.</p><p>Don’t wait as long as I did to learn this lesson. Take time to nurture your relationships, to celebrate your successes, and to recover from your losses.</p><p>Take a break when you need to. Take it easy on the people around you when they need it, too.</p><p>And before you begin the next stage of your lives, take a moment and have some fun. Tonight, this weekend, this summer, whenever. You deserve it.</p><p>Class of 2023, the future belongs to you. I believe you will be the ones to solve the climate crisis and reduce the gap between the rich and poor.</p><p>You have already made history by attending college during some truly unprecedented times. I have no doubt that you will continue to make history throughout the rest of your lives. I cannot wait to see how you will drive progress around the world.</p><p>Congratulations on reaching this momentous milestone. Go Lumberjacks!</p>]]></content>
<summary type="html"><blockquote><p><img src="/images/pasted-0.png"><br>The advice I shared with the class of 2023 is advice I could have used myself.</p>
</blockquote></summary>
<category term="speech" scheme="https://oldmee.github.io/tags/speech/"/>
</entry>
<entry>
<title>paper-about-PML(Casbin论文)</title>
<link href="https://oldmee.github.io/2022/08/19/paper-about-PML/"/>
<id>https://oldmee.github.io/2022/08/19/paper-about-PML/</id>
<published>2022-08-19T06:28:00.000Z</published>
<updated>2023-08-19T13:48:15.202Z</updated>
<content type="html"><![CDATA[<blockquote><p>PERM modeling language<br>PML:AnInterpreter-BasedAccessControl PolicyLanguageforWebServices<br>找到一篇关于casbin起源的论文,原文链接:<a href="https://arxiv.org/pdf/1903.09756">Casbin</a></p></blockquote><span id="more"></span><br><h3 id="产生的背景"><a href="#产生的背景" class="headerlink" title="产生的背景"></a>产生的背景</h3><p>过去的几年里,云计算成为了一个为了减少基础计算需求的企业级能力的革命者,其中公有云在互联网上暴露了接口,云数据的访问控制就成了非常重要的一个部分,过去十年里,学术界提出了几个访问控制策略语言,比如:XACML,SPL,Ponder等等。</p><p>介绍了一下云计算的发展,特别是公有云的安全认证问题,不同的厂家有不同的实现,虽然功能都是一样的,而且为了多平台适配还开发了不同语言版本的安全认证,,这就导致了几个问题,比如一个用户可能在好几个云服务商上都部署了自己的业务,所以如果想要在不同的云服务商上迁移的时候,就会出现安全认证代码在其它平台不兼容的情况。而且云服务商需要开发对应的安全策略语言,这也是需要成本的,而且由于他们缺乏安全方面的知识,开发出来的安全策略可能引发安全漏洞。</p><p>所以为了解决这些问题,PERM模型语言(PML)就应运而生了。</p><h3 id="特点"><a href="#特点" class="headerlink" title="特点"></a>特点</h3><p>PML可以提供很多访问控制模型,比如像:<code>access control list(ACL)</code>,<code>RBAC</code>,<code>ABAC</code>等等</p><p>PML运行机制被设计具有两个特点:</p><ol><li>访问控制模型独立 </li><li>实现语言独立</li></ol><p>核心的PML-EM使用lua语言实现的,lua经常可以嵌入到其它的程序语言中,部分工作孵化成了目前入驻在github的开源项目casbin里,而且已经被一些公司应用在自己的生产环境中。<br><br></p><h5 id="PML"><a href="#PML" class="headerlink" title="PML"></a>PML</h5><p>将抽象的认证逻辑与策略规范分开</p><p>PML-EM:PML的运行机制,采用LUA语言实现,并融入了编译器内的编译器(<code>interpreter-oninterpreter</code>)思想,这使得它可以直接使用所有支持LUA的语言,而且实践证明,PML-EM并不会造成明显的运行开销。<br><br></p><h5 id="Request"><a href="#Request" class="headerlink" title="Request"></a>Request</h5><p>request作为一个键值对就像这样:</p><figure class="highlight plaintext"><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">request::=r:attributes</span><br><span class="line">attributes::={attr1,attr2,attr3,...}</span><br></pre></td></tr></table></figure><br><h5 id="Policy"><a href="#Policy" class="headerlink" title="Policy"></a>Policy</h5><p>同样定义成键值对:</p><figure class="highlight plaintext"><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">policy::=p:attributes</span><br><span class="line">attributes::={attr1,attr2,attr3,...}</span><br></pre></td></tr></table></figure><br><h5 id="Policy-Rule"><a href="#Policy-Rule" class="headerlink" title="Policy Rule"></a>Policy Rule</h5><p>它是上面policy的实例,它定义成值的数据,就像这样:</p><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">policy_rule::={value1,value2,value3...}</span><br></pre></td></tr></table></figure><br><h5 id="Matcher"><a href="#Matcher" class="headerlink" title="Matcher"></a>Matcher</h5><p>它的作用是决定策略规则怎样作用于request,它被定义成boolean表达式</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">matcher::<boolean_expr>(variables,constants,stub_functions)</span><br><span class="line">variables::={r.attr1,r.attr2,...,p.attr1,p.attr2}</span><br><span class="line">constants::={const1,const2,const3,...}</span><br></pre></td></tr></table></figure><br><h5 id="Effect"><a href="#Effect" class="headerlink" title="Effect"></a>Effect</h5><p>影响范围,比如说 <code>some|any|max|min</code><br><br></p><h5 id="Stub-Function"><a href="#Stub-Function" class="headerlink" title="Stub Function"></a>Stub Function</h5><p>可以用户自定义的策略设计<br><br></p><h5 id="Has-Role"><a href="#Has-Role" class="headerlink" title="Has_Role"></a>Has_Role</h5><p>在PML中不会直接定义角色的概念,取而代之的是用stub函数描述两个对象的角色继承关系,定义如下:</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">has_role::=function_name:parameters</span><br><span class="line">function_name::="g"</span><br><span class="line">parameters::{attr1,attr2}</span><br></pre></td></tr></table></figure><p>通用的<code>has_role</code>函数使用如下:</p><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">m=g(r.sub,p.sub) && r.obj==p.obj && r.act==p.act</span><br></pre></td></tr></table></figure><p>matcher会检查是否p.sub是r.obj的一个角色,基于has_role的能力,PML也就提供了对RBAC的支持</p><p><img src="/images/pasted-17.png" alt="upload successful"></p><h3 id="关于IoI的解释:"><a href="#关于IoI的解释:" class="headerlink" title="关于IoI的解释:"></a>关于IoI的解释:</h3><p>因为在策略执行期间直接运行用户侧代码会因为执行了不受控制的代码而遭遇攻击,例举了一些预防的措施:</p><ol><li>在沙盒中执行stub函数,这样就不会影响到外面的PML解释器或者整个系统</li><li>当stub函数注册到云服务提供商中时执行静态代码检查,恶意代码会在这个过程中检测出来</li><li>提供一个用于函数编辑的接口,提供预定于构建模块用来构建一个stub函数</li></ol><p>然而要实现上面这三个措施需要额外的机制,实现起来很不方便。这里团队成员采用了另一种平替方案,用Lua语言写PML解释器,也就意味着PML解释器是跑在Lua解释器上的,这就是<code>interpreter-on-interpreter(IoI)</code>的由来.市面上很多流行的编程语言都对Lua解释器有一个很成熟的实现,而且体积非常小(小于1000KB),因此可以很容易的嵌入到需要被访问控制的底层系统里。</p><p>PML matcher与Lua的语法基本相同,因此PML interpreter直接使用Lua的解释器,类似于虚拟技术里面的硬件辅助,直接用物理处理器执行机器码而不是二进制的模拟器。</p><p>所有的benchmarks的请求延迟都少于5.9微秒,即使不考虑在云端运行的延迟,通过PML-EM的总体延迟跟正常事物延迟差距依然少于0.2%(当时ping的往返时间RTT大概在30-100ms)</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2022/08/19/paper-about-PML/">https://oldmee.github.io/2022/08/19/paper-about-PML/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><blockquote>
<p>PERM modeling language<br>PML:AnInterpreter-BasedAccessControl PolicyLanguageforWebServices<br>找到一篇关于casbin起源的论文,原文链接:<a href="https://arxiv.org/pdf/1903.09756">Casbin</a></p>
</blockquote></summary>
</entry>
<entry>
<title>process-of-the-sourcecode-compile-into-bytecode-of-Java</title>
<link href="https://oldmee.github.io/2022/05/02/process-of-the-sourcecode-compile-into-bytecode-of-Java/"/>
<id>https://oldmee.github.io/2022/05/02/process-of-the-sourcecode-compile-into-bytecode-of-Java/</id>
<published>2022-05-02T01:15:00.000Z</published>
<updated>2023-08-13T02:10:44.576Z</updated>
<content type="html"><![CDATA[<p>how to compiler generates the bytecode,let me show you with the simplest words.<br><br></p><span id="more"></span><p>think of the class below:</p><figure class="highlight java"><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="keyword">public</span> <span class="keyword">class</span> <span class="title class_">HelloWorld</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> System.out.println(<span class="string">"Hello, World!"</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><ul><li><p>Step 1: Parse: Reads a set of *.java source files and maps the resulting token sequence into AST (Abstract Syntax Tree)-Nodes.</p></li><li><p>Step 2: Enter: Enters symbols for the definitions into the symbol table.</p></li><li><p>Step 3: Process annotations: If Requested, processes annotations found in the specified compilation units.</p></li><li><p>Step 4: Attribute: Attributes the Syntax trees. This step includes name resolution, type checking and constant folding.(<code>folding eg:"a=1+2" is optimized to "a=3"</code>)</p></li><li><p>Step 5: Flow: Performs dataflow analysis on the trees from the previous step. This includes checks for assignments and reachability.</p></li><li><p>Step 6: Desugar: Rewrites the AST and translates away some syntactic sugar.</p></li><li><p>Step 7: Generate: Generates ‘.Class’ files.</p></li></ul><p>finally,The AST for our example code looks something like this:</p><figure class="highlight plaintext"><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">CompilationUnit</span><br><span class="line"> └── TypeDeclaration (class: HelloWorld)</span><br><span class="line"> └── MethodDeclaration (public static void main(String[] args))</span><br><span class="line"> └── Statement (System.out.println("Hello, World!"))</span><br></pre></td></tr></table></figure><p>if you want more details,step to <code>com.sun.tools.javac.main.JavaCompiler</code> and find out</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2022/05/02/process-of-the-sourcecode-compile-into-bytecode-of-Java/">https://oldmee.github.io/2022/05/02/process-of-the-sourcecode-compile-into-bytecode-of-Java/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p>how to compiler generates the bytecode,let me show you with the simplest words.<br><br></p></summary>
</entry>
<entry>
<title>数据链路层frame中用Java实现字节填充</title>
<link href="https://oldmee.github.io/2021/08/23/Byte-Stuffing-using-Java/"/>
<id>https://oldmee.github.io/2021/08/23/Byte-Stuffing-using-Java/</id>
<published>2021-08-23T00:39:00.000Z</published>
<updated>2023-08-23T02:06:23.076Z</updated>
<content type="html"><![CDATA[<p>在数据链路层中,帧的大小各式各样,怎样把不同的帧区分开来?</p><p><code>字节填充</code>就是用来干这个事情的。它的实现原理很简单,就是在每个帧的开头和结尾加上一个8位的标识<code>F</code>,用这个标识来区分每一个帧。</p><p>那么问题来了,如果帧本身的内容就包含这个标识<code>F</code>呢?也不复杂,可以类比正则表达式,用转义字符修饰普通的字符<code>F</code>就可以了,这里我们同样用一个8位标识<code>E</code>作为转义字符,你可能又会问,那如果帧本身内容也包含这个转义字符<code>E</code>呢?我们在转义字符前面再加上一个转义字符即可。</p><p>举个例子:</p><figure class="highlight text"><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></pre></td><td class="code"><pre><span class="line">发送端将要发送的原始内容 : </span><br><span class="line">DDEDFFDE</span><br><span class="line">字符填充之后的内存变为 : </span><br><span class="line">FDDEEDEFEFDEEF</span><br><span class="line"></span><br><span class="line">接收端接收到的内容 :</span><br><span class="line">FDDEEDEFEFDEEF</span><br><span class="line">还原成原本的内容 : </span><br><span class="line">DDEDFFDE</span><br></pre></td></tr></table></figure><br><h5 id="用Java实现客户端与服务端"><a href="#用Java实现客户端与服务端" class="headerlink" title="用Java实现客户端与服务端"></a>用Java实现客户端与服务端</h5><ul><li><h6 id="客户端"><a href="#客户端" class="headerlink" title="客户端"></a>客户端</h6></li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Java Code for Byte_Stuffing Sender</span></span><br><span class="line"><span class="keyword">package</span> byte_stuffing;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.util.*;</span><br><span class="line"><span class="keyword">import</span> java.net.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Byte_Stuffing_Client</span> {</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String args[])</span> <span class="keyword">throws</span> IOException</span><br><span class="line">{</span><br><span class="line"><span class="type">InetAddress</span> <span class="variable">ip</span> <span class="operator">=</span> InetAddress.getLocalHost();</span><br><span class="line"><span class="type">int</span> <span class="variable">port</span> <span class="operator">=</span> <span class="number">45678</span>;</span><br><span class="line"><span class="type">Scanner</span> <span class="variable">sc</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Scanner</span>(System.in);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Opens a socket for connection</span></span><br><span class="line"><span class="type">Socket</span> <span class="variable">s</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Socket</span>(ip, port);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Declaring I/O Streams</span></span><br><span class="line"><span class="type">DataInputStream</span> <span class="variable">dis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataInputStream</span>(s.getInputStream());</span><br><span class="line"><span class="type">DataOutputStream</span> <span class="variable">dos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataOutputStream</span>(s.getOutputStream());</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line">System.out.println(<span class="string">"Enter the Message to be Sent : "</span>);</span><br><span class="line"><span class="type">String</span> <span class="variable">data</span> <span class="operator">=</span> sc.nextLine();</span><br><span class="line"><span class="type">String</span> <span class="variable">res</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Data in each frame is stuffed by 'F' at beginning and end</span></span><br><span class="line">data = <span class="string">'F'</span> + data + <span class="string">'F'</span>;</span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < data.length(); i++) {</span><br><span class="line"></span><br><span class="line"><span class="comment">// Stuff with 'E' if 'F' is found in the data to be sent</span></span><br><span class="line"><span class="keyword">if</span> (data.charAt(i) == <span class="string">'F'</span> && i != <span class="number">0</span> && i != (data.length() - <span class="number">1</span>))</span><br><span class="line">res = res + <span class="string">'E'</span> + data.charAt(i);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Stuff with 'E' if 'E' is found in the data to be sent</span></span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (data.charAt(i) == <span class="string">'E'</span>)</span><br><span class="line">res = res + <span class="string">'E'</span> + data.charAt(i);</span><br><span class="line"><span class="keyword">else</span></span><br><span class="line">res = res + data.charAt(i);</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line">System.out.println(<span class="string">"The data being sent (with byte stuffed) is : "</span> + res);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Send the data to the receiver</span></span><br><span class="line">dos.writeUTF(res);</span><br><span class="line">System.out.println(<span class="string">"Seding Message...."</span>);</span><br><span class="line"><span class="keyword">if</span> (dis.readUTF().equals(<span class="string">"success"</span>))</span><br><span class="line">System.out.println(<span class="string">"Thanks for the Feedback Server!!"</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// End Messaging</span></span><br><span class="line">dos.writeUTF(<span class="string">"bye"</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Close all connections</span></span><br><span class="line">s.close();</span><br><span class="line">dis.close();</span><br><span class="line">dos.close();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br><ul><li><h6 id="服务端"><a href="#服务端" class="headerlink" title="服务端"></a>服务端</h6></li></ul><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">// Java code for Byte_Stuffing Receiver</span></span><br><span class="line"><span class="keyword">package</span> byte_stuffing;</span><br><span class="line"><span class="keyword">import</span> java.io.*;</span><br><span class="line"><span class="keyword">import</span> java.net.*;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Byte_Stuffing</span> {</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException</span><br><span class="line">{</span><br><span class="line"><span class="comment">// Opens a socket for connection</span></span><br><span class="line"><span class="type">ServerSocket</span> <span class="variable">servsock</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ServerSocket</span>(<span class="number">45678</span>);</span><br><span class="line"></span><br><span class="line"><span class="comment">// Used to block until a client connects to the server</span></span><br><span class="line"><span class="type">Socket</span> <span class="variable">socket</span> <span class="operator">=</span> servsock.accept();</span><br><span class="line"></span><br><span class="line"><span class="comment">// Declaring I/O Streams</span></span><br><span class="line"><span class="type">DataInputStream</span> <span class="variable">dis</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataInputStream</span>(socket.getInputStream());</span><br><span class="line"><span class="type">DataOutputStream</span> <span class="variable">dos</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">DataOutputStream</span>(socket.getOutputStream());</span><br><span class="line"></span><br><span class="line"><span class="keyword">while</span> (<span class="literal">true</span>) {</span><br><span class="line"><span class="type">String</span> <span class="variable">out</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">String</span>();</span><br><span class="line"><span class="comment">// Used to read the data sent by client</span></span><br><span class="line"><span class="type">String</span> <span class="variable">res</span> <span class="operator">=</span> dis.readUTF();</span><br><span class="line">System.out.println(<span class="string">"Message Received...Successfully!!!"</span>);</span><br><span class="line">System.out.println(<span class="string">"The Stuffed Message is : "</span> + res);</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">1</span>; i < res.length() - <span class="number">1</span>; i++) {</span><br><span class="line"></span><br><span class="line"><span class="comment">// If data contains a 'D' or 'F' do not unstuff it</span></span><br><span class="line"><span class="keyword">if</span> (res.charAt(i) == <span class="string">'D'</span> || res.charAt(i) == <span class="string">'F'</span>)</span><br><span class="line">out = out + res.charAt(i);</span><br><span class="line"></span><br><span class="line"><span class="comment">// If data contains 'E' followed by 'E', de-stuff the former 'E'</span></span><br><span class="line"><span class="keyword">else</span> <span class="keyword">if</span> (res.charAt(i) == <span class="string">'E'</span> && res.charAt(i + <span class="number">1</span>) == <span class="string">'E'</span>) {</span><br><span class="line">out = out + <span class="string">'E'</span>;</span><br><span class="line">i++;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line">System.out.println(<span class="string">"The Destuffed Message is : "</span> + out);</span><br><span class="line">dos.writeUTF(<span class="string">"success"</span>);</span><br><span class="line"><span class="type">String</span> <span class="variable">ch</span> <span class="operator">=</span> dis.readUTF();</span><br><span class="line"><span class="keyword">if</span> (ch.equals(<span class="string">"bye"</span>)) {</span><br><span class="line">System.out.println(<span class="string">"Messaging is over.....EXITING"</span>);</span><br><span class="line"><span class="keyword">break</span>;</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="comment">// Closing all connections</span></span><br><span class="line">socket.close();</span><br><span class="line">dis.close();</span><br><span class="line">dos.close();</span><br><span class="line">}</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这里要注意一点,服务端应该先于客户端启动,因为服务端要先开启一个socket客户端才能进行连接</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2015/08/23/Byte-Stuffing-using-Java/">https://oldmee.github.io/2015/08/23/Byte-Stuffing-using-Java/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p>在数据链路层中,帧的大小各式各样,怎样把不同的帧区分开来?</p>
<p><code>字节填充</code>就是用来干这个事情的。它的实现原理很简单,就是在每个帧的开头和结尾加上一个8位的标识<code>F</code>,用这个标识来区分每一个帧。</p>
<p>那么问题来</summary>
</entry>
<entry>
<title>记一次多租户下http请求被503的应对过程</title>
<link href="https://oldmee.github.io/2021/01/17/multitenancy-503/"/>
<id>https://oldmee.github.io/2021/01/17/multitenancy-503/</id>
<published>2021-01-17T06:12:00.000Z</published>
<updated>2023-05-19T13:00:57.915Z</updated>
<content type="html"><![CDATA[<p>起因,因为获取数据的服务跟本服务无法在同一个注册中心下,于是没法走RPC只能http调用,这不可避免的会走到nginx上,于是引发了限流,导致503错误</p><span id="more"></span><h3 id="第一次改进"><a href="#第一次改进" class="headerlink" title="第一次改进"></a>第一次改进</h3><p>设置随机缓存时间,从1800秒到3600秒,方法开始判断缓存是否存在,方法结束将最新值写入缓存中,如果http调用数据为空则直接返回默认值而不会走到方法最后设置缓存了。<br>原本运行良好,没有任何异常,结果http被调用接口改了一个需求挂了,导致每次http调用拿到的值都为空,导致每次都没有设置缓存,于是每次都会不停调用http方法,结果就是,Kibana上半个小时打印了将近一万六千次异常日志……</p><h3 id="第二次改进"><a href="#第二次改进" class="headerlink" title="第二次改进"></a>第二次改进</h3><p>有了这个漏洞后只想弥补这个漏洞,于是加了一个状态,就是如果从http调用中返回空值,那么这个状态就开启,设置个过期时间,状态打开后请求就直接返回默认值,而不会走http了。但是忽略了一种情况,那就是同时很多请求过来,缓存此时已经过期,那么这些请求还是会跳过缓存而打到http请求上去。</p><h3 id="第三次改进"><a href="#第三次改进" class="headerlink" title="第三次改进"></a>第三次改进</h3><p>缓存改为写更新,有一个定时器,每10分钟执行一次,调用http请求,将最新的数据更新到缓存中,这样写完以后发现时不时就是一个503,感觉又回到解放前了,查询日志发现是因为请求后面带的随机参数是<code>System.currentTimeMillis()</code>,最细粒度是毫秒,所以会有那么多重复请求,于是想着把<code>System.currentTimeMillis()</code>改成<code>System.nanoTime()</code>,纳秒总不会有重复值的情况了吧,改完了一部署,发现还是503,头疼……</p><h3 id="第四次改进"><a href="#第四次改进" class="headerlink" title="第四次改进"></a>第四次改进</h3><p>灵机一动,想到服务器节点达到22个之多,每到时间定时任务就在22个节点上执行,其实只要一个节点运行就可以了嘛,于是果断找到问题,用redis的<code>setIfAbsent</code>控制每次只会在一个节点上执行定时任务即可,改完之后果然没再出现503</p><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2021/01/17/multitenancy-503/">https://oldmee.github.io/2021/01/17/multitenancy-503/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。转载请注明出处!</p></blockquote>]]></content>
<summary type="html"><p>起因,因为获取数据的服务跟本服务无法在同一个注册中心下,于是没法走RPC只能http调用,这不可避免的会走到nginx上,于是引发了限流,导致503错误</p></summary>
</entry>
<entry>
<title>mybatis索引越界问题</title>
<link href="https://oldmee.github.io/2020/09/06/mybatis-indexOutOfBoundsException/"/>
<id>https://oldmee.github.io/2020/09/06/mybatis-indexOutOfBoundsException/</id>
<published>2020-09-06T08:44:00.000Z</published>
<updated>2023-09-06T09:46:33.771Z</updated>
<content type="html"><![CDATA[<h3 id="导火索"><a href="#导火索" class="headerlink" title="导火索"></a>导火索</h3><p>最近碰到了一个很诡异的问题,通过<code>mybatis</code>原生的<code>selectList</code>正常查询数据库,结果<code>mybatis</code>报了一个<code>indexOutOfBoundsException</code>的异常,百思不得其解,为啥查询会导致索引越界呢?</p><blockquote><p>主要原因就在于<code>lombok</code>的一个注解<code>@Builder</code>,以及<code>@TableField(exist=false)</code>,导致查询后回填数据到实体异常</p></blockquote><h3 id="原因"><a href="#原因" class="headerlink" title="原因"></a>原因</h3><p>读了一下mybatis源码,主要起因是<code>DefaultResultSetHandler</code>类中的<code>createResultObject</code>方法,里面有一堆条件判断,主要是最后两个条件判断,当类有默认构造器与没有默认构造器执行的逻辑是不一样的:</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Object <span class="title function_">createResultObject</span><span class="params">(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes,</span></span><br><span class="line"><span class="params"> List<Object> constructorArgs, String columnPrefix)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="keyword">final</span> Class<?> resultType = resultMap.getType();</span><br><span class="line"> <span class="keyword">final</span> <span class="type">MetaClass</span> <span class="variable">metaType</span> <span class="operator">=</span> MetaClass.forClass(resultType, reflectorFactory);</span><br><span class="line"> <span class="keyword">final</span> List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();</span><br><span class="line"> <span class="keyword">if</span> (hasTypeHandlerForResultObject(rsw, resultType)) {</span><br><span class="line"> <span class="keyword">return</span> createPrimitiveResultObject(rsw, resultMap, columnPrefix);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (!constructorMappings.isEmpty()) {</span><br><span class="line"> <span class="keyword">return</span> createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs,</span><br><span class="line"> columnPrefix);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (resultType.isInterface() || metaType.hasDefaultConstructor()) {</span><br><span class="line"> <span class="comment">// 不加@Builder注解会走此逻辑</span></span><br><span class="line"> <span class="keyword">return</span> objectFactory.create(resultType);</span><br><span class="line"> } <span class="keyword">else</span> <span class="keyword">if</span> (shouldApplyAutomaticMappings(resultMap, <span class="literal">false</span>)) {</span><br><span class="line"> <span class="comment">// 加了@Builder后默认构造器被替换为了一个全参的构造器,于是</span></span><br><span class="line"> <span class="comment">// 就不会走上面的逻辑了</span></span><br><span class="line"> <span class="keyword">return</span> createByConstructorSignature(rsw, resultMap, columnPrefix, resultType, constructorArgTypes,</span><br><span class="line"> constructorArgs);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">ExecutorException</span>(<span class="string">"Do not know how to create an instance of "</span> + resultType);</span><br><span class="line"> }</span><br><span class="line"></span><br></pre></td></tr></table></figure><h5 id="createByConstructorSignature方法跟进去就能看到真正报错的地方"><a href="#createByConstructorSignature方法跟进去就能看到真正报错的地方" class="headerlink" title="createByConstructorSignature方法跟进去就能看到真正报错的地方"></a><code>createByConstructorSignature</code>方法跟进去就能看到真正报错的地方</h5><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> Object <span class="title function_">createUsingConstructor</span><span class="params">(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor)</span> <span class="keyword">throws</span> SQLException {</span><br><span class="line"> <span class="type">boolean</span> <span class="variable">foundValues</span> <span class="operator">=</span> <span class="literal">false</span>;</span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i < constructor.getParameterTypes().length; i++) {</span><br><span class="line"> Class<?> parameterType = constructor.getParameterTypes()[i];</span><br><span class="line"> <span class="comment">// 就是这一行报的错</span></span><br><span class="line"> <span class="type">String</span> <span class="variable">columnName</span> <span class="operator">=</span> rsw.getColumnNames().get(i);</span><br><span class="line"> TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);</span><br><span class="line"> <span class="type">Object</span> <span class="variable">value</span> <span class="operator">=</span> typeHandler.getResult(rsw.getResultSet(), columnName);</span><br><span class="line"> constructorArgTypes.add(parameterType);</span><br><span class="line"> constructorArgs.add(value);</span><br><span class="line"> foundValues = value != <span class="literal">null</span> || foundValues;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : <span class="literal">null</span>;</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><p>因为<code>rsw.getColumnNames</code>拿到的是实体对应表的字段数量,而<code>constructor.getParameterTypes().length</code>拿到的是实体全字段的数量(其中包括了<code>@TableField(exist=false)</code>修饰的字段),所以导致<code>get(i)</code>的越界而抛出<code>indexOutOfBoundsException</code>的异常</p><h3 id="结论"><a href="#结论" class="headerlink" title="结论"></a>结论</h3><p>我碰到的是这种情况,但是我在网上并没有找到原因,网文只是告诉你加上无参的构造器就行,而并没有分析源码解释问题,很多时候原因比答案更重要</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2020/09/06/mybatis-indexOutOfBoundsException/">https://oldmee.github.io/2020/09/06/mybatis-indexOutOfBoundsException/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><h3 id="导火索"><a href="#导火索" class="headerlink" title="导火索"></a>导火索</h3><p>最近碰到了一个很诡异的问题,通过<code>mybatis</code>原生的<code>selectList</code>正常查询</summary>
</entry>
<entry>
<title>lee's-algorithm</title>
<link href="https://oldmee.github.io/2020/06/22/lee-s-algorithm/"/>
<id>https://oldmee.github.io/2020/06/22/lee-s-algorithm/</id>
<published>2020-06-22T03:52:00.000Z</published>
<updated>2023-08-22T04:39:02.029Z</updated>
<content type="html"><![CDATA[<blockquote><p>居然有个算法叫lee,跟我的英文名一样,如此的亲切,当然要了解一下</p></blockquote><br><p>场景是二位矩阵(一些点是1,另一些是0,只有为1的点可以通过),然后给定一个起点和一个终点,算出起点到终点的最短距离</p><p>算法的核心其实也很简单,就是每一个点我尽量都去走一走,就像多条路线一起出发,看哪个先到,那么这条路径就是最短路径,可能唯一巧妙的地方就在于这个<code>多条路线一起出发</code>,关键是要这多条路径交替进行,就像以前的<code>《仙剑奇侠传》</code>那种回合制的游戏,你一下我一下,作者在算法中用到了队列这种数据结构,巧妙的实现了交替运行的逻辑:从队列头部拿出需要执行的点,再将这个点上下左右四个方向可达的点放到队列的尾部,直到找到目标或者没有可达路径而最终退出程序。</p><br><h4 id="算法实现步骤"><a href="#算法实现步骤" class="headerlink" title="算法实现步骤"></a>算法实现步骤</h4><ol><li><p>创建一个空队列,然后将起点入队,并且把距离记录为0,然后把节点的访问状态设置为已访问(需要一个同样的二维数组记录对应节点的访问状态)</p></li><li><p>一直循环直到队列为空</p><ol><li>从队列的头部出队一个节点</li><li>如果这个节点是目标节点,则返回它的距离</li><li>否则,对于当前节点的四个相邻节点(上下左右)进行判断,如果是合法(值是1而且未被访问)的那么就进行入队,并且把距离加1,访问状态设置为已访问</li></ol></li><li><p>如果所有的节点都执行过依然没有找到目标节点,说明目标节点不可达</p></li></ol><br><h6 id="下面是c-的具体代码实现"><a href="#下面是c-的具体代码实现" class="headerlink" title="下面是c++的具体代码实现"></a>下面是c++的具体代码实现</h6><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><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">"library.h"</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><iostream></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><queue></span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string"><vector></span></span></span><br><span class="line"></span><br><span class="line">using namespace <span class="built_in">std</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// A Queue Node</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Node</span> {</span></span><br><span class="line"> <span class="comment">// (x, y) represents matrix cell coordinates, and</span></span><br><span class="line"> <span class="comment">// `dist` represents their minimum distance from the source</span></span><br><span class="line"> <span class="type">int</span> x, y, dist;</span><br><span class="line">};</span><br><span class="line"></span><br><span class="line"><span class="comment">// Function to check if it is possible to go to position (row, col)</span></span><br><span class="line"><span class="comment">// from the current position. The function returns false if (row, col)</span></span><br><span class="line"><span class="comment">// is not a valid position or has a value 0 or already visited.</span></span><br><span class="line"><span class="type">bool</span> <span class="title function_">isValid</span><span class="params">(<span class="built_in">vector</span><<span class="built_in">vector</span><<span class="type">int</span>>> <span class="type">const</span> &mat, <span class="built_in">vector</span><<span class="built_in">vector</span><<span class="type">bool</span>>> &visited,</span></span><br><span class="line"><span class="params"> <span class="type">int</span> row, <span class="type">int</span> col)</span> {</span><br><span class="line"> <span class="keyword">return</span> (row >= <span class="number">0</span> && row < mat.size()) && (col >= <span class="number">0</span> && col < mat[<span class="number">0</span>].size())</span><br><span class="line"> && mat[row][col] && !visited[row][col];</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">findShortestPathLength</span><span class="params">(<span class="built_in">vector</span><<span class="built_in">vector</span><<span class="type">int</span>>> &mat, <span class="built_in">pair</span><<span class="type">int</span>, <span class="type">int</span>> &src, <span class="built_in">pair</span><<span class="type">int</span>, <span class="type">int</span>> &dest)</span> {</span><br><span class="line"> <span class="comment">// base case: invalid input</span></span><br><span class="line"> <span class="keyword">if</span> (mat.size() == <span class="number">0</span> || mat[src.first][src.second] == <span class="number">0</span> ||</span><br><span class="line"> mat[dest.first][dest.second] == <span class="number">0</span>) {</span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// `M × N` matrix</span></span><br><span class="line"> <span class="type">int</span> M = mat.size();</span><br><span class="line"> <span class="type">int</span> N = mat[<span class="number">0</span>].size();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 上左右下 四个方向</span></span><br><span class="line"> <span class="type">int</span> row[] = {<span class="number">-1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>};</span><br><span class="line"> <span class="type">int</span> col[] = {<span class="number">0</span>, <span class="number">-1</span>, <span class="number">1</span>, <span class="number">0</span>};</span><br><span class="line"></span><br><span class="line"> <span class="built_in">queue</span><Node> q;</span><br><span class="line"> <span class="comment">// get source cell (i, j)</span></span><br><span class="line"> <span class="type">int</span> i = src.first;</span><br><span class="line"> <span class="type">int</span> j = src.second;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// construct a `M × N` matrix to keep track of visited cells</span></span><br><span class="line"> <span class="built_in">vector</span><<span class="built_in">vector</span><<span class="type">bool</span>>> visited;</span><br><span class="line"> visited.resize(M, <span class="built_in">vector</span><<span class="type">bool</span>>(N));</span><br><span class="line"></span><br><span class="line"> <span class="comment">// mark the source cell as visited and enqueue the source node</span></span><br><span class="line"> visited[i][j] = <span class="literal">true</span>;</span><br><span class="line"> q.push({i, j, <span class="number">0</span>});</span><br><span class="line"></span><br><span class="line"> <span class="comment">// stores length of the longest path from source to destination</span></span><br><span class="line"> <span class="type">int</span> min_dist = INT_MAX;</span><br><span class="line"></span><br><span class="line"> <span class="keyword">while</span> (!q.empty()) {</span><br><span class="line"> <span class="comment">// dequeue front node and process it</span></span><br><span class="line"> Node node = q.front();</span><br><span class="line"> q.pop();</span><br><span class="line"></span><br><span class="line"> <span class="comment">// (i, j) represents a current cell, and `dist` stores its</span></span><br><span class="line"> <span class="comment">// minimum distance from the source</span></span><br><span class="line"> <span class="type">int</span> i = node.x, j = node.y, dist = node.dist;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// if the destination is found, update `min_dist` and stop</span></span><br><span class="line"> <span class="keyword">if</span> (i == dest.first && j == dest.second)</span><br><span class="line"> {</span><br><span class="line"> min_dist = dist;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// check for all four possible movements from the current cell</span></span><br><span class="line"> <span class="comment">// and enqueue each valid movement</span></span><br><span class="line"> <span class="keyword">for</span> (<span class="type">int</span> k = <span class="number">0</span>; k < <span class="number">4</span>; k++)</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// check if it is possible to go to position</span></span><br><span class="line"> <span class="comment">// (i + row[k], j + col[k]) from current position</span></span><br><span class="line"> <span class="keyword">if</span> (isValid(mat, visited, i + row[k], j + col[k]))</span><br><span class="line"> {</span><br><span class="line"> <span class="comment">// mark next cell as visited and enqueue it</span></span><br><span class="line"> visited[i + row[k]][j + col[k]] = <span class="literal">true</span>;</span><br><span class="line"> q.push({ i + row[k], j + col[k], dist + <span class="number">1</span> });</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (min_dist != INT_MAX) {</span><br><span class="line"> <span class="keyword">return</span> min_dist;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">}</span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">()</span> {</span><br><span class="line"> <span class="built_in">vector</span><<span class="built_in">vector</span><<span class="type">int</span>>> mat =</span><br><span class="line"> {</span><br><span class="line"> { <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span> },</span><br><span class="line"> { <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">1</span> },</span><br><span class="line"> { <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span>, <span class="number">1</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">1</span> },</span><br><span class="line"> };</span><br><span class="line"></span><br><span class="line"> <span class="built_in">pair</span><<span class="type">int</span>, <span class="type">int</span>> src = <span class="built_in">make_pair</span>(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"> <span class="built_in">pair</span><<span class="type">int</span>, <span class="type">int</span>> dest = <span class="built_in">make_pair</span>(<span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line"></span><br><span class="line"> <span class="type">int</span> min_dist = findShortestPathLength(mat, src, dest);</span><br><span class="line"> <span class="keyword">if</span> (min_dist != <span class="number">-1</span>)</span><br><span class="line"> {</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"The shortest path from source to destination "</span></span><br><span class="line"> <span class="string">"has length "</span> << min_dist;</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">else</span> {</span><br><span class="line"> <span class="built_in">cout</span> << <span class="string">"Destination cannot be reached from a given source"</span>;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2020/06/22/lee-s-algorithm/">https://oldmee.github.io/2020/06/22/lee-s-algorithm/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><blockquote>
<p>居然有个算法叫lee,跟我的英文名一样,如此的亲切,当然要了解一下</p>
</blockquote>
<br>
<p>场景是二位矩阵(一些点是1,另一些是0,只有为1的点可以通过),然后给定一个起点和一个终点,算出起点到终点的最短距离</p>
</summary>
<category term="algorithm" scheme="https://oldmee.github.io/categories/algorithm/"/>
<category term="algorithm" scheme="https://oldmee.github.io/tags/algorithm/"/>
</entry>
<entry>
<title>JavaScript最佳实践</title>
<link href="https://oldmee.github.io/2020/04/08/JavaScript-best-practices/"/>
<id>https://oldmee.github.io/2020/04/08/JavaScript-best-practices/</id>
<published>2020-04-08T11:54:00.000Z</published>
<updated>2023-08-19T13:42:25.476Z</updated>
<content type="html"><![CDATA[<p>鉴于公司JavaScript写的千奇百怪,整理一篇规范以便参考</p><span id="more"></span><p>Avoid global variables, avoid new, avoid ==, avoid eval()</p><h3 id="Avoid-Global-Variables"><a href="#Avoid-Global-Variables" class="headerlink" title="Avoid Global Variables"></a>Avoid Global Variables</h3><p>Minimize the use of global variables.</p><p>This includes all data types, objects, and functions.</p><p>Global variables and functions can be overwritten by other scripts.</p><p>Use local variables instead, and learn how to use closures.</p><h3 id="Always-Declare-Local-Variables"><a href="#Always-Declare-Local-Variables" class="headerlink" title="Always Declare Local Variables"></a>Always Declare Local Variables</h3><p>All variables used in a function should be declared as local variables.</p><p>Local variables must be declared with the var, the let, or the const keyword, otherwise they will become global variables.</p><p>Strict mode does not allow undeclared variables.</p><h3 id="Declarations-on-Top"><a href="#Declarations-on-Top" class="headerlink" title="Declarations on Top"></a>Declarations on Top</h3><p>It is a good coding practice to put all declarations at the top of each script or function.</p><p>This will:</p><p>Give cleaner code<br><br>Provide a single place to look for local variables<br><br>Make it easier to avoid unwanted (implied) global variables<br><br>Reduce the possibility of unwanted re-declarations<br><br>// Declare at the beginning<br><br>let firstName, lastName, price, discount, fullPrice;</p><p>// Use later</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">firstName = "John";</span><br><span class="line">lastName = "Doe";</span><br><span class="line"></span><br><span class="line">price = 19.90;</span><br><span class="line">discount = 0.10;</span><br><span class="line"></span><br><span class="line">fullPrice = price - discount;</span><br><span class="line">This also goes for loop variables:</span><br><span class="line"></span><br><span class="line">for (let i = 0; i < 5; i++) {}</span><br></pre></td></tr></table></figure><h3 id="Initialize-Variables"><a href="#Initialize-Variables" class="headerlink" title="Initialize Variables"></a>Initialize Variables</h3><p>It is a good coding practice to initialize variables when you declare them.</p><p>This will:</p><p>Give cleaner code<br>Provide a single place to initialize variables</p><p>Avoid undefined values<br><br>// Declare and initiate at the beginning</p><figure class="highlight plaintext"><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">let firstName = "";</span><br><span class="line">let lastName = "";</span><br><span class="line">let price = 0;</span><br><span class="line">let discount = 0;</span><br><span class="line">let fullPrice = 0,</span><br><span class="line">const myArray = [];</span><br><span class="line">const myObject = {};</span><br></pre></td></tr></table></figure><p>Initializing variables provides an idea of the intended use (and intended data type).</p><h3 id="Declare-Objects-with-const"><a href="#Declare-Objects-with-const" class="headerlink" title="Declare Objects with const"></a>Declare Objects with const</h3><p>Declaring objects with const will prevent any accidental change of type:</p><p>Example<br><br>let car = {type:”Fiat”, model:”500”, color:”white”};<br><br>car = “Fiat”; // Changes object to string</p><p>const car = {type:”Fiat”, model:”500”, color:”white”};<br><br>car = “Fiat”; // Not possible</p><h3 id="Declare-Arrays-with-const"><a href="#Declare-Arrays-with-const" class="headerlink" title="Declare Arrays with const"></a>Declare Arrays with const</h3><p>Declaring arrays with const will prevent any accidential change of type:</p><p>Example<br>let cars = [“Saab”, “Volvo”, “BMW”];<br>cars = 3; // Changes array to number</p><p>const cars = [“Saab”, “Volvo”, “BMW”];<br>cars = 3; // Not possible</p><h3 id="Don’t-Use-new-Object"><a href="#Don’t-Use-new-Object" class="headerlink" title="Don’t Use new Object()"></a>Don’t Use new Object()</h3><p>Use “” instead of new String()<br><br>Use 0 instead of new Number()<br><br>Use false instead of new Boolean()<br><br>Use {} instead of new Object()<br><br>Use [] instead of new Array()<br><br>Use /()/ instead of new RegExp()<br><br>Use function (){} instead of new Function()<br><br>Example</p><figure class="highlight plaintext"><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">let x1 = ""; // new primitive string</span><br><span class="line">let x2 = 0; // new primitive number</span><br><span class="line">let x3 = false; // new primitive boolean</span><br><span class="line">const x4 = {}; // new object</span><br><span class="line">const x5 = []; // new array object</span><br><span class="line">const x6 = /()/; // new regexp object</span><br><span class="line">const x7 = function(){}; // new function object</span><br></pre></td></tr></table></figure><h3 id="Beware-of-Automatic-Type-Conversions"><a href="#Beware-of-Automatic-Type-Conversions" class="headerlink" title="Beware of Automatic Type Conversions"></a>Beware of Automatic Type Conversions</h3><p>JavaScript is loosely typed.</p><p>A variable can contain all data types.</p><p>A variable can change its data type:</p><p>Example</p><figure class="highlight plaintext"><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">let x = "Hello"; // typeof x is a string</span><br><span class="line">x = 5; // changes typeof x to a number</span><br></pre></td></tr></table></figure><p>Beware that numbers can accidentally be converted to strings or NaN (Not a Number).<br></p><p>When doing mathematical operations, JavaScript can convert numbers to strings:<br></p><p>Example</p><figure class="highlight plaintext"><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">let x = 5 + 7; // x.valueOf() is 12, typeof x is a number</span><br><span class="line">let x = 5 + "7"; // x.valueOf() is 57, typeof x is a string</span><br><span class="line">let x = "5" + 7; // x.valueOf() is 57, typeof x is a string</span><br><span class="line">let x = 5 - 7; // x.valueOf() is -2, typeof x is a number</span><br><span class="line">let x = 5 - "7"; // x.valueOf() is -2, typeof x is a number</span><br><span class="line">let x = "5" - 7; // x.valueOf() is -2, typeof x is a number</span><br><span class="line">let x = 5 - "x"; // x.valueOf() is NaN, typeof x is a number</span><br></pre></td></tr></table></figure><p>Subtracting a string from a string, does not generate an error but returns <br>NaN (Not a Number):</p><p>Example<br><br>“Hello” - “Dolly” // returns NaN</p><h3 id="Use-x3D-x3D-x3D-Comparison"><a href="#Use-x3D-x3D-x3D-Comparison" class="headerlink" title="Use === Comparison"></a>Use === Comparison</h3><p>The == comparison operator always converts (to matching types) before comparison.</p><p>The === operator forces comparison of values and type:</p><p>Example</p><figure class="highlight plaintext"><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">0 == ""; // true</span><br><span class="line">1 == "1"; // true</span><br><span class="line">1 == true; // true</span><br><span class="line"></span><br><span class="line">0 === ""; // false</span><br><span class="line">1 === "1"; // false</span><br><span class="line">1 === true; // false</span><br></pre></td></tr></table></figure><h3 id="Use-Parameter-Defaults"><a href="#Use-Parameter-Defaults" class="headerlink" title="Use Parameter Defaults"></a>Use Parameter Defaults</h3><p>If a function is called with a missing argument, the value of the missing argument is set to undefined.<br></p><p>Undefined values can break your code. It is a good habit to assign default values to arguments.<br></p><p>Example</p><figure class="highlight plaintext"><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">function myFunction(x, y) {</span><br><span class="line"> if (y === undefined) {</span><br><span class="line"> y = 0;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>ECMAScript 2015 allows default parameters in the function definition:<br></p><p>function (a=1, b=1) { /<em>function code</em>/ }<br><br>Read more about function parameters and arguments at Function Parameters<br></p><h3 id="End-Your-Switches-with-Defaults"><a href="#End-Your-Switches-with-Defaults" class="headerlink" title="End Your Switches with Defaults"></a>End Your Switches with Defaults</h3><p>Always end your switch statements with a default. Even if you think there is no need for it.<br></p><p>Example<br></p><figure class="highlight javascript"><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="keyword">switch</span> (<span class="keyword">new</span> <span class="title class_">Date</span>().<span class="title function_">getDay</span>()) {</span><br><span class="line"> <span class="keyword">case</span> <span class="number">0</span>:</span><br><span class="line"> day = <span class="string">"Sunday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">1</span>:</span><br><span class="line"> day = <span class="string">"Monday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">2</span>:</span><br><span class="line"> day = <span class="string">"Tuesday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">3</span>:</span><br><span class="line"> day = <span class="string">"Wednesday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">4</span>:</span><br><span class="line"> day = <span class="string">"Thursday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">5</span>:</span><br><span class="line"> day = <span class="string">"Friday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="keyword">case</span> <span class="number">6</span>:</span><br><span class="line"> day = <span class="string">"Saturday"</span>;</span><br><span class="line"> <span class="keyword">break</span>;</span><br><span class="line"> <span class="attr">default</span>:</span><br><span class="line"> day = <span class="string">"Unknown"</span>;</span><br><span class="line">}</span><br></pre></td></tr></table></figure><h3 id="Avoid-Number-String-and-Boolean-as-Objects"><a href="#Avoid-Number-String-and-Boolean-as-Objects" class="headerlink" title="Avoid Number, String, and Boolean as Objects"></a>Avoid Number, String, and Boolean as Objects</h3><p>Always treat numbers, strings, or booleans as primitive values. Not as objects.</p><p>Declaring these types as objects, slows down execution speed, and produces nasty side effects:</p><p>Example</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">let x = "John"; </span><br><span class="line">let y = new String("John");</span><br><span class="line">(x === y) // is false because x is a string and y is an object.</span><br></pre></td></tr></table></figure><p>Or even worse:</p><p>Example</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">let x = new String("John"); </span><br><span class="line">let y = new String("John");</span><br><span class="line">(x == y) // is false because you cannot compare objects.</span><br></pre></td></tr></table></figure><h3 id="Avoid-Using-eval"><a href="#Avoid-Using-eval" class="headerlink" title="Avoid Using eval()"></a>Avoid Using eval()</h3><p>The eval() function is used to run text as code. In almost all cases, it should not be necessary to use it.</p><p>Because it allows arbitrary code to be run, it also represents a security problem.</p><br><blockquote><p>本文作者:oldmee<br>本文链接:<a href="https://oldmee.github.io/2020/04/08/JavaScript-best-practices/">https://oldmee.github.io/2020/04/08/JavaScript-best-practices/</a><br>版权声明:本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/">CC BY-NC-SA 4.0</a> 许可协议。</p></blockquote>]]></content>
<summary type="html"><p>鉴于公司JavaScript写的千奇百怪,整理一篇规范以便参考</p></summary>
</entry>
<entry>
<title>websocket</title>
<link href="https://oldmee.github.io/2019/04/04/websocket/"/>
<id>https://oldmee.github.io/2019/04/04/websocket/</id>
<published>2019-04-04T02:46:52.000Z</published>
<updated>2023-08-08T08:18:11.334Z</updated>
<content type="html"><![CDATA[<p>现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。</p><p>HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。<br><img src="/images/ws.png"></p><span id="more"></span><p>Websocket协议是为了解决web即时应用中服务器与客户端浏览器全双工通信的问题而设计的,是完全意义上的Web应用端的双向通信技术,可以取代之前使用半双工HTTP协议而模拟全双工通信,同时克服了带宽和访问速度等的诸多问题。协议定义为ws和wss协议,分别为普通请求和基于SSL的安全传输,占用端口与http协议系统,ws为80端口,wss为443端口,这样可以支持HTTP代理。</p><p>协议包含两个部分,第一个是“握手”,第二个是数据传输。</p><h3 id="一、Websocket-URI"><a href="#一、Websocket-URI" class="headerlink" title="一、Websocket URI"></a>一、Websocket URI</h3><p>定义的两个协议框架ws和wss与http类似,而且各自部分的要求也是在HTTP协议中使用的一样,各自的URI如下:</p><p>ws-URI = “ws:” “//“ host [ “:” port ] path [ “?” query ]<br> wss-URI = “wss:” “//“ host [ “:” port ] path [ “?” query ]</p><p>其中port是可选项,query前接“?”。</p><h3 id="二、握手(Opening-amp-Closing-Handshake)打开连接"><a href="#二、握手(Opening-amp-Closing-Handshake)打开连接" class="headerlink" title="二、握手(Opening & Closing Handshake)打开连接"></a>二、握手(Opening & Closing Handshake)打开连接</h3><p>当建立一个Websocket连接时,为了保持基于HTTP协议的服务器软件和中间件进行兼容工作,客户端打开一个连接时使用与HTTP连接的同一个端口到服务器进行连接,这样被设计为一个升级的HTTP请求。</p><h4 id="1、发送握手请求"><a href="#1、发送握手请求" class="headerlink" title="1、发送握手请求"></a>1、发送握手请求</h4><p>此时的连接状态是CONNECTING,客户端需要提供host、port、resource-name和一个是否是安全连接的标记,也就是一个WebSocket URI。</p><p>客户端发送的一个到服务器端握手请求如下:</p><code> GET /chat HTTP/1.1 Host: server.example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Origin: http://example.com Sec-WebSocket-Protocol: chat, superchat Sec-WebSocket-Version: 13</code>这个升级的HTTP请求头中的字段顺序是可以随便的。与普通HTTP请求相比多了一些字段。<ul><li>Sec-WebSocket-Protocol:字段表示客户端可以接受的子协议类型,也就是在Websocket协议上的应用层协议类型。上面可以看到客户端支持chat和superchat两个应用层协议,当服务器接受到这个字段后要从中选出一个协议返回给客户端。</li><li>Upgrade:告诉服务器这个HTTP连接是升级的Websocket连接。</li><li>Connection:告知服务器当前请求连接是升级的。</li><li>Origin:该字段是用来防止客户端浏览器使用脚本进行未授权的跨源攻击,这个字段在WebSocket协议中非常重要。服务器要根据这个字段判断是否接受客户端的Socket连接。可以返回一个HTTP错误状态码来拒绝连接。</li><li>Sec-WebSocket-Key:为了表示服务器同意和客户端进行Socket连接,服务器端需要使用客户端发送的这个Key进行校验,然后返回一个校验过的字符串给客户端,客户端验证通过后才能正式建立Socket连接。服务器验证方法是:首先进行 Key + 全局唯一标示符(GUID)“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”连接起来,然后将连接起来的字符串使用SHA-1哈希加密,再进行base64加密,将得到的字符串返回给客户端作为握手依据。其中GUID是一个对于不识别WebSocket的网络端点不可能使用的字符串。</li></ul><p>发送请求的要求:</p><ul><li>请求的WebSocket URI必须要是定义的有效的URI。</li><li>如果客户端已经有一个WebSocket连接到远程服务器端,不论是否是同一个服务器,客户端必须要等待上一个连接关闭后才能发送新的连接请求,也就是同一客户端一次只能存在一个WebSocket连接。如果想同一个服务器有多个连接,客户端必须要串行化进行。如果客户端检测到多个到不同服务器的连接,应该限制一个最大连接数,在web浏览器中应该设定最多可以打开的标签页的数目。这样可以防止到远程服务器的DDOS攻击,但这是对到多个服务器的连接,如果是到同一个服务器连接,并没有数目限制。</li><li>如果使用了代理服务器,那么客户端建立连接的时候需要告知代理服务器向目标服务器打开TCP连接。</li><li>如果连接没有打开,一定是某一方出现错误,此时客户端必须要关闭再次连接的尝试。</li><li>连接建立后,握手必须要是一个有效的HTTP请求</li><li>请求的方式必须是GET,HTTP协议的版本至少是1.1</li><li>Upgrade字段必须包含而且必须是”websocket”,Connection字段必须内容必须是“Upgrade”</li><li>Sec-Websocket-Version必须,而且必须是13</li></ul><h4 id="2、返回握手应答"><a href="#2、返回握手应答" class="headerlink" title="2、返回握手应答"></a>2、返回握手应答</h4><p>服务器返回正确的相应头后,客户端验证后将建立连接,此时状态为OPEN。服务器响应头如下:<br><code><br> HTTP/1.1 101 Switching Protocols<br> Upgrade: websocket<br> Connection: Upgrade<br> Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=<br> Sec-WebSocket-Protocol: chat<br></code><br>响应头握手过程中是服务器返回的是否同意握手的依据。</p><ul><li>首行返回的是HTTP/1.1协议版本和状态码101,表示变换协议(Switching Protocol)</li><li>Upgrade 和 Connection:这两个字段是服务器返回的告知客户端同意使用升级并使用websocket协议,用来完善HTTP升级响应</li><li>Sec-WebSocket-Accept:服务器端将加密处理后的握手Key通过这个字段返回给客户端表示服务器同意握手建立连接。</li><li>Sec-Websocket-Procotol:服务器选择的一个应用层协议。<br>上述响应头字段被客户端浏览器解析,如果验证到Sec-WebSocket-Accept字段的信息符合要求就会建立连接,同时就可以发送WebSocket的数据帧了。如果该字段不符合要求或者为空或者HTTP状态码不为101,就不会建立连接。</li></ul><p>服务器端响应步骤:</p><ul><li>解析握手请求头:获取握手依据Key并进行处理,检测HTTP的GET请求和版本是否准确,Host字段是否有权限,Upgrade字段中websocket是一个与大小写无关的ASCII字符串,Connection字段是一个大小写无关的”Upgrade”ASCII字符串,Websocket协议版本必须为13,其他的关于Origin、Protocol和Extensions可选。</li><li>发送握手响应头:检测是否是wss协议连接,如果是就是用TLS握手连接,否则就是普通连接。服务器可以添加额外的验证信息到客户端进行验证。当进行一系列验证之后,服务器必须返回一个有效的HTTP响应头。响应头中每一行一个字段,结束必须为“\r\n”,使用的ABNF语法。</li></ul><p>除了上述必要头字段之外,其他的HTTP协议定义的字段都可以使用,如Set-Cookie等。</p><h3 id="WebSocket不实行同源政策"><a href="#WebSocket不实行同源政策" class="headerlink" title="WebSocket不实行同源政策"></a>WebSocket不实行同源政策</h3><p>WebSocket协议的目标是在一个独立的持久连接上提供全双工双向通信。客户端和服务器可以向对方主动发送和接受数据。在JS中创建WebSocket后,会有一个HTTP请求发向浏览器以发起请求。在取得服务器响应后,建立的连接会使用HTTP升级将HTTP协议转换为WebSocket协议。也就是说,使用标准的HTTP协议无法实现WebSocket,只有支持那些协议的专门浏览器才能正常工作。</p><p>由于WebScoket使用了自定义协议,所以URL与HTTP协议略有不同。未加密的连接为ws://,而不是http://。加密的连接为wss://,而不是https://。</p><p>WebSocket是应用层协议,是TCP/IP协议的子集,通过HTTP/1.1协议的101状态码进行握手。也就是说,WebSocket协议的建立需要先借助HTTP协议,在服务器返回101状态码之后,就可以进行websocket全双工双向通信了,就没有HTTP协议什么事情了。</p><p>HTTP/1.1 101 Switching Protocols:101状态码表示升级协议,在返回101状态码后,HTTP协议完成工作,转换为WebSocket协议。此时就可以进行全双工双向通信了。</p>]]></content>
<summary type="html"><p>现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。</p>
<p>HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。<br><img src="/images/ws.png"></p></summary>
</entry>
<entry>
<title>一秒钟搞懂webservice</title>
<link href="https://oldmee.github.io/2019/04/03/webservice/"/>
<id>https://oldmee.github.io/2019/04/03/webservice/</id>
<published>2019-04-03T09:42:00.000Z</published>
<updated>2019-04-04T02:28:27.000Z</updated>
<content type="html"><![CDATA[<blockquote><p>虽然现在都是http的api,但是有些老项目依然用的是webservice,如果碰到了也需要用webservice来调用。所以像这种可能会用到的知识,花一秒钟搞懂概念就行,用到的时候再说。</p></blockquote><span id="more"></span><h3 id="webservice(SOAP)与HTTP接口的区别"><a href="#webservice(SOAP)与HTTP接口的区别" class="headerlink" title="webservice(SOAP)与HTTP接口的区别"></a>webservice(SOAP)与HTTP接口的区别</h3><h4 id="什么是web-service?"><a href="#什么是web-service?" class="headerlink" title="什么是web service?"></a>什么是web service?</h4><p>soap请求是HTTP POST的一个专用版本,遵循一种特殊的xml消息格式Content-type设置为: text/xml任何数据都可以xml化。</p><h4 id="为什么要学习web-service?"><a href="#为什么要学习web-service?" class="headerlink" title="为什么要学习web service?"></a>为什么要学习web service?</h4><p>大多数对外接口会实现web service方法而不是http方法,如果你不会,那就没有办法对接。<br>web service相对http (post/get)有好处吗?</p><ol><li>接口中实现的方法和要求参数一目了然</li><li>不用担心大小写问题</li><li>不用担心中文urlencode问题</li><li>代码中不用多次声明认证(账号,密码)参数</li><li>传递参数可以为数组,对象等…</li></ol><h4 id="web-service相对http(post-x2F-get)快吗?"><a href="#web-service相对http(post-x2F-get)快吗?" class="headerlink" title="web service相对http(post/get)快吗?"></a>web service相对http(post/get)快吗?</h4><p>由于要进行xml解析,速度可能会有所降低。</p><h4 id="web-service-可以被http(post-x2F-get)替代吗?"><a href="#web-service-可以被http(post-x2F-get)替代吗?" class="headerlink" title="web service 可以被http(post/get)替代吗?"></a>web service 可以被http(post/get)替代吗?</h4><p>完全可以,而且现在的开放平台都是用的HTTP(post/get)实现的。</p><h4 id="SOAP-请求:"><a href="#SOAP-请求:" class="headerlink" title="SOAP 请求:"></a>SOAP 请求:</h4><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line">POST /InStock HTTP/1.1</span><br><span class="line">Host: www.example.org</span><br><span class="line">Content-Type: application/soap+xml; charset=utf-8</span><br><span class="line">Content-Length: nnn</span><br><span class="line"></span><br><span class="line"><span class="meta"><?xml version=<span class="string">"1.0"</span>?></span></span><br><span class="line"><span class="tag"><<span class="name">soap:Envelope</span></span></span><br><span class="line"><span class="tag"><span class="attr">xmlns:soap</span>=<span class="string">"http://www.w3.org/2001/12/soap-envelope"</span></span></span><br><span class="line"><span class="tag"><span class="attr">soap:encodingStyle</span>=<span class="string">"http://www.w3.org/2001/12/soap-encoding"</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">soap:Body</span> <span class="attr">xmlns:m</span>=<span class="string">"http://www.example.org/stock"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">m:GetStockPrice</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">m:StockName</span>></span>IBM<span class="tag"></<span class="name">m:StockName</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">m:GetStockPrice</span>></span></span><br><span class="line"><span class="tag"></<span class="name">soap:Body</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">soap:Envelope</span>></span></span><br></pre></td></tr></table></figure><h4 id="SOAP-响应:"><a href="#SOAP-响应:" class="headerlink" title="SOAP 响应:"></a>SOAP 响应:</h4><figure class="highlight xml"><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></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">Content-Type: application/soap+xml; charset=utf-8</span><br><span class="line">Content-Length: nnn</span><br><span class="line"></span><br><span class="line"><span class="meta"><?xml version=<span class="string">"1.0"</span>?></span></span><br><span class="line"><span class="tag"><<span class="name">soap:Envelope</span></span></span><br><span class="line"><span class="tag"><span class="attr">xmlns:soap</span>=<span class="string">"http://www.w3.org/2001/12/soap-envelope"</span></span></span><br><span class="line"><span class="tag"><span class="attr">soap:encodingStyle</span>=<span class="string">"http://www.w3.org/2001/12/soap-encoding"</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"><<span class="name">soap:Body</span> <span class="attr">xmlns:m</span>=<span class="string">"http://www.example.org/stock"</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">m:GetStockPriceResponse</span>></span></span><br><span class="line"> <span class="tag"><<span class="name">m:Price</span>></span>34.5<span class="tag"></<span class="name">m:Price</span>></span></span><br><span class="line"> <span class="tag"></<span class="name">m:GetStockPriceResponse</span>></span></span><br><span class="line"><span class="tag"></<span class="name">soap:Body</span>></span></span><br><span class="line"></span><br><span class="line"><span class="tag"></<span class="name">soap:Envelope</span>></span></span><br></pre></td></tr></table></figure>]]></content>
<summary type="html"><blockquote><p>虽然现在都是http的api,但是有些老项目依然用的是webservice,如果碰到了也需要用webservice来调用。所以像这种可能会用到的知识,花一秒钟搞懂概念就行,用到的时候再说。</p>
</blockquote></summary>
</entry>
<entry>
<title>王者人机模式有Bug</title>
<link href="https://oldmee.github.io/2019/03/14/KPL-BUG/"/>
<id>https://oldmee.github.io/2019/03/14/KPL-BUG/</id>
<published>2019-03-14T02:00:29.000Z</published>
<updated>2023-05-16T06:50:27.493Z</updated>
<content type="html"><![CDATA[<p>用米莱迪站在对面水晶与高地塔之间的安全区机器人是看不见的,然后用米莱迪的技能慢慢的把对方的水晶推掉,其他人守塔就行,要赶紧,估计版本更新这个bug也就修复了,那时候再要过人机20级可就难喽~</p><span id="more"></span><p><img src="/images/kpl_1.jpg"></p><p><img src="/images/kpl_2.jpg"></p>]]></content>
<summary type="html"><p>用米莱迪站在对面水晶与高地塔之间的安全区机器人是看不见的,然后用米莱迪的技能慢慢的把对方的水晶推掉,其他人守塔就行,要赶紧,估计版本更新这个bug也就修复了,那时候再要过人机20级可就难喽~</p></summary>
</entry>
<entry>
<title>责任链模式</title>
<link href="https://oldmee.github.io/2019/02/26/chain-of-responsibility-pattern/"/>
<id>https://oldmee.github.io/2019/02/26/chain-of-responsibility-pattern/</id>
<published>2019-02-25T16:01:24.000Z</published>
<updated>2019-02-26T01:32:07.000Z</updated>
<content type="html"><![CDATA[<p>在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。</p><span id="more"></span><p>应用实例: 1、红楼梦中的”击鼓传花”。 2、JS 中的事件冒泡。 3、JAVA WEB 中 Apache Tomcat 对 Encoding 的处理,Struts2 的拦截器,jsp servlet 的 Filter。</p><p>责任链模式demo</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line">AbstractLogger.java</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">AbstractLogger</span> {</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">INFO</span> <span class="operator">=</span> <span class="number">1</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">DEBUG</span> <span class="operator">=</span> <span class="number">2</span>;</span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="variable">ERROR</span> <span class="operator">=</span> <span class="number">3</span>;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">protected</span> <span class="type">int</span> level;</span><br><span class="line"> </span><br><span class="line"> <span class="comment">//责任链中的下一个元素</span></span><br><span class="line"> <span class="keyword">protected</span> AbstractLogger nextLogger;</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setNextLogger</span><span class="params">(AbstractLogger nextLogger)</span>{</span><br><span class="line"> <span class="built_in">this</span>.nextLogger = nextLogger;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">logMessage</span><span class="params">(<span class="type">int</span> level, String message)</span>{</span><br><span class="line"> <span class="keyword">if</span>(<span class="built_in">this</span>.level <= level){</span><br><span class="line"> write(message);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span>(nextLogger !=<span class="literal">null</span>){</span><br><span class="line"> nextLogger.logMessage(level, message);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">abstract</span> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">(String message)</span>;</span><br><span class="line"> </span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">ConsoleLogger.java</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ConsoleLogger</span> <span class="keyword">extends</span> <span class="title class_">AbstractLogger</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ConsoleLogger</span><span class="params">(<span class="type">int</span> level)</span>{</span><br><span class="line"> <span class="built_in">this</span>.level = level;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">(String message)</span> { </span><br><span class="line"> System.out.println(<span class="string">"Standard Console::Logger: "</span> + message);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">ErrorLogger.java</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ErrorLogger</span> <span class="keyword">extends</span> <span class="title class_">AbstractLogger</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">ErrorLogger</span><span class="params">(<span class="type">int</span> level)</span>{</span><br><span class="line"> <span class="built_in">this</span>.level = level;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">(String message)</span> { </span><br><span class="line"> System.out.println(<span class="string">"Error Console::Logger: "</span> + message);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight java"><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">FileLogger.java</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">FileLogger</span> <span class="keyword">extends</span> <span class="title class_">AbstractLogger</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="title function_">FileLogger</span><span class="params">(<span class="type">int</span> level)</span>{</span><br><span class="line"> <span class="built_in">this</span>.level = level;</span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">protected</span> <span class="keyword">void</span> <span class="title function_">write</span><span class="params">(String message)</span> { </span><br><span class="line"> System.out.println(<span class="string">"File::Logger: "</span> + message);</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">ChainPatternDemo.java</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ChainPatternDemo</span> {</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> AbstractLogger <span class="title function_">getChainOfLoggers</span><span class="params">()</span>{</span><br><span class="line"> </span><br><span class="line"> <span class="type">AbstractLogger</span> <span class="variable">errorLogger</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ErrorLogger</span>(AbstractLogger.ERROR);</span><br><span class="line"> <span class="type">AbstractLogger</span> <span class="variable">fileLogger</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">FileLogger</span>(AbstractLogger.DEBUG);</span><br><span class="line"> <span class="type">AbstractLogger</span> <span class="variable">consoleLogger</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">ConsoleLogger</span>(AbstractLogger.INFO);</span><br><span class="line"> </span><br><span class="line"> errorLogger.setNextLogger(fileLogger);</span><br><span class="line"> fileLogger.setNextLogger(consoleLogger);</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">return</span> errorLogger; </span><br><span class="line"> }</span><br><span class="line"> </span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> {</span><br><span class="line"> <span class="type">AbstractLogger</span> <span class="variable">loggerChain</span> <span class="operator">=</span> getChainOfLoggers();</span><br><span class="line"> </span><br><span class="line"> loggerChain.logMessage(AbstractLogger.INFO, </span><br><span class="line"> <span class="string">"This is an information."</span>);</span><br><span class="line"> </span><br><span class="line"> loggerChain.logMessage(AbstractLogger.DEBUG, </span><br><span class="line"> <span class="string">"This is an debug level information."</span>);</span><br><span class="line"> </span><br><span class="line"> loggerChain.logMessage(AbstractLogger.ERROR, </span><br><span class="line"> <span class="string">"This is an error information."</span>);</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">Standard Console::Logger: This is an information.</span><br><span class="line">File::Logger: This is an debug level information.</span><br><span class="line">Standard Console::Logger: This is an debug level information.</span><br><span class="line">Error Console::Logger: This is an error information.</span><br><span class="line">File::Logger: This is an error information.</span><br><span class="line">Standard Console::Logger: This is an error information.</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>最高级别的error会被输出三次,最低级别的info只会输出一次。</p>]]></content>
<summary type="html"><p>在这种模式中,通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。</p></summary>
</entry>
<entry>
<title>hexo-bugs-000</title>
<link href="https://oldmee.github.io/2019/02/25/hexo-bugs-000/"/>
<id>https://oldmee.github.io/2019/02/25/hexo-bugs-000/</id>
<published>2019-02-25T12:04:00.000Z</published>
<updated>2019-02-26T01:32:07.000Z</updated>
<content type="html"><![CDATA[<p>在hexo本地服务器模式下,一旦文章内容过多(具体没测试,可以多放些内容试试),则生成的html在本地就会出问题,没有上一页下一页以及脚标信息,在浏览器里查看网页源代码发现都是些小方格,不知道是什么鬼。但是用户不知道啊,我搞了半天,发现原来是个bug,部署到github上一切正常,真的是脑壳痛……</p><span id="more"></span>]]></content>
<summary type="html"><p>在hexo本地服务器模式下,一旦文章内容过多(具体没测试,可以多放些内容试试),则生成的html在本地就会出问题,没有上一页下一页以及脚标信息,在浏览器里查看网页源代码发现都是些小方格,不知道是什么鬼。但是用户不知道啊,我搞了半天,发现原来是个bug,部署到github上一切正常,真的是脑壳痛……</p></summary>
<category term="bugs" scheme="https://oldmee.github.io/tags/bugs/"/>
</entry>
</feed>