-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlocal-search.xml
1409 lines (679 loc) · 713 KB
/
local-search.xml
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
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>errgroup-新方法解析</title>
<link href="/errgroup-%E6%96%B0%E6%96%B9%E6%B3%95%E8%A7%A3%E6%9E%90/"/>
<url>/errgroup-%E6%96%B0%E6%96%B9%E6%B3%95%E8%A7%A3%E6%9E%90/</url>
<content type="html"><![CDATA[<p>可能是全网第一篇?</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>前几天在用 errgroup 的时候发现了新的 api ,一看是 6月1号 才更新的。那这就来试试抢个首发解析新 api 吧</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="新加了哪些方法?"><a href="#新加了哪些方法?" class="headerlink" title="新加了哪些方法?"></a>新加了哪些方法?</h2><ul><li>SetLimit(n int)</li><li>TryGo(f func() error) bool</li></ul><h2 id="有什么用?"><a href="#有什么用?" class="headerlink" title="有什么用?"></a>有什么用?</h2><h3 id="SetLimit"><a href="#SetLimit" class="headerlink" title="SetLimit"></a>SetLimit</h3><p>之前用 <code>errgroup</code> 的时候没有提供 <em>SetLimit</em> 来限制并发数,所以在写业务逻辑的时候就只能先把任务分批,然后再一批批地放进一个 <code>errgroup</code> 里面执行。但现在加了 <em>SetLimit</em> 了,就可以先调用这个来设置最大并发数,然后再无脑使用 <em>Go()</em> 来把所有任务放进来,在循环完成后再使用 <em>Wait</em> 来看这个任务是不是都成功了</p><h3 id="TryGo"><a href="#TryGo" class="headerlink" title="TryGo"></a>TryGo</h3><p>这个应该是和 <em>SetLimit</em> 配套的一个方法,和 <em>Go</em> 方法的区别是,如果 errgroup 有并发限制,并且现在已经到了并发上限的话,那么就会返回 false 不执行传入的任务。这个设计应该是和 go 1.18 带来的 Mutex.TryLock 相似,因为有需求,所以就加了。之后再看看邮件列表,看大佬们对这个 api 有啥讨论。</p><h2 id="有哪些变动?"><a href="#有哪些变动?" class="headerlink" title="有哪些变动?"></a>有哪些变动?</h2><h3 id="Go"><a href="#Go" class="headerlink" title="Go"></a>Go</h3><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></pre></td><td class="code"><pre><code class="hljs go"><br><span class="hljs-keyword">type</span> token <span class="hljs-keyword">struct</span>{}<br><br><span class="hljs-keyword">type</span> Group <span class="hljs-keyword">struct</span> {<br>cancel <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span><br><br>wg sync.WaitGroup<br><br>sem <span class="hljs-keyword">chan</span> token<br><br>errOnce sync.Once<br>err <span class="hljs-type">error</span><br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(g *Group)</span></span> Go(f <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span>) {<br><span class="hljs-keyword">if</span> g.sem != <span class="hljs-literal">nil</span> {<br>g.sem <- token{}<br>}<br><br>g.wg.Add(<span class="hljs-number">1</span>)<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">defer</span> g.done()<br><br><span class="hljs-keyword">if</span> err := f(); err != <span class="hljs-literal">nil</span> {<br>g.errOnce.Do(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>g.err = err<br><span class="hljs-keyword">if</span> g.cancel != <span class="hljs-literal">nil</span> {<br>g.cancel()<br>}<br>})<br>}<br>}()<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(g *Group)</span></span> done() {<br><span class="hljs-keyword">if</span> g.sem != <span class="hljs-literal">nil</span> {<br><-g.sem<br>}<br>g.wg.Done()<br>}<br><br></code></pre></td></tr></table></figure><p>让我们从熟悉的 <em>Go</em> 方法看起,这里和以前的区别是先判断了当前的 <em>errgroup</em> 有没有并发限制的 <code>channel</code> <em>sem</em>,如果有的话那么就往这个 <code>channel</code> 里发送一个空的结构体用于抢占资源,相当于信号量的概念。之后就是我们熟悉的处理流程了,执行函数,如果 <code>err != nil</code> 那么就记录下这个 err 并且 cancel 掉这个 <em>errgroup</em> 的 <code>context</code></p><p>值得注意的是新增的这个 <em>done</em> 方法,之前是直接调用 <em>wg.Done</em> ,但是现在因为有了并发数的限制,所以在一个任务处理完之后还得判断当前的 <em>errgroup</em> 是不是有并发限制,如果有的话就把之前抢到的一个并发的机会给释放掉 <code><- g.sem</code>,让其他的方法能够继续去抢并发的机会</p><p>看到了这里,那这个 <em>g.sem</em> 是怎么来的呢?答案是来自新提供的方法 <em>SetLimit</em></p><h3 id="SetLimit-1"><a href="#SetLimit-1" class="headerlink" title="SetLimit"></a>SetLimit</h3><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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">// SetLimit limits the number of active goroutines in this group to at most n.</span><br><span class="hljs-comment">// A negative value indicates no limit.</span><br><span class="hljs-comment">//</span><br><span class="hljs-comment">// Any subsequent call to the Go method will block until it can add an active</span><br><span class="hljs-comment">// goroutine without exceeding the configured limit.</span><br><span class="hljs-comment">//</span><br><span class="hljs-comment">// The limit must not be modified while any goroutines in the group are active.</span><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(g *Group)</span></span> SetLimit(n <span class="hljs-type">int</span>) {<br><span class="hljs-keyword">if</span> n < <span class="hljs-number">0</span> {<br>g.sem = <span class="hljs-literal">nil</span><br><span class="hljs-keyword">return</span><br>}<br><span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(g.sem) != <span class="hljs-number">0</span> {<br><span class="hljs-built_in">panic</span>(fmt.Errorf(<span class="hljs-string">"errgroup: modify limit while %v goroutines in the group are still active"</span>, <span class="hljs-built_in">len</span>(g.sem)))<br>}<br>g.sem = <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> token, n)<br>}<br></code></pre></td></tr></table></figure><p>可以看到,即使 errgroup 不是从 WithContext 创建的,也可以设置最大并发数。</p><ul><li>如果 <code>n<0</code> 那么就认为不设限,那么就把当前的 channel 置空。</li><li>如果 <code>len(g.sem) != 0</code> 那么就说明当前还有任务在执行中,这个时候 errgroup 的处理方式是直接 panic ,这个在注释里面也提到了</li></ul><blockquote><p>The limit must not be modified while any goroutines in the group are active</p></blockquote><p>然后值得注意的是,如果 SetLimit = 0 那么就会陷入死锁。因为 <code>channel</code> 的长度为 0,此时不会有方法能够抢到并发的机会。即使用这种骚操作,最开始开起来的那个协程也会永久阻塞掉,相当于发生了泄露</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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-comment">// 骚操作</span><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br>g := errgroup.Group{}<br>g.SetLimit(<span class="hljs-number">0</span>)<br><br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>time.Sleep(time.Second)<br>g.SetLimit(<span class="hljs-number">1</span>)<br>}()<br><br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>time.Sleep(time.Second * <span class="hljs-number">4</span>)<br>fmt.Println(g.Wait())<br>}()<br><br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"不可能的 err"</span>)<br>})<br>}()<br><br>time.Sleep(time.Second * <span class="hljs-number">2</span>)<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">return</span> errors.New(<span class="hljs-string">"会返回的 err"</span>)<br>})<br>time.Sleep(time.Second * <span class="hljs-number">5</span>)<br>}<br><br><span class="hljs-comment">// 最后只会输出 **会返回的 err**</span><br></code></pre></td></tr></table></figure><h3 id="TryGo-1"><a href="#TryGo-1" class="headerlink" title="TryGo"></a>TryGo</h3><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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(g *Group)</span></span> TryGo(f <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span>) <span class="hljs-type">bool</span> {<br><span class="hljs-keyword">if</span> g.sem != <span class="hljs-literal">nil</span> {<br><span class="hljs-keyword">select</span> {<br><span class="hljs-keyword">case</span> g.sem <- token{}:<br><span class="hljs-comment">// Note: this allows barging iff channels in general allow barging.</span><br><span class="hljs-keyword">default</span>:<br><span class="hljs-keyword">return</span> <span class="hljs-literal">false</span><br>}<br>}<br><br>g.wg.Add(<span class="hljs-number">1</span>)<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">defer</span> g.done()<br><br><span class="hljs-keyword">if</span> err := f(); err != <span class="hljs-literal">nil</span> {<br>g.errOnce.Do(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>g.err = err<br><span class="hljs-keyword">if</span> g.cancel != <span class="hljs-literal">nil</span> {<br>g.cancel()<br>}<br>})<br>}<br>}()<br><span class="hljs-keyword">return</span> <span class="hljs-literal">true</span><br>}<br></code></pre></td></tr></table></figure><p>这个就比较好懂了,先判断当前是不是限制了并发数,如果限制了那么就用 </p><p><code>select case default</code> 这种形式做一次尝试抢并发机会的逻辑,如果抢到了的话就会走和 <em>Go</em> 抢到了锁后相同的逻辑</p><h2 id="怎么用?"><a href="#怎么用?" class="headerlink" title="怎么用?"></a>怎么用?</h2><p>这里直接看 test 文件里的测试样例就好</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><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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestTryGo</span><span class="hljs-params">(t *testing.T)</span></span> {<br>g := &errgroup.Group{}<br>n := <span class="hljs-number">42</span><br>g.SetLimit(<span class="hljs-number">42</span>)<br>ch := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{})<br>fn := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br>ch <- <span class="hljs-keyword">struct</span>{}{}<br><span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span><br>}<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < n; i++ {<br><span class="hljs-keyword">if</span> !g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo should succeed but got fail at %d-th call."</span>, i)<br>}<br>}<br><span class="hljs-keyword">if</span> g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo is expected to fail but succeeded."</span>)<br>}<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < n; i++ {<br><-ch<br>}<br>}()<br>g.Wait()<br><br><span class="hljs-keyword">if</span> !g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo should success but got fail after all goroutines."</span>)<br>}<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> { <-ch }()<br>g.Wait()<br><br><span class="hljs-comment">// Switch limit.</span><br>g.SetLimit(<span class="hljs-number">1</span>)<br><span class="hljs-keyword">if</span> !g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo should success but got failed."</span>)<br>}<br><span class="hljs-keyword">if</span> g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo should fail but succeeded."</span>)<br>}<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> { <-ch }()<br>g.Wait()<br><br><span class="hljs-comment">// Block all calls.</span><br>g.SetLimit(<span class="hljs-number">0</span>)<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-number">1</span><<<span class="hljs-number">10</span>; i++ {<br><span class="hljs-keyword">if</span> g.TryGo(fn) {<br>t.Fatalf(<span class="hljs-string">"TryGo should fail but got succeded."</span>)<br>}<br>}<br>g.Wait()<br>}<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">TestGoLimit</span><span class="hljs-params">(t *testing.T)</span></span> {<br><span class="hljs-keyword">const</span> limit = <span class="hljs-number">10</span><br><br>g := &errgroup.Group{}<br>g.SetLimit(limit)<br><span class="hljs-keyword">var</span> active <span class="hljs-type">int32</span><br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i <= <span class="hljs-number">1</span><<<span class="hljs-number">10</span>; i++ {<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br>n := atomic.AddInt32(&active, <span class="hljs-number">1</span>)<br><span class="hljs-keyword">if</span> n > limit {<br><span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"saw %d active goroutines; want ≤ %d"</span>, n, limit)<br>}<br>time.Sleep(<span class="hljs-number">1</span> * time.Microsecond) <span class="hljs-comment">// Give other goroutines a chance to increment active.</span><br>atomic.AddInt32(&active, <span class="hljs-number">-1</span>)<br><span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span><br>})<br>}<br><span class="hljs-keyword">if</span> err := g.Wait(); err != <span class="hljs-literal">nil</span> {<br>t.Fatal(err)<br>}<br>}<br></code></pre></td></tr></table></figure><ul><li><em>TestTryGo</em> 里面展示了各种情况下(包括调用 <code>SetLimit</code> 设置并发与否)应该得到的是 <code>true</code> or <code>false</code></li><li><em>TestGoLimit</em> 里面则简单一点,只是用于验证会不会有超过预期数量的并发</li></ul><h2 id="具体的示例"><a href="#具体的示例" class="headerlink" title="具体的示例"></a>具体的示例</h2><p>来点具体的示例吧, 并发处理 <em>x</em> 个任务,最大并发为 <em>4</em></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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"log"</span><br><br><span class="hljs-string">"golang.org/x/sync/errgroup"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">const</span> limit = <span class="hljs-number">4</span><br>tasks := <span class="hljs-built_in">make</span>([]<span class="hljs-type">int</span>, <span class="hljs-number">20</span>)<br>g := errgroup.Group{}<br><br>doSomeThing := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(task <span class="hljs-type">int</span>)</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">if</span> task > <span class="hljs-number">5</span> && task%<span class="hljs-number">5</span> == <span class="hljs-number">0</span> {<br><span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"%d task err"</span>, task)<br>}<br><span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span><br>}<br><br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i+limit < <span class="hljs-built_in">len</span>(tasks); i += limit {<br>j := i + limit<br><span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(tasks) < j {<br>j = <span class="hljs-built_in">len</span>(tasks)<br>}<br><span class="hljs-keyword">for</span> task := i; task < j; task++ {<br>task := task<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">return</span> doSomeThing(task)<br>})<br>}<br><br>err := g.Wait()<br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br>log.Fatal(err)<br>}<br>}<br>}<br><br></code></pre></td></tr></table></figure><p>我们之前用 errgroup 但是又想限制并发数的话,这是个比较简单的写法。但是就真的是批处理,最大并发为 4 ,这一批四个任务,全部走完了才能走下一批。如果要写能够实时填充的任务池的话,其实相对而言写起来更简单,但是对业务逻辑的侵入比较明显</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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"log"</span><br><br><span class="hljs-string">"golang.org/x/sync/errgroup"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">const</span> limit = <span class="hljs-number">4</span><br>tasks := <span class="hljs-built_in">make</span>([]<span class="hljs-type">int</span>, <span class="hljs-number">20</span>)<br>g := errgroup.Group{}<br><br>doSomeThing := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(task <span class="hljs-type">int</span>)</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">if</span> task > <span class="hljs-number">5</span> && task%<span class="hljs-number">5</span> == <span class="hljs-number">0</span> {<br><span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"%d task err"</span>, task)<br>}<br><span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span><br>}<br><br>workChan := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">struct</span>{}, limit)<br><span class="hljs-keyword">for</span> task := <span class="hljs-keyword">range</span> tasks {<br>task := task<br>workChan <- <span class="hljs-keyword">struct</span>{}{}<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">return</span> doSomeThing(task)<br>})<br><-workChan<br>}<br>err := g.Wait()<br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br>log.Fatal(err)<br>}<br>}<br></code></pre></td></tr></table></figure><p>明显要清爽一些了,但是得创建一个用于限制并发数的 channel ,对于看业务逻辑而言不太友好。毕竟主要是看你的业务逻辑是怎么样的,而不是看你怎么写并发和同步的</p><p>用新版的来改造的话就用着简单,看着也很清爽</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></pre></td><td class="code"><pre><code class="hljs go"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"log"</span><br><br><span class="hljs-string">"golang.org/x/sync/errgroup"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">const</span> limit = <span class="hljs-number">4</span><br>tasks := <span class="hljs-built_in">make</span>([]<span class="hljs-type">int</span>, <span class="hljs-number">20</span>)<br>g := errgroup.Group{}<br>g.SetLimit(limit)<br><br>doSomeThing := <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">(task <span class="hljs-type">int</span>)</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">if</span> task > <span class="hljs-number">5</span> && task%<span class="hljs-number">5</span> == <span class="hljs-number">0</span> {<br><span class="hljs-keyword">return</span> fmt.Errorf(<span class="hljs-string">"%d task err"</span>, task)<br>}<br><span class="hljs-keyword">return</span> <span class="hljs-literal">nil</span><br>}<br><br><span class="hljs-keyword">for</span> task := <span class="hljs-keyword">range</span> tasks {<br>task := task<br>g.Go(<span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> <span class="hljs-type">error</span> {<br><span class="hljs-keyword">return</span> doSomeThing(task)<br>})<br>}<br><br>err := g.Wait()<br><span class="hljs-keyword">if</span> err != <span class="hljs-literal">nil</span> {<br>log.Fatal(err)<br>}<br>}<br><br></code></pre></td></tr></table></figure><p>这样别人看你代码的时候能够直接看到你的业务逻辑,而限制并发数只是一个调用而已,对 CR 的同学而言知道了这个用法就行,不用再 <code>Review</code> 你的并发限制写得有没有问题了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><ul><li><a href="https://cs.opensource.google/go/x/sync/">https://cs.opensource.google/go/x/sync/</a></li></ul>]]></content>
<categories>
<category>go</category>
</categories>
<tags>
<tag>go</tag>
</tags>
</entry>
<entry>
<title>Arch-Linux安装指南</title>
<link href="/Arch-Linux%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/"/>
<url>/Arch-Linux%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<p>爽</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="下载镜像"><a href="#下载镜像" class="headerlink" title="下载镜像"></a>下载镜像</h2><h2 id="放入介质"><a href="#放入介质" class="headerlink" title="放入介质"></a>放入介质</h2><h2 id="重新启动"><a href="#重新启动" class="headerlink" title="重新启动"></a>重新启动</h2><h2 id="连上网络"><a href="#连上网络" class="headerlink" title="连上网络"></a>连上网络</h2><h3 id="无线网"><a href="#无线网" class="headerlink" title="无线网"></a>无线网</h3><h4 id="iwd"><a href="#iwd" class="headerlink" title="iwd"></a>iwd</h4><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">iwctl<br></code></pre></td></tr></table></figure><figure class="highlight bash"><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><code class="hljs bash">station wlan0 scan <span class="hljs-comment"># 扫描</span><br>station wlan0 get-networks <span class="hljs-comment"># 显示WiFi</span><br>station wlan0 connect WIFI_NAME <span class="hljs-comment"># 连接到 WIFI,有加密则提示输入密码</span><br>station list <span class="hljs-comment"># 查看是否连上网络</span><br><span class="hljs-built_in">exit</span> <span class="hljs-comment"># 退出</span><br></code></pre></td></tr></table></figure><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">ip address <span class="hljs-comment"># 查看 ip 地址是否正常</span><br>ping archlinux.org <span class="hljs-comment"># 查看网络连通性</span><br></code></pre></td></tr></table></figure><h2 id="系统时间同步"><a href="#系统时间同步" class="headerlink" title="系统时间同步"></a>系统时间同步</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">timedatectl set-ntp <span class="hljs-literal">true</span> <span class="hljs-comment"># 设置网络同步时间</span><br>timedatectl status <span class="hljs-comment"># 检查是否进行了网络同步</span><br></code></pre></td></tr></table></figure><h2 id="选择最快的镜像源"><a href="#选择最快的镜像源" class="headerlink" title="选择最快的镜像源"></a>选择最快的镜像源</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">reflector -c China -a 6 --<span class="hljs-built_in">sort</span> rate --save /etc/pacman.d/mirrorlist<br></code></pre></td></tr></table></figure><p>这是找到你能连上的中国最快的几个镜像源。为了方便之后安装。其实也可以不用管,因为</p><blockquote><p>在连接到因特网后,reflector 会通过选择 20 个最新同步的 HTTPS 镜像并按下载速率对其进行排序来更新镜像列表。</p></blockquote><p>官方说会自动选择最快的镜像。</p><h2 id="建立硬盘分区"><a href="#建立硬盘分区" class="headerlink" title="建立硬盘分区"></a>建立硬盘分区</h2><p>推荐用 <code>cfdisk</code> 图形化的界面非常轻松<br>直接用 cfdisk 是默认连上 /dev/sda 这块硬盘,如果需要连上其他的硬盘就输入对应的即可。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">cfdisk /dev/sdb <span class="hljs-comment"># 这是连上 sdb 这块硬盘</span><br></code></pre></td></tr></table></figure><p>其实这个就相对于 <code>fdisk</code> 简单很多了,就是用上下键选择对应的分区,然后左右键选择对应的功能即可。</p><h2 id="格式化分区"><a href="#格式化分区" class="headerlink" title="格式化分区"></a>格式化分区</h2><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 对于 EFI 分区 格式化成 fat32 类型的</span><br>mkfs.fat -F32 /dev/sdb1<br><br><span class="hljs-comment"># 对于 交换分区 采用如下的方法格式化</span><br>mkswap /dev/sdb4<br><span class="hljs-comment"># 然后将其启用,之后在生成引导的时候会自动检测 swap 分区</span><br>swapon /dev/sdb4<br><br><span class="hljs-comment"># 对于其他的分区如 / 和 /home 分区,格式化成 ext4 即可</span><br>mkfs.ext4 /dev/sdb2<br>mkfs.ext4 /dev/sdb3<br><br><span class="hljs-comment"># 如果是装到 U 盘里的话,就可以用取消日志系统</span><br>mkfs.ext4 -O <span class="hljs-string">"^has_journal"</span> /dev/sdb2 <br></code></pre></td></tr></table></figure><h2 id="挂载到-x2F-mnt"><a href="#挂载到-x2F-mnt" class="headerlink" title="挂载到 /mnt"></a>挂载到 /mnt</h2><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 将根分区挂载到 /mnt 下</span><br>mount /dev/sdb2 /mnt <br><span class="hljs-comment"># 在根分区建立 /efi 目录,并把对应分区挂载上</span><br><span class="hljs-built_in">mkdir</span> /mnt/efi<br>mount /dev/sdb1 /mnt/efi<br><span class="hljs-comment"># 在根分区建立 /home 目录,并把对应分区挂载上</span><br><span class="hljs-built_in">mkdir</span> /mnt/home<br>mount /dev/sdb3 /mnt/home<br></code></pre></td></tr></table></figure><h2 id="安装系统及程序到对应的目录"><a href="#安装系统及程序到对应的目录" class="headerlink" title="安装系统及程序到对应的目录"></a>安装系统及程序到对应的目录</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacstrap /mnt base linux linux-firmware nano <br></code></pre></td></tr></table></figure><h2 id="生成-fstab-文件"><a href="#生成-fstab-文件" class="headerlink" title="生成 fstab 文件"></a>生成 fstab 文件</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">genfstab -U /mnt >> /mnt/etc/fstab<br></code></pre></td></tr></table></figure><p>用 <code>cat /mnt/etc/fstab</code> 检查一下是不是和之前规划的分区一样。</p><h2 id="Chroot"><a href="#Chroot" class="headerlink" title="Chroot"></a>Chroot</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">arch-chroot /mnt<br></code></pre></td></tr></table></figure><p>chroot 到 /mnt 中。</p><h2 id="设置密码"><a href="#设置密码" class="headerlink" title="设置密码"></a>设置密码</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">passwd<br></code></pre></td></tr></table></figure><p>设置 root 用户的密码</p><h2 id="设置时区"><a href="#设置时区" class="headerlink" title="设置时区"></a>设置时区</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><br><span class="hljs-comment"># 可以通过手动设置</span><br><span class="hljs-built_in">ln</span> -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime<br><span class="hljs-comment"># 运行 hwclock(8) 以生成 /etc/adjtime:</span><br>hwclock --systohc<br><br><span class="hljs-comment"># 也可以通过工具设置</span><br>timedatectl set-timezone Asia/Shanghai<br><br><span class="hljs-comment"># 最后检查一下是否正确设置了</span><br>timedatectl status<br></code></pre></td></tr></table></figure><h2 id="本地化"><a href="#本地化" class="headerlink" title="本地化"></a>本地化</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 编辑 /etc/locale.gen 把 需要的地区的 # 删除掉</span><br>nano /etc/locale.gen<br><span class="hljs-comment"># 执行 locale-gen 生成 locale 信息</span><br>locale-gen <br><span class="hljs-comment"># 编辑本地化语言</span><br><span class="hljs-built_in">echo</span> LANG=en_US.UTF-8 >> /etc/locale.conf<br></code></pre></td></tr></table></figure><h2 id="网络配置"><a href="#网络配置" class="headerlink" title="网络配置"></a>网络配置</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 设置主机名</span><br><span class="hljs-built_in">echo</span> 自己设定的主机名 >> /etc/hostname<br></code></pre></td></tr></table></figure><h3 id="编辑-x2F-etc-x2F-hosts-文件"><a href="#编辑-x2F-etc-x2F-hosts-文件" class="headerlink" title="编辑 /etc/hosts 文件"></a>编辑 /etc/hosts 文件</h3><figure class="highlight accesslog"><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><code class="hljs accesslog"><span class="hljs-number">127.0.0.1</span>localhost<br>::<span class="hljs-number">1</span>localhost<br><span class="hljs-number">127.0.1.1</span>myhostname.localdomainmyhostname # 主机名.本地域名 主机名<br></code></pre></td></tr></table></figure><h2 id="安装-CPU-微码"><a href="#安装-CPU-微码" class="headerlink" title="安装 CPU 微码"></a>安装 CPU 微码</h2><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># intel 用这个</span><br>pacman -S intel-ucode<br><span class="hljs-comment"># amd 用这个</span><br>pacman -S amd-ucode<br></code></pre></td></tr></table></figure><h2 id="安装基本的包"><a href="#安装基本的包" class="headerlink" title="安装基本的包"></a>安装基本的包</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -S grub efibootmgr iwd networkmanager network-manager-applet reflector git sudo<br></code></pre></td></tr></table></figure><h2 id="grub-生成引导"><a href="#grub-生成引导" class="headerlink" title="grub 生成引导"></a>grub 生成引导</h2><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 安装 grub </span><br>grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=ArchLinux<br><span class="hljs-comment"># 生成 grub 配置文件</span><br>grub-mkconfig -o /boot/grub/grub.cfg<br></code></pre></td></tr></table></figure><h2 id="重新启动-1"><a href="#重新启动-1" class="headerlink" title="重新启动"></a>重新启动</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 退出 chroot 环境</span><br><span class="hljs-built_in">exit</span> <br><span class="hljs-comment"># 取消挂载</span><br>umount -R /mnt<br><span class="hljs-comment"># 重启,记得拔出优盘</span><br>reboot<br></code></pre></td></tr></table></figure><h2 id="连接网络"><a href="#连接网络" class="headerlink" title="连接网络"></a>连接网络</h2><p>这里可以用 <code>iwctl</code> 来连接网络</p><h4 id="iwctl"><a href="#iwctl" class="headerlink" title="iwctl"></a>iwctl</h4><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 启动服务</span><br>systemctl start iwd.service <br><span class="hljs-comment"># 开机自启动服务</span><br>systemctl <span class="hljs-built_in">enable</span> iwd.service <br><span class="hljs-comment"># 解析服务</span><br>systemctl start systemd-resolved.service<br>systemctl <span class="hljs-built_in">enable</span> systemd-resolved.service<br></code></pre></td></tr></table></figure><h5 id="配置-dhcp"><a href="#配置-dhcp" class="headerlink" title="配置 dhcp"></a>配置 dhcp</h5><p>打开 <code>/etc/iwd/main.conf</code> 然后输入以下内容,就能自动获取 ip 地址了。</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-section">[General]</span><br><span class="hljs-attr">EnableNetworkConfiguration</span>=<span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><p>然后和上面一样,用<code>iwctl</code> 连上网即可。</p><p>也可以用 networkmanager 来管理网络</p><h4 id="networkmanager"><a href="#networkmanager" class="headerlink" title="networkmanager"></a>networkmanager</h4><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 图形化的连接网络的方式</span><br>nmtui<br><span class="hljs-comment"># 之后选择 Activate a connection 即可像平时一样连接网络</span><br></code></pre></td></tr></table></figure><h2 id="修改默认编辑器"><a href="#修改默认编辑器" class="headerlink" title="修改默认编辑器"></a>修改默认编辑器</h2><figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs gradle">echo export EDITOR=<span class="hljs-regexp">/usr/</span>bin<span class="hljs-regexp">/nano >> /</span>etc/profile<br><span class="hljs-keyword">source</span> <span class="hljs-regexp">/etc/</span>profile<br></code></pre></td></tr></table></figure><h2 id="修改-sudo-权限"><a href="#修改-sudo-权限" class="headerlink" title="修改 sudo 权限"></a>修改 sudo 权限</h2><figure class="highlight ebnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ebnf"><span class="hljs-attribute">visudo</span><br></code></pre></td></tr></table></figure><p>然后把 <code>wheel</code> 用户组前面的注释取消掉即可。</p><h2 id="添加新用户"><a href="#添加新用户" class="headerlink" title="添加新用户"></a>添加新用户</h2><p>这里添加新用户是为了之后能够登录到桌面环境所以新建的。</p><figure class="highlight bash"><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><code class="hljs bash">useradd -G wheel -m username<br><span class="hljs-comment"># 给新建用户设置密码</span><br>passwd username <span class="hljs-comment"># 刚才设置的那个</span><br></code></pre></td></tr></table></figure><h2 id="添加-archlinuxcn-源"><a href="#添加-archlinuxcn-源" class="headerlink" title="添加 archlinuxcn 源"></a>添加 archlinuxcn 源</h2><p>在 <code>/etc/pacman.conf</code> 最后添加如下的内容</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><code class="hljs conf">[archlinuxcn]<br>Server = https://mirrors.tuna.tsinghua.edu.cn/archlinuxcn/$arch<br></code></pre></td></tr></table></figure><p>然后安装 <code>archlinuxcn-keyring</code> 导入 GPG key。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -Syy<br>pacman -S archlinuxcn-keyring<br></code></pre></td></tr></table></figure><h2 id="安装桌面"><a href="#安装桌面" class="headerlink" title="安装桌面"></a>安装桌面</h2><h3 id="安装-Xorg"><a href="#安装-Xorg" class="headerlink" title="安装 Xorg"></a>安装 Xorg</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -S xorg<br></code></pre></td></tr></table></figure><h3 id="安装显卡驱动"><a href="#安装显卡驱动" class="headerlink" title="安装显卡驱动"></a>安装显卡驱动</h3><table><thead><tr><th>显卡</th><th>驱动</th></tr></thead><tbody><tr><td>通用显卡</td><td>xf86-video-vesa</td></tr><tr><td>Intel英特尔</td><td>xf86-video-intel</td></tr><tr><td>AMD显卡</td><td>xf86-video-amdgpu</td></tr><tr><td>NVIDIA显卡Geforce7±</td><td>xf86-video-nouveau</td></tr></tbody></table><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -S xf86-video-vesa xf86-video-intel<br></code></pre></td></tr></table></figure><h3 id="安装-KDE-Plasma-以及桌面管理器-SDDM"><a href="#安装-KDE-Plasma-以及桌面管理器-SDDM" class="headerlink" title="安装 KDE Plasma 以及桌面管理器 SDDM"></a>安装 KDE Plasma 以及桌面管理器 SDDM</h3><figure class="highlight bash"><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><code class="hljs bash">pacman -S sddm plasma kde-applications <br><span class="hljs-comment"># sddm 自启动</span><br>systemctl <span class="hljs-built_in">enable</span> sddm<br></code></pre></td></tr></table></figure><h3 id="安装中文字体"><a href="#安装中文字体" class="headerlink" title="安装中文字体"></a>安装中文字体</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -S noto-fonts-cjk<br>pacman -S noto-fonts-emoji<br></code></pre></td></tr></table></figure><h3 id="安装中文输入法"><a href="#安装中文输入法" class="headerlink" title="安装中文输入法"></a>安装中文输入法</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pacman -S fcitx kcm-fcitx fcitx-configtool <br></code></pre></td></tr></table></figure><p>然后编辑 <code>~/xprofile</code> 的内容</p><figure class="highlight routeros"><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><code class="hljs routeros"><span class="hljs-built_in">export</span> <span class="hljs-attribute">LANG</span>=zh_CN.UTF-8<br><span class="hljs-built_in">export</span> <span class="hljs-attribute">GTK_IM_MODULE</span>=fcitx<br><span class="hljs-built_in">export</span> <span class="hljs-attribute">QT_IM_MODULE</span>=fcitx<br><span class="hljs-built_in">export</span> <span class="hljs-attribute">XMODIFIERS</span>=<span class="hljs-string">"@im=fcitx"</span><br></code></pre></td></tr></table></figure><p>好了 现在就基本上可以重启,然后正常使用了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1>]]></content>
<tags>
<tag>Linux</tag>
<tag>Arch</tag>
</tags>
</entry>
<entry>
<title>自动爬取 Leetcode 题目,并保存为 Markdown 格式</title>
<link href="/%E8%87%AA%E5%8A%A8%E7%88%AC%E5%8F%96-Leetcode-%E9%A2%98%E7%9B%AE%EF%BC%8C%E5%B9%B6%E4%BF%9D%E5%AD%98%E4%B8%BA-Markdown-%E6%A0%BC%E5%BC%8F/"/>
<url>/%E8%87%AA%E5%8A%A8%E7%88%AC%E5%8F%96-Leetcode-%E9%A2%98%E7%9B%AE%EF%BC%8C%E5%B9%B6%E4%BF%9D%E5%AD%98%E4%B8%BA-Markdown-%E6%A0%BC%E5%BC%8F/</url>
<content type="html"><![CDATA[<p>复制,粘贴,运行</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在 <strong>leetcode</strong> 刷题的时候我习惯在本地写好题解,不过每题都复制就太麻烦了,而且也不是<strong>Markdown</strong>格式的。于是想能不能爬取内容,然后自动转换格式。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>自己来写的话因为对爬虫并不是很熟悉(主要是对于抓包并不熟),所以直接搜索,于是发现了一个<a href="https://wanakiki.github.io/2020/leetcode-spider/">博客</a>写这个事情。看起来挺不错的,那我就直接用<strong>CV</strong>大法了。这里主要是用了转换格式和爬取内容的方法。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p><strong>leetcode</strong> 的请求都是用的 <strong>GraphQL</strong> 技术。相比起 <strong>RESTful</strong> 格式而言,它更加灵活,能够减少请求数(一次就能查询多个数据)。查询的时候可以只请求部分内容。</p><p>对于本例而言,用 <strong>F12</strong> ,然后看 <strong>Network</strong>,搜索<strong>graphql</strong>的请求后,筛选一下就能得到合适的结果</p><figure class="highlight bash"><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><code class="hljs bash">curl <span class="hljs-string">'https://leetcode-cn.com/graphql/'</span> \<br> -H <span class="hljs-string">'authority: leetcode-cn.com'</span> \<br> -H <span class="hljs-string">'x-timezone: undefined'</span> \<br> -H <span class="hljs-string">'x-operation-name: questionData'</span> \<br> -H <span class="hljs-string">'accept-language: zh-CN'</span> \<br> -H <span class="hljs-string">'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.141 Safari/537.36'</span> \<br> -H <span class="hljs-string">'content-type: application/json'</span> \<br> -H <span class="hljs-string">'accept: */*'</span> \<br> -H <span class="hljs-string">'x-csrftoken: balabalabala'</span> \<br> -H <span class="hljs-string">'dnt: 1'</span> \<br> -H <span class="hljs-string">'x-definition-name: question'</span> \<br> -H <span class="hljs-string">'origin: https://leetcode-cn.com'</span> \<br> -H <span class="hljs-string">'sec-fetch-site: same-origin'</span> \<br> -H <span class="hljs-string">'sec-fetch-mode: cors'</span> \<br> -H <span class="hljs-string">'sec-fetch-dest: empty'</span> \<br> -H <span class="hljs-string">'referer: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/'</span> \<br> -H <span class="hljs-string">'cookie: gbalabalabala'</span> \<br> --data-binary $<span class="hljs-string">'{"operationName":"questionData","variables":{"titleSlug":"best-time-to-buy-and-sell-stock-iii"},"query":"query questionData($titleSlug: String\u0021) {\\n question(titleSlug: $titleSlug) {\\n questionId\\n questionFrontendId\\n boundTopicId\\n title\\n titleSlug\\n content\\n translatedTitle\\n translatedContent\\n isPaidOnly\\n difficulty\\n likes\\n dislikes\\n isLiked\\n similarQuestions\\n contributors {\\n username\\n profileUrl\\n avatarUrl\\n __typename\\n }\\n langToValidPlayground\\n topicTags {\\n name\\n slug\\n translatedName\\n __typename\\n }\\n companyTagStats\\n codeSnippets {\\n lang\\n langSlug\\n code\\n __typename\\n }\\n stats\\n hints\\n solution {\\n id\\n canSeeDetail\\n __typename\\n }\\n status\\n sampleTestCase\\n metaData\\n judgerAvailable\\n judgeType\\n mysqlSchemas\\n enableRunCode\\n envInfo\\n book {\\n id\\n bookName\\n pressName\\n source\\n shortDescription\\n fullDescription\\n bookImgUrl\\n pressImgUrl\\n productUrl\\n __typename\\n }\\n isSubscribed\\n isDailyQuestion\\n dailyRecordStatus\\n editorType\\n ugcQuestionId\\n style\\n __typename\\n }\\n}\\n"}'</span> \<br> --compressed<br></code></pre></td></tr></table></figure><p>可以看到还是蛮多的请求项的,不过这样太花眼了,转换一下格式吧。</p><figure class="highlight dust"><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></pre></td><td class="code"><pre><code class="hljs dust"><span class="hljs-template-variable">{</span><br><span class="hljs-template-variable"> operationName: "questionData"</span><br><span class="hljs-template-variable"> query: "query questionData($titleSlug: String!) {</span><br><span class="hljs-template-variable"> question(titleSlug: $titleSlug) {</span><br><span class="hljs-template-variable"> questionId</span><br><span class="hljs-template-variable"> questionFrontendId</span><br><span class="hljs-template-variable"> boundTopicId</span><br><span class="hljs-template-variable"> title</span><br><span class="hljs-template-variable"> titleSlug</span><br><span class="hljs-template-variable"> content</span><br><span class="hljs-template-variable"> translatedTitle</span><br><span class="hljs-template-variable"> translatedContent</span><br><span class="hljs-template-variable"> isPaidOnly</span><br><span class="hljs-template-variable"> difficulty</span><br><span class="hljs-template-variable"> likes</span><br><span class="hljs-template-variable"> dislikes</span><br><span class="hljs-template-variable"> isLiked</span><br><span class="hljs-template-variable"> similarQuestions</span><br><span class="hljs-template-variable"> contributors {</span><br><span class="hljs-template-variable"> username</span><br><span class="hljs-template-variable"> profileUrl</span><br><span class="hljs-template-variable"> avatarUrl</span><br><span class="hljs-template-variable"> __typename</span><br><span class="hljs-template-variable"> }</span><span class="language-xml"></span><br><span class="language-xml"> langToValidPlayground</span><br><span class="language-xml"> topicTags </span><span class="hljs-template-variable">{</span><br><span class="hljs-template-variable"> name</span><br><span class="hljs-template-variable"> slug</span><br><span class="hljs-template-variable"> translatedName</span><br><span class="hljs-template-variable"> __typename</span><br><span class="hljs-template-variable"> }</span><span class="language-xml"></span><br><span class="language-xml"> companyTagStats</span><br><span class="language-xml"> codeSnippets </span><span class="hljs-template-variable">{</span><br><span class="hljs-template-variable"> lang</span><br><span class="hljs-template-variable"> langSlug</span><br><span class="hljs-template-variable"> code</span><br><span class="hljs-template-variable"> __typename</span><br><span class="hljs-template-variable"> }</span><span class="language-xml"></span><br><span class="language-xml"> stats</span><br><span class="language-xml"> hints</span><br><span class="language-xml"> solution </span><span class="hljs-template-variable">{</span><br><span class="hljs-template-variable"> id</span><br><span class="hljs-template-variable"> canSeeDetail</span><br><span class="hljs-template-variable"> __typename</span><br><span class="hljs-template-variable"> }</span><span class="language-xml"></span><br><span class="language-xml"> status</span><br><span class="language-xml"> sampleTestCase</span><br><span class="language-xml"> metaData</span><br><span class="language-xml"> judgerAvailable</span><br><span class="language-xml"> judgeType</span><br><span class="language-xml"> mysqlSchemas</span><br><span class="language-xml"> enableRunCode</span><br><span class="language-xml"> envInfo</span><br><span class="language-xml"> book </span><span class="hljs-template-variable">{</span><br><span class="hljs-template-variable"> id</span><br><span class="hljs-template-variable"> bookName</span><br><span class="hljs-template-variable"> pressName</span><br><span class="hljs-template-variable"> source</span><br><span class="hljs-template-variable"> shortDescription</span><br><span class="hljs-template-variable"> fullDescription</span><br><span class="hljs-template-variable"> bookImgUrl</span><br><span class="hljs-template-variable"> pressImgUrl</span><br><span class="hljs-template-variable"> productUrl</span><br><span class="hljs-template-variable"> __typename</span><br><span class="hljs-template-variable"> }</span><span class="language-xml"></span><br><span class="language-xml"> isSubscribed</span><br><span class="language-xml"> isDailyQuestion</span><br><span class="language-xml"> dailyRecordStatus</span><br><span class="language-xml"> editorType</span><br><span class="language-xml"> ugcQuestionId</span><br><span class="language-xml"> __typename</span><br><span class="language-xml"> }</span><br><span class="language-xml">}</span><br><span class="language-xml">"</span><br><span class="language-xml"> variables: </span><span class="hljs-template-variable">{titleSlug: "merge-two-sorted-lists"}</span><span class="language-xml"></span><br><span class="language-xml">}</span><br></code></pre></td></tr></table></figure><p>而转换成 Python 代码的就大概是这个样子</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">get_all</span>(<span class="hljs-params">slug</span>):<br> user_agent = <span class="hljs-string">"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.122 Safari/537.36"</span><br> session = requests.Session()<br> url = <span class="hljs-string">"https://leetcode-cn.com/graphql"</span><br> params = {<br> <span class="hljs-string">'operationName'</span>:<br> <span class="hljs-string">"getQuestionDetail"</span>,<br> <span class="hljs-string">'variables'</span>: {<br> <span class="hljs-string">'titleSlug'</span>: slug<br> },<br> <span class="hljs-string">'query'</span>:<br> <span class="hljs-string">'''query getQuestionDetail($titleSlug: String!) {</span><br><span class="hljs-string"> question(titleSlug: $titleSlug) {</span><br><span class="hljs-string"> questionId</span><br><span class="hljs-string"> questionFrontendId</span><br><span class="hljs-string"> title</span><br><span class="hljs-string"> titleSlug</span><br><span class="hljs-string"> content</span><br><span class="hljs-string"> translatedTitle</span><br><span class="hljs-string"> translatedContent</span><br><span class="hljs-string"> difficulty</span><br><span class="hljs-string"> topicTags {</span><br><span class="hljs-string"> name</span><br><span class="hljs-string"> slug</span><br><span class="hljs-string"> translatedName</span><br><span class="hljs-string"> __typename</span><br><span class="hljs-string"> }</span><br><span class="hljs-string"> codeSnippets {</span><br><span class="hljs-string"> lang</span><br><span class="hljs-string"> langSlug</span><br><span class="hljs-string"> code</span><br><span class="hljs-string"> __typename</span><br><span class="hljs-string"> }</span><br><span class="hljs-string"> __typename</span><br><span class="hljs-string"> }</span><br><span class="hljs-string"> }'''</span><br> }<br> json_data = json.dumps(params).encode(<span class="hljs-string">'utf8'</span>)<br> headers = {<br> <span class="hljs-string">'User-Agent'</span>: user_agent,<br> <span class="hljs-string">'Connection'</span>: <span class="hljs-string">'keep-alive'</span>,<br> <span class="hljs-string">'Content-Type'</span>: <span class="hljs-string">'application/json'</span>,<br> <span class="hljs-string">'Referer'</span>: <span class="hljs-string">'https://leetcode-cn.com/problems/'</span> + slug<br> }<br> resp = session.post(url, data=json_data, headers=headers, timeout=<span class="hljs-number">10</span>)<br> resp.encoding = <span class="hljs-string">'utf8'</span><br> content = resp.json()<br> <span class="hljs-comment"># 题目详细信息</span><br> <span class="hljs-comment"># print(content)</span><br> question = content[<span class="hljs-string">'data'</span>][<span class="hljs-string">'question'</span>]<br> <span class="hljs-keyword">return</span> question<br></code></pre></td></tr></table></figure><p>把它们格式化成 <strong>json</strong> 格式的内容即可。而后把响应按<strong>json</strong>进行解析,直接获取<code>data:question:</code>里面的项即可。</p><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><p>直接复制粘贴,然后运行就可以啦。哦对了,记得改一下 <strong>url</strong></p><details> <summary>给一个 <strong>GitHub Gist</strong></summary> <script src="https://gist.github.com/yikakia/5b8112706c28570a63a1ec14866fa031.js"></script></details><details> <summary>刷不出<strong>GitHub Gist</strong>的话看<strong>gitee</strong>的</summary> <script src='https://gitee.com/yikakia/codes/tdav6w7m903i1s2cugzxk76/widget_preview?title=%E4%BF%AE%E6%94%B9+url+%E5%8D%B3%E5%8F%AF'></script></details><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://wanakiki.github.io/2020/leetcode-spider/">爬虫获取力扣题目信息并转为Markdown</a><br><a href="https://www.cnblogs.com/ZhaoxiCheung/p/9333476.html">爬取LeetCode题目——如何发送GraphQL Query获取数据</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Python</tag>
<tag>Markdown</tag>
</tags>
</entry>
<entry>
<title>单线复用 iptv</title>
<link href="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/"/>
<url>/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/</url>
<content type="html"><![CDATA[<p>有两个支持 <strong>vlan</strong> 的设备就可以了。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>家里搬了新房,但是搞网络的时候遇到了问题,就是弱电箱在门口,而客厅只有两个接口。</p><p>一般来说无线路由器放在房子中央比较好,因为这样每个房间都能够有较强的信号。但又想每个房间里面都能够用网口的话,就得在网络汇聚处(一般家里都是弱电箱)放置一个交换机,交换机再接路由器的 <strong>lan</strong> 口,这个样子来进行使用。</p><p>但是问题来了,一般家里的弱电箱都是在入户处,并且往往只会有一个无线路由器来同时进行拨号上网以及路由的功能。这个时候如果把无线路由器放置在弱电箱的话,一般来说都会有一个房间信号特别差(要穿两到三堵墙)。</p><p>那么有什么好办法来解决呢?就是把无线路由器放到客厅里面,光猫的网口连接到路由器的 <strong>wan</strong> 口,然后路由器的 <strong>lan</strong> 口再连回弱电箱中的交换机,各个房间的网线连到交换机上,这样就可以每个房间的网口都能上网了。但是又有一个问题了,客厅有两个网口,一个网口接到了路由器的 <strong>wan</strong> 口上,一个网口接到了路由器的 <strong>lan</strong> 口上,那么 <strong>iptv</strong> 的网口该怎么接呢?</p><p>有一种解决方法是获取光猫的超级密码后,把光猫自带的无线功能绑定到<strong>iTV</strong>的端口上,这样机顶盒就可以通过无线连接来获取信息了。不过毕竟是对光猫进行操作,万一搞崩了呢?所以就另外想办法吧。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="vlan-的介绍"><a href="#vlan-的介绍" class="headerlink" title="vlan 的介绍"></a><strong>vlan</strong> 的介绍</h2><p>这个时候就是用到 <strong>vlan</strong> 的时候了。</p><p>简单来说, <strong>vlan</strong> 就是虚拟的(<code>v</code>)局域网(<code>lan</code>),它是一个工作在 <strong>OSI 模型</strong> 中的第二层数据链路层的广播域。这个主要是为了区分各个单位的广播。如果没有 <strong>vlan</strong> 的话,那么就会直接在整个局域网里进行广播,消耗的资源与局域网中的设备成正比。即使在三层网络层中划分了子网,但是也只是在三层中进行了丢弃,实际上对于数据链路而言,这个数据包还是会占用资源。</p><p>因此就在第二层再划分一次<strong>子网</strong>,只在这个<strong>子网</strong>中进行广播。这样就减少了占用的资源。</p><p>做一个不恰当的比方,比如说在你面前有个几条车道</p><figure class="highlight gherkin"><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><code class="hljs gherkin">|<span class="hljs-string"> 1 </span>|<span class="hljs-string"> 2 </span>|<span class="hljs-string"> 3 </span>|<span class="hljs-string"> 4 </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>[_______________]<br></code></pre></td></tr></table></figure><p>不划分 <strong>vlan</strong> 的话,在局域网中遇到 <strong>BUM</strong> 流量</p><ul><li><strong>B</strong>(<strong>Broadcast</strong> 广播)</li><li><strong>U</strong>(<strong>Unknown Unicast</strong> 未知的流量)</li><li><strong>M</strong>(<strong>Multicast</strong> 组播)</li></ul><p>就会同时占用<code>1~4</code>四个车道进行货物的运输,即对四个端口都转发数据包。</p><p>四个的负载可能不高,那么四十个,四百个呢?</p><p>这个时候就要划分好 <strong>vlan</strong> 了。<strong>vlan</strong> 就相当于是把这几个车道做了物理隔离,不能转到别的车道了。</p><figure class="highlight gherkin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs gherkin">|<span class="hljs-string"> vlan 1</span>|<span class="hljs-string"> </span>|<span class="hljs-string"> vlan 2</span>|<br>|<span class="hljs-string"> 1 </span>|<span class="hljs-string"> 2 </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> 3 </span>|<span class="hljs-string"> 4 </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<span class="hljs-string"> </span>|<br>[_______|<span class="hljs-string"> </span>|<span class="hljs-string">_______]</span><br></code></pre></td></tr></table></figure><p>这个时候就是划分了两个 <strong>vlan</strong> 了。1,2车道的货物可以互相传递,而不能和3,4车道进行互联互通。遇到了 <strong>BUM</strong>流量也只在自己的广播域 <strong>vlan1</strong>,<strong>vlan2</strong> 中进行广播。在端口收到了数据后,如果自己不属于这个数据的<strong>vlan</strong> 那么就会直接进行舍弃,相对与子网划分而言安全性更高,隔离性更好。</p><h2 id="实际操作"><a href="#实际操作" class="headerlink" title="实际操作"></a>实际操作</h2><p>下面我给一张我家的拓扑图</p><img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/%E5%AE%B6%E5%BA%AD%E7%BD%91%E7%BB%9C%E6%8B%93%E6%89%91%E5%9B%BE.png" class="" title="iptv 单线复用 家庭网络拓扑图.png"><p>我这种拓扑图的需求是</p><ol><li>光猫桥接,路由器拨号</li><li>需要观看 <strong>IPTV</strong></li><li>路由器在客厅,和<strong>IPTV</strong>在一起</li></ol><p>其实要做的我在<a href="#%E5%89%8D%E8%A8%80">前言</a>里面写的差不多了,大致分为以下几步</p><ol><li><p>购买两个支持 <strong>vlan</strong> 的交换机,一般来说直接找网管交换机就可以了(路由器支持<strong>vlan</strong>的话只用购买一个网管交换机放在弱电箱里面就好了)。</p></li><li><p>在两个交换机中分别划分好 <strong>vlan</strong></p><ul><li>第一个交换机 <img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/vlan1.png" class="" title="vlan1"></li></ul> <img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/pvid1.png" class="" title="pvid1"><ul><li>第二个交换机 <img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/vlan2.png" class="" title="vlan2"></li></ul> <img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/pvid2.png" class="" title="pvid2"><p> 这里我是把第一个交换机的第五个端口作为汇聚端口,可以同时传输<strong>vlan2</strong>和<strong>vlan3</strong>的数据。<br> 然后第一个交换机的第一个端口作为iptv的端口 即 <strong>vlan2</strong> 而第二到第四端口作为网络的端口 即 <strong>vlan3</strong><br> 而第二个交换机的第八个端口作为汇聚端口,同时传输 <strong>vlan2</strong> 和 <strong>vlan3</strong> 的数据。<br> 然后第二个交换机的第七个端口作为iptv的端口 即 <strong>vlan2</strong> 而第一到第六端口作为网络的端口 即 <strong>vlan3</strong></p><p> 下面简单说明一下tag和untag的作用</p><ul><li>普通终端设备网卡(itv,电脑,电视)只能接收到无<strong>vlan</strong>标识的数据包</li><li>untag端口<ul><li>接收到没有标识的数据包,会打上当前端口的<strong>pvid</strong>标识然后转发</li><li>接收到带<strong>vlan</strong>标识的数据包<ul><li><strong>vlan</strong>标识和端口对应的<strong>pvid</strong>相同,接收转发</li><li><strong>vlan</strong>标识和端口对应的<strong>pvid</strong>不同,丢弃</li></ul></li></ul></li><li>tag端口接收到数据包,<ul><li>接收到没有标识的数据包,会打上当前端口的<strong>pvid</strong>标识然后转发</li><li>接收到带<strong>vlan</strong>标识的数据包<ul><li>这个端口属于标识的<strong>vlan</strong>,接收转发</li><li>这个端口不属于标识的<strong>vlan</strong>,丢弃</li></ul></li></ul></li></ul><p> 用个表格来表示的话如下所示:</p><table><thead><tr><th align="center"></th><th align="center">Tagged 数据</th><th align="center"></th><th align="center">Untagged 数据</th><th align="center"></th></tr></thead><tbody><tr><td align="center"></td><td align="center">in</td><td align="center">out</td><td align="center">in</td><td align="center">out</td></tr><tr><td align="center">Tagged 端口</td><td align="center">看情况接收</td><td align="center">原样发送</td><td align="center">接收</td><td align="center">按照端口的 PVID 打 TAG 标记</td></tr><tr><td align="center">Untagged 端口</td><td align="center">看情况接收</td><td align="center">去掉 TAG 标记</td><td align="center">接收</td><td align="center">按端口的 PVID 打 TAG 标记</td></tr></tbody></table></li></ol><h2 id="最后跑一下网速"><a href="#最后跑一下网速" class="headerlink" title="最后跑一下网速"></a>最后跑一下网速</h2><img src="/%E5%8D%95%E7%BA%BF%E5%A4%8D%E7%94%A8-iptv/%E7%BD%91%E9%80%9F.png" class=""><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://post.smzdm.com/p/alpozp40/">不改光猫任何配置,水星SG105 Pro完美解决电信ITV、网络单线复用</a><br><a href="https://post.smzdm.com/p/alpzdxpo/">网络设备 篇一:家庭网络改造-单线复用实践总结</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>计算机网络</tag>
<tag>iptv</tag>
<tag>vlan</tag>
</tags>
</entry>
<entry>
<title>golang 交叉编译</title>
<link href="/golang-%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91/"/>
<url>/golang-%E4%BA%A4%E5%8F%89%E7%BC%96%E8%AF%91/</url>
<content type="html"><![CDATA[<p>不试不知道,一试吓一跳</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>期末做了个项目,刚好是用的 golang ,于是试试 golang 的交叉编译是有多神奇。没想到,这个编译这么方便。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><ul><li>go version go1.15.6 windows/amd64</li></ul><h2 id="怎么交叉编译"><a href="#怎么交叉编译" class="headerlink" title="怎么交叉编译"></a>怎么交叉编译</h2><p>简单来说就是设置好 <strong>go</strong> 的相关参数,然后编译就可以了。<br>说实话挺简单的,先设置好<strong>目标系统</strong>,然后是<strong>目标架构</strong>,关掉 <strong>CGO</strong> ,然后就可以实现了。<br>简单来说是下面这样</p><table><thead><tr><th>目标系统</th><th>目标架构</th><th>命令</th></tr></thead><tbody><tr><td>Windows</td><td>x64</td><td><code>CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o output_file_name</code></td></tr><tr><td>Linux</td><td>x64</td><td><code>CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o output_file_name</code></td></tr><tr><td>MacOS</td><td>x64</td><td><code>CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -o output_file_name</code></td></tr><tr><td>Linux</td><td>arm</td><td><code>CGO_ENABLED=0 GOOS=linux GOARCH=arm go build -o output_file_name</code></td></tr><tr><td>Linux</td><td>mips</td><td><code>CGO_ENABLED=0 GOOS=linux GOARCH=mips GOMIPS=softfloat go build -trimpath -ldflags="-s -w" -o output_file_name</code></td></tr></tbody></table><p>其实最开始没想找 <strong>mips</strong> 上的编译方法的。我最开始是想把一个小项目放到我的路由器上跑,于是我直接用的 <strong>Linux/arm</strong> 上的编译方法来编译的。结果直接报错了,说</p><blockquote><p>line 1: syntax error: unexpected word (expecting “)”)</p></blockquote><p>于是一番查找,发现是可执行文件的格式不对,这个报错说明这个文件和这个架构不兼容。</p><p>于是用 <code>uname -a</code> 查看了一下路由器的架构,结果才发现是 <strong>mips</strong> 架构的。</p><blockquote><p>Linux OpenWrt 4.14.195 #0 Mon Sep 21 07:10:02 2020 mips GNU/Linux</p></blockquote><p>于是又是一番查找,才在<a href="https://github.com/ehang-io/nps/issues/97#issuecomment-720943422">openwrt环境下无法运行 #97</a>中发现了<a href="https://github.com/golang/go/wiki/GoMips#building-for-ar71xx-openwrt">GoMips#building-for-ar71xx-openwrt</a>。于是才找到了对应的方法</p><blockquote><p>env GOOS=linux GOARCH=mips GOMIPS=softfloat go build -trimpath -ldflags=”-s -w” ‘server.go’<br>upx -9 server</p></blockquote><h2 id="Windows-下交叉编译"><a href="#Windows-下交叉编译" class="headerlink" title="Windows 下交叉编译"></a>Windows 下交叉编译</h2><h3 id="通过写-bat-文件进行交叉编译"><a href="#通过写-bat-文件进行交叉编译" class="headerlink" title="通过写 bat 文件进行交叉编译"></a>通过写 bat 文件进行交叉编译</h3><p>因为 <strong>Windows</strong> 平台下的 <strong>powershell</strong> 和 <strong>cmd</strong> 不支持像 <code>*nix</code> 系的系统的 <code>bash</code> 可以在一条命令中设置环境变量,所以把上面的写成 <strong>.bat</strong> 文件来进行跨平台编译。下面就用编译 Linux/amd64 来举例<br>在项目的<strong>main</strong>包的<strong>main</strong>函数所在文件的位置新建一个 <strong>bat</strong>文件,名字随意,然后填入下面的内容</p><figure class="highlight bat"><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><code class="hljs bat"><span class="hljs-built_in">SET</span> CGO_ENABLED=<span class="hljs-number">0</span><br><span class="hljs-built_in">SET</span> GOOS=linux<br><span class="hljs-built_in">SET</span> GOARCH=amd64<br>go build -o release_linux_x64<br></code></pre></td></tr></table></figure><p>保存,然后运行,就可以发现编译出来了。</p><h4 id="更新-2020年12月17日-:"><a href="#更新-2020年12月17日-:" class="headerlink" title="更新 (2020年12月17日):"></a>更新 (2020年12月17日):</h4><p>在 <strong>GOOS</strong> 等项后面不能跟空格,直接复制的话会出问题,复制好了之后记得检查一下末尾的空格。</p><h3 id="通过-Git-Bash-编译"><a href="#通过-Git-Bash-编译" class="headerlink" title="通过 Git-Bash 编译"></a>通过 Git-Bash 编译</h3><p>不过这样太麻烦了,不是么?其实如果安装了 <strong>Git</strong> 的话,直接在对应的目录右键打开<strong>Git Bash Here</strong>,然后就可以像 <strong>Linux</strong> 和 <strong>MacOS</strong> 下一样直接用 </p><blockquote><p>CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o output_file_name</p></blockquote><p>就可以进行编译了。轻松加愉悦~</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.csdn.net/panshiqu/article/details/53788067">Golang 在 Mac、Linux、Windows 下如何交叉编译</a><br><a href="https://github.com/ehang-io/nps/issues/97#issuecomment-720943422">openwrt环境下无法运行 #97</a><br><a href="https://github.com/golang/go/wiki/GoMips#building-for-ar71xx-openwrt">GoMips#building-for-ar71xx-openwrt</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Windows</tag>
<tag>golang</tag>
<tag>x64</tag>
<tag>arm</tag>
<tag>mips</tag>
<tag>MacOS</tag>
</tags>
</entry>
<entry>
<title>为"Windows 10"忘记有线网络</title>
<link href="/%E4%B8%BA-Windows10-%E5%BF%98%E8%AE%B0%E6%9C%89%E7%BA%BF%E7%BD%91%E7%BB%9C/"/>
<url>/%E4%B8%BA-Windows10-%E5%BF%98%E8%AE%B0%E6%9C%89%E7%BA%BF%E7%BD%91%E7%BB%9C/</url>
<content type="html"><![CDATA[<p>注册表,永远滴神</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>折腾 openwrt 的时候重置了很多次系统,每次都记住了网络,结果就是网络 id 越来越多,最多到了 <code>网络 34</code>的地步。终于忍不住了,想要把没用的删掉。</p><p>大概就像下面这个样子:</p><img src="/%E4%B8%BA-Windows10-%E5%BF%98%E8%AE%B0%E6%9C%89%E7%BA%BF%E7%BD%91%E7%BB%9C/%E7%BD%91%E7%BB%9C%E7%A4%BA%E4%BE%8B.png" class="" title="示例"><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>这个竟然不像 <strong>wifi</strong> 一样可以直接忘记,而是必须得到注册表里面去删除,很奇怪。</p><h2 id="通过注册表删除"><a href="#通过注册表删除" class="headerlink" title="通过注册表删除"></a>通过注册表删除</h2><p>打开注册表</p><ul><li><code>Ctrl + R</code> 然后输入 <code>regedit</code></li><li>或者 <code>Win</code> 然后输入 <code>regedit</code></li></ul><p>找到如下路径</p><figure class="highlight moonscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs moonscript">计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles\<br></code></pre></td></tr></table></figure><p>这个时候我们就可以看到所有保存的网络了,选择不需要的删除掉即可。</p><p>哦对了,在删除之前记得先备份好这个 <code>\Profiles</code> 下的东西,避免删除到不该删除的东西。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.howtogeek.com/176148/how-to-%E2%80%9Cforget%E2%80%9D-a-wired-or-wireless-network-in-windows-8.1/">How to “Forget” a Wired (or Wireless) Network in Windows 8.1</a></p><p><a href="https://www.howtogeek.com/364291/how-to-change-or-rename-the-active-network-profile-name-in-windows-10/">How to Change or Rename the Active Network Profile Name in Windows 10</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Windows</tag>
</tags>
</entry>
<entry>
<title>unicode与utf-8的相关知识</title>
<link href="/unicode%E4%B8%8Eutf-8%E7%9A%84%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/"/>
<url>/unicode%E4%B8%8Eutf-8%E7%9A%84%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/</url>
<content type="html"><![CDATA[<p><code>unicode</code>是字符集,<code>utf-8</code>是字符集的编码方式。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>折腾<a href="https://github.com/yikakia/cheru">切噜语转换器</a>的时候踩了不少坑,不过也学到了不少的知识,于是记录一下。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="什么是-unicode"><a href="#什么是-unicode" class="headerlink" title="什么是 unicode"></a>什么是 unicode</h2><p>简单来说 <code>unicode</code>是一种字符和数字的映射方式。因为计算机传输文本的时候不可能给你传输字形(图片),所以就约定了传输一个数字来表示一个字符。而怎么显示和处理这个字符就是这个平台自己的事情了。</p><p>比如<code>我</code>这个字符,对于 <code>unicode</code> 而言就是<code>25105</code>,也就是说计算机 A 要给计算机 B 发一个字符 <code>我</code> 的时候,就给他发送<code>25105</code>,转换成二进制的话就是<code>110001000010001</code>,那么发送这一串0,1就可以了。</p><p>但是这只是一个字符而已,对于多个字符而言该怎么办呢?比如<code>你好</code>,分别是 <code>20320</code> 和 <code>22909</code>。转换成二进制的话就是<code>100111101100000</code>和<code>101100101111101</code>,为了方便起见,就用十六进制来表示,分别是<code>4f60</code>和<code>597d</code>,这个数字在<code>unicode</code>被称为<code>码位</code>(<code>code point</code>,即<code>编码位置</code>)。</p><p>那么假如一个字符是<code>a</code>,假如它的<code>unicode</code>码转换成二进制的话是<code>01100000</code>(实际上是<code>1100001</code>,这里只是为了演示),那么用十六进制表示的话就是<code>60</code>,发现没有,和<code>你</code>的后面一半是一样的。</p><p>我们再假设另一个字符是<code>b</code>,假如它的 <code>unicode</code> 码转换成二进制的话是<code>1011001</code>,那么用十六进制表示就是<code>59</code>,这和<code>好</code>的前半部分是一样的。这个时候假如我们舍弃掉<code>你</code>的前半部分,而是去读后半部分,同时再读取<code>好</code>的前半部分,那么读到的数字是<code>6159</code>(十六进制下),事实上这个数字在 <code>unicode</code> 中表示的字符是<code>恙</code>。</p><p>这就是问题所在了,事实上在计算机通信的时候,发出的信息是0,1组成的串,我们的 <code>unicode</code> 只是实现了字符与码位的映射关系,而对于解码的时候,不可避免地会遇到类似与在上面举的例子的情况,即不知道怎么才算读完了一个字符,这样就可能出现读到一半后文本的理解就出现了偏差的情况。</p><p>因此我们应该有一个用于表示 <code>unicode</code> 的方法,这个方法能够有效地表示<code>unicode</code> 字符集。这就是 <code>utf-8</code></p><h2 id="什么是-utf-8"><a href="#什么是-utf-8" class="headerlink" title="什么是 utf-8"></a>什么是 utf-8</h2><p>承接上文,我们可以发现表示 <code>unicode</code> 的时候需要有一个编码方式来让传输后的字符串能够没有歧义地解码,<code>utf-8</code>就是其中一种方式。</p><h3 id="utf-8是怎么编码的"><a href="#utf-8是怎么编码的" class="headerlink" title="utf-8是怎么编码的"></a>utf-8是怎么编码的</h3><p><code>utf-8</code>是这样定义的,对于一个<code>码位</code>而言如果范围在</p><ul><li><code>0~7f</code>之间的,就用第一种编码方式,第一位置零,后面七位原样计入</li><li><code>80~7ff</code>之间的,就用第二种编码方式,用两个字节来表示,其中<code>码位</code>的高五位,置入第一个字节的低五位,置第一个字节的高三位为<code>110</code>,而<code>码位</code>的低六位,置入第二个字节的低六位,置第二个字节的高二位为<code>10</code></li><li><code>800~ffff</code>之间的参照下面的表格</li><li><code>10000~10ffff</code>之间的参照下面的表格</li></ul><table><thead><tr><th>Unicode符号范围(码位)</th><th>UTF-8编码方式</th></tr></thead><tbody><tr><td>(十六进制)</td><td>(二进制)</td></tr><tr><td>0000 0000-0000 007F</td><td>0xxxxxxx</td></tr><tr><td>0000 0080-0000 07FF</td><td>110xxxxx 10xxxxxx</td></tr><tr><td>0000 0800-0000 FFFF</td><td>1110xxxx 10xxxxxx 10xxxxxx</td></tr><tr><td>0001 0000-0010 FFFF</td><td>11110xxx 10xxxxxx 10xxxxxx 10xxxxxx</td></tr></tbody></table><p>简单来说,<code>utf-8</code>的编码方式是将第一个字节从开头开始的连续<code>1</code>的个数记为这个字符一共需要几个字节来表示。比如说<code>110xxxxx</code>就表示这个字符需要<code>两</code>个字节来表示,因为开头的连续1是<code>11</code>,一共有两个<code>1</code>。那么<code>1110xxxx</code>就是表示这个字符需要<code>三</code>个字节来表示,而<code>11110xxx</code>就表示这个字符需要<code>四</code>个字节来表示。但是特殊的,我们会发现当首位为<code>0</code>的时候,它表示这个字符只需要<code>1</code>个字节来表示。事实上这正是<code>ASCII</code>码的编码方式(指只有一个字节时表示的<code>unicode</code>码的码位和 <code>ASCII</code>的同码位所代表的字符是同一个)。</p><p>说完了第一个,接下来就是后面的部分了。和表中的一样,我们会发现凡是用多个字节来表示的字符,它们的第二个及以后的字节的开头都是<code>10</code>。这就是第二个规则,第二个及以后的字节的开头都是<code>10</code>。</p><p>这样我们就可以没有歧义地传输代表<code>unicode</code>的码位的0,1序列了。</p><h3 id="解码举例"><a href="#解码举例" class="headerlink" title="解码举例"></a>解码举例</h3><p>比如我们如果读到一个字节开头是<code>10</code>的话,就说明这是这个字符的后面部分,并不完整。要读取完整的字符的话就得考虑向前走几个字节,直到找到高几位是连续1的字节。而对于字节开头是<code>0</code>的话,就说明它的低七位就是要代表的字符。</p><p>比如说我们读到这样的序列<code>11100100</code> <code>10111101</code> <code>10100000</code> <code>11100101</code> <code>10100101</code> <code>10111101</code>的时候,我们先读第一个字节<code>11100100</code>,这个时候首位不是<code>0</code>,那么就找连续的1的个数,发现是<code>1110</code>,这说明这个字符需要由三个字节表示,那么先存入的第一个字节开头的后半部分<code>0100</code>,接着继续往后走,读取到了第二个字节,开头是<code>10</code>,符合<code>utf-8</code>的编码规则,取出第二个字节的后半部分<code>111101</code>并将其放入之前取出的部分的后面,拼装起来就是<code>0100 111101</code>(空格只是为了方便观察是哪一部分),之前是说这个字符要三个字节表示对吧,那么就继续往后面走,发现下一个字节的开头是<code>10</code>,符合<code>utf-8</code>的编码规则,于是取出第三个字节的后面六位<code>100000</code>,把它拼在之前拼装的结果的后面,拼装后的结果为<code>0100 111101 100000</code>,把它转成十进制表示的话正好是<code>20320</code>,查询<code>unicode</code>的定义发现代表的是<code>你</code>。</p><p>后面的三个字节如法炮制即可,我们可以发现后面三个字节得到的数字 <code>0101 100101 111101</code> 转换成十进制是 <code>22909</code>,查询<code>unicode</code>的定义发现是<code>好</code>这个字符。因此,我们之前传输的这六个字节表示<code>你好</code>这个字符串。</p><h3 id="如果格式不匹配呢"><a href="#如果格式不匹配呢" class="headerlink" title="如果格式不匹配呢"></a>如果格式不匹配呢</h3><p>这个时候我们就有问题了,当我们读这个0,1序列的时候,如果发现部分满足<code>utf-8</code>格式,部分不满足的时候该怎么办呢?这个时候出现的情形就是乱码。即程序会把能够匹配<code>utf-8</code>规则的字符显示出来,而不能成功解码的则会显示为或者�这种符号。这时候我们就可以考虑是文档损坏了,还是这个文档的编码方式有问题,可能不是<code>utf-8</code>格式而是其他的格式,比如说<code>gbk</code>。</p><h2 id="golang-对-unicode-的支持"><a href="#golang-对-unicode-的支持" class="headerlink" title="golang 对 unicode 的支持"></a>golang 对 unicode 的支持</h2><p>golang 默认采取的是<code>utf-8</code>编码(顺便插一句,Go语言的发明者之一Ken Thompson正是UTF-8的发明人,而他也同时是C,Unix,Plan9等的创始人),不同于 c 语言中的<code>char</code>作为字符的基本单位,golang中是用<code>rune</code>作为基本单位,其对应的是用<code>utf-8</code>编码后的<code>byte</code>数组(<code>byte</code>可以认为是<code>uint8</code>)。这里用别人的一张图可能更加直观</p><img src="/unicode%E4%B8%8Eutf-8%E7%9A%84%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/bgbiao.jpg" class=""><p><code>人</code>的码位是<code>4eba</code>,将其转换成<code>utf-8</code>后就是<code>e4 ba ba</code>。所以我们平时对 <code>string</code> 数组进行遍历的时候,如果按照下标进行遍历,其实是遍历<code>4e</code>和<code>ba</code>,而不是将其作为整体<code>4eba</code>,这个时候就会出现错误。因此我们可以知道<code>rune</code>储存的是码点<code>4eba</code>,而将<code>string('人')</code>,转换为<code>byte</code>数组<code>[]byte(string('人'))</code>则为<code>e4 ba ba</code>,这正是<code>utf-8</code>的编码方式,也就是实际进行储存和传输时的格式。</p><p>于是我们可以知道,平时遍历的时候取到的值只是<code>unicdoe</code>而已,对于需要修改储存方式或者是加密字符串的时候,就要对实际储存的数值进行修改了,这里再用我做的一个图来看看就知道了。</p><img src="/unicode%E4%B8%8Eutf-8%E7%9A%84%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86/%E6%88%91.png" class=""><p>这里 <code>rune</code> 表示的是 <code>a:=rune("我")</code>中的 <code>a</code> 用二进制表示的时候值。</p><p>而<code>byte1,2,3</code>则是则是转换成<code>utf-8</code>编码之后的表现形式。也就是实际储存和传输的值。<code>b:=[]byte("我")</code></p><p>这里为了方便看到对齐的效果,我将<code>rune</code>位上的值为 1 的部分表现为绿色,值为<code>0</code>的部分表现为红色,而<code>byte</code>数组中用于标注的部分表现为蓝色,这样我们就可以清楚地看到这个是怎么对齐的了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="http://www.qianxingzhem.com/post-1499.html">网页编码就是那点事</a><br><a href="https://studygolang.com/articles/28962">Golang下的Unicode和字符串</a></p>]]></content>
<categories>
<category>学习</category>
</categories>
<tags>
<tag>golang</tag>
<tag>unicode</tag>
<tag>utf-8</tag>
</tags>
</entry>
<entry>
<title>利用官方工具将python2的代码转换为python3的代码</title>
<link href="/%E5%88%A9%E7%94%A8%E5%AE%98%E6%96%B9%E5%B7%A5%E5%85%B7%E5%B0%86python2%E7%9A%84%E4%BB%A3%E7%A0%81%E8%BD%AC%E6%8D%A2%E4%B8%BApython3%E7%9A%84%E4%BB%A3%E7%A0%81/"/>
<url>/%E5%88%A9%E7%94%A8%E5%AE%98%E6%96%B9%E5%B7%A5%E5%85%B7%E5%B0%86python2%E7%9A%84%E4%BB%A3%E7%A0%81%E8%BD%AC%E6%8D%A2%E4%B8%BApython3%E7%9A%84%E4%BB%A3%E7%A0%81/</url>
<content type="html"><![CDATA[<p>一键搞定</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>简单地说教材上给的代码是 py2 的,但我的环境只有 py3。所以找了找,发现还真的有转换的代码</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>先定位到你的<code>python3</code>的安装路径,我这里是<code>D:\DevEnv\Python\Python38</code>,然后到它下面的<code>.\Tools\scripts</code>中去,然后执行其中的<code>2to3.py</code>脚本。这个脚本接受路径后会显示如果把路径下的所有<code>py2</code>格式的文件转换为<code>py3</code>格式的文件后两者的区别。而要直接转换成<code>py3</code>的文件的话则需要再传入参数 <code>-w</code>,接受这个参数后脚本会完成转换,并且保存原来的<code>py2</code>的脚本的副本。</p><figure class="highlight powershell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs powershell"><span class="hljs-built_in">cd</span> D:\DevEnv\Python\Python38\Tools\scripts<br>python .\<span class="hljs-number">2</span>to3.py <span class="hljs-literal">-w</span> <span class="hljs-string">"D:\Codes\Chapter 7_Code"</span><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://docs.python.org/zh-cn/3/library/2to3.html">2to3 - 自动将 Python 2 代码转为 Python 3 代码</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>python</tag>
</tags>
</entry>
<entry>
<title>Sleep Sort 的 Golang 实现</title>
<link href="/sleep-sort-%E7%9A%84-golang-%E5%AE%9E%E7%8E%B0/"/>
<url>/sleep-sort-%E7%9A%84-golang-%E5%AE%9E%E7%8E%B0/</url>
<content type="html"><![CDATA[<p>多线程排序的蛋疼算法</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在网上乱逛的时候看到了这个 sleep-sort 的算法,感觉很有趣。刚好在学 golang, 就用这个来实践一下并发操作吧。</p><p>这个算法原本是来自 4chan 的一个帖子,不过好像原帖早就被冲水了?只能说 4chan 老哥欢乐多。</p><p>原本是给的一个 shell 脚本</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-meta">#!/bin/bash</span><br><span class="hljs-keyword">function</span> <span class="hljs-function"><span class="hljs-title">f</span></span>() {<br> <span class="hljs-built_in">sleep</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span><br> <span class="hljs-built_in">echo</span> <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span><br>}<br><span class="hljs-keyword">while</span> [ -n <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> ]<br><span class="hljs-keyword">do</span><br> f <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> &<br> <span class="hljs-built_in">shift</span><br><span class="hljs-keyword">done</span><br><span class="hljs-built_in">wait</span><br></code></pre></td></tr></table></figure><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>先上源代码</p><figure class="highlight golang"><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></pre></td><td class="code"><pre><code class="hljs golang"><span class="hljs-keyword">package</span> main<br><br><span class="hljs-keyword">import</span> (<br><span class="hljs-string">"fmt"</span><br><span class="hljs-string">"log"</span><br><span class="hljs-string">"os"</span><br><span class="hljs-string">"path/filepath"</span><br><span class="hljs-string">"strconv"</span><br><span class="hljs-string">"time"</span><br>)<br><br><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-title">main</span><span class="hljs-params">()</span></span> {<br><span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(os.Args) < <span class="hljs-number">2</span> || os.Args[<span class="hljs-number">1</span>] == <span class="hljs-string">"-h"</span> || os.Args[<span class="hljs-number">1</span>] == <span class="hljs-string">"--help"</span> {<br>fmt.Printf(<span class="hljs-string">"使用方法: %s [需要排序的数组 空格隔开]\n"</span>, filepath.Base(os.Args[<span class="hljs-number">0</span>]))<br>fmt.Printf(<span class="hljs-string">"如: %s 2 2 1 3 4\n"</span>, filepath.Base(os.Args[<span class="hljs-number">0</span>]))<br>os.Exit(<span class="hljs-number">1</span>)<br>}<br>answer := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-type">int</span>, <span class="hljs-built_in">len</span>(os.Args)<span class="hljs-number">-1</span>)<br><span class="hljs-keyword">defer</span> <span class="hljs-built_in">close</span>(answer)<br><span class="hljs-keyword">for</span> _, num := <span class="hljs-keyword">range</span> os.Args[<span class="hljs-number">1</span>:] {<br><span class="hljs-keyword">if</span> sleeptime, err := strconv.Atoi(num); err != <span class="hljs-literal">nil</span> {<br>log.Fatal(err)<br>} <span class="hljs-keyword">else</span> {<br><span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {<br>time.Sleep(time.Duration(sleeptime) * time.Millisecond * <span class="hljs-number">120</span>)<br>answer <- sleeptime<br>}()<br>}<br>}<br>DONE:<br><span class="hljs-keyword">for</span> {<br><span class="hljs-keyword">switch</span> <span class="hljs-built_in">len</span>(answer) {<br><span class="hljs-keyword">case</span> <span class="hljs-built_in">len</span>(os.Args) - <span class="hljs-number">1</span>:<br><span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i < <span class="hljs-built_in">len</span>(os.Args)<span class="hljs-number">-1</span>; i++ {<br>output := <-answer<br>fmt.Print(output, <span class="hljs-string">" "</span>)<br>}<br><span class="hljs-keyword">break</span> DONE<br>}<br>}<br>}<br></code></pre></td></tr></table></figure><p>我这边倒没有专门写一个排序的包,不过单独摘出来其实也很简单的。改成输入的参数是一个 int 类型的函数就好了。</p><p>我这个主要是通过命令行的方式来调用,所以也顺便练习了一下 os.Args 的使用。</p><p>算法的实现其实很简单,就是对要排序的每个数字开一个 goroutine 然后等待对应的时长。在时间到了之后就把结果放到 answer 这个通道里面。</p><p>然后主函数中就是等所有的数字处理好之后就可以开始一个一个输出了。因为不知道要等待的时长,所以就是用了一个无限循环的函数来检测answer的长度。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.reddit.com/r/golang/comments/2qg4ey/sleep_sort_with_goroutines/">Sleep sort with goroutines</a></p>]]></content>
<categories>
<category>学习</category>
</categories>
<tags>
<tag>Golang</tag>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>Lets-Encrypt-更新报错</title>
<link href="/Lets-Encrypt-%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99/"/>
<url>/Lets-Encrypt-%E6%9B%B4%E6%96%B0%E6%8A%A5%E9%94%99/</url>
<content type="html"><![CDATA[<p>复制 粘贴 搜索 解决问题</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>证书快过期了,我就去手动更新一下,结果报错了??没辙,只好想办法解决了。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">certbot-auto renew --renew-hook <span class="hljs-string">"sudo nginx -s reload"</span><br></code></pre></td></tr></table></figure><p>利用上面的命令更新证书的时候遇到了下面这样的报错信息</p><figure class="highlight reasonml"><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><code class="hljs reasonml">Cert is due <span class="hljs-keyword">for</span> renewal, auto-renewing...<br>Could not choose appropriate plugin: The manual plugin is not working; there may be problems <span class="hljs-keyword">with</span> your existing configuration.<br>The error was: <span class="hljs-constructor">PluginError('An <span class="hljs-params">authentication</span> <span class="hljs-params">script</span> <span class="hljs-params">must</span> <span class="hljs-params">be</span> <span class="hljs-params">provided</span> <span class="hljs-params">with</span> --<span class="hljs-params">manual</span>-<span class="hljs-params">auth</span>-<span class="hljs-params">hook</span> <span class="hljs-params">when</span> <span class="hljs-params">using</span> <span class="hljs-params">the</span> <span class="hljs-params">manual</span> <span class="hljs-params">plugin</span> <span class="hljs-params">non</span>-<span class="hljs-params">interactively</span>.',)</span><br>Attempting <span class="hljs-keyword">to</span> renew cert (yikakia.com) from /etc/letsencrypt/renewal/yikakia.com.conf produced an unexpected error: The manual plugin is not working; there may be problems <span class="hljs-keyword">with</span> your existing configuration.<br>The error was: <span class="hljs-constructor">PluginError('An <span class="hljs-params">authentication</span> <span class="hljs-params">script</span> <span class="hljs-params">must</span> <span class="hljs-params">be</span> <span class="hljs-params">provided</span> <span class="hljs-params">with</span> --<span class="hljs-params">manual</span>-<span class="hljs-params">auth</span>-<span class="hljs-params">hook</span> <span class="hljs-params">when</span> <span class="hljs-params">using</span> <span class="hljs-params">the</span> <span class="hljs-params">manual</span> <span class="hljs-params">plugin</span> <span class="hljs-params">non</span>-<span class="hljs-params">interactively</span>.',)</span>. Skipping.<br>All renewal attempts failed. The following certs could not be renewed:<br> /etc/letsencrypt/live/yikakia.com/fullchain.pem (failure)<br></code></pre></td></tr></table></figure><p>这个时候我们就手动更新就好了</p><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 先到你放 letsencrypt 的地方</span><br><span class="hljs-built_in">cd</span> ~/certbot<br><br><span class="hljs-comment"># 然后输入如下命令强制执行更新</span><br>./letsencrypt-auto certonly --debug --force-renew -a manual -d yikakia.com<br></code></pre></td></tr></table></figure><p>这个时候会出现下面这样的提示</p><figure class="highlight awk"><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></pre></td><td class="code"><pre><code class="hljs awk"><br>Saving debug log to <span class="hljs-regexp">/var/</span>log<span class="hljs-regexp">/letsencrypt/</span>letsencrypt.log<br>Plugins selected: Authenticator manual, Installer None<br>Obtaining a new certificate<br>Performing the following challenges:<br>http-<span class="hljs-number">01</span> challenge <span class="hljs-keyword">for</span> yikakia.com<br><br>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br>NOTE: The IP of this machine will be publicly logged as having requested this<br>certificate. If yo<span class="hljs-string">u're running certbot in manual mode on a machine that is not</span><br><span class="hljs-string">your server, please ensure you'</span>re okay with that.<br><br>Are you OK with your IP being logged?<br>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br>(Y)es/(N)o: y<br><br>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br>Create a file containing just this data:<br><br>一大串英文与数字,作为文件的内容,用于验证你对这个网址的所有权<br><br>And make it available on your web server at this URL:<br><br>http:<span class="hljs-regexp">//yi</span>kakia.com<span class="hljs-regexp">/.well-known/</span>acme-challenge/一大串英文与数字<br><br><span class="hljs-comment"># 这里就是说让你在你的网站的目录下新建一个/.well-known/acme-challeng/ 的文件夹,然后在里面放一个含有对应验证内容的文件。文件名也要是对应的才行。</span><br></code></pre></td></tr></table></figure><p>现在放完了你测试下能不能获取到对应的内容就好了。如果可以的话,你就输入回车键开始验证吧。验证成功的话会出现下面这样的信息提示你验证成功了。</p><figure class="highlight lasso"><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></pre></td><td class="code"><pre><code class="hljs lasso">- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -<br>Press Enter <span class="hljs-keyword">to</span> Continue<br>Waiting for verification<span class="hljs-params">...</span><br>Cleaning up challenges<br><br>IMPORTANT NOTES:<br> - Congratulations! Your certificate <span class="hljs-literal">and</span> chain have been saved at:<br> /公钥储存的地址<br> Your key file has been saved at:<br> /私钥储存的地址<br> Your cert will expire <span class="hljs-keyword">on</span> <span class="hljs-number">2020</span><span class="hljs-number">-11</span><span class="hljs-number">-19.</span> <span class="hljs-keyword">To</span> obtain a <span class="hljs-literal">new</span> <span class="hljs-literal">or</span> tweaked<br> version of this certificate <span class="hljs-keyword">in</span> the future, simply run<br> letsencrypt<span class="hljs-params">-auto</span> again. <span class="hljs-keyword">To</span> non<span class="hljs-params">-interactively</span> renew *<span class="hljs-literal">all</span>* of your<br> certificates, run <span class="hljs-string">"letsencrypt-auto renew"</span><br> - <span class="hljs-keyword">If</span> you like Certbot, please consider supporting our work <span class="hljs-keyword">by</span>:<br><br> Donating <span class="hljs-keyword">to</span> ISRG / <span class="hljs-keyword">Let</span><span class="hljs-string">'s Encrypt: https://letsencrypt.org/donate</span><br><span class="hljs-string"> Donating to EFF: https://eff.org/donate-le</span><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://kyle.ai/blog/6333.html">使用Let’s Encrypt给网站加上免费HTTPS证书 |Kyle’s Blog</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>error</tag>
<tag>SSL</tag>
</tags>
</entry>
<entry>
<title>寻找重复数-快慢指针解法原理</title>
<link href="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/"/>
<url>/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/</url>
<content type="html"><![CDATA[<p>是龟兔赛跑。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>突然刷到了一个视频<a href="https://www.youtube.com/watch?v=pKO9UjSeLew">If Programming Was An Anime</a></p><p>里面的快慢指针很有趣,刚好有兴趣,那就写一下吧。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>要用快慢指针解决寻找重复数的话要证明两个部分。一个部分是这个题一定会构造出一个环,一个是快慢指针用来寻找环的入口的证明。</p><h2 id="证明根据题意一定会构造出一个环"><a href="#证明根据题意一定会构造出一个环" class="headerlink" title="证明根据题意一定会构造出一个环"></a>证明根据题意一定会构造出一个环</h2><p>我们可以先想象出一个由1到n+1的数列,将它们打乱放置在下标从0到n的数组nums[]中。假设有个函数可以根据值返回它在数组中的下标 getIndex()</p><p>我们可以知道nums[0]的入度为0,而值为n+1的nums[getIndex(n+1)]的出度为0,数组中的其他的入度和出度都是1。这个时候可能会生成很多的环,但是如果将nums[0]作为入口的话,是不可能出现环的,因为nums[0]的入度为0,没有指向nums[0]的值。</p><p>现在我们将由nums[0]为起点的这个链表找到,假设值为n+1的数字在这个链表中,那么把它改为1~n中的任意一个数,记为p,此时我们可以知道nums[p]的入度为2,因为有两个指向它的指针。同时原本值为n+1的这个数的有了出边,指向了nums[p]</p><p>当值为p的nums[getIndex(p)]在以nums[0]开头的这个链表中时,我们可以很轻易的想象出来这个这条链表形成了一个环,包括了nums[p]到nums[x]的这一系列节点。</p><p>那么当这个值为p的nums[getIndex(p)]不在以nums[0]开头的这个链表中时,它在另外的一个链表中。举个例子[1,4,3,2,5]。此时nums[2]和nums[3]形成了一个环,我们将nums[4]的值改为3,即 nums == [1,4,3,2,3] 我们可以看到从nums[0]开始的链表最后还是会进入到一个环中。</p><p>那么值为n+1的数字不在这个链表中呢?其实这并不可能,因为它没有出边,那么它不可能在一个环中,因为所有的节点出度都是1,所以必然不存在一个环中的节点既能指向环中的节点,又能指向环外的节点。因此这个nums[getIndex(n+1)]必然在以nums[0]开头的链表中。</p><h2 id="证明使用快慢指针来寻找环的入口"><a href="#证明使用快慢指针来寻找环的入口" class="headerlink" title="证明使用快慢指针来寻找环的入口"></a>证明使用快慢指针来寻找环的入口</h2><p>通过上面的证明我们知道了根据题意我们会构造出一个环,而环的入口就是那个重复的数。</p><p>那么我们应该怎么找到这个重复的数呢?简单地说定义两个指针,一个慢指针(slow)每次走一步,一个快指针(fast)每次走两步。当快慢指针指向的数组下标相等时就将快指针放回数组的头部,然后继续走,当快慢指针指向的数组下标相等时,这个值就是要找的环的入口。</p><p>那么问题是,怎么证明呢?</p><p>如下图,令A点为起始点,B点为环的入口,C点为慢指针首次到达B点时快指针的位置,D点为快慢指针首次在环中相遇的地点。记AB的距离为a,BC的距离为b,环的周长为R。</p><img src="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/%E5%9B%BE1.png" class="" title="定义"><p>我们让慢指针的速度为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_{1} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> ,快指针的速度为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>2</mn></msub></mrow><annotation encoding="application/x-tex">v_{2} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 。令<span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>2</mn></msub><mo>=</mo><mn>2</mn><mo>∗</mo><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_{2} = 2 * v_{1} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span>,即慢指针每次走一步,快指针每次走两步</p><img src="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/%E5%9B%BE2.png" class="" title="快慢指针"><p>那么当慢指针到达B点时,快指针已经走了 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>1</mn></msub><mo>=</mo><mi>a</mi><mo>+</mo><mi>b</mi><mo>+</mo><mi>n</mi><mo>∗</mo><mi>R</mi></mrow><annotation encoding="application/x-tex">S_{1} = a+b+n*R </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.66666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.77777em;vertical-align:-0.08333em;"></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.46528em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.68333em;vertical-align:0em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span></span></span></span> 其中 n 为快指针在环里已经绕过的圈数。又知道快指针的速度为慢指针的两倍,所以快指针走过的路程 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>1</mn></msub><mo>=</mo><mn>2</mn><mo>∗</mo><mi>a</mi></mrow><annotation encoding="application/x-tex">S_{1} = 2 * a </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span></span></span></span> 即慢指针走过的路程的两倍。我们将其整理可以得到 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>a</mi><mo>=</mo><mi>n</mi><mo>∗</mo><mi>R</mi><mo>+</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">a = n * R + b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.46528em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span></p><img src="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/%E5%9B%BE3.png" class="" title="慢指针到B点"><p>因为快指针每次走两步,慢指针每次走一步。所以快指针每次比慢指针多走一步。在慢指针到达B点时,快指针和慢指针的距离是 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>2</mn></msub><mo>=</mo><msub><mi>S</mi><mrow><mi>c</mi><mi>b</mi></mrow></msub><mo>=</mo><mi>R</mi><mo>−</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">S_{2} = S_{cb} = R - b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.33610799999999996em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mathnormal mtight">c</span><span class="mord mathnormal mtight">b</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span> 。也就是说从现在开始,到两者首次相遇在D点,慢指针要走 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>3</mn></msub><mo>=</mo><msub><mi>S</mi><mn>2</mn></msub><mo>=</mo><mi>R</mi><mo>−</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">S_{3} = S_{2} = R-b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span> 这么多步。那么这个时候因为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>2</mn></msub><mo>=</mo><mn>2</mn><mo>∗</mo><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_{2} = 2 * v_{1} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 所以快指针走的距离为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>4</mn></msub><mo>=</mo><mn>2</mn><mo>∗</mo><msub><mi>S</mi><mn>2</mn></msub><mo>=</mo><mn>2</mn><mo>∗</mo><mo stretchy="false">(</mo><mi>R</mi><mo>−</mo><mi>b</mi><mo stretchy="false">)</mo></mrow><annotation encoding="application/x-tex">S_{4} = 2 * S_{2} = 2 * (R - b) </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">2</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">b</span><span class="mclose">)</span></span></span></span>。</p><p>因为在慢指针刚到达B点时,快指针在C点,所以当两者在D点相遇时,快指针相对于B点的距离为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>5</mn></msub><mo>=</mo><msub><mi>S</mi><mn>4</mn></msub><mo>+</mo><mi>b</mi><mo>=</mo><mn>2</mn><mo>∗</mo><mi>R</mi><mo>−</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">S_{5} = S_{4} + b = 2 * R - b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">5</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">4</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.64444em;vertical-align:0em;"></span><span class="mord">2</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span> 。因为R为环的周长所以可以约去,因此此时快指针相对于B点的距离为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi mathvariant="normal">∣</mi><mo>−</mo><mi>b</mi><mi mathvariant="normal">∣</mi><mo>=</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">|-b| = b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord">∣</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">−</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mord mathnormal">b</span><span class="mord">∣</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span> 即D点与C点刚好形成一个对称关系。</p><img src="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/%E5%9B%BE4.png" class="" title="快慢指针D点相遇"><p>此时我们将快指针移回原点A,并且让它的速度为 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>v</mi><mn>3</mn></msub><mo>=</mo><msub><mi>v</mi><mn>1</mn></msub></mrow><annotation encoding="application/x-tex">v_{3} = v_{1} </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">3</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.58056em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.03588em;">v</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.03588em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">1</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span></span></span></span> 如果让快指针从A点走到B点那么可以知道此时快慢指针走过的路程相同 <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><msub><mi>S</mi><mn>6</mn></msub><mo>=</mo><mi>a</mi><mo>=</mo><mi>n</mi><mo>∗</mo><mi>R</mi><mo>+</mo><mi>b</mi></mrow><annotation encoding="application/x-tex">S_{6} = a = n * R + b </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.83333em;vertical-align:-0.15em;"></span><span class="mord"><span class="mord mathnormal" style="margin-right:0.05764em;">S</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.30110799999999993em;"><span style="top:-2.5500000000000003em;margin-left:-0.05764em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mtight"><span class="mord mtight">6</span></span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.43056em;vertical-align:0em;"></span><span class="mord mathnormal">a</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span><span class="mrel">=</span><span class="mspace" style="margin-right:0.2777777777777778em;"></span></span><span class="base"><span class="strut" style="height:0.46528em;vertical-align:0em;"></span><span class="mord mathnormal">n</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">∗</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.76666em;vertical-align:-0.08333em;"></span><span class="mord mathnormal" style="margin-right:0.00773em;">R</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span><span class="mbin">+</span><span class="mspace" style="margin-right:0.2222222222222222em;"></span></span><span class="base"><span class="strut" style="height:0.69444em;vertical-align:0em;"></span><span class="mord mathnormal">b</span></span></span></span> 。因为R为环的周长所以对于在环里的慢指针而言可以约去,此时我们会发现当快指针到达B点的时候,慢指针也到达了B点,此时的B点正好是环的入口。</p><img src="/%E5%AF%BB%E6%89%BE%E9%87%8D%E5%A4%8D%E6%95%B0-%E5%BF%AB%E6%85%A2%E6%8C%87%E9%92%88%E8%A7%A3%E6%B3%95%E5%8E%9F%E7%90%86/%E5%9B%BE5.png" class="" title="快指针移回原点"><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.csdn.net/donghuaan/article/details/78988987">【链表】【证明】快慢指针判断链表有环、寻找环入口、计算环大小的原理</a></p>]]></content>
</entry>
<entry>
<title>hexo-更新tag的大小写后标签页出现错误</title>
<link href="/hexo-%E6%9B%B4%E6%96%B0tag%E7%9A%84%E5%A4%A7%E5%B0%8F%E5%86%99%E5%90%8E%E6%A0%87%E7%AD%BE%E9%A1%B5%E5%87%BA%E7%8E%B0%E9%94%99%E8%AF%AF/"/>
<url>/hexo-%E6%9B%B4%E6%96%B0tag%E7%9A%84%E5%A4%A7%E5%B0%8F%E5%86%99%E5%90%8E%E6%A0%87%E7%AD%BE%E9%A1%B5%E5%87%BA%E7%8E%B0%E9%94%99%E8%AF%AF/</url>
<content type="html"><![CDATA[<p>大小写,永远的痛</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在看自己的博客的时候,突然发现我的标签页面很多个 tag 页面打开都是 404 报错。<br>对多个 tag 查了之后才发现,问题应该是出现在大小写上。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><ul><li>本地: Windows10</li><li>服务器: Debian10</li></ul><h2 id="现象"><a href="#现象" class="headerlink" title="现象"></a>现象</h2><p>本地运行<code>hexo s</code>查看到的 tag 页面是正常的,大小写的网址都能区分开,而在服务器上运行时则出现了 404 错误。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>参考这个 <code>issue</code> <a href="https://github.com/hexojs/hexo/issues/818">BUG反馈:大写开头的标签出现404 #818</a></p><p>简单是说就是在<code>Windows</code>平台的<code>Git</code>是默认大小写不敏感的,因为<code>Windows</code>本身就是大小写不敏感的,于是<code>Git</code>便遵守了平台的规范,默认设置了大小写不敏感,因此当你在本地新建了一个 <code>a.txt</code> 的文件并提交后,又把这个文件重命名为了<code>A.txt</code>。这个时候你就会出现无法提交的情况。因为<code>Git</code>默认你的文件大小写不影响,所以你的服务器上只有一个<code>a.txt</code>存在。</p><p>到了我们这个现实的例子上就是原本有个 tag 页面是 <code>git</code> 的,现在改名成了<code>Git</code> 这个时候你会发现本地运行<code>hexo s</code>,查看这个<code>Git</code>页面是没问题的,但是到了服务器上就会出现<code>404</code>错误。而在这个时候你查看<code>git</code>这个页面的时侯又没有问题了。</p><p>知道了原理就好解决了。</p><h2 id="解决"><a href="#解决" class="headerlink" title="解决"></a>解决</h2><p>到本地的<code>hexo</code>博客目录下,找到<code>\.deploy_git\.git</code>这个目录,把这个目录下的<code>config</code>中的<code>[core]</code>这一项下的<code>ignorcase</code>这一项从<code>true</code>修改为<code>false</code>。这样就解决了大小写不敏感的问题。</p><p>简单地说就是改成这个样子</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-attr">ignorecase</span> = <span class="hljs-literal">false</span><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://github.com/hexojs/hexo/issues/818">BUG反馈:大写开头的标签出现404 #818</a></p><p><a href="https://www.lovesofttech.com/general/hexoTagsAndCategories404Error.html#%E5%89%8D%E6%8F%90">hexo 标签、分类,大小写问题导致404错误,原因分析和解决</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Git</tag>
<tag>hexo</tag>
</tags>
</entry>
<entry>
<title>win10更新后导致manjaro的引导文件失效的解决</title>
<link href="/win10%E6%9B%B4%E6%96%B0%E5%90%8E%E5%AF%BC%E8%87%B4manjaro%E7%9A%84%E5%BC%95%E5%AF%BC%E6%96%87%E4%BB%B6%E5%A4%B1%E6%95%88%E7%9A%84%E8%A7%A3%E5%86%B3/"/>
<url>/win10%E6%9B%B4%E6%96%B0%E5%90%8E%E5%AF%BC%E8%87%B4manjaro%E7%9A%84%E5%BC%95%E5%AF%BC%E6%96%87%E4%BB%B6%E5%A4%B1%E6%95%88%E7%9A%84%E8%A7%A3%E5%86%B3/</url>
<content type="html"><![CDATA[<p>windows bug 10, best windows 10!</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>更新了 Windows10 2004 的更新后发现 manjaro 的系统进不去了。进去了是 grub rescue 救援模式。<br>参考了救援模式的解决,但好像只看到了<code>/boot</code>的挂载点,没看到<code>/boot/efi</code>的挂载点,更别提<code>/</code>的挂载点了。</p><p>所以没办法,就烧了个<code>manjaro</code> 的 livecd 进去修复 grub .其中也踩了几个坑,这里记一下,方便遇到相同问题的人解决。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="我的环境"><a href="#我的环境" class="headerlink" title="我的环境"></a>我的环境</h2><p>这里我列一下我的文件目录的挂载点。之前出错就是因为这里有问题。</p><figure class="highlight tap"><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></pre></td><td class="code"><pre><code class="hljs tap">设备 启动 起点 末尾 扇区 大小 Id 类型<br>/dev/sda1 * <span class="hljs-number"> 64 </span>1848663470<span class="hljs-number"> 1848663407 </span>881.5G <span class="hljs-number"> 7 </span>HPFS/NTFS/exFAT<br>/dev/sda2 <span class="hljs-number"> 1848664064 </span>1893720063 <span class="hljs-number"> 45056000 </span> 21.5G<span class="hljs-number"> 83 </span>Linux<br>/dev/sda3 <span class="hljs-number"> 1893720064 </span>1934680063 <span class="hljs-number"> 40960000 </span> 19.5G<span class="hljs-number"> 83 </span>Linux<br>/dev/sda4 <span class="hljs-number"> 1934680064 </span>1953520064 <span class="hljs-number"> 18840001 </span> 9G<span class="hljs-number"> 82 </span>Linux swap / Solaris<br><br>设备 起点 末尾 扇区 大小 类型<br>/dev/sdb1 <span class="hljs-number"> 2048 </span> <span class="hljs-number"> 1085439 </span> <span class="hljs-number"> 1083392 </span> 529M Windows 恢复环境<br>/dev/sdb2 <span class="hljs-number"> 1085440 </span> <span class="hljs-number"> 1290239 </span> <span class="hljs-number"> 204800 </span> 100M EFI 系统<br>/dev/sdb3 <span class="hljs-number"> 1290240 </span> <span class="hljs-number"> 1323007 </span> <span class="hljs-number"> 32768 </span> 16M Microsoft 保留<br>/dev/sdb4 <span class="hljs-number"> 1323008 </span>244098048<span class="hljs-number"> 242775041 </span>115.8G Microsoft 基本数据<br>/dev/sdb5 <span class="hljs-number"> 244099072 </span>245411839 <span class="hljs-number"> 1312768 </span> 641M Windows 恢复环境<br>/dev/sdb6 <span class="hljs-number"> 245413888 </span>247463902 <span class="hljs-number"> 2050015 </span> 1001M Linux 文件系统<br></code></pre></td></tr></table></figure><p>这里我是因为用双硬盘装了<code>Windows</code>和<code>Manjaro</code>的双系统,所以看起来很麻烦。其实还好啦。</p><table><thead><tr><th>设备</th><th>挂载点</th></tr></thead><tbody><tr><td>/dev/sda2</td><td>/</td></tr><tr><td>/dev/sdb6</td><td>/boot</td></tr><tr><td>/dev/sdb2</td><td>/boot/efi</td></tr></tbody></table><p>和表格中显示的一样,我是分了三个分区分别用来挂载不同的目录的。</p><h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>我们要做的,就是通过使用<code>Manjaro</code>的 livecd 来使用 <code>manjaro-chroot</code>进行 grub 的修复。</p><p>我的操作是</p><ol><li>挂载 <code>/dev/sda2</code> 到 <code>/mnt</code> </li><li>挂载 <code>/dev/sdb6</code> 到 <code>/mnt/boot</code> </li><li>挂载 <code>/dev/sdb2</code> 到 <code>/mnt/boot/efi</code></li></ol><p>然后使用<code>manjaro-chroot /mnt</code> 进入系统进行修复。</p><p>所以对于挂载点的情况一定要记得清楚!我的操作是针对我这种 <code>/boot</code> 和 <code>/boot/efi</code> 挂载在不同分区上的情况。操作时要按照自己的实际情况改变命令。</p><p>下面就是具体的操作啦</p><h2 id="具体操作"><a href="#具体操作" class="headerlink" title="具体操作"></a>具体操作</h2><p>用 <code>Manjaro</code> 的 LiveCD 进入系统,然后在 <code>root</code> 用户中输入以下命令</p><ol start="0"><li>查看硬盘的挂载情况<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">fdisk -l<br></code></pre></td></tr></table></figure></li></ol><p>用这个命令来查看你的文件系统的情况。如果你清楚了那就不用了。</p><ol><li><p>挂载实际系统中的 <code>/</code> 到 <code>/mnt</code><br>在这里我的硬盘是 <code>/dev/sda2</code> </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">mount /dev/sda2 /mnt<br></code></pre></td></tr></table></figure></li><li><p>挂载实际系统中的 <code>/boot</code> 到 <code>/mnt/boot</code><br>在这里我的硬盘是 <code>/dev/sdb6</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">mount /dev/sdb6 /mnt/boot<br></code></pre></td></tr></table></figure></li><li><p>挂载实际系统中的 <code>/boot/efi</code> 到 <code>/mnt/boot/efi</code><br>在这里我的硬盘是 <code>/dev/sdb2</code> </p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">mount /dev/sdb2 /mnt/boot/efi<br></code></pre></td></tr></table></figure></li><li><p>进入 <code>manjaro-chroot</code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">manjaro-chroot /mnt<br></code></pre></td></tr></table></figure></li><li><p>在EFI启动分区创建引导文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">grub-install --recheck /dev/sda --efi-directory=/boot/efi<br></code></pre></td></tr></table></figure></li><li><p>生成<code>grub</code>的配置文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">grub-mkconfig -o /boot/grub/grub.cfg<br></code></pre></td></tr></table></figure></li><li><p>重启试试能不能进入manjaro</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">exit</span><br>reboot<br></code></pre></td></tr></table></figure><p>记得拔掉U盘!</p></li></ol><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>其实原理就是通过<code>manjaro-chroot</code>进入到实际的系统中,然后用<code>grub-install</code>修复引导文件。</p><p>因此我们挂载操作的主要目的就是为了让<code>manjaro-chroot</code>工作,和<code>grub-install</code>能够用正确的方式来生成引导文件。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.mynoee.com/archives/146/">Manjaro UEFI 启动修复 - 云酱的笔记本</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Manjaro</tag>
<tag>Windows</tag>
<tag>问题</tag>
</tags>
</entry>
<entry>
<title>在CentOS 8 下配置 Hadoop 开发环境</title>
<link href="/%E5%9C%A8CentOS-%E4%B8%8B%E9%85%8D%E7%BD%AEHadoop%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/"/>
<url>/%E5%9C%A8CentOS-%E4%B8%8B%E9%85%8D%E7%BD%AEHadoop%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83/</url>
<content type="html"><![CDATA[<p>下载,解压,设置环境变量,结束</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>生产实训来搞大数据,全是之前没用过的,就记录一下咯</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><ul><li>CentOS 8</li><li>Java8(jdk1.8)</li><li>findbugs-1.3.9</li><li>protobuf-2.5.0</li><li>hadoop-2.9.2</li></ul><h2 id="在Vmware-中安装-CentOS-8"><a href="#在Vmware-中安装-CentOS-8" class="headerlink" title="在Vmware 中安装 CentOS 8"></a>在Vmware 中安装 CentOS 8</h2><p>简单的就是在<a href="https://www.centos.org/download/">官网</a>中下载镜像,然后在 Vmware 中依次选择 创建虚拟机 -> 典型 -> 安装程序光盘映像文件 然后输入账户密码,选择虚拟机文件的保存位置,选择磁盘大小,最后确认就行。</p><p>但是有可能会遇到虚拟机在启动的时候卡住的情况,这个时候就查看那个光盘映像文件,看是不是被替换成了一个叫类似于 <code>autoXXX.iso</code> 的 iso 文件,如果是的话,就修改为你的 CentOS 8 的 iso 文件就可以了。</p><p>当然,如果从官网下载速度慢的话可以从清华的镜像站<a href="https://mirror.tuna.tsinghua.edu.cn/centos/8/isos/">下载</a></p><p>一般来说是下载 <code>/x86_x64</code> 下面的 <code>CentOS-8.2.2004-x86_64-dvd1.iso</code> 文件</p><p>然后在 CentOS 8 安装的时候一路下一步就行。如果需要GUI的话可以在安装需要的软件包的时候选择GUI,软件包的选择上我是选了开发工具包<code>Development Tools</code></p><p>其实安装过程基本就是一路下一步就行了。</p><p>安装完成后记得更新一下系统的程序</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">yum update<br>yum upgrade<br></code></pre></td></tr></table></figure><h2 id="关闭防火墙"><a href="#关闭防火墙" class="headerlink" title="关闭防火墙"></a>关闭防火墙</h2><p>因为是在自己的内网中用,所以就关掉防火墙啦。免得到时候还需要开放端口。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">systemctl stop firewalld.service && systemctl <span class="hljs-built_in">disable</span> firewalld.service<br></code></pre></td></tr></table></figure><h2 id="关闭-SELinux"><a href="#关闭-SELinux" class="headerlink" title="关闭 SELinux"></a>关闭 SELinux</h2><p>编辑 /etc/selinux/config 这个文件,找到 <code>SELINUX</code> 这一项,改成 <code>SELINUX=disabled </code></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nano /etc/selinux/config<br></code></pre></td></tr></table></figure><p>简单地说就是大概配置成这个样子</p><figure class="highlight ini"><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><code class="hljs ini"><span class="hljs-comment"># enforcing - SELinux security policy is enforced.</span><br><span class="hljs-comment"># permissive - SELinux prints warnings instead of enforcing.</span><br><span class="hljs-comment"># disabled - No SELinux policy is loaded.</span><br><span class="hljs-attr">SELINUX</span>=disabled<br><span class="hljs-comment"># SELINUXTYPE= can take one of these three values:</span><br><span class="hljs-comment"># targeted - Targeted processes are protected,</span><br><span class="hljs-comment"># minimum - Modification of targeted policy. Only selected processes are protected. </span><br><span class="hljs-comment"># mls - Multi Level Security protection.</span><br><span class="hljs-attr">SELINUXTYPE</span>=targeted<br></code></pre></td></tr></table></figure><h2 id="修改主机名"><a href="#修改主机名" class="headerlink" title="修改主机名"></a>修改主机名</h2><p>这个是因为之后可能会用到使用 hadoop 的 web 界面,这个时候配置下主机名就方便了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nano /etc/sysconfig/network<br></code></pre></td></tr></table></figure><p>之后修改成类似于这样就行</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-comment"># Created by anaconda</span><br><span class="hljs-attr">HOSTNAME</span>=你的主机的名字<br></code></pre></td></tr></table></figure><h2 id="修改主机名与IP的对应关系"><a href="#修改主机名与IP的对应关系" class="headerlink" title="修改主机名与IP的对应关系"></a>修改主机名与IP的对应关系</h2><p>修改 Host 文件,将主机名与本机IP联系起来</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nano /etc/hosts<br></code></pre></td></tr></table></figure><p>在最后面添加你的主机的IP和你的主机名就行了,修改后大概是这样的</p><figure class="highlight accesslog"><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><code class="hljs accesslog"><span class="hljs-number">127.0.0.1</span> localhost localhost.localdomain localhost4 localhost4.localdomain4<br>::<span class="hljs-number">1</span> localhost localhost.localdomain localhost6 localhost6.localdomain6<br><span class="hljs-number">1.2.3.4</span> 你的主机名<br></code></pre></td></tr></table></figure><p>这里修改了主机名就得重启一下,顺便也刷新了一下你的hosts文件。</p><h2 id="配置-ssh-免密钥登录"><a href="#配置-ssh-免密钥登录" class="headerlink" title="配置 ssh 免密钥登录"></a>配置 ssh 免密钥登录</h2><p>hadoop到时候使用的时候需要用到 SSH 来登录,为了方便,不用每次都输入密码,这里就配置一下 ssh 的免密钥登陆吧。</p><h3 id="生成公钥私钥"><a href="#生成公钥私钥" class="headerlink" title="生成公钥私钥"></a>生成公钥私钥</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">ssh-key-gen -t rsa <br></code></pre></td></tr></table></figure><p>这里一路下一步就行了</p><h3 id="拷贝公钥到本机"><a href="#拷贝公钥到本机" class="headerlink" title="拷贝公钥到本机"></a>拷贝公钥到本机</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">ssh-copy-id 你的主机名<br></code></pre></td></tr></table></figure><p>然后输入你的密码,一路回车就行了。<br>这个时候如果弹出类似于</p><figure class="highlight livecodeserver"><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><code class="hljs livecodeserver">Now <span class="hljs-keyword">try</span> logging <span class="hljs-keyword">into</span> <span class="hljs-keyword">the</span> machine, <span class="hljs-keyword">with</span> <span class="hljs-string">"ssh '1.2.3.4'"</span>, <span class="hljs-keyword">and</span> check <span class="hljs-keyword">in</span>:.ssh/authorized_keys<br><br><span class="hljs-built_in">to</span> make sure we haven<span class="hljs-string">'t added extra keys that you weren'</span>t expecting.<br><br></code></pre></td></tr></table></figure><p>这样的字样就是成功了。<br>你可以输入 <code>who</code> 来看是不是现在有两个登录用户</p><h2 id="配置-Java-环境"><a href="#配置-Java-环境" class="headerlink" title="配置 Java 环境"></a>配置 Java 环境</h2><p>为啥配置 Java 环境呢?因为 Hadoop 是用 Java 实现的啊。</p><h3 id="下载安装包,并且解压"><a href="#下载安装包,并且解压" class="headerlink" title="下载安装包,并且解压"></a>下载安装包,并且解压</h3><p>下载 Java8 的安装包<code>jdk1.8.0_162.tar.gz</code>,然后把上传到服务器,再解压到你指定的位置就行。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">tar -zxf jdk1.8.0_162.tar.gz -C /home/dev/java8<br></code></pre></td></tr></table></figure><p>这里就是解压到了 <code>/home</code>目录下的<code>/dev</code>文件夹中</p><h3 id="修改环境变量"><a href="#修改环境变量" class="headerlink" title="修改环境变量"></a>修改环境变量</h3><p>编辑 <code>/etc/profile</code> 文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nano /etc/profile<br></code></pre></td></tr></table></figure><p>添加如下几行</p><figure class="highlight routeros"><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><code class="hljs routeros"><span class="hljs-built_in">export</span> <span class="hljs-attribute">JAVA_HOME</span>=/home/dev/java8<br><span class="hljs-built_in">export</span> <span class="hljs-attribute">CLASSPATH</span>=<span class="hljs-variable">$JAVA_HOME</span>/jre/lib/ext:$JAVA_HOME/lib/tools.jar<br><br><span class="hljs-built_in">export</span> <span class="hljs-attribute">PATH</span>=<span class="hljs-variable">$PATH</span>:$JAVA_HOME/bin<br></code></pre></td></tr></table></figure><p>然后退出来刷新一下</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">source</span> /etc/profile<br></code></pre></td></tr></table></figure><p>这样就好了。<br>你可以输入 <code>java -version</code>来查看是否更新了环境变量。</p><h2 id="配置-Hadoop-依赖"><a href="#配置-Hadoop-依赖" class="headerlink" title="配置 Hadoop 依赖"></a>配置 Hadoop 依赖</h2><p>接下来就是配置 Hadoop 的依赖了。</p><h3 id="配置-findbugs"><a href="#配置-findbugs" class="headerlink" title="配置 findbugs"></a>配置 findbugs</h3><p>简单是说就是下载<code>findbugs</code>的安装包,然后解压到指定的目录,配置环境变量</p><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 解压</span><br>tar -zxf findbugs-1.3.9.tar.gz -C /home/dev/<br><span class="hljs-comment"># 编辑环境变量</span><br>nano /etc/profile<br><span class="hljs-comment"># 加入下面两句</span><br><span class="hljs-built_in">export</span> FINDBUGS_HOME=/home/dev/findbugs-1.3.9<br><span class="hljs-built_in">export</span> PATH=<span class="hljs-variable">$PATH</span>:<span class="hljs-variable">$FINDBUGS_HOME</span>/bin<br><span class="hljs-comment"># 刷新环境变量</span><br><span class="hljs-built_in">source</span> /etc/profile<br><span class="hljs-comment"># 查看是否配置成功</span><br>findbugs -version<br><span class="hljs-comment"># 输出版本号就是正确的了</span><br></code></pre></td></tr></table></figure><h3 id="配置-protobuf"><a href="#配置-protobuf" class="headerlink" title="配置 protobuf"></a>配置 protobuf</h3><p>这个流程稍微有点不一样,就是要自己手动编译。</p><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 解压</span><br>tar -zxf protobuf-2.5.0.tar.gz -C /home/dev/<br><span class="hljs-comment"># 到程序的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/protobuf-2.5.0<br><span class="hljs-comment"># 确认能否安装</span><br>./configure<br><span class="hljs-comment"># 这里如果提示了 success 就是成功了就可以进行安装了</span><br>make install<br><span class="hljs-comment"># 等安装完后看是否安装成功</span><br>protoc --version<br></code></pre></td></tr></table></figure><h3 id="配置-maven"><a href="#配置-maven" class="headerlink" title="配置 maven"></a>配置 maven</h3><p>下载,解压,配置环境变量</p><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 解压</span><br>tar -zxf apache-maven-3.0.5-bin.tar.gz -C /home/dev/<br><span class="hljs-comment"># 编辑环境变量</span><br>nano /etc/profile<br><span class="hljs-comment"># 加入下面两句</span><br><span class="hljs-built_in">export</span> MAVEN_HOME=/home/dev/apache-maven-3.0.5<br><span class="hljs-built_in">export</span> PATH=<span class="hljs-variable">$PATH</span>:<span class="hljs-variable">$MAVEN_HOME</span>/bin<br><span class="hljs-comment"># 刷新环境变量</span><br><span class="hljs-built_in">source</span> /etc/profile<br><span class="hljs-comment"># 查看是否配置成功</span><br>mvn --version<br><span class="hljs-comment"># 输出版本号就是正确的了</span><br></code></pre></td></tr></table></figure><h2 id="配置-Hadoop-开发环境"><a href="#配置-Hadoop-开发环境" class="headerlink" title="配置 Hadoop 开发环境"></a>配置 Hadoop 开发环境</h2><p>这里就是要准备配置 Hadoop 了</p><h3 id="配置-Hadoop"><a href="#配置-Hadoop" class="headerlink" title="配置 Hadoop"></a>配置 Hadoop</h3><p>下载,解压,配置环境变量</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 解压</span><br>tar -zxf hadoop-2.9.2-linux-64.tar.gz -C /home/dev/<br><span class="hljs-comment"># 编辑环境变量</span><br>nano /etc/profile<br><span class="hljs-comment"># 加入下面几句</span><br><span class="hljs-built_in">export</span> HADOOP_HOME=/home/dev/hadoop-2.9.2<br><span class="hljs-built_in">export</span> HADOOP_COMMON_LIB_NATIVE_DIR=<span class="hljs-variable">$HADOOP_HOME</span>/lib/native<br><span class="hljs-built_in">export</span> HADOOP_USER_NAME=root<br><span class="hljs-comment"># 刷新环境变量</span><br><span class="hljs-built_in">source</span> /etc/profile<br><br></code></pre></td></tr></table></figure><h3 id="配置-env-sh"><a href="#配置-env-sh" class="headerlink" title="配置 env.sh"></a>配置 env.sh</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><span class="hljs-comment"># 修改 hadoop-env.sh</span><br>nano /etc/hadoop/hadoop-env.sh<br><span class="hljs-comment"># 对 JAVA_HOME 这一行进行修改</span><br><span class="hljs-built_in">export</span> JAVA_HOME=/home/dev/java8<br></code></pre></td></tr></table></figure><h3 id="配置-core-site-xml"><a href="#配置-core-site-xml" class="headerlink" title="配置 core-site.xml"></a>配置 core-site.xml</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><span class="hljs-comment"># 新建临时目录</span><br><span class="hljs-built_in">mkdir</span> data<br><span class="hljs-built_in">cd</span> data<br><span class="hljs-built_in">mkdir</span> tmp<br><span class="hljs-comment"># 回到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><br><span class="hljs-comment"># 修改 core-site.xml</span><br>nano etc/hadoop/core-site.xml <br></code></pre></td></tr></table></figure><p>在文件中添加如下的配置</p><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></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">property</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>fs.defaultFS<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">value</span>></span>hdfs://hadoop:8020<span class="hljs-tag"></<span class="hljs-name">value</span>></span><br><span class="hljs-tag"></<span class="hljs-name">property</span>></span> <br><span class="hljs-tag"><<span class="hljs-name">property</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>hadoop.tmp.dir<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">value</span>></span>/home/softwares/hadoop-2.9.1/data/tmp<span class="hljs-tag"></<span class="hljs-name">value</span>></span><br><span class="hljs-tag"></<span class="hljs-name">property</span>></span><br><br></code></pre></td></tr></table></figure><h3 id="配置-hdfs-site-xml"><a href="#配置-hdfs-site-xml" class="headerlink" title="配置 hdfs-site.xml"></a>配置 hdfs-site.xml</h3><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><span class="hljs-comment"># 修改 hdfs-site.xml </span><br>nano etc/hadoop/hdfs-site.xml <br></code></pre></td></tr></table></figure><p>在文件中添加如下的配置</p><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></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">configuration</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">property</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>dfs.replication<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">value</span>></span>1<span class="hljs-tag"></<span class="hljs-name">value</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">property</span>></span><br><span class="hljs-tag"></<span class="hljs-name">configuration</span>></span><br></code></pre></td></tr></table></figure><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 格式化 namenode</span><br>./bin/hdfs namenode -format<br><span class="hljs-comment"># 当提示 success 的时候就是正确格式化了</span><br></code></pre></td></tr></table></figure><h3 id="配置-mapred-site-xml"><a href="#配置-mapred-site-xml" class="headerlink" title="配置 mapred-site.xml"></a>配置 mapred-site.xml</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><span class="hljs-comment"># 复制 mapred-site.xml</span><br><span class="hljs-built_in">cp</span> etc/hadoop/mapred-site.xml.template etc/hadoop/mapred-site.xml<br><span class="hljs-comment"># 修改 mapred-site.xml</span><br>nano etc/hadoop/mapred-site.xml <br></code></pre></td></tr></table></figure><p>在文件中添加如下的配置</p><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></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">configuration</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">property</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>mapreduce.framework.name<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">value</span>></span>yarn<span class="hljs-tag"></<span class="hljs-name">value</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">property</span>></span><br><span class="hljs-tag"></<span class="hljs-name">configuration</span>></span><br><br></code></pre></td></tr></table></figure><h3 id="配置-yarn-site-xml"><a href="#配置-yarn-site-xml" class="headerlink" title="配置 yarn-site.xml"></a>配置 yarn-site.xml</h3><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 到 hadoop 的目录</span><br><span class="hljs-built_in">cd</span> /home/dev/hadoop-2.9.2<br><span class="hljs-comment"># 修改 yarn-site.xml</span><br>nano etc/hadoop/yarn-site.xml <br></code></pre></td></tr></table></figure><p>在文件中添加如下的配置</p><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></pre></td><td class="code"><pre><code class="hljs xml"><span class="hljs-tag"><<span class="hljs-name">configuration</span>></span><br><span class="hljs-comment"><!-- Site specific YARN configuration properties --></span><br> <span class="hljs-tag"><<span class="hljs-name">property</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">name</span>></span>yarn.nodemanager.aux-services<span class="hljs-tag"></<span class="hljs-name">name</span>></span><br> <span class="hljs-tag"><<span class="hljs-name">value</span>></span>mapreduce_shuffle<span class="hljs-tag"></<span class="hljs-name">value</span>></span><br> <span class="hljs-tag"></<span class="hljs-name">property</span>></span><br><span class="hljs-tag"></<span class="hljs-name">configuration</span>></span><br></code></pre></td></tr></table></figure><p>这样就配置好了</p><h3 id="启动-hadoop"><a href="#启动-hadoop" class="headerlink" title="启动 hadoop"></a>启动 hadoop</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># 一个是通过环境变量启动,一个是通过绝对路径启动</span><br>bash <span class="hljs-variable">${HADOOP_HOME}</span>/sbin/start-dfs.sh<br>bash /home/softwares/hadoop-2.9.2/sbin/start-yarn.sh<br><span class="hljs-comment"># 等执行完之后查看是否正确,就输入</span><br>jps<br><span class="hljs-comment"># 这样来查看就知道是否配置正确了,正确的话应该会一共有五个进程。</span><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/hanhaotian/p/11754393.html">CENTOS 8 安装HADOOP</a></p>]]></content>
<categories>
<category>学习</category>
<category>大数据</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Hadoop</tag>
<tag>CentOS</tag>
</tags>
</entry>
<entry>
<title>pacman的报错处理</title>
<link href="/pacman%E7%9A%84%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/"/>
<url>/pacman%E7%9A%84%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/</url>
<content type="html"><![CDATA[<p>针对 manjaro 日常使用过程中的 pacman 报错的处理</p><span id="more"></span><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="错误:无法提交处理-无效或已损坏的软件包"><a href="#错误:无法提交处理-无效或已损坏的软件包" class="headerlink" title="错误:无法提交处理 (无效或已损坏的软件包)"></a>错误:无法提交处理 (无效或已损坏的软件包)</h2><p>我的电脑上这个问题出现的时候是下载软件包的时候出错了,这个时候清除缓存即可。<br>一般报错的时间是在检查完密钥之后。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo pacman -Sc<br></code></pre></td></tr></table></figure><p>这个是清除所有的未安装软件包的缓存,仅保留当前软件包的版本。</p><p>在几百个软件包等着更新的时候,你也没办法检查是哪个软件包下载的时候出错。你能做的也只能全部清除了。</p><h2 id="错误:无法提交处理-传递了错误的或-NULL-参数"><a href="#错误:无法提交处理-传递了错误的或-NULL-参数" class="headerlink" title="错误:无法提交处理 (传递了错误的或 NULL 参数)"></a>错误:无法提交处理 (传递了错误的或 NULL 参数)</h2><p>和上面的 <code>错误:无法提交处理 (无效或已损坏的软件包)</code> 一样,是软件包下载的时候出错了。一般这个问题出现的时候是这个样子的</p><figure class="highlight clean"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs clean">(<span class="hljs-number">1</span>/<span class="hljs-number">1</span>) 正在检查软件包完整性[####################################################] <span class="hljs-number">100</span>%<br>错误:无法提交处理 (传递了错误的或 NULL 参数)<br></code></pre></td></tr></table></figure><p>和上面一样,只能清除掉软件包的缓存了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo pacman -Sc<br></code></pre></td></tr></table></figure><p>不过说实话,这个错误信息写得很不好,看不出来到底是什么地方出错了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://wiki.archlinux.org/index.php/Pacman_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87)">pacman (简体中文) - ArchWiki</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Manjaro</tag>
<tag>pacman</tag>
</tags>
</entry>
<entry>
<title>numpy中的各种乘法</title>
<link href="/numpy%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8D%E4%B9%98%E6%B3%95/"/>
<url>/numpy%E4%B8%AD%E7%9A%84%E5%90%84%E7%A7%8D%E4%B9%98%E6%B3%95/</url>
<content type="html"><![CDATA[<p>点乘,叉乘,内积,外积,数量积,向量积。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>做数字图像处理的时候会需要卷积,虽然 OpenCV 自带了对应的函数<code>filter2D()</code>来进行卷积,<br>不过实验嘛,还是自己动手理解原理才是最好的。不过 numpy 的各种乘法混着看不懂有啥区别啊,所以就看看咯。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>下面我会把满足条件的方法合并起来演示。</p><h2 id="点乘、内积、数量积"><a href="#点乘、内积、数量积" class="headerlink" title="点乘、内积、数量积"></a>点乘、内积、数量积</h2><p>简单地说就是将数组 a 中的每个元素与数组 b 中的每一个对应位置的元素相乘,相乘的结果放在和数组 a 相同大小的数组中。</p><p>下面就用 python来演示下咯</p><h3 id="array-与-array-求点乘"><a href="#array-与-array-求点乘" class="headerlink" title="array 与 array 求点乘"></a>array 与 array 求点乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.array(a)<br>b = np.array(b)<br><br>a*b<br><br>array([[ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">648</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>]])<br><br>np.multiply(a,b)<br><br>array([[ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">648</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>]])<br></code></pre></td></tr></table></figure><h3 id="mat-与-mat-求点乘"><a href="#mat-与-mat-求点乘" class="headerlink" title="mat 与 mat 求点乘"></a>mat 与 mat 求点乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.mat(b)<br><br><br>np.multiply(a,b)<br><br>matrix([[ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">648</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>]])<br><br></code></pre></td></tr></table></figure><h3 id="mat-与-array-求点乘"><a href="#mat-与-array-求点乘" class="headerlink" title="mat 与 array 求点乘"></a>mat 与 array 求点乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.array(b)<br><br><br>np.multiply(a,b)<br>matrix([[ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">648</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">0</span>, <span class="hljs-number">162</span>, <span class="hljs-number">0</span>]])<br><br><br></code></pre></td></tr></table></figure><h2 id="叉乘、外积、向量积"><a href="#叉乘、外积、向量积" class="headerlink" title="叉乘、外积、向量积"></a>叉乘、外积、向量积</h2><h3 id="array-与-array-求叉乘"><a href="#array-与-array-求叉乘" class="headerlink" title="array 与 array 求叉乘"></a>array 与 array 求叉乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.array(a)<br>b = np.array(b)<br><br>np.matmul(a,b)<br><br>array([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br>np.dot(a,b)<br><br>array([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br></code></pre></td></tr></table></figure><h3 id="mat-与-mat-求叉乘"><a href="#mat-与-mat-求叉乘" class="headerlink" title="mat 与 mat 求叉乘"></a>mat 与 mat 求叉乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.mat(b)<br><br>a*b<br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br>np.dot(a,b)<br><br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br>np.matmul(a,b)<br><br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br></code></pre></td></tr></table></figure><h3 id="mat-与-array-求叉乘"><a href="#mat-与-array-求叉乘" class="headerlink" title="mat 与 array 求叉乘"></a>mat 与 array 求叉乘</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.array(b)<br><br>a*b<br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br>np.dot(a,b)<br><br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br><br>np.matmul(a,b)<br><br>matrix([[ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">324</span>, <span class="hljs-number">162</span>],<br> [ <span class="hljs-number">162</span>, -<span class="hljs-number">323</span>, <span class="hljs-number">162</span>]])<br></code></pre></td></tr></table></figure><p>多说一句,这里的 mat 和 array 的顺序可以前后交换。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><table><thead><tr><th align="center">目标\类型</th><th align="center">array 与 array</th><th align="center">mat 与 mat</th><th align="center">mat 与 array</th></tr></thead><tbody><tr><td align="center">点乘、内积、数量积</td><td align="center">a * b或者np.multiply(a,b)</td><td align="center">np.multiply(a,b)</td><td align="center">np.multiply(a,b)</td></tr><tr><td align="center">叉乘、外积、向量积</td><td align="center">np.dot(a,b) 或者 np.matmul(a,b)</td><td align="center">a*b 或者 np.dot(a,b) 或者 np.matmul(a,b)</td><td align="center">a*b 或者 np.dot(a,b) 或者 np.matmul(a,b)</td></tr></tbody></table><p>这个时候可以看到</p><ol><li>在求点乘的情况下,除了 array 与 array 相乘可以用 a*b 其他类型都应该用 np.multiply(a,b)</li><li>在求叉积的情况下,除了 array 与 array 相乘<strong>不</strong>可以用 a*b 其他类型用几种乘法都可以。</li></ol><h2 id="求卷积"><a href="#求卷积" class="headerlink" title="求卷积"></a>求卷积</h2><p>卷积就是求了点乘之后把矩阵求和,然后把这个和作为结果放入新的矩阵中。</p><h3 id="array-与-array-求卷积"><a href="#array-与-array-求卷积" class="headerlink" title="array 与 array 求卷积"></a>array 与 array 求卷积</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">163</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.array(a)<br>b = np.array(b)<br><br>np.<span class="hljs-built_in">sum</span>(a*b)<br><br>-<span class="hljs-number">4</span><br><br>np.vdot(a,b)<br><br>-<span class="hljs-number">4</span><br><br></code></pre></td></tr></table></figure><h3 id="mat-与-mat-求卷积"><a href="#mat-与-mat-求卷积" class="headerlink" title="mat 与 mat 求卷积"></a>mat 与 mat 求卷积</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">163</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.mat(b)<br><br>np.<span class="hljs-built_in">sum</span>(np.multiply(a,b))<br><br>-<span class="hljs-number">4</span><br><br></code></pre></td></tr></table></figure><h3 id="mat-与-array-求卷积"><a href="#mat-与-array-求卷积" class="headerlink" title="mat 与 array 求卷积"></a>mat 与 array 求卷积</h3><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> numpy <span class="hljs-keyword">as</span> np<br><br>a = [[<span class="hljs-number">163</span>,<span class="hljs-number">162</span>,<span class="hljs-number">161</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">163</span>,<span class="hljs-number">162</span>],[<span class="hljs-number">162</span>,<span class="hljs-number">162</span>,<span class="hljs-number">163</span>]]<br>b = [[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>],[<span class="hljs-number">1</span>,-<span class="hljs-number">4</span>,<span class="hljs-number">1</span>],[<span class="hljs-number">0</span>,<span class="hljs-number">1</span>,<span class="hljs-number">0</span>]]<br>a = np.mat(a)<br>b = np.array(b)<br><br>np.<span class="hljs-built_in">sum</span>(np.multiply(a,b))<br><br>-<span class="hljs-number">4</span> <br><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/gxcdream/p/7597865.html">向量内积(点乘)和外积(叉乘)概念及几何意义</a></p><p><a href="https://blog.csdn.net/hxg2006/article/details/79626288">卷积及理解图像卷积操作的意义</a></p><p><a href="https://www.runoob.com/numpy/numpy-linear-algebra.html">NumPy 线性代数</a></p>]]></content>
<categories>
<category>学习</category>
<category>Python</category>
</categories>
<tags>
<tag>Python</tag>
<tag>numpy</tag>
</tags>
</entry>
<entry>
<title>PyQt5的安装指南</title>
<link href="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/"/>
<url>/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<p>从入坑到入土</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>数字图像处理的作业要求有图形化的设计。我都是用的Python来实现的代码的,感觉转成用C来写的话各种类型太麻烦了,还是直接用Python试试GUI开发。</p><p>结果只能说差强人意。我也没用到什么槽函数感觉也可以写出来。不过打包成.exe文件的时候却发现整个包太大了。估计是打包了Python运行环境的原因。所以要想开发小而美的软件还是得用C啊</p><h1 id="从pip安装"><a href="#从pip安装" class="headerlink" title="从pip安装"></a>从pip安装</h1><p>安装很简单,用pip就行</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cmd">pip install PyQt5<br></code></pre></td></tr></table></figure><p>不过一般还得安装个插件,这样才能用QT Designer进行可视化的编辑</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cmd">pip install pyqt5-tools<br></code></pre></td></tr></table></figure><h1 id="汉化QT-Designer"><a href="#汉化QT-Designer" class="headerlink" title="汉化QT Designer"></a>汉化QT Designer</h1><p>找到你的对应的包的地址,如下</p><figure class="highlight moonscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs moonscript">\python\python381\Lib\site-packages\pyqt5_tools\Qt\bin\translations<br></code></pre></td></tr></table></figure><p>如果没有 <code>translations</code> 这个文件夹的话你可以自己新建一个。然后把<a href="designer_zh_CN.qm">designer_zh_CN.qm</a>这个文件放进去。还有下载地址是<a href="https://pan.baidu.com/s/1jzkumqjw-3VQiJxvo4V6Xw">https://pan.baidu.com/s/1jzkumqjw-3VQiJxvo4V6Xw</a><br>大概的效果是这样的</p><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E6%B1%89%E5%8C%96%E7%A4%BA%E4%BE%8B.jpg" class="" title="汉化示例"><h1 id="设置环境变量"><a href="#设置环境变量" class="headerlink" title="设置环境变量"></a>设置环境变量</h1><p>这是为了避免到时候如下报错</p><figure class="highlight livecodeserver"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs livecodeserver">this application failed <span class="hljs-built_in">to</span> <span class="hljs-built_in">start</span> because no Qt <span class="hljs-built_in">platform</span> plugin could be initialized, Reinstalling <span class="hljs-keyword">the</span> application may fix this problem, available <span class="hljs-built_in">platform</span><br></code></pre></td></tr></table></figure><p>打开<code>我的电脑</code>,在上方的<code>文件</code>选项卡里面选择<code>系统属性</code>,然后在弹出来的界面的<code>相关设置</code>栏中选择<code>系统信息</code>。</p><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E6%96%87%E4%BB%B6%E9%80%89%E9%A1%B9%E5%8D%A1.jpg" class="" title="文件选项卡.jpg"><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E7%B3%BB%E7%BB%9F%E4%BF%A1%E6%81%AF.jpg" class="" title="系统信息.jpg"><p>在弹出的页面中选择<code>高级系统设置</code>,然后点击<code>环境变量</code></p><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E9%AB%98%E7%BA%A7%E7%B3%BB%E7%BB%9F%E8%AE%BE%E7%BD%AE.jpg" class="" title="高级系统设置.jpg"><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E7%82%B9%E5%87%BB%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F.jpg" class="" title="点击环境变量.jpg"><p>编辑系统环境变量中的Path项,在里面添加如下的地址</p><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E6%B7%BB%E5%8A%A0%E7%8E%AF%E5%A2%83%E5%8F%98%E9%87%8F.jpg" class="" title="添加环境变量.jpg"><p>大概的就是这样的</p><figure class="highlight moonscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs moonscript">你的Python地址\Lib\site-packages\PyQt5\Qt\plugins\platforms<br></code></pre></td></tr></table></figure><p>然后再在系统变量中新建项,命名为<code>QT_PLUGIN_PATH</code><br>然后把值设置为</p><figure class="highlight moonscript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs moonscript">你的Python地址\Lib\site-packages\PyQt5\Qt\plugins<br></code></pre></td></tr></table></figure><img src="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/%E6%B7%BB%E5%8A%A0QT_Plugin_Path.jpg" class="" title="添加QT_Plugin_Path.jpg"><p>现在搞定后重启就可以了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/awakenedy/articles/9492017.html">PyQt(pyqt-tools)中的Qt Designer改为中文界面</a><br><a href="https://blog.csdn.net/lyzwjaa/article/details/79429901">python3+PyQt5+Qt designer+pycharm安装及配置+将ui文件转py文件</a><br><a href="https://blog.csdn.net/Bingoooooo_/article/details/81535892">如何将PyQt(pyqt-tools)中的Qt Designer改为中文界面(汉化)</a></p>]]></content>
<categories>
<category>学习</category>
</categories>
<tags>
<tag>Python</tag>
<tag>PyQt5</tag>
<tag>QT Designer</tag>
</tags>
</entry>
<entry>
<title>数字图像处理大作业记录-边缘检测与阈值分割的Python实现及利用PyQt5的GUI开发</title>
<link href="/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/"/>
<url>/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/</url>
<content type="html"><![CDATA[<p>用 python 可以不用管数据类型,而用 .net 又可以方便的进行GUI开发。两者结合起来的话是多么的棒啊。可惜我太菜了结合不了。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这学期开的数字图像处理也有实验,实验项目是边缘检测和阈值开发。老师推荐的是用 .net 来做。但感觉太麻烦了,所以问了老师,得到了能用 python 的许可。</p><p>不过看起来老师还是希望有个 GUI 界面的,那就试试 PyQt 怎么样咯。刚好也想折腾一下。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>写的代码各种文盲,格式乱飞希望不要介意,有疑问的地方可以和我交流。<br>这个作业的项目地址 :<br><a class="btn" href="https://github.com/yikakia/DigtalPicHomework" title="Github地址">数字图像处理作业</a></p><h2 id="安装库"><a href="#安装库" class="headerlink" title="安装库"></a>安装库</h2><p>用的包方面看我的那个 <code>requirements.txt</code>就行了。</p><figure class="highlight abnf"><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><code class="hljs abnf"><span class="hljs-attribute">qimage2ndarray</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">1.8</span>.<span class="hljs-number">3</span><br>opencv_python<span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">4.2</span>.<span class="hljs-number">0.34</span><br><span class="hljs-attribute">numpy</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">1.18</span>.<span class="hljs-number">2</span><br><span class="hljs-attribute">PyQt5</span><span class="hljs-operator">=</span><span class="hljs-operator">=</span><span class="hljs-number">5.14</span>.<span class="hljs-number">2</span><br></code></pre></td></tr></table></figure><h2 id="用QT-Designer设计UI"><a href="#用QT-Designer设计UI" class="headerlink" title="用QT Designer设计UI"></a>用QT Designer设计UI</h2><p>在GUI方面我用的是QT Designer来辅助设计,这样所见即所得的体验很好。<br>哦对了,要QT Desinger的安装使用和汉化如果有需求的话可以参考我的<a href="/PyQt5%E7%9A%84%E5%AE%89%E8%A3%85%E6%8C%87%E5%8D%97/" title="这篇文章">这篇文章</a>。<br>打开后大概是这个样子的,这里我们一般用 <code>Main Window</code> 这一项,因为这个会自动附带上工具栏和状态栏,一般还是比较好用的</p><img src="/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/QTDesigner%E7%95%8C%E9%9D%A2.jpg" class=""><p>然后就是实际使用啦,实际上的话和利用VS开发差不了多少,都是拖控件然后命名控件,设置控件的各种属性。</p><p>对于开发的话有个小的建议就是把UI界面和实际的业务逻辑分开。就是说UI界面只管各种界面的属性,而不涉及实际的操作的函数。这样在维护的时候很方便。</p><p>总之最后我是设计成了这样,能用就行了。</p><img src="/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/UI%E7%A4%BA%E4%BE%8B.jpg" class=""><p>实际运行时的效果大概是这样的。</p><img src="/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95.png" class=""><p>最后保存你设计的UI文件就可以了,现在我们保存的是.ui文件,并不能直接用于python编程,所以需要使用PyQt自带的程序<code>pyuic5.exe</code>来实现将.ui文件转换为.py文件。</p><p>具体的方法如下,打开终端然后输入以下命令</p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cmd">你的Python的文件夹\Scripts\pyuic5.exe -o 目标文件保存地址 UI文件保存路径<br></code></pre></td></tr></table></figure><p>在实例中大概是这个样子的,我这里是在.ui文件所在的文件夹启动了终端,然后把生成的.py文件保存在了和.ui文件相同的文件夹里面并且命名为<code>MainWindow.py</code></p><figure class="highlight cmd"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs cmd"><span class="hljs-function">D:\<span class="hljs-title">DevEnv</span>\<span class="hljs-title">python</span>\<span class="hljs-title">python381</span>\<span class="hljs-title">Scripts</span>\<span class="hljs-title">pyuic5.exe</span> -<span class="hljs-title">o</span> <span class="hljs-title">MainWindow.py</span> .\<span class="hljs-title">UI.ui</span></span><br></code></pre></td></tr></table></figure><p>我推荐把这个写成.bat或者.sh的脚本文件,来方便每次修改完UI之后都可以通过直接调用脚本来进行转换。</p><h2 id="注册响应函数"><a href="#注册响应函数" class="headerlink" title="注册响应函数"></a>注册响应函数</h2><p>在设计完UI之后,我们就新建一个.py程序来实现业务逻辑吧。新建一个类继承之前的UI文件的类和QMainWindow这个类。</p><p>继承完了之后写一个初始化,然后在这个初始化的函数里面注册响应函数。</p><p>注册响应函数的大概格式是这样的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">self.控件名.触发的消息类型.connect(响应消息的函数)<br></code></pre></td></tr></table></figure><p>实际写的话大概是这样的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">self.actionOpen_File.triggered.connect(self.openfile)<br></code></pre></td></tr></table></figure><p>这里的话我是在这个类里面写了一个 openfile 的函数来实现相应的功能。要注意这里调用函数的时候不需要写括号,就是如同下面这样的形式</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">self.actionOpen_File.triggered.connect(self.openfile())<br></code></pre></td></tr></table></figure><p>如果这样写了的话会报错 TypeError: argument 1 has unexpected type ‘NoneType’ ,原理大概是这个响应并不期待有返回值?之前写作业的时候忙着解决问题就没有仔细看原理了,这里有StackOverFlow的讨论的<a href="https://stackoverflow.com/questions/45793966/clicked-connect-error">链接</a>,感兴趣的可以看看。</p><h2 id="保存长高比的情况下的最大缩放"><a href="#保存长高比的情况下的最大缩放" class="headerlink" title="保存长高比的情况下的最大缩放"></a>保存长高比的情况下的最大缩放</h2><p>这个问题主要是读入的图像大小和宽高比都不同,但我们想要把它完整地显示出来,这个时候我们就得找到一个合适的缩放比例来把<br>原图像完整的放入目标窗口中。</p><p>其实这个问题可以化简成给定目标窗口的宽和高,让你求按原图像放进去,最大能放多少。</p><p>实际上我们可以很简单的推出来,要达到最大的时候,原图像的宽或者高必然有一个等于目标窗口的宽或高。因为没到的话就可以说明还没到最大的缩放。</p><p>这里我们可以用极限法来试着看看</p><p>定义原图像为 <code>srcImg</code> ,目标窗口为 <code>tarWindow</code></p><h3 id="一种极限情况"><a href="#一种极限情况" class="headerlink" title="一种极限情况"></a>一种极限情况</h3><p>当满足下面的情况的时候<br><code>srcImg.h = 100000</code><br><code>srcImg.w = 1 </code><br><code>tarWindow.h = 1</code><br><code>tarWindow.w = 100000</code><br>原图像为一个竖着的图,目标窗口为一个横着的图。这个时候要把原图像按原比例放进目标窗口的话,必然有 </p><p><code>srcImg.h = tarWindow.h </code></p><p>同时还可以得到</p><p><code>srcImg.w = srcImg.w * tarWindow.h/srcImg.h</code> (这里的<code>srcImg.h</code>的值是更新前的值,这样是通过缩放比例放大)</p><p>这个时候原图像的高等于目标窗口的高,而原图像的宽可以通过缩放比例,或者原图像原本的比例来求得。</p><h3 id="另外一种极限情况"><a href="#另外一种极限情况" class="headerlink" title="另外一种极限情况"></a>另外一种极限情况</h3><p>当满足下面的情况的时候<br><code>srcImg.h = 1</code><br><code>srcImg.w = 100000 </code><br><code>tarWindow.h = 100000</code><br><code>tarWindow.w = 1</code><br>原图像是一个横着的图,目标窗口是一个竖着的图,这个时候要把原图像按原比例放进目标窗口的话,必然有</p><p><code>srcImg.w = tarWindow.w</code></p><p>同时还可以得到</p><p><code>srcImg.h = srcImg.h * tarWindow.w/srcImg.w</code> (这里的<code>srcImg.w</code>的值是更新前的值,这样是通过缩放比例来放大)</p><p>这个时候原图像的宽等于目标窗口的宽,而原图像的高可以通过缩放比例,或者原图像原本的比例来求得。</p><h3 id="算法流程"><a href="#算法流程" class="headerlink" title="算法流程"></a>算法流程</h3><p>当然这个只是通过极限法推出来的。实际情况中应该怎么判断呢?我给个我的解决方案。</p><ol><li><code>p1 = tarWindow.w/srcImg.w</code></li><li><code>p2 = tarWindow.h/srcImg.h</code></li><li><code>p = p1 < p2 ? p1 : p2</code></li><li><code>newImg.h = srcImg.h * p</code> </li><li><code>newImg.w = srcImg.w * p</code></li></ol><p>简单地说就是求出两种缩放比例的值,分别是根据高或者宽缩放,然后实际应用的值就是取两者之中小的那个。这样就可以在不超过目标窗口的大小的情况下获得最大的缩放。</p><p>为什么要这样求呢?<br>我们先假设原图像的长宽都小于目标窗口的长宽,这个时候我们把原图像从小到大一点点的放大,当第一次接触到目标窗口的边的时候,<br>你就发现这个时候已经是最大缩放了,你再继续放大的话就会超出目标窗口的限制了。</p><p>而当原图像的长宽都大于目标窗口的时候,这时我们将原图像一点点的缩小,当第一次接触到目标窗口的时候,目标窗口依然被你包裹着,<br>原图像并没有完全显示在目标窗口中。这个时候我们要达到最大缩放的话就得用小的那个情况了。</p><p>综合以上的两种情况,很轻松的就可以得到与我的流程相同的结果。</p><p>我推导的时候用了Geogebra来帮忙推导,可视化的推导对于没有空间想象力的人来说真是方便。这是<a href="%E5%9B%BE%E5%83%8F%E5%9C%A8%E7%AA%97%E5%8F%A3%E7%9A%84%E7%BC%A9%E6%94%BE%E7%9A%84%E6%A8%A1%E5%9E%8B.ggb">文件</a></p><h2 id="读入并显示图片"><a href="#读入并显示图片" class="headerlink" title="读入并显示图片"></a>读入并显示图片</h2><p>我这里的实现原理是通过 OpenCV 的 imread 读入图像,然后把OpenCV保存的Numpy格式的数据转换成QT的QImage的数据类型。<br>显示图像的时候是把图像先放入 QGraphicsScene() 中,然后把这个QGraphicsScene()设置为对应的QGraphicsView()的 Scene 。</p><p>这里我转化三通道的图没问题,但单通道的灰度图就不知道怎么的就有错,具体的表现形式是灰度图会被转化成没有意义的黑色条纹。</p><p>我各种搜索都没找到解决方法,最后看到有人提到了有<code>qimage2ndarray</code>这个包我才搞定了显示灰度图的问题。</p><p>我的显示是这个样子的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># 将OpenCV格式储存的图片转换为QT可处理的图片类型</span><br>qimg = self.cvPic2Qimg(tmpImg)<br><span class="hljs-comment"># 将图片放入图片显示窗口</span><br>scene = QGraphicsScene()<br>scene.addPixmap(QPixmap.fromImage(qimg))<br>self.picview_source.setScene(scene)<br>self.hasOpen = <span class="hljs-literal">True</span><br></code></pre></td></tr></table></figure><h3 id="转换array数组到qiamge类"><a href="#转换array数组到qiamge类" class="headerlink" title="转换array数组到qiamge类"></a>转换array数组到qiamge类</h3><p>这里我直接把我的函数复制过来吧</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">cvPic2Qimg</span>(<span class="hljs-params">self, img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 将用 opencv 读入的图像转换成qt可以读取的图像</span><br><span class="hljs-string"></span><br><span class="hljs-string"> ========== =====================</span><br><span class="hljs-string"> 序号 支持类型</span><br><span class="hljs-string"> ========== =================</span><br><span class="hljs-string"> 1 灰度图 Gray</span><br><span class="hljs-string"> 2 三通道的图 BGR顺序</span><br><span class="hljs-string"> 3 四通道的图 BGRA顺序</span><br><span class="hljs-string"> ========= ===================</span><br><span class="hljs-string"> """</span><br> <span class="hljs-keyword">if</span> (<span class="hljs-built_in">len</span>(img.shape)==<span class="hljs-number">2</span>):<br> <span class="hljs-comment"># 读入灰度图的时候</span><br> image = array2qimage(img)<br> <span class="hljs-keyword">elif</span> (<span class="hljs-built_in">len</span>(img.shape)==<span class="hljs-number">3</span>): <br> <span class="hljs-comment"># 读入RGB或RGBA的时候</span><br> <span class="hljs-keyword">if</span> (img.shape[<span class="hljs-number">2</span>] == <span class="hljs-number">3</span>):<br> <span class="hljs-comment">#转换为RGB排列</span><br> RGBImg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)<br> <span class="hljs-comment">#RGBImg.shape[1]*RGBImg.shape[2]这一句时用来解决扭曲的问题</span><br> <span class="hljs-comment">#详情参考 https://blog.csdn.net/owen7500/article/details/50905659 这篇博客</span><br> image = QtGui.QImage(RGBImg, RGBImg.shape[<span class="hljs-number">1</span>], RGBImg.shape[<span class="hljs-number">0</span>],<br> RGBImg.shape[<span class="hljs-number">1</span>]*RGBImg.shape[<span class="hljs-number">2</span>], QtGui.QImage.Format_RGB888)<br> <span class="hljs-keyword">elif</span> (img.shape[<span class="hljs-number">2</span>] == <span class="hljs-number">4</span>):<br> <span class="hljs-comment">#读入为RGBA的时候</span><br> RGBAImg = cv2.cvtColor(img, cv2.COLOR_BGRA2RGBA)<br> image = array2qimage(RGBAImg)<br> <span class="hljs-keyword">return</span> image<br><br></code></pre></td></tr></table></figure><h3 id="解决-OpenCV-读取的图像转换成-QImage-时出现扭曲的现象"><a href="#解决-OpenCV-读取的图像转换成-QImage-时出现扭曲的现象" class="headerlink" title="解决 OpenCV 读取的图像转换成 QImage 时出现扭曲的现象"></a>解决 OpenCV 读取的图像转换成 QImage 时出现扭曲的现象</h3><p>最开始我是直接用的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">image = QtGui.QImage(RGBImg, RGBImg.shape[<span class="hljs-number">1</span>], RGBImg.shape[<span class="hljs-number">0</span>],<br> QtGui.QImage.Format_RGB888) <br></code></pre></td></tr></table></figure><p>这样在对于是四个字节一行的数据的图像的时候没有问题,但对于不是四个字节一行的图片的时候就会出现不能对齐的问题了。<br>错误的原理是图片数据没有按四个字节对齐,具体可以参考<a href="https://blog.csdn.net/u012342051/article/details/79728117">这篇博客</a></p><p>具体表现出来的形式就是图像被左右颠倒,并且大幅度的从左到右的扭曲了。</p><p>我的解决方法是参考<a href="https://blog.csdn.net/owen7500/article/details/50905659">这篇博客</a>的解决方案。</p><p>这样修改后的转换函数就是下面这个样子的。我这里多了一个参数<code>RGBImg.shape[1]*RGBImg.shape[2]</code>,这个就是用来指明一行有多少个字节的。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">image = QtGui.QImage(RGBImg, RGBImg.shape[<span class="hljs-number">1</span>], RGBImg.shape[<span class="hljs-number">0</span>],<br> RGBImg.shape[<span class="hljs-number">1</span>]*RGBImg.shape[<span class="hljs-number">2</span>], QtGui.QImage.Format_RGB888)<br></code></pre></td></tr></table></figure><h3 id="解决-OpenCV-读取的灰度图像转换成-QImage-时出现变成黑白条纹的现象"><a href="#解决-OpenCV-读取的灰度图像转换成-QImage-时出现变成黑白条纹的现象" class="headerlink" title="解决 OpenCV 读取的灰度图像转换成 QImage 时出现变成黑白条纹的现象"></a>解决 OpenCV 读取的灰度图像转换成 QImage 时出现变成黑白条纹的现象</h3><p>其实这个不算是解决了,只是调用了别人的库,不过我看了别人的源码也没看懂这个到底是怎么做到转换的。大概的实现方式就是下面这样,调用别人的包就完事了。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">if</span> (<span class="hljs-built_in">len</span>(img.shape)==<span class="hljs-number">2</span>):<br> <span class="hljs-comment"># 读入灰度图的时候</span><br> image = array2qimage(img)<br></code></pre></td></tr></table></figure><h2 id="保存图像"><a href="#保存图像" class="headerlink" title="保存图像"></a>保存图像</h2><p>具体的实现方式是通过调用QFileDialog.getSaveFileName()来获取要保存的文件的类型和地址,然后利用OpenCV的imwrite()来实现保存图片的功能。</p><p>保存方面参考的<a href="https://blog.csdn.net/qq_42105426/article/details/89446716">这篇博客</a></p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># 利用OpenCV保存图片</span><br><span class="hljs-comment"># 按不同的格式区分,分别对应不同的参数</span><br><span class="hljs-keyword">if</span> imgType == <span class="hljs-string">"*.jpg"</span>:<br> cv2.imwrite(imgName, self.destImg, [cv2.IMWRITE_JPEG_QUALITY, <span class="hljs-number">50</span>])<br><span class="hljs-keyword">elif</span> imgType == <span class="hljs-string">"*.png"</span>:<br> cv2.imwrite(imgName, self.destImg, [cv2.IMWRITE_PNG_COMPRESSION, <span class="hljs-number">0</span>])<br></code></pre></td></tr></table></figure><p>说完了业务逻辑的设计,接下来就是我的各种算法的实现啦。</p><h2 id="边缘检测"><a href="#边缘检测" class="headerlink" title="边缘检测"></a>边缘检测</h2><p>其实这几种都大同小异,都是利用模板然后进行卷积。为了方便看可以把结果二值化处理</p><h3 id="利用-sobel-算子进行边缘检测"><a href="#利用-sobel-算子进行边缘检测" class="headerlink" title="利用 sobel 算子进行边缘检测"></a>利用 sobel 算子进行边缘检测</h3><p>简单地说就是定义x,y两个方向的sobel算子,然后利用两个算子分别对原图像卷积,最后对两个方向上的结果进行求和。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">sobel</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 利用 sobel 算子 进行边缘检测</span><br><span class="hljs-string"> 读入 OpenCV格式的BGR图像,返回OpenCV格式的灰度图像</span><br><span class="hljs-string"> """</span><br><br> <span class="hljs-comment"># 定义sobel算子</span><br> sobel_x = [[-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>],<br> [-<span class="hljs-number">2</span>, <span class="hljs-number">0</span>, <span class="hljs-number">2</span>],<br> [-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>]]<br> sobel_y = [[-<span class="hljs-number">1</span>, -<span class="hljs-number">2</span>, <span class="hljs-number">1</span>],<br> [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],<br> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, -<span class="hljs-number">1</span>]]<br> <span class="hljs-comment"># 定义阈值</span><br> valve = <span class="hljs-number">188</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> result = np.zeros((row, col))<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, row-<span class="hljs-number">1</span>):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, col-<span class="hljs-number">1</span>):<br> <span class="hljs-comment"># 不管四个边进行边缘检测</span><br> sub = img_gray[x-<span class="hljs-number">1</span>:x+<span class="hljs-number">2</span>, y-<span class="hljs-number">1</span>:y+<span class="hljs-number">2</span>]<br> var_x = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, sobel_x))<br> var_y = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, sobel_y))<br> var = <span class="hljs-built_in">abs</span>(var_x) + <span class="hljs-built_in">abs</span>(var_y)<br> <span class="hljs-keyword">if</span>(var > valve):<br> var = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span>:<br> var = <span class="hljs-number">255</span><br> result[x, y] = var<br> <span class="hljs-keyword">return</span> result<br></code></pre></td></tr></table></figure><h3 id="利用-prewitt-算子进行边缘检测"><a href="#利用-prewitt-算子进行边缘检测" class="headerlink" title="利用 prewitt 算子进行边缘检测"></a>利用 prewitt 算子进行边缘检测</h3><p>和 sobel 算子大同小异,定义x,y方向上的算子,然后分别进行卷积,最后求和。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">prewitt</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 利用 prewitt 算子进行边缘检测</span><br><span class="hljs-string"> 读入 OpenCV格式的BGR图像,返回OpenCV格式的灰度图像</span><br><span class="hljs-string"> """</span><br> <span class="hljs-comment"># 定义prewitt算子</span><br> prewittx = [[-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>],<br> [-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>],<br> [-<span class="hljs-number">1</span>, <span class="hljs-number">0</span>, <span class="hljs-number">1</span>]]<br> prewitty = [[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">1</span>],<br> [<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],<br> [-<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>, -<span class="hljs-number">1</span>]]<br> prewittx = np.array(prewittx)<br> prewitty = np.array(prewitty)<br> <span class="hljs-comment"># 定义阈值</span><br> valve = <span class="hljs-number">188</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> result = np.zeros((row, col))<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, row-<span class="hljs-number">1</span>):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, col-<span class="hljs-number">1</span>):<br> <span class="hljs-comment"># 不管四个边进行边缘检测</span><br> sub = img_gray[x-<span class="hljs-number">1</span>:x+<span class="hljs-number">2</span>, y-<span class="hljs-number">1</span>:y+<span class="hljs-number">2</span>]<br> var_x = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, prewittx))<br> var_y = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, prewitty))<br> var = sqrt(var_x*var_x+var_y*var_y)<br> <span class="hljs-keyword">if</span>(var > valve):<br> var = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span>:<br> var = <span class="hljs-number">255</span><br> result[x, y] = var<br><br> <span class="hljs-keyword">return</span> result<br></code></pre></td></tr></table></figure><h3 id="利用-laplace-算子进行边缘检测"><a href="#利用-laplace-算子进行边缘检测" class="headerlink" title="利用 laplace 算子进行边缘检测"></a>利用 laplace 算子进行边缘检测</h3><p>这个有点不一样的就是只有一个算子,但这个算子兼顾了x,y方向上的结果。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">laplace</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 利用拉普拉斯算子进行边缘检测</span><br><span class="hljs-string"> 读入 OpenCV格式的BGR图像,返回OpenCV格式的灰度图像</span><br><span class="hljs-string"> """</span><br> <span class="hljs-comment"># 定义 laplace 算子</span><br> laplaceop = [[<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>],<br> [<span class="hljs-number">1</span>, -<span class="hljs-number">4</span>, <span class="hljs-number">1</span>],<br> [<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">0</span>]]<br> laplaceop = np.array(laplaceop)<br> <span class="hljs-comment"># 定义阈值</span><br> valve = <span class="hljs-number">81</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> result = np.zeros((row, col))<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, row-<span class="hljs-number">1</span>):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>, col-<span class="hljs-number">1</span>):<br> <span class="hljs-comment"># 不管四个边进行边缘检测</span><br> sub = img_gray[x-<span class="hljs-number">1</span>:x+<span class="hljs-number">2</span>, y-<span class="hljs-number">1</span>:y+<span class="hljs-number">2</span>]<br> var = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, laplaceop))<br> <span class="hljs-keyword">if</span>(var > valve):<br> var = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span>:<br> var = <span class="hljs-number">255</span><br> result[x, y] = var<br> <span class="hljs-keyword">return</span> result<br><br></code></pre></td></tr></table></figure><h2 id="阈值分割"><a href="#阈值分割" class="headerlink" title="阈值分割"></a>阈值分割</h2><p>我试了下,基本就是找到一个大概的阈值。然后通过这个阈值我就可以将图像从原图中分离出来。可以是背景也可以前景主体。</p><h3 id="利用-迭代阈值法-进行阈值分割"><a href="#利用-迭代阈值法-进行阈值分割" class="headerlink" title="利用 迭代阈值法 进行阈值分割"></a>利用 迭代阈值法 进行阈值分割</h3><img src="/%E6%95%B0%E5%AD%97%E5%9B%BE%E5%83%8F%E5%A4%84%E7%90%86%E5%A4%A7%E4%BD%9C%E4%B8%9A%E8%AE%B0%E5%BD%95/%E8%BF%AD%E4%BB%A3%E9%98%88%E5%80%BC%E6%B3%95%E5%8E%9F%E7%90%86.jpg" class="" title="迭代阈值法原理"><p>迭代阈值法主要思想就是</p><ol><li>先假定一个阈值</li><li>然后不停的计算低于阈值的像素的平均值T1和高于阈值的像素的平均值T2。</li><li>最后将这两个平均值求平均T=(T1+T2)/2</li><li>把这个T和当前的阈值相比较,如果没变动,或者进入一个循环了就退出迭代。如果有变动就到步骤2继续循环</li></ol><p>我这里为了判断退出循环的条件引入了一个变量计算每次的阈值变化的差值。如果上次变化的差值和当前变化的差值相同,或者更小,那我就退出循环。</p><p>因为随着迭代,每一步的变动必然是也来越小的,如果出现了差值反而变大的情况,那就直接退出。</p><p>下面是我的代码实现</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">genrate</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 迭代阈值法</span><br><span class="hljs-string"> 输入OpenCV格式的BGR图,输出OpenCV格式的灰度图</span><br><span class="hljs-string"> """</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> result = np.zeros((row, col))<br> <span class="hljs-comment"># 求第一代阈值</span><br> value = <span class="hljs-built_in">int</span>((<span class="hljs-built_in">int</span>(img_gray.<span class="hljs-built_in">max</span>()) + <span class="hljs-built_in">int</span>(img_gray.<span class="hljs-built_in">min</span>()))/<span class="hljs-number">2</span>)<br> <span class="hljs-comment"># 生成直方图便于计算</span><br> F = np.zeros(<span class="hljs-number">256</span>)<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(row) :<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(col) :<br> F[img_gray[x][y]] = F[img_gray[x][y]] + <span class="hljs-number">1</span><br> <span class="hljs-comment"># 获得前景色的数量</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">getFrontColorNum</span>(<span class="hljs-params">median</span>):<br> nFrontColor = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span> (median,<span class="hljs-number">256</span>):<br> nFrontColor = nFrontColor + F[i]<br> <span class="hljs-keyword">return</span> nFrontColor<br> <br> <span class="hljs-comment"># 获得背景色的数量</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">getBackColorNum</span>(<span class="hljs-params">median</span>):<br> nBackColor = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(median): <br> nBackColor = nBackColor + F[i]<br> <span class="hljs-keyword">return</span> nBackColor<br><br> <span class="hljs-comment"># 计算下一代阈值</span><br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">getNextValue</span>(<span class="hljs-params">median</span>):<br> tmp1 = <span class="hljs-number">0</span><br> tmp2 = <span class="hljs-number">0</span><br> sum1 = <span class="hljs-number">0</span><br> sum2 = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(median,<span class="hljs-number">256</span>):<br> tmp1 = tmp1 + F[i] * i<br> sum1 = tmp1/getFrontColorNum(median)<br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(median):<br> tmp2 = tmp2 + F[i] * i<br> sum2 = tmp2/getBackColorNum(median)<br> <span class="hljs-keyword">return</span> (sum1+sum2)/<span class="hljs-number">2</span><br> <br> nextValue = <span class="hljs-built_in">int</span>(getNextValue(value))<br> difference = <span class="hljs-built_in">abs</span>(nextValue - value)<br> <span class="hljs-comment"># 迭代阈值</span><br> <span class="hljs-keyword">while</span> (nextValue!=value):<br> value = nextValue<br> nextValue = <span class="hljs-built_in">int</span>(getNextValue(value))<br> <span class="hljs-comment"># 当差值不再减小时说明就找到了合适的阈值</span><br> <span class="hljs-keyword">if</span> difference <= <span class="hljs-built_in">abs</span>(nextValue - value):<br> <span class="hljs-keyword">break</span><br> value = <span class="hljs-built_in">int</span>(value)<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"迭代阈值法的结果为"</span>,value)<br> <span class="hljs-comment"># 二值化</span><br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(row):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(col):<br> <span class="hljs-keyword">if</span> value > img_gray[x][y]:<br> result[x][y] = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span> :<br> result[x][y] = <span class="hljs-number">255</span><br> <span class="hljs-keyword">return</span> result<br></code></pre></td></tr></table></figure><h3 id="利用-LOG-算子-进行阈值分割"><a href="#利用-LOG-算子-进行阈值分割" class="headerlink" title="利用 LOG 算子 进行阈值分割"></a>利用 LOG 算子 进行阈值分割</h3><p>其实我觉得这个应该算是边缘检测的,但是老师把这个归入了阈值分割那我就跟着她做吧。</p><p>简单地说就是定义一个5x5的模板,然后和原图卷积。其实最好还要求零交叉,不过我还没搞定这个,等搞定再说。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">log</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> log算法 阈值分割</span><br><span class="hljs-string"> 输入OpenCV格式的BGR图片,输出OpenCV格式的灰度图</span><br><span class="hljs-string"> threshold</span><br><span class="hljs-string"> """</span><br> <span class="hljs-comment"># 定义 LOG 算子</span><br> logop = [[-<span class="hljs-number">2</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">2</span>],<br> [-<span class="hljs-number">4</span>,<span class="hljs-number">0</span>,<span class="hljs-number">8</span>,<span class="hljs-number">0</span>,-<span class="hljs-number">4</span>],<br> [-<span class="hljs-number">4</span>,<span class="hljs-number">8</span>,<span class="hljs-number">24</span>,<span class="hljs-number">8</span>,-<span class="hljs-number">4</span>],<br> [-<span class="hljs-number">4</span>,<span class="hljs-number">0</span>,<span class="hljs-number">8</span>,<span class="hljs-number">0</span>,-<span class="hljs-number">4</span>],<br> [-<span class="hljs-number">2</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">4</span>,-<span class="hljs-number">2</span>]]<br> logop =np.array(logop)<br> <span class="hljs-comment"># 定义阈值</span><br> valve = <span class="hljs-number">368</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> result = np.zeros((row, col))<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">2</span>, row-<span class="hljs-number">2</span>):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">2</span>, col-<span class="hljs-number">2</span>):<br> <span class="hljs-comment"># 不管四个边进行边缘检测</span><br> sub = img_gray[x-<span class="hljs-number">2</span>:x+<span class="hljs-number">3</span>, y-<span class="hljs-number">2</span>:y+<span class="hljs-number">3</span>]<br> var = np.<span class="hljs-built_in">sum</span>(np.matmul(sub, logop))<br> <span class="hljs-keyword">if</span>(var > valve):<br> var = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span>:<br> var = <span class="hljs-number">255</span><br> result[x, y] = var<br> <span class="hljs-keyword">return</span> result <br></code></pre></td></tr></table></figure><h3 id="利用-一维最大熵-进行阈值分割"><a href="#利用-一维最大熵-进行阈值分割" class="headerlink" title="利用 一维最大熵 进行阈值分割"></a>利用 一维最大熵 进行阈值分割</h3><p>简单地说就是通过信息熵的公式求出前景熵和背景熵,通过循环来取不同的值来遍历整个颜色的深度,使得前景熵和背景熵之和最大。这就是一维最大熵的原理。</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">def</span> <span class="hljs-title function_">maximus</span>(<span class="hljs-params">img</span>):<br> <span class="hljs-string">"""</span><br><span class="hljs-string"> 一维最大熵</span><br><span class="hljs-string"> 输入OpenCV格式的BGR图片,输出OpenCV格式的灰度图</span><br><span class="hljs-string"> Threshold 阈值</span><br><span class="hljs-string"> 参考 https://blog.csdn.net/Robin__Chou/article/details/53931442</span><br><span class="hljs-string"> """</span><br> <span class="hljs-comment"># 转换为灰度图</span><br> img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)<br> <span class="hljs-comment"># 获取长宽</span><br> row, col = img_gray.shape<br> <span class="hljs-comment"># 生成结果图像矩阵</span><br> result = np.zeros((row, col))<br> <span class="hljs-comment"># 生成直方图便于计算</span><br> F = np.zeros(<span class="hljs-number">256</span>)<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(row) :<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(col) :<br> F[img_gray[x][y]] = F[img_gray[x][y]] + <span class="hljs-number">1</span><br> <br> <br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">getFrontColorNum</span>(<span class="hljs-params">median</span>):<br> <span class="hljs-string">"""获得前景色的数量,输入 median 为阈值的大小"""</span><br> nFrontColor = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span> (median,<span class="hljs-number">256</span>):<br> nFrontColor = nFrontColor + F[i]<br> <span class="hljs-keyword">return</span> nFrontColor<br> <br> <span class="hljs-keyword">def</span> <span class="hljs-title function_">getBackColorNum</span>(<span class="hljs-params">median</span>):<br> <span class="hljs-string">"""获得背景色的数量,输入 median 为阈值的大小"""</span><br> nBackColor = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(median): <br> nBackColor = nBackColor + F[i]<br> <span class="hljs-keyword">return</span> nBackColor<br><br> maxEntropy = -<span class="hljs-number">10</span><br> threshold = <span class="hljs-number">0</span><br> <span class="hljs-comment"># 求出最大熵</span><br> <span class="hljs-keyword">for</span> tmpThreshold <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">256</span>) :<br> nFrontColor = getFrontColorNum(tmpThreshold)<br> nBackColor = getBackColorNum(tmpThreshold)<br> <span class="hljs-comment"># 计算背景熵</span><br> backEntropy = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(tmpThreshold):<br> <span class="hljs-keyword">if</span> F[i]!=<span class="hljs-number">0</span> :<br> Property = F[i]/nBackColor<br> backEntropy = -Property*log10(<span class="hljs-built_in">float</span>(Property)) + backEntropy<br> <span class="hljs-comment"># 计算前景熵</span><br> frontEntropy = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(tmpThreshold,<span class="hljs-number">256</span>):<br> <span class="hljs-keyword">if</span> F[i] != <span class="hljs-number">0</span> :<br> Property = F[i]/nFrontColor<br> frontEntropy = -Property*log10(<span class="hljs-built_in">float</span>(Property)) + frontEntropy<br> <span class="hljs-comment"># 求最大熵</span><br> <span class="hljs-keyword">if</span> (frontEntropy + backEntropy >= maxEntropy) :<br> maxEntropy = frontEntropy + backEntropy<br> threshold = tmpThreshold<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"一维最大熵的阈值为:"</span>,threshold)<br> <span class="hljs-comment"># 二值化结果</span><br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(row):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(col):<br> <span class="hljs-keyword">if</span> threshold > img_gray[x][y]:<br> result[x][y] = <span class="hljs-number">0</span><br> <span class="hljs-keyword">else</span> :<br> result[x][y] = <span class="hljs-number">255</span><br> <span class="hljs-keyword">return</span> result<br><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.csdn.net/qq_32973061/article/details/81139689">pyqt5 从本地选择图片 并显示在label上</a><br><a href="https://doc.qt.io/qtforpython/PySide2/QtWidgets/QGraphicsView.html">QT官方文档:QGraphicsView</a><br><a href="https://amin-ahmadi.com/2015/12/16/how-to-display-a-mat-image-in-qt/">How to display a Mat image in Qt</a><br><a href="https://www.programcreek.com/python/example/108103/PyQt5.QtWidgets.QGraphicsScene">Python PyQt5.QtWidgets.QGraphicsScene() Examples</a><br><a href="https://blog.csdn.net/owen7500/article/details/50905659">解决QLabel显示图片扭曲的问题</a><br><a href="https://blog.csdn.net/qq_42105426/article/details/89446716">Opencv 随笔1------ 图片的读写(png jpg)</a><br><a href="https://blog.csdn.net/qq_36441393/article/details/104766967">opencv 报错’depth’ is 6 (CV_64F)全因numpy 默认float类型是float64位</a><br><a href="https://blog.csdn.net/Robin__Chou/article/details/53931442">OpenCV - 最大熵分割</a><br><a href="https://www.jianshu.com/p/5b063c5745d0">PyQT5速成教程-2 Qt Designer介绍与入门</a></p>]]></content>
<categories>
<category>学习</category>
<category>数字图像处理</category>
</categories>
<tags>
<tag>Python</tag>
<tag>PyQt5</tag>
<tag>OpenCV</tag>
<tag>数字图像处理</tag>
</tags>
</entry>
<entry>
<title>pyqt5的报错处理</title>
<link href="/pyqt5%E7%9A%84%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/"/>
<url>/pyqt5%E7%9A%84%E6%8A%A5%E9%94%99%E5%A4%84%E7%90%86/</url>
<content type="html"><![CDATA[<p>收集遇到的报错</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>摸了好久终于搞定了,不知道下次更新是什么时候了。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="报错-TypeError-argument-1-has-unexpected-type-‘NoneType’"><a href="#报错-TypeError-argument-1-has-unexpected-type-‘NoneType’" class="headerlink" title="报错 TypeError: argument 1 has unexpected type ‘NoneType’"></a>报错 TypeError: argument 1 has unexpected type ‘NoneType’</h2><p>参考这个StackOverFlow上的<a href="https://stackoverflow.com/questions/45793966/clicked-connect-error">回答</a>,将报错的函数改成直接调用即可。<br>比如之前的是</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs python">self.action_genrate.triggered.connect(self.genrateWork()) <span class="hljs-comment"># 报错</span><br>self.action_genrate.triggered.connect(self.genrateWork) <span class="hljs-comment"># 正确</span><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://stackoverflow.com/questions/45793966/clicked-connect-error">clicked.connect() Error</a></p>]]></content>
<categories>
<category>学习</category>
<category>Python</category>
</categories>
<tags>
<tag>error</tag>
<tag>Python</tag>
<tag>pyqt</tag>
</tags>
</entry>
<entry>
<title>Manjaro开机自动打开NumLock</title>
<link href="/Manjaro%E5%BC%80%E6%9C%BA%E8%87%AA%E5%8A%A8%E6%89%93%E5%BC%80NumLock/"/>
<url>/Manjaro%E5%BC%80%E6%9C%BA%E8%87%AA%E5%8A%A8%E6%89%93%E5%BC%80NumLock/</url>
<content type="html"><![CDATA[<p>安装Numlockx,配置/etc/sddm.conf,把None改成on</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>每次登录Manjaro的时候因为密码里面有数字,而Manjaro 又不会自动打开数字键,所以每次都得去手动打开,非常麻烦。于是就去搜了搜,发现解决方式还挺简单的。</p><h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><ul><li>OS: Manjaro 20.0.1 Lysia</li><li>numlockx: 1.2-5</li></ul><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="安装Numlockx"><a href="#安装Numlockx" class="headerlink" title="安装Numlockx"></a>安装<code>Numlockx</code></h2><p>这个我看了看,我的Manjaro是自带的,没有的话就安装一下吧。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo pacman -S numlockx<br></code></pre></td></tr></table></figure><h2 id="配置ssdm-conf"><a href="#配置ssdm-conf" class="headerlink" title="配置ssdm.conf"></a>配置<code>ssdm.conf</code></h2><p>安装好之后配置一下就行了。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo nano /etc/sddm.conf<br></code></pre></td></tr></table></figure><p>打开文件后,找到类似于下面这样的一行</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><code class="hljs conf">[General]<br>HaltCommand=/usr/bin/systemctl poweroff<br>InputMethod=<br>Numlock=none<br>RebootCommand=/usr/bin/systemctl reboot<br></code></pre></td></tr></table></figure><p>然后把<code>Numlock=none</code>这一条改成<code>Numlock=on</code>就行了。</p><figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs ini"><span class="hljs-attr">Numlock</span>=<span class="hljs-literal">on</span><br></code></pre></td></tr></table></figure><p>修改后的结果大概长这样</p><figure class="highlight ini"><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><code class="hljs ini"><span class="hljs-section">[General]</span><br><span class="hljs-attr">HaltCommand</span>=/usr/bin/systemctl power<span class="hljs-literal">off</span><br><span class="hljs-attr">InputMethod</span>=<br><span class="hljs-attr">Numlock</span>=<span class="hljs-literal">on</span><br><span class="hljs-comment">#Numlock=none</span><br><span class="hljs-attr">RebootCommand</span>=/usr/bin/systemctl reboot<br><br></code></pre></td></tr></table></figure><p>现在重启一下就好啦。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/sigma0/p/10317866.html">安装manjaro kde linux的个人步骤</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Manjaro</tag>
<tag>Numlockx</tag>
</tags>
</entry>
<entry>
<title>为OracleDatabase配置PDB登录</title>
<link href="/%E4%B8%BAOracleDatabase%E9%85%8D%E7%BD%AEPDB%E7%99%BB%E5%BD%95/"/>
<url>/%E4%B8%BAOracleDatabase%E9%85%8D%E7%BD%AEPDB%E7%99%BB%E5%BD%95/</url>
<content type="html"><![CDATA[<p>原理简单,懂之前觉得麻烦。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>做数据库的大作业了,要求自己设计一个数据库。之前用的HR数据库姑且是通过改权限强行让CDB能够添加不以C##开头的用户名了。<br>然而大作业也要求搞一个以自己名字命名的用户名,想了想还是试试PDB的结构吧。试了半天终于搞定了。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>我是默认就有了一个自带的叫<code>orclpdb</code>的PDB数据库了,所以就没有新建一个PDB数据库了。</p><h2 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h2><ul><li>Oracle Database 19.3c</li><li>Windows10</li></ul><h2 id="登录到CDB"><a href="#登录到CDB" class="headerlink" title="登录到CDB"></a>登录到CDB</h2><p>就用你的账号登录就好啦,下面我就以<code>testuser</code>作为用户名,<code>pswd</code>作为密码来演示吧。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql">sqlplus testuser <span class="hljs-keyword">as</span> sysdba<span class="hljs-operator">/</span>pswd<span class="hljs-variable">@localhost</span>:<span class="hljs-number">1521</span><span class="hljs-operator">/</span>orcl<br></code></pre></td></tr></table></figure><h2 id="切换到PDB"><a href="#切换到PDB" class="headerlink" title="切换到PDB"></a>切换到PDB</h2><p>先查看你是否已经有了PDB</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span> <span class="hljs-keyword">show</span> pdbs;<br></code></pre></td></tr></table></figure><p>之后大概会弹出这样的结果</p><figure class="highlight pgsql"><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><code class="hljs pgsql"> CON_ID CON_NAME <span class="hljs-keyword">OPEN</span> MODE RESTRICTED<br><span class="hljs-comment">---------- ------------------------------ ---------- ----------</span><br> <span class="hljs-number">2</span> PDB$SEED <span class="hljs-keyword">READ</span> <span class="hljs-keyword">ONLY</span> <span class="hljs-keyword">NO</span><br> <span class="hljs-number">3</span> ORCLPDB <span class="hljs-keyword">READ</span> <span class="hljs-keyword">WRITE</span> <span class="hljs-keyword">NO</span><br></code></pre></td></tr></table></figure><p>这了的 <code>ORCLPDB</code>就是我们已经有了的默认PDB啦。接下来我们就登录进去吧。</p><h2 id="打开PDB"><a href="#打开PDB" class="headerlink" title="打开PDB"></a>打开PDB</h2><p>现在我们切换到PDB <code>ORCLPDB</code>中去。</p><figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span> <span class="hljs-keyword">alter</span> session <span class="hljs-keyword">set</span> container<span class="hljs-operator">=</span>orclpdb; <br></code></pre></td></tr></table></figure><p>正常的会显示如下的字样</p><figure class="highlight"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs">会话已更改。<br></code></pre></td></tr></table></figure><p>我们检查一下是否已经切换成功了</p><figure class="highlight sql"><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><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span> <span class="hljs-keyword">show</span> pdbs;<br><br> CON_ID CON_NAME <span class="hljs-keyword">OPEN</span> MODE RESTRICTED<br><span class="hljs-comment">---------- ------------------------------ ---------- ----------</span><br> <span class="hljs-number">3</span> ORCLPDB READ WRITE <span class="hljs-keyword">NO</span><br></code></pre></td></tr></table></figure><p>然后就把这个PDB打开吧</p><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs abnf">SQL> startup<span class="hljs-comment">;</span><br></code></pre></td></tr></table></figure><h2 id="为PDB创建用户"><a href="#为PDB创建用户" class="headerlink" title="为PDB创建用户"></a>为PDB创建用户</h2><p>下面我们来创建用于专门连接这个PDB的用户。</p><figure class="highlight sql"><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><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span> <span class="hljs-keyword">create</span> <span class="hljs-keyword">user</span> test identified <span class="hljs-keyword">by</span> pswd; <br><br>用户已创建。<br><br></code></pre></td></tr></table></figure><h2 id="授予用户该PDB的DBA权限"><a href="#授予用户该PDB的DBA权限" class="headerlink" title="授予用户该PDB的DBA权限"></a>授予用户该PDB的DBA权限</h2><figure class="highlight sql"><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><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span> <span class="hljs-keyword">grant</span> dba <span class="hljs-keyword">to</span> test;<br><br>授权成功。<br></code></pre></td></tr></table></figure><h2 id="配置listener-ora"><a href="#配置listener-ora" class="headerlink" title="配置listener.ora"></a>配置listener.ora</h2><p>这里找到<code>listener.ora</code>这个文件,它的地址是在<code>ORACLE_HOME/network/admin/listener.ora</code>这里。<br>先找到下面这一段</p><figure class="highlight jboss-cli"><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><code class="hljs jboss-cli">SID_LIST_LISTENER =<br> <span class="hljs-params">(<span class="hljs-attr">SID_LIST</span> =</span><br><span class="hljs-params"> (<span class="hljs-attr">SID_DESC</span> =</span><br><span class="hljs-params"> (<span class="hljs-attr">SID_NAME</span> = CLRExtProc)</span><br> <span class="hljs-params">(<span class="hljs-attr">ORACLE_HOME</span> = D:\Oracle\WINDOWS.X64_193000_db_home)</span><br> <span class="hljs-params">(<span class="hljs-attr">PROGRAM</span> = extproc)</span><br> <span class="hljs-params">(<span class="hljs-attr">ENVS</span> = "<span class="hljs-attr">EXTPROC_DLLS</span>=ONLY:D:\Oracle\WINDOWS.X64_193000_db_home\bin\oraclr19.dll")</span><br> )<br> )<br></code></pre></td></tr></table></figure><p>然后加上这样一段配置就行了</p><figure class="highlight abnf"><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><code class="hljs abnf">(SID_DESC <span class="hljs-operator">=</span><br>(GLOBAL_DBNAME <span class="hljs-operator">=</span> orclpdb)<br>(SID_NAME <span class="hljs-operator">=</span> orcl)<br>)<br></code></pre></td></tr></table></figure><p>整体的结果是类似于这样的</p><figure class="highlight jboss-cli"><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></pre></td><td class="code"><pre><code class="hljs jboss-cli">SID_LIST_LISTENER =<br> <span class="hljs-params">(<span class="hljs-attr">SID_LIST</span> =</span><br><span class="hljs-params"> (<span class="hljs-attr">SID_DESC</span> =</span><br><span class="hljs-params"> (<span class="hljs-attr">SID_NAME</span> = CLRExtProc)</span><br> <span class="hljs-params">(<span class="hljs-attr">ORACLE_HOME</span> = D:\Oracle\WINDOWS.X64_193000_db_home)</span><br> <span class="hljs-params">(<span class="hljs-attr">PROGRAM</span> = extproc)</span><br> <span class="hljs-params">(<span class="hljs-attr">ENVS</span> = "<span class="hljs-attr">EXTPROC_DLLS</span>=ONLY:D:\Oracle\WINDOWS.X64_193000_db_home\bin\oraclr19.dll")</span><br> )<br> <span class="hljs-params">(<span class="hljs-attr">SID_DESC</span> =</span><br><span class="hljs-params"> (<span class="hljs-attr">GLOBAL_DBNAME</span> = orclpdb)</span><br> <span class="hljs-params">(<span class="hljs-attr">SID_NAME</span> = orcl)</span><br> )<br> )<br></code></pre></td></tr></table></figure><h1 id="优化"><a href="#优化" class="headerlink" title="优化"></a>优化</h1><h2 id="设置PDB自动启动"><a href="#设置PDB自动启动" class="headerlink" title="设置PDB自动启动"></a>设置PDB自动启动</h2><p>每次要用PDB的时候都得从CDB切换到PDB然后打开,为了简单我们就用触发器来自动打开吧。</p><figure class="highlight sql"><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><code class="hljs sql"><span class="hljs-keyword">SQL</span><span class="hljs-operator">></span><br><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> REPLACE <span class="hljs-keyword">TRIGGER</span> open_pdbs<br>AFTER STARTUP <span class="hljs-keyword">ON</span> DATABASE<br><span class="hljs-keyword">BEGIN</span><br><span class="hljs-keyword">EXECUTE</span> IMMEDIATE <span class="hljs-string">'ALTER PLUGGABLE DATABASE ALL OPEN'</span>;<br><span class="hljs-keyword">END</span> open_pdbs;<br><span class="hljs-operator">/</span><br></code></pre></td></tr></table></figure><p>这样就搞定了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/ray-bk/p/9711757.html">Oracle 12c中新建pdb用户登录问题分析</a></p><p><a href="https://www.cnblogs.com/zhjh256/p/9353579.html">oracle 12c多租户下的日常操作变化</a></p><p><a href="https://www.cnblogs.com/polestar/p/5892410.html">Oracle 12C 创建用户连接pdb</a></p>]]></content>
<categories>
<category>学习</category>
<category>OracleDatabase</category>
</categories>
<tags>
<tag>OracleDatabase</tag>
<tag>PDB</tag>
</tags>
</entry>
<entry>
<title>去除Chrome请停用以开发者模式运行的扩展程序</title>
<link href="/%E5%8E%BB%E9%99%A4Chrome%E8%AF%B7%E5%81%9C%E7%94%A8%E4%BB%A5%E5%BC%80%E5%8F%91%E8%80%85%E6%A8%A1%E5%BC%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%89%A9%E5%B1%95%E7%A8%8B%E5%BA%8F/"/>
<url>/%E5%8E%BB%E9%99%A4Chrome%E8%AF%B7%E5%81%9C%E7%94%A8%E4%BB%A5%E5%BC%80%E5%8F%91%E8%80%85%E6%A8%A1%E5%BC%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%89%A9%E5%B1%95%E7%A8%8B%E5%BA%8F/</url>
<content type="html"><![CDATA[<p>下载,运行,搞定</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>看这个真的很不舒服,于是就这么搞了</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>我这个是直接用的别人的工具,原帖在这里👉<a href="https://www.52pojie.cn/thread-1093576-1-1.html">完美去除Chrome「请停用以开发者模式运行的扩展程序」</a></p><p>简单的说就是下载这个工具,然后放到chrome程序的文件夹中,然后以管理员程序运行这个工具就好。</p><p>先下载这个工具,可以直接走我的<a href="https://od.yikakia.com/down/%E8%BD%AF%E4%BB%B6/%E5%8E%BB%E9%99%A4Chrome%E8%AF%B7%E5%81%9C%E7%94%A8%E4%BB%A5%E5%BC%80%E5%8F%91%E8%80%85%E6%A8%A1%E5%BC%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%89%A9%E5%B1%95%E7%A8%8B%E5%BA%8F.exe">分流</a>,也可以直接下载原帖的</p><blockquote><p>链接: <a href="https://pan.baidu.com/s/1nDrEiVSEHVde6WOAaXxMKQ">https://pan.baidu.com/s/1nDrEiVSEHVde6WOAaXxMKQ</a> 提取码: s2qd</p></blockquote><p>然后把下载好的这个程序放在你的<code>Chrome</code>程序的目录下,如下👇</p><img src="/%E5%8E%BB%E9%99%A4Chrome%E8%AF%B7%E5%81%9C%E7%94%A8%E4%BB%A5%E5%BC%80%E5%8F%91%E8%80%85%E6%A8%A1%E5%BC%8F%E8%BF%90%E8%A1%8C%E7%9A%84%E6%89%A9%E5%B1%95%E7%A8%8B%E5%BA%8F/%E6%94%BE%E7%BD%AE%E4%BD%8D%E7%BD%AE.png" class="" title="放置位置"><p>然后点击右键,以管理员权限运行即可。对了,先要退出<code>Chrome</code>再运行这个程序。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.52pojie.cn/thread-1093576-1-1.html">完美去除Chrome「请停用以开发者模式运行的扩展程序」</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Chrome</tag>
</tags>
</entry>
<entry>
<title>中值滤波及快速中值滤波的Python实现</title>
<link href="/%E4%B8%AD%E5%80%BC%E6%BB%A4%E6%B3%A2%E5%8F%8A%E5%BF%AB%E9%80%9F%E4%B8%AD%E5%80%BC%E6%BB%A4%E6%B3%A2%E7%9A%84Python%E5%AE%9E%E7%8E%B0/"/>
<url>/%E4%B8%AD%E5%80%BC%E6%BB%A4%E6%B3%A2%E5%8F%8A%E5%BF%AB%E9%80%9F%E4%B8%AD%E5%80%BC%E6%BB%A4%E6%B3%A2%E7%9A%84Python%E5%AE%9E%E7%8E%B0/</url>
<content type="html"><![CDATA[<p>写完发现比opencv自带的慢了十倍。😂</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>原理倒是不难,但是对于优化而言就麻烦了。最开始看他们说利用直方图的时候我还没看懂,看了别人的源码才明白原来说的直方图就是桶排序嘛。</p><p>但是在测试性能的时候发现比opencv自带的函数慢了十倍,还是用了优化过的算法。不知道是哪里出了问题。</p><h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><ul><li>python 3.8.1</li><li>opencv-python 4.2.0.34</li></ul><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><h2 id="中值滤波的原理"><a href="#中值滤波的原理" class="headerlink" title="中值滤波的原理"></a>中值滤波的原理</h2><p>简单地说就是对于像素点<code>p[x][y]</code>,它的颜色由它及周围的像素的颜色的组成的序列的中位数来确定。这个周围可以是十字形的,可以是以他为中心的<code>3*3</code> 矩阵或者<code>5*5</code>,<code>n*n</code>(n最好为奇数,这样直接取排序后中间的那个值就可以了,不然还得求平均数)的矩阵。而这个的时间复杂度明显就至少是<code>O(M*N*P^2)</code>的,其中M,N分别为原图像的长宽,而P则为你用于取色的那个窗口的大小。这性能开销明显是不可接受的,那么怎么优化呢?</p><h2 id="快速中值滤波的原理"><a href="#快速中值滤波的原理" class="headerlink" title="快速中值滤波的原理"></a>快速中值滤波的原理</h2><p>通过上面的分析我们可以知道,这里面最大的开销就是排序的这个过程了。而仔细观察的话就能发现,排序的这个过程会有相当大程度的重复。</p><p>就拿<code>3*3</code>的矩阵来举例。每次向右移动一个像素的话,最左边的p[x-1]这一列的像素是没有用的,而中间和右边的p[x],p[x+1]这两列在接下来的排序还是可以继续使用的。那么应该怎么去实现呢?</p><h3 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h3><p>这里我们可以通过计数排序来实现。<br>我们先建立一个有256个位数的数组<code>Histogram</code>,这里面每一位表示这个颜色的像素有几个。没有就记为0。</p><p>这里选取256的原因是因为我是对单一通道进行处理的,每一个颜色的范围是[0,255]。如果用其他色彩空间的话可以根据需求更改。</p><p>现在我们开始对这个点进行维护,对于每一列的最下面的那个点,直接将周围的像素存进<code>Histogram</code>就可以了。而要写入的新的颜色值,就是根据这个<code>Histogram</code>得到的中位数。当然了,也可以直接通过<code>numpy</code>自带的求中位数的函数<code>numpy.median()</code>来求得。</p><h3 id="计数排序求中位数"><a href="#计数排序求中位数" class="headerlink" title="计数排序求中位数"></a>计数排序求中位数</h3><p>我们每次都要确定中位数,而在这种计数排序中,为了方便确定,我们引入一个<code>n</code>用来记住小于等于中位数的数字的个数。</p><p>每次在更新了数组<code>Histogram</code>之后,要及时的修改<code>n</code>的值。这样方便接下来的操作。</p><p>现在在更新完了数组<code>Histogram</code>之后,我们应该及时地更新中位数<code>med</code>。我们可以像下面这样做👇</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">if</span> n > <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">while</span> n > <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">if</span> med == <span class="hljs-number">0</span> :<br> <span class="hljs-keyword">break</span><br> n = n - <span class="hljs-built_in">int</span>(Histogram[med])<br> med = med - <span class="hljs-number">1</span><br><span class="hljs-keyword">elif</span> n < <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">while</span> n < <span class="hljs-number">5</span> :<br> med = med + <span class="hljs-number">1</span><br> n = n + <span class="hljs-built_in">int</span>(Histogram[med])<br></code></pre></td></tr></table></figure><p>在这里我们判断,比起更新前的中位数<code>med1</code>,为了便于区别这里用<code>med1</code>代替,现在的中位数<code>med</code>是大了还是小了?</p><p>这就是我们之前记录<code>n</code>的目的了。当<code>n > 5</code>的时候我们可以发现现在要求的中位数<code>med</code>应该小于之前的中位数<code>med1</code>,即<code>med < med1</code>,这个时候就应该让<code>med</code>逐渐减小,直到第一次<code>n <= 5 </code>为止,这个时候的<code>med</code>就是我们要求的<code>med</code>了。</p><p>当然还有特殊情况就是当<code>med = 0</code>的时候。这个时候是不会再小了,那么直接退出就可以了。</p><p>同样的逻辑可以解决<code>n < 5</code>的情况。而这里没有特殊情况的原因是因为我们之前定义<code>n</code>的时候,是把它记为<em>记住小于等于中位数的数字的个数</em>。<br>如果<code>med1 = 255</code> 那么可以知道,<code>n</code>此时是必然等于<code>9</code>的。因为不存在比<code>255</code>更大的颜色了。</p><h2 id="源码实现"><a href="#源码实现" class="headerlink" title="源码实现"></a>源码实现</h2><p>要对比性能的话可以修改<code>medianBlur()</code>函数中的</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-comment"># b = medianBlurChannel(b)</span><br><span class="hljs-comment"># g = medianBlurChannel(g)</span><br><span class="hljs-comment"># r = medianBlurChannel(r)</span><br>b = fastMedianBlurChannel(b)<br>g = fastMedianBlurChannel(g)<br>r = fastMedianBlurChannel(r)<br></code></pre></td></tr></table></figure><p>这一段,上面的是中值滤波,下面的是快速中值滤波。<br>下面是源码👇</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><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></pre></td><td class="code"><pre><code class="hljs python"><span class="hljs-keyword">import</span> cv2 <br><span class="hljs-keyword">import</span> numpy<br><span class="hljs-keyword">import</span> copy<br><span class="hljs-keyword">import</span> datetime<br><span class="hljs-comment"># 对于单一通道进行中值滤波</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">medianBlurChannel</span>(<span class="hljs-params">channel</span>):<br> channel2 = copy.copy(channel)<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>,<span class="hljs-built_in">len</span>(channel)-<span class="hljs-number">1</span>):<br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>,<span class="hljs-built_in">len</span>(channel[<span class="hljs-number">0</span>])-<span class="hljs-number">1</span>):<br> channel2[x][y]=numpy.median(channel[x-<span class="hljs-number">1</span>:x+<span class="hljs-number">2</span>,y-<span class="hljs-number">1</span>:y+<span class="hljs-number">2</span>])<br> <span class="hljs-keyword">return</span> channel2<br><br><span class="hljs-comment"># 快速中值滤波</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">fastMedianBlurChannel</span>(<span class="hljs-params">channel</span>):<br> channel2 = copy.copy(channel)<br> <span class="hljs-keyword">for</span> x <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>,<span class="hljs-built_in">len</span>(channel)-<span class="hljs-number">1</span>):<br> <span class="hljs-comment"># 初始化直方图</span><br> Histogram = numpy.zeros(<span class="hljs-number">256</span>,dtype=<span class="hljs-built_in">int</span>)<br> <span class="hljs-comment"># 对每一列的第一个像素初始化</span><br> <span class="hljs-comment"># 它的颜色取channel[x][1]它及周围的八个像素的颜色的中位数</span><br> med = <span class="hljs-built_in">int</span>(numpy.median(channel[x-<span class="hljs-number">1</span>:x+<span class="hljs-number">2</span>,<span class="hljs-number">0</span>:<span class="hljs-number">3</span>]))<br> <span class="hljs-comment"># 用n确定中值的偏移量</span><br> n = <span class="hljs-number">0</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(-<span class="hljs-number">1</span>,<span class="hljs-number">2</span>):<br> <span class="hljs-keyword">for</span> j <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">0</span>,<span class="hljs-number">3</span>):<br> Histogram[channel[x+i][j]] = Histogram[channel[x+i][j]] +<span class="hljs-number">1</span><br> <span class="hljs-keyword">if</span> channel[x+i][j] <= med :<br> n = n + <span class="hljs-number">1</span><br> <span class="hljs-keyword">for</span> y <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(<span class="hljs-number">1</span>,<span class="hljs-built_in">len</span>(channel[<span class="hljs-number">0</span>])-<span class="hljs-number">1</span>):<br> <span class="hljs-keyword">if</span> y == <span class="hljs-number">1</span>:<br> <span class="hljs-keyword">pass</span><br> <span class="hljs-keyword">else</span> :<br> <span class="hljs-comment"># 更新直方图,并更新n的值</span><br> <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> <span class="hljs-built_in">range</span>(-<span class="hljs-number">1</span>,<span class="hljs-number">2</span>) :<br> <span class="hljs-comment"># 在直方图中删除下方不用的像素</span><br> Histogram[channel[x+i][y-<span class="hljs-number">2</span>]] = Histogram[channel[x+i][y-<span class="hljs-number">2</span>]] - <span class="hljs-number">1</span><br> <span class="hljs-keyword">if</span> channel[x+i][y-<span class="hljs-number">2</span>] <= med :<br> n = n - <span class="hljs-number">1</span><br> <span class="hljs-comment"># 在直方图中添加上方要用的像素</span><br> Histogram[channel[x+i][y+<span class="hljs-number">1</span>]] = Histogram[channel[x+i][y+<span class="hljs-number">1</span>]] + <span class="hljs-number">1</span><br> <span class="hljs-keyword">if</span> channel[x+i][y+<span class="hljs-number">1</span>] <= med :<br> n = n + <span class="hljs-number">1</span><br> <span class="hljs-comment"># 更新 med 的值</span><br> <span class="hljs-keyword">if</span> n > <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">while</span> n > <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">if</span> med == <span class="hljs-number">0</span> :<br> <span class="hljs-keyword">break</span><br> n = n - <span class="hljs-built_in">int</span>(Histogram[med])<br> med = med - <span class="hljs-number">1</span><br> <span class="hljs-keyword">elif</span> n < <span class="hljs-number">5</span> :<br> <span class="hljs-keyword">while</span> n < <span class="hljs-number">5</span> :<br> med = med + <span class="hljs-number">1</span><br> n = n + <span class="hljs-built_in">int</span>(Histogram[med])<br> <span class="hljs-comment"># 存入结果</span><br> channel2[x][y] = med<br> <span class="hljs-keyword">return</span> channel2 <br> <br><span class="hljs-comment"># 对图像进行中值滤波</span><br><span class="hljs-keyword">def</span> <span class="hljs-title function_">medianBlur</span>(<span class="hljs-params">image</span>):<br> shape = <span class="hljs-built_in">list</span>(image.shape)<br> <span class="hljs-keyword">if</span> <span class="hljs-built_in">len</span>(shape) != <span class="hljs-number">3</span>:<br> <span class="hljs-built_in">print</span>(<span class="hljs-string">"请输入三通道的图像!"</span>)<br> <span class="hljs-keyword">return</span><br> <span class="hljs-keyword">else</span>:<br> b,g,r=cv2.split(image)<br> <span class="hljs-comment"># b = medianBlurChannel(b)</span><br> <span class="hljs-comment"># g = medianBlurChannel(g)</span><br> <span class="hljs-comment"># r = medianBlurChannel(r)</span><br> b = fastMedianBlurChannel(b)<br> g = fastMedianBlurChannel(g)<br> r = fastMedianBlurChannel(r)<br> <span class="hljs-keyword">return</span> cv2.merge([b,g,r])<br><br><span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">"__main__"</span>:<br> start = datetime.datetime.now()<br> img = cv2.imread(<span class="hljs-string">'45-salt.jpg'</span>)<br> img2 = medianBlur(img)<br> img3 = cv2.medianBlur(img,<span class="hljs-number">3</span>)<br> cv2.imshow(<span class="hljs-string">'src'</span>,img)<br> cv2.imshow(<span class="hljs-string">'result'</span>,img2)<br> cv2.imshow(<span class="hljs-string">'standard'</span>,img3)<br> end = datetime.datetime.now()<br> <span class="hljs-built_in">print</span>(end-start)<br> cv2.waitKey(<span class="hljs-number">0</span>)<br> cv2.destroyAllWindows()<br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://blog.csdn.net/rocketeerLi/article/details/88017306">快速中值滤波——Python实现</a></p>]]></content>
<categories>
<category>学习</category>
<category>数字图像处理</category>
</categories>
<tags>
<tag>Python</tag>
<tag>算法</tag>
<tag>OpenCV</tag>
<tag>中值滤波</tag>
</tags>
</entry>
<entry>
<title>利用rclone 将别人分享的GoogleDrive文件保存到OneDrive中</title>
<link href="/%E5%88%A9%E7%94%A8rclone-%E5%B0%86%E5%88%AB%E4%BA%BA%E5%88%86%E4%BA%AB%E7%9A%84GoogleDrive%E6%96%87%E4%BB%B6%E4%BF%9D%E5%AD%98%E5%88%B0OneDrive%E4%B8%AD/"/>
<url>/%E5%88%A9%E7%94%A8rclone-%E5%B0%86%E5%88%AB%E4%BA%BA%E5%88%86%E4%BA%AB%E7%9A%84GoogleDrive%E6%96%87%E4%BB%B6%E4%BF%9D%E5%AD%98%E5%88%B0OneDrive%E4%B8%AD/</url>
<content type="html"><![CDATA[<p>一句话解决问题,<code>--drive-shared-with-me</code></p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>之前买了<code>Office365</code>的家庭版,感觉用着挺爽的。1T的容量加上不限速,难道不香么?在vps上搞一个Aria2下载,下载好后调用Rclone直接上传到OneDrive上,那感觉简直爽翻了。于是我就开始了资源搬运的道路。毕竟Google Drive的资源那是真的多。最开始我是直接通过复制到我的网盘里面,然后用Rclone的<code>copy</code>指令来迁移。不过挺麻烦的,因为我的没买Google Drive的服务,所以只能和蚂蚁搬山一样,一部分一部分的复制,然后迁移。今天搬运的时候突然发现有一个添加快捷方式的选项,于是上网搜了一下,发现有直接复制快捷方式的方法。这就很好了,省去了无聊的手动时间。</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><p>简单地说,就是加一个参数<code>--drive-shared-with-me</code>,就可以了。比如下面这样</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">rclone copy gd:<span class="hljs-string">"TestFile"</span> <span class="hljs-built_in">od</span>:<span class="hljs-string">"TestFile"</span> --drive-shared-with-me -P --transfers=1<br></code></pre></td></tr></table></figure><p>这里你是把Google Drive<code>gd</code>里面的<code>TestFile</code>复制到OneDrive<code>od</code>里面了。这里的<code>TestFile</code>是快捷方式,并不会占用你的Google Drive里面的空间😀</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.hostloc.com/thread-667776-2-1.html">google drive 只能添加快捷方式到自己硬盘了?</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>rclone</tag>
<tag>OneDrive</tag>
<tag>GoogleDrive</tag>
</tags>
</entry>
<entry>
<title>First集 Follow集 Select集分别有什么意义</title>
<link href="/First%E9%9B%86-Follow%E9%9B%86-Select%E9%9B%86%E5%88%86%E5%88%AB%E6%9C%89%E4%BB%80%E4%B9%88%E6%84%8F%E4%B9%89/"/>
<url>/First%E9%9B%86-Follow%E9%9B%86-Select%E9%9B%86%E5%88%86%E5%88%AB%E6%9C%89%E4%BB%80%E4%B9%88%E6%84%8F%E4%B9%89/</url>
<content type="html"><![CDATA[<p>这三个集合是为了后期规约与分解方便</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>记录一下,方便以后查阅</p><h1 id="First集"><a href="#First集" class="headerlink" title="First集"></a>First集</h1><p>First集表示对于非终结符A,First(A)表示这个非终结符转换为终结符形式后的第一个终结符的集合。</p><h1 id="Follow集"><a href="#Follow集" class="headerlink" title="Follow集"></a>Follow集</h1><p>Follow集表示对于非终结符A,Follow(A)表示这个终结符转换为终结符型时候的紧跟在它最后的第一个终结符的集合。</p><h1 id="Select集"><a href="#Select集" class="headerlink" title="Select集"></a>Select集</h1><p>Select集表示对于生成式A->α,Select(A->α)表示</p><ol><li>α不能推出空的时候,α转换为终结符形式后的第一个终结符的集合</li><li>α可以推出空的时候,α转换为终结符形式后的第一个终结符且去除空集的集合,与A转换为终结符型时候的紧跟在它最后的第一个终结符的集合的并集。</li></ol>]]></content>
<categories>
<category>学习</category>
<category>编译原理</category>
</categories>
<tags>
<tag>编译原理</tag>
</tags>
</entry>
<entry>
<title>如何禁用Software-Reporter-Tool</title>
<link href="/%E5%A6%82%E4%BD%95%E7%A6%81%E7%94%A8Software-Reporter-Tool/"/>
<url>/%E5%A6%82%E4%BD%95%E7%A6%81%E7%94%A8Software-Reporter-Tool/</url>
<content type="html"><![CDATA[<p>不作恶的谷歌扫硬盘搞毛。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>今天发现电脑CPU占用很高,风扇在狂转。想了想我好像后台没开什么应用啊?于是打开了任务管理器看了看,发现有个叫<code>software reporter tool</code>的进程在后台使劲跑。觉得纳闷就上网搜了下,发现原来是谷歌Chrome的后台程序。下面简单的说下这个软件是干嘛的吧。</p><p>这个<code>software reporter tool</code>会扫描你电脑的硬盘,然后把扫描的结果报告给谷歌,让谷歌分析这些结果,看是什么软件影响了用户的网页浏览体验。然后推荐用户删除这些软件。<br>看起来好像没啥问题是不是?但是这里面有两个让人很不爽的点啊。</p><ol><li>当它扫描的时候,会让CPU的负载过高,而且持续时间还很久。而且还可能会在你工作的时候干这种事情。换句话说,谷歌为了解决可能影响到用户网页浏览体验的问题,而影响到了用户日常的体验!</li><li>这个扫描结果会发给谷歌。虽然说这是匿名的,脱敏的。但谁有能信得过谷歌呢?这样的东西真的没问题么?棱镜计划虽然现在已经没多少人提了,但它所暴露出的问题是不容辩驳的。真的能放心的将隐私交给谷歌么?</li></ol><p>说是为了清除让Chrome崩溃的软件,但是你这个扫描硬盘是不是有点过了啊?<br>总之,让人心生疑虑了,就把它干掉吧。</p><h1 id="通过修改权限禁用"><a href="#通过修改权限禁用" class="headerlink" title="通过修改权限禁用"></a>通过修改权限禁用</h1><p>查了之后发现这个文件是就算你删除了,谷歌也可能会给你装回来的。是不是有点眼熟这个全家桶操作?😀<br>所以我们要做的就是禁止谷歌启动这个程序。</p><p>这个软件的位置大概是在这里:</p><figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs crmsh">C:\Users\USERNAME\AppData\Local\Google\Chrome\<span class="hljs-keyword">User</span> <span class="hljs-title">Data</span>\SwReporter\<span class="hljs-keyword">VERSION</span><br></code></pre></td></tr></table></figure><p>把这里面的<code>USERNAME</code>改成你的用户名,<code>VERSION</code>改成你的Chrome版本。然后就可以看到这个文件了。<br>这里我的版本是 <code>81.233.200</code></p><img src="/%E5%A6%82%E4%BD%95%E7%A6%81%E7%94%A8Software-Reporter-Tool/%E5%A6%82%E4%BD%95%E7%A6%81%E7%94%A8Software-Reporter-Tool.png" class=""><ol><li>在这里我们往上退两步,到<code>C:\Users\USERNAME\AppData\Local\Google\Chrome\User Data\</code>这一层,然后右键<code>SwReporter</code>这个文件夹,选择属性。</li></ol><img src="/%E5%A6%82%E4%BD%95%E7%A6%81%E7%94%A8Software-Reporter-Tool/%E5%8F%B3%E9%94%AESwReporter.png" class=""><ol start="2"><li>选择<code>安全</code>选项卡</li><li>点击<code>高级</code></li></ol><ol start="4"><li>点击<code>禁用继承</code></li></ol><ol start="5"><li>选择<code>从此对象中删除所有继承的权限</code>,之后一路确定。</li></ol><p>这样就没有人可以访问<code>SwReporter</code>文件夹并启动<code>software reporter tool</code>了。</p><h1 id="通过修改注册表禁用"><a href="#通过修改注册表禁用" class="headerlink" title="通过修改注册表禁用"></a>通过修改注册表禁用</h1><p>不推荐,修改注册表前请做好备份工作。<br>这里先给一段原文</p><figure class="highlight vbnet"><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><code class="hljs vbnet">Google introduced support <span class="hljs-keyword">for</span> policies that administrators may use <span class="hljs-keyword">to</span> configure certain Chrome features; one <span class="hljs-keyword">of</span> the available policies manages the Software Reporter Tool <span class="hljs-keyword">of</span> the browser.<br><br>Open the Registry Editor <span class="hljs-keyword">on</span> Windows, e.g. <span class="hljs-keyword">by</span> opening the Start Menu, typing regedit.exe, <span class="hljs-built_in">and</span> selecting the item <span class="hljs-keyword">from</span> the list <span class="hljs-keyword">of</span> results.<br>Go <span class="hljs-keyword">to</span> HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome.<br><span class="hljs-symbol">Note:</span> <span class="hljs-keyword">if</span> one <span class="hljs-keyword">of</span> the keys does <span class="hljs-built_in">not</span> exist create it <span class="hljs-keyword">with</span> a right-click <span class="hljs-keyword">on</span> the previous <span class="hljs-keyword">key</span> <span class="hljs-built_in">and</span> the selection <span class="hljs-keyword">of</span> <span class="hljs-built_in">New</span> > <span class="hljs-keyword">Key</span>.<br>Right-click <span class="hljs-keyword">on</span> the Chrome <span class="hljs-keyword">key</span> <span class="hljs-built_in">and</span> <span class="hljs-keyword">select</span> <span class="hljs-built_in">New</span> > Dword (<span class="hljs-number">32</span>-bit) Value.<br>Name the <span class="hljs-built_in">new</span> Dword ChromeCleanupEnabled.<br>Make sure its value <span class="hljs-built_in">is</span> <span class="hljs-number">0</span>.<br>Right-click <span class="hljs-keyword">on</span> the Chrome <span class="hljs-keyword">key</span> again <span class="hljs-built_in">and</span> <span class="hljs-keyword">select</span> <span class="hljs-built_in">New</span> > Dword (<span class="hljs-number">32</span>-bit) Value.<br>Name it ChromeCleanupReportingEnabled.<br>Make sure its value <span class="hljs-built_in">is</span> <span class="hljs-number">0</span>.<br>ChromeCleanupEnabled<span class="hljs-comment">'s value determines whether the Software Reporter Tool may run on the system.</span><br><br>A value <span class="hljs-keyword">of</span> <span class="hljs-number">0</span> means the tool <span class="hljs-built_in">is</span> disabled <span class="hljs-built_in">and</span> won<span class="hljs-comment">'t be run.</span><br>A value <span class="hljs-keyword">of</span> <span class="hljs-number">1</span> means the Software Reporter <span class="hljs-built_in">is</span> enabled <span class="hljs-built_in">and</span> will be run <span class="hljs-keyword">by</span> Chrome.<br>ChromeCleanupReportingEnabled<span class="hljs-comment">'s value determines whether the results are reported to Google.</span><br><br>A value <span class="hljs-keyword">of</span> <span class="hljs-number">0</span> means the reporting <span class="hljs-built_in">is</span> disabled.<br>A value <span class="hljs-keyword">of</span> <span class="hljs-number">1</span> means the reporting <span class="hljs-built_in">is</span> enabled.<br></code></pre></td></tr></table></figure><p>简单地说就是打开注册表,在<code>HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome</code>这项下面新建叫做<code>ChromeCleanupEnabled</code>和<code>ChromeCleanupReportingEnabled</code>的键,它们的类型都是<code>Dword</code>(32位)双字节数据类型,把它们都赋值为0。<br>下面是不同键值的作用</p><table><thead><tr><th></th><th>0</th><th>1</th></tr></thead><tbody><tr><td>ChromeCleanupEnabled</td><td>这个工具将被禁用并且不会运行</td><td>这个工具将被启用,并且会被Chrome运行</td></tr><tr><td>ChromeCleanupReportingEnabled</td><td>禁止将报告传回谷歌</td><td>生成的报告将会传给谷歌</td></tr><tr><td>然后没有<code>\Google\Chrome</code>这一项的话,就自己新建就行。不过,还是不建议不清楚自己这么做了有什么后果的人通过这一项来修改。</td><td></td><td></td></tr></tbody></table><h1 id="通过Chrome浏览器来设置"><a href="#通过Chrome浏览器来设置" class="headerlink" title="通过Chrome浏览器来设置"></a>通过Chrome浏览器来设置</h1><p>这个我觉得是不行的,不过看到网上说有用的,那就也一并记录下来吧。</p><ol><li>进入Chrome的设置界面->高级->系统<br>在这个选项下的<code>关闭 Google Chrome 后继续运行后台应用</code>关闭掉。</li><li>把<code>向Google报告在此次清理期间,在您计算机中发现的有害软件、系统设置和进程的相关详情</code>反选掉。</li></ol><p>这样就好了。<br>不过我在这么搞的时候发现我的这个已经设置过了。看来谷歌这小子浓眉大眼的,结果还是不好好做事啊。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.ghacks.net/2018/01/20/how-to-block-the-chrome-software-reporter-tool-software_reporter_tool-exe/">How to block the Chrome Software Reporter Tool (software_reporter_tool.exe)</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Windows</tag>
<tag>Chrome</tag>
</tags>
</entry>
<entry>
<title>删除右键菜单中的新建office文件</title>
<link href="/%E5%88%A0%E9%99%A4%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95%E4%B8%AD%E7%9A%84%E6%96%B0%E5%BB%BAoffice%E6%96%87%E4%BB%B6/"/>
<url>/%E5%88%A0%E9%99%A4%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95%E4%B8%AD%E7%9A%84%E6%96%B0%E5%BB%BAoffice%E6%96%87%E4%BB%B6/</url>
<content type="html"><![CDATA[<p>简单总结,改注册表。</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>为什么突然想到要搞这个呢?因为我突然发现我卸载了Access和Publisher之后,右键还是有这两位的新建方式。这明显就是没有卸载干净嘛!</p><h1 id="正文"><a href="#正文" class="headerlink" title="正文"></a>正文</h1><ol><li>按下<code>Win+R</code>,输入<code>regedit</code>进入注册表编辑器。</li><li>在上面的目录,输入<code>计算机\HKEY_CLASSES_ROOT\.mdb</code>进入相关项。<br>这里我是用Access的<code>.mbd</code>格式举例。因为Access还有一个格式<code>.accdb</code>。所以还要做同样的操作来删除新建<code>.accdb</code>。而Publisher相关的格式是<code>.pub</code>,重复这个步骤也可以搞定。</li><li>这个时候你应该能看到和我这个相似的界面。<img src="/%E5%88%A0%E9%99%A4%E5%8F%B3%E9%94%AE%E8%8F%9C%E5%8D%95%E4%B8%AD%E7%9A%84%E6%96%B0%E5%BB%BAoffice%E6%96%87%E4%BB%B6/Snipaste_2020-04-14_20-54-35.png" class=""></li></ol><p>因为我现在已经删除了,所以没有<code>ShellNew</code>这一项。而你应该做的,就是删除这一项。删除之后你可以在桌面右键点击看看,是不是那一项没有了?😀</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://answers.microsoft.com/zh-hans/msoffice/forum/msoffice_word-mso_other-mso_2007/%e5%b7%b2%e5%8d%b8%e8%bd%bdword%e5%90%8e%e4%bb%8d/6ada6678-2f01-4ff0-a6e3-902e25f78bb5">已卸载Word后仍在右键的新建菜单中显示,如何删除</a><br><a href="https://blog.csdn.net/q290994/article/details/72587931">右键新建项的增加和删除</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Windows</tag>
<tag>Access</tag>
<tag>Publisher</tag>
</tags>
</entry>
<entry>
<title>双系统双硬盘安装Manjaro,Windows10</title>
<link href="/%E5%8F%8C%E7%B3%BB%E7%BB%9F%E5%8F%8C%E7%A1%AC%E7%9B%98%E5%AE%89%E8%A3%85ManjaroWin10/"/>
<url>/%E5%8F%8C%E7%B3%BB%E7%BB%9F%E5%8F%8C%E7%A1%AC%E7%9B%98%E5%AE%89%E8%A3%85ManjaroWin10/</url>
<content type="html"><![CDATA[<p>Manjaro自带的分区功能真是弱鸡</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>这次想起来搞这个双系统主要是我服务器端用的多了,感觉对Linux比较熟悉了,所以就想着搞搞双系统。</p><p>而我以前又装过<code>deepin</code>,那个时候觉得引导界面太丑了于是就又搞了些事情想让Windows10的Metro引导来引导Linux。结果最后失败了,还把引导搞坏了。所以最后还得重装一次系统。</p><p>现在的话就知道了,这个引导界面是Grub的,是可以有主题进行美化的。所以没必要直接格掉,换个主题的事情。</p><p>而我选用<code>Manjaro</code>的原因,是因为感觉<code>Ubuntu</code>太重了。虚拟机里面装的<code>Ubuntu 1804</code>感觉界面不是很合我的胃口,有点太油腻的感觉。所以就找了找,发现<code>Manjaro</code>这么一个发行版,背靠<code>ArchLinux</code>,坐拥浩大的软件仓库。同时还兼有易用性和稳定性,可以开箱即用,也可以有稳定的体验。那这感情好,还不得体验体验。于是去官网看了看,选择了<code>manjaro-kde-19.0.2-200311-linux54</code>。因为问了大佬,大佬说<code>Xfce</code>对高分屏支持不好,<code>kde</code>和<code>gnome</code>还好一点。而<code>kde</code>的主题我看着还比较清爽,于是就选择了这么一个版本。</p><h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>还是惯例说下我的环境和配置</p><ul><li>已经有的部分<ul><li>系统<ul><li>Windows 10</li></ul></li><li>硬盘<ul><li>C盘SSD,GPT分区格式</li><li>D盘机械硬盘,MBR分区格式</li></ul></li><li>引导<ul><li>UEFI引导</li></ul></li></ul></li><li>要做的部分<ul><li><input disabled="" type="checkbox"> 在Windows下分好区(原因之后会讲)</li><li><input disabled="" type="checkbox"> 做一个启动盘</li></ul></li><li>需要准备的东西<ul><li><input disabled="" type="checkbox"> <a href="https://manjaro.org/download/">官网下载好的镜像</a></li><li><input disabled="" type="checkbox"> 用于烧录镜像的<a href="https://rufus.ie/">rufus</a></li><li><input disabled="" type="checkbox"> 一个用于写入镜像的U盘。(大于等于8g最好)</li><li>可能会需要的东西<br> 有科学上网的需求的话,可以提前准备好Linux中对应的客户端。<br> 在这里我用的是<code>V2Ray</code>,用的是图形化的程序<a href="https://github.com/Qv2ray/Qv2ray">Qv2ray</a>。当然,如果喜欢用V2ray原版的话也可以。安装好Manjaro后可以在官方仓库中进行下载。</li></ul></li></ul><p>前期的准备做好后,就可以开始尝试实操了。</p><h1 id="Windows下的操作"><a href="#Windows下的操作" class="headerlink" title="Windows下的操作"></a>Windows下的操作</h1><p>Windows下主要是要提前进行分区。因为Manjaro自带的分区功能太废柴了,直接报错,分不了。所以我们就在这里提前分好区。下图就是报错的提示<br><img src="https://od.yikakia.com/view/blog/%E7%A1%AC%E7%9B%98%E6%8A%A5%E9%94%99%E7%A4%BA%E6%84%8F.png" alt="硬盘报错示意"></p><h2 id="分区"><a href="#分区" class="headerlink" title="分区"></a>分区</h2><ol><li>打开资源管理器<code>Win+E</code>,点击<code>管理</code></li></ol><p><img src="https://od.yikakia.com/view/blog/%E8%B5%84%E6%BA%90%E7%AE%A1%E7%90%86%E5%99%A8%E7%AE%A1%E7%90%86.png"></p><ol start="2"><li>选择磁盘管理</li></ol><p><img src="https://od.yikakia.com/view/blog/%E9%80%89%E6%8B%A9%E7%A3%81%E7%9B%98%E7%AE%A1%E7%90%86.png"></p><ol start="3"><li>对C盘的最后一个分区右键压缩卷,压缩一个G就好,用于之后挂载<code>/boot</code>分区</li></ol><p><img src="https://od.yikakia.com/view/blog/%E5%8E%8B%E7%BC%A9%E5%8D%B71.png"><br>这里我们可以看到你的C盘的那个磁盘,第二个分区是100MB的,那个就是你的电脑的<code>EFI</code>分区,这个里面储存了这台电脑所有的引导程序。这是GPT格式的硬盘必然有的。这个盘我们用于挂载<code>/boot/efi</code>分区。<br><img src="https://od.yikakia.com/view/blog/%E5%8E%8B%E7%BC%A9%E5%8D%B72.png"></p><ol start="4"><li><p>对D盘的最后一个分区右键压缩卷。看你的需求压缩多少空间,至少压20g吧。具体要求多低你可以自己尝试。这里因为我已经是装好了的,所以不是压缩之后的样子。压缩之后应该是一个黑色的未分区。<br><img src="https://od.yikakia.com/view/blog/%E5%8E%8B%E7%BC%A9%E5%8D%B73.png"><br>在这里我们要分三个区,分别用于挂载<code>/</code>,<code>/home</code>和<code>swap</code>交换分区。</p></li><li><p>对D盘压缩好的未分区进行分区。右键新建简单卷,分配一定的空间用于挂载<code>/</code>目录。这里最好是10g以上,主要是用于存放Linux系统相关的东西,就相当于是Windows下的C盘。所以就按你的需要看分多少。</p></li><li><p>对剩下未分区的部分继续右键,新建简单卷,分配一定的空间用于挂载<code>/home</code>目录。这个就是你的用户文件夹。把这个单独分区了的话,你重装Linux直接重装<code>/</code>所在的那个分区就行了,而你的用户文件还保留着。这里分区的时候大小要注意一下,要预留等同于内存的大小的空间给<code>swap</code>交换分区。</p></li><li><p>对剩下的未分区的部分右键,新建简单卷。这里就可以全部的空间用于新建了。</p></li></ol><h2 id="制作启动盘"><a href="#制作启动盘" class="headerlink" title="制作启动盘"></a>制作启动盘</h2><p>打开rufus,插入U盘,选择你之前下载好的镜像,然后点击开始即可开始烧录。<br>这个时候要注意,新版的rufus是默认用dd模式进行烧录的。而老版的话一定要选择用dd模式进行烧录!总结一下就是,提示你用dd模式烧录的话,就一定要用dd模式进行烧录!<br><img src="https://od.yikakia.com/view/blog/rufus%E9%80%89%E6%8B%A9.png" alt="rufus选择"></p><p><img src="https://od.yikakia.com/view/blog/rufus%E9%80%89%E6%8B%A9%E9%95%9C%E5%83%8F%E5%90%8E%E7%A4%BA%E4%BE%8B.png" alt="rufus选择镜像后示例.png"></p><p><img src="https://od.yikakia.com/view/blog/rufus%E7%82%B9%E5%87%BB%E5%BC%80%E5%A7%8B.png" alt="rufus点击开始.png"></p><p>烧录完成后你的U盘可能会变成这样👇<br><img src="https://od.yikakia.com/view/blog/%E7%83%A7%E5%BD%95%E5%AE%8C%E6%88%90%E7%A4%BA%E6%84%8F.png" alt="烧录完成示意.png"></p><p>不要担心,这是Windows不能识别而已,你的U盘并没有坏。你可以在磁盘管理中看到这一点。<br><img src="https://od.yikakia.com/view/blog/u%E7%9B%98%E7%A3%81%E7%9B%98%E7%AE%A1%E7%90%86.png" alt="u盘磁盘管理.png"></p><p>用完之后你可以用rufus,选择非可引导进行烧录,这样就自动把你的U盘分区找回来了。</p><h1 id="在主板中的操作"><a href="#在主板中的操作" class="headerlink" title="在主板中的操作"></a>在主板中的操作</h1><p>为了安装Manjaro,我们需要</p><ol><li><p>到BIOS中关闭<code>Secure boot</code>。</p></li><li><p>把启动顺序改成从USB启动在从硬盘(harddrive)启动之前。<br>具体的修改位置和方法你可以通过搜索你主板的型号来看。我的微星主板是开机后按<code>Delete</code>键进入BIOS。</p></li></ol><p>当然也可以不进行修改,我的微星主板是开机后按<code>F11</code>选择从哪个引导程序启动。这个也可以通过搜索你的主板的型号来看。</p><h1 id="安装Manjaro"><a href="#安装Manjaro" class="headerlink" title="安装Manjaro"></a>安装Manjaro</h1><p>现在所有准备都准备好了,接下来就是正式开干了。</p><p>现在我们关机,插入我们的U盘,然后开机。从U盘中启动。<br>接下来的步骤我用的是VirtualBox进行演示,因为已经装好了系统了。</p><h2 id="语言选择"><a href="#语言选择" class="headerlink" title="语言选择"></a>语言选择</h2><p><img src="https://od.yikakia.com/view/blog/language%E9%80%89%E6%8B%A9.png" alt="language选择.png"><br><img src="https://od.yikakia.com/view/blog/language%E9%80%89%E6%8B%A92.png" alt="language选择2.png"><br><img src="https://od.yikakia.com/view/blog/language%E9%80%89%E6%8B%A93.png" alt="language选择3.png"></p><h2 id="驱动选择"><a href="#驱动选择" class="headerlink" title="驱动选择"></a>驱动选择</h2><p>这里要说,这里的驱动选择要根据你的实际情况来看。可以参考下面这个表格</p><table><thead><tr><th>CPU</th><th>GPU</th><th>选择</th></tr></thead><tbody><tr><td>Intet</td><td>无独立显卡</td><td>free</td></tr><tr><td>AMD</td><td>无独立显卡</td><td>free</td></tr><tr><td>AMD</td><td>NVIDIA</td><td>no free</td></tr><tr><td>Intet</td><td>AMD</td><td>free</td></tr><tr><td>Intet</td><td>NVIDIA</td><td>no free</td></tr><tr><td><img src="https://od.yikakia.com/view/blog/%E9%A9%B1%E5%8A%A8%E9%80%89%E6%8B%A9.png" alt="驱动选择.png"></td><td></td><td></td></tr></tbody></table><h2 id="时区选择"><a href="#时区选择" class="headerlink" title="时区选择"></a>时区选择</h2><p><img src="https://od.yikakia.com/view/blog/%E6%97%B6%E5%8C%BA%E9%80%89%E6%8B%A9.png" alt="时区选择.png"><br><img src="https://od.yikakia.com/view/blog/%E6%97%B6%E5%8C%BA%E9%80%89%E6%8B%A92.png" alt="时区选择2.png"><br><img src="https://od.yikakia.com/view/blog/%E6%97%B6%E5%8C%BA%E9%80%89%E6%8B%A93.png" alt="时区选择3.png"></p><p>这些都搞定之后,就选择主界面中的<code>Boot: Manjaro.x86_64 kde</code>开始安装吧。</p><h2 id="安装界面开始安装"><a href="#安装界面开始安装" class="headerlink" title="安装界面开始安装"></a>安装界面开始安装</h2><ol><li>在左上角选择语言<br><img src="https://od.yikakia.com/view/blog/%E5%AE%89%E8%A3%85%E7%95%8C%E9%9D%A2%E8%AF%AD%E8%A8%80%E9%80%89%E6%8B%A9.png" alt="安装界面语言选择.png"></li><li>点击启动安装程序,一路下一步到分区<br><img src="https://od.yikakia.com/view/blog/%E5%88%86%E5%8C%BA%E5%BC%80%E5%A7%8B.png" alt="分区开始.png"></li></ol><h2 id="如何分区"><a href="#如何分区" class="headerlink" title="如何分区"></a>如何分区</h2><p>这里我就从网上找图了,因为当时没想着截图。<br>我这里用语言说一下。</p><ol><li>到你的C盘,选择那个100MB的分区,点击它,选择保留,挂载选择挂载<code>/boot/efi</code></li><li>选择那个一个G的空白分区,点击它,选择挂载为<code>/boot</code>分区。</li><li>到你的机械硬盘,选择分好的那三个分区,分别按你之前的选择挂载<code>/</code> <code>/home</code> 和<code>linuxswap</code>分区。</li></ol><p>下面是一些图片示例。</p><p><img src="https://img2020.cnblogs.com/blog/1539665/202003/1539665-20200304160721050-258020564.png" alt="boot/efi"><br><img src="https://img2020.cnblogs.com/blog/1539665/202003/1539665-20200304155717689-599131037.png" alt="boot"><br><img src="https://img2020.cnblogs.com/blog/1539665/202003/1539665-20200304155758720-1352697870.png" alt="root"><br><img src="https://img2020.cnblogs.com/blog/1539665/202003/1539665-20200304155812007-314480847.png" alt="home"><br><img src="https://img2020.cnblogs.com/blog/1539665/202003/1539665-20200304155457688-1847811638.png" alt="swap"></p><p>现在就一路下一步就好了。<br>安装完成后就可以关闭电脑,然后拔出U盘,准备正式进入系统了。</p><p>这个时候可以通过进入Windows后再通过Windows的高级恢复,重启到Boot界面,然后选择从U盘等介质恢复里面选择Manjaro即可。</p><p>当然也可以在开机的时候狂按那个选择是哪个驱动引导的键来选择Manjaro。</p><h2 id="更换国内源"><a href="#更换国内源" class="headerlink" title="更换国内源"></a>更换国内源</h2><p>开机之后,按F12打开终端,输入如下命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo pacman-mirrors -c China -m rank <span class="hljs-comment"># 更改源</span><br></code></pre></td></tr></table></figure><h2 id="安装输入法"><a href="#安装输入法" class="headerlink" title="安装输入法"></a>安装输入法</h2><p>这个可以直接通过软件商城来安装。直接输入<code>fcitx</code>来搜索,选择安装,并且安装可选依赖项。这样就可以用了。</p><h2 id="Manjaro和Windows的时间差了8小时的解决方案"><a href="#Manjaro和Windows的时间差了8小时的解决方案" class="headerlink" title="Manjaro和Windows的时间差了8小时的解决方案"></a>Manjaro和Windows的时间差了8小时的解决方案</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo timedatectl set-local-rtc <span class="hljs-literal">true</span><br></code></pre></td></tr></table></figure><h1 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h1><p>这次踩的坑还行,主要就是被Manjaro自带的弱鸡分区给坑了,其他的都还好,没啥大问题。使用的话挺顺滑的。哦对了,安装好后一定要把所有的软件更新到最新版!</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.bysb.net/3557.html">在Windows基础上安装Manjaro双系统和基本配置 手柄君的小阁</a><br><a href="https://blog.csdn.net/lj402159806/article/details/80218360">manjaro 安装分区以及配置方案</a><br><a href="https://mogeko.me/2019/059/">安装 Manjaro 双系统</a><br><a href="https://www.cnblogs.com/Jaywhen-xiang/p/11561661.html">win10环境下安装manjaro kde(双系统)Jaywhen-xiang</a><br><a href="https://www.biaodianfu.com/windows-manjaro.html">Windows、Manjaro双系统的安装</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Manjaro</tag>
<tag>Windows</tag>
</tags>
</entry>
<entry>
<title>利用docker部署Olaindex</title>
<link href="/%E5%88%A9%E7%94%A8docker%E9%83%A8%E7%BD%B2Olaindex/"/>
<url>/%E5%88%A9%E7%94%A8docker%E9%83%A8%E7%BD%B2Olaindex/</url>
<content type="html"><![CDATA[<p>吹爆<code>docker</code>!</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>利用Aria2和Rclone成功地让我的小鸡实现了远程下载,下载完成后自动上传到OneDrive的功能。想知道的话可以看我的这篇博客<a href=""></a>。</p><p>这个功能搞定后我又想整一个方便直接显示想分享的文件的列表。于是找了找,发现了Oneindex。不过看别人说这个不好用,那就算了吧。于是尝试了Olaindex。</p><p>但是官网要求的php环境我不会搭啊,用了官网介绍的Oneinstack也没有用。在安装的过程中会报错,我怀疑是我的内存不够大造成的。而且报错就算了,报错之后它还把我的环境给搞坏了,导致我想自己手动安装配置 php 环境都失败了。所以只好无奈的回滚了。</p><p>回滚之后我还是不甘心,又突然想到了docker。因为我搜Oneindex的时候找到了Oneindex的docker,又因为经常听说docker是方便部署的,所有的环境需求都被封装了,所以是即开即用。真的这么神奇么?于是我就试了下,没想到真的就有**这 么 神 奇!**。直接从下载安装,配置Nginx的转发就搞定了!</p><h1 id="我的环境"><a href="#我的环境" class="headerlink" title="我的环境"></a>我的环境</h1><ul><li>debian10 </li><li>amd64架构的CPU</li><li>512M内存</li></ul><h1 id="安装docker"><a href="#安装docker" class="headerlink" title="安装docker"></a>安装docker</h1><p>安装过程可以参考我的这篇博客<a href="https://www.yikakia.com/%E5%88%A9%E7%94%A8%E5%AE%98%E6%96%B9%E8%84%9A%E6%9C%AC%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85docker.html">利用官方脚本一键安装 docker</a></p><p>安装过程真的很简单。</p><h1 id="下载docker镜像"><a href="#下载docker镜像" class="headerlink" title="下载docker镜像"></a>下载docker镜像</h1><p>在安装好docker,并且确定正确配置了之后,输入以下命令</p><figure class="highlight bash"><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></pre></td><td class="code"><pre><code class="hljs bash">docker run -d \<br>--name=olaindex \<br>--restart always \<br>-p 8085:80 \<br>-p 8443:443 \<br>--mount <span class="hljs-built_in">type</span>=tmpfs,destination=/tmp \<br>-v /home/hacklog/.config/olaindex/conf:/vol/conf \<br>-v /home/hacklog/.config/olaindex/storage:/vol/storage \<br>-v /home/hacklog/.config/olaindex/ssl:/vol/ssl \<br>-e PHP_TZ=Asia/Shanghai \<br>-e PHP_MAX_EXECUTION_TIME=600 \<br>-e APP_DEBUG=<span class="hljs-literal">false</span> \<br>80x86/olaindex:latest<br></code></pre></td></tr></table></figure><h1 id="配置nginx"><a href="#配置nginx" class="headerlink" title="配置nginx"></a>配置nginx</h1><p>新建一个olaindex.conf文件</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">nano /etc/nginx/conf.d/olaindex.conf<br></code></pre></td></tr></table></figure><p>之后这样配置nginx,我这里默认使用<code>olaindex.yikakia.com</code>作为访问网站Olaindex服务的域名。</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><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></pre></td><td class="code"><pre><code class="hljs conf">server {<br> listen 80;<br> server_name olaindex.yikakia.com; #这里改成你的用于访问olaindex的域名<br><br> #charset koi8-r;<br> access_log /var/log/nginx/rom.nanodm.net.access.log;<br> error_log /var/log/nginx/rom.nanodm.net.error.log;<br><br> location / {<br><br> proxy_set_header Host $host;<br> proxy_set_header X-Real-IP $remote_addr;<br> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br> proxy_set_header X-Forwarded-Proto $scheme;<br> proxy_max_temp_file_size 0;<br><br> #this is the maximum upload size<br> client_max_body_size 100m;<br> client_body_buffer_size 256k;<br><br> proxy_connect_timeout 90;<br> proxy_send_timeout 90;<br> proxy_read_timeout 90;<br> proxy_buffering off;<br> proxy_request_buffering off;<br> proxy_set_header Connection ""; # Clear for keepalive<br><br> proxy_pass http://127.0.0.1:8085;<br> }<br>}<br><br><br>server {<br><br> listen 443;<br> server_name olaindex.yikakia.com; # 这里改成你用于访问Olaindex的域名<br><br> ssl_certificate /etc/nginx/ssl/ssl.crt; #这里写你的ssl证书公钥<br> ssl_certificate_key /etc/nginx/ssl/ssl.key; #这里写你的ssl证书私钥<br><br> ssl on;<br> ssl_session_cache builtin:1000 shared:SSL:10m;<br> ssl_protocols TLSv1.1 TLSv1.2;<br> ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4;<br> ssl_prefer_server_ciphers on;<br><br> access_log /var/log/nginx/rom.nanodm.net_ssl.access.log;<br> error_log /var/log/nginx/rom.nanodm.net_ssl.error.log;<br><br> location / {<br><br> proxy_set_header Host $host;<br> proxy_set_header X-Real-IP $remote_addr;<br> proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br> proxy_set_header X-Forwarded-Proto $scheme;<br> proxy_max_temp_file_size 0;<br><br> #this is the maximum upload size<br> client_max_body_size 100m;<br> client_body_buffer_size 256k;<br><br> proxy_connect_timeout 90;<br> proxy_send_timeout 90;<br> proxy_read_timeout 90;<br> proxy_buffering off;<br> proxy_request_buffering off;<br> proxy_set_header Connection ""; # Clear for keepalive<br><br> proxy_pass https://127.0.0.1:8443;<br> }<br> }<br><br></code></pre></td></tr></table></figure><p>没有ssl证书的话可以参考我的这篇博客 <a href="https://www.yikakia.com/%E5%88%A9%E7%94%A8Let%60s%20Encrypt%E4%B8%BA%E4%BD%A0%E7%9A%84%E7%BD%91%E7%AB%99%E5%8A%A0%E6%8A%8A%E5%B0%8F%E9%94%81.html">利用 Lets Encrypt 为你的网站加把小锁 </a></p><p>现在重启nginx</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">service nginx restart<br></code></pre></td></tr></table></figure><p>再去访问你用于Olaindex的域名就可以了。这里最好专门另外申请一个二级域名。就是类似于这样的:<code>olaindex.yikakia.com</code>。</p><h1 id="配置Olaindex,申请账号"><a href="#配置Olaindex,申请账号" class="headerlink" title="配置Olaindex,申请账号"></a>配置Olaindex,申请账号</h1><h2 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h2><p>做到了这一步,艰难的事情就做完了。<br>现在你可以在浏览器输入<code>olaindex.yikakia.com</code>(替换成你用于访问Olaindex服务的域名)来进行配置。<br>可以直接参考官网这个配置<br><img src="https://i.loli.net/2018/10/27/5bd46f7f160a6.png"><br>在这里这么填写你的域名,把图片上的<code>http://localhost:8000/oauth</code>改成<code>https://olaindex.yikakia.com</code>,就是你自己设定的那个域名。</p><p>然后点击申请。</p><h2 id="获取密钥"><a href="#获取密钥" class="headerlink" title="获取密钥"></a>获取密钥</h2><p>打开一个记事本,把你获取的那个应用机密复制保存好。<br><img src="https://i.loli.net/2018/10/27/5bd47070cd1b0.png"><br>然后点击继续。</p><h2 id="获取id"><a href="#获取id" class="headerlink" title="获取id"></a>获取id</h2><p><img src="https://i.loli.net/2018/10/27/5bd470721f1a3.png"></p><p>把获得的那个client_id也复制到记事本里面。</p><h2 id="保存提交"><a href="#保存提交" class="headerlink" title="保存提交"></a>保存提交</h2><p><img src="https://i.loli.net/2018/10/27/5bd470719602a.png"><br>接下来就把之前获取的那两个输入进去。同时第一个回调地址就是你之前申请的那个。<br>如果没错的话,现在就配置完成了。你可以访问<code>olaindex.yikakia.com/admin</code>进入管理后台,默认的密码是<code>12345678</code>。一定要改!</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://wangningkai.github.io/OLAINDEX/#/">OLAINDEX官方文档</a><br><a href="https://hub.docker.com/r/80x86/olaindex">80x86/olaindex docker镜像提供者</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Docker</tag>
<tag>olaindex</tag>
</tags>
</entry>
<entry>
<title>利用官方脚本一键安装Docker</title>
<link href="/%E5%88%A9%E7%94%A8%E5%AE%98%E6%96%B9%E8%84%9A%E6%9C%AC%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85docker/"/>
<url>/%E5%88%A9%E7%94%A8%E5%AE%98%E6%96%B9%E8%84%9A%E6%9C%AC%E4%B8%80%E9%94%AE%E5%AE%89%E8%A3%85docker/</url>
<content type="html"><![CDATA[<p>我可以简单的理解docker为一个简便的应用封装器么?</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>为了用Olaindex建一个分享网盘,我需要在服务器上配置php环境。我按照Olaindex的教程用Oneinstack安装了,结果是成功的失败了。<br>无奈只能把服务器回滚了。然后我想了想,不是说docker很方便么?于是就去搜了搜,结果还真找到了Olaindex的镜像。于是就安装了docker后试了试,还挺好用的。</p><p>真的是要吹爆docker。把需求的环境都封装了,剩下的就只有简单的配置了,怪不得这么多人用。</p><h1 id="利用官方脚本安装"><a href="#利用官方脚本安装" class="headerlink" title="利用官方脚本安装"></a>利用官方脚本安装</h1><p>还是说一下我的环境</p><ul><li>系统: debian10<br>一键安装真的是方便,导致这个文章的正文看起来没啥。<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">curl -fsSL get.docker.com -o get-docker.sh<br>sudo sh get-docker.sh<br></code></pre></td></tr></table></figure>这样就可以了。这样就安装完成了。<br>安装完成之后验证是否安装成功。</li></ul><h1 id="启动Docker"><a href="#启动Docker" class="headerlink" title="启动Docker"></a>启动Docker</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo systemctl <span class="hljs-built_in">enable</span> docker<br>sudo systemctl start docker<br></code></pre></td></tr></table></figure><h1 id="建立-docker-用户组"><a href="#建立-docker-用户组" class="headerlink" title="建立 docker 用户组"></a>建立 docker 用户组</h1><p>默认情况下,只有 root 用户和 docker 组的用户才可以访问 Docker。出于安全考虑,一般 Linux 系统上不会直接使用 root 用户。因此,更好地做法是将需要使用 docker 的用户加入 docker 用户组。</p><h2 id="建立-docker-组:"><a href="#建立-docker-组:" class="headerlink" title="建立 docker 组:"></a>建立 docker 组:</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo groupadd docker<br></code></pre></td></tr></table></figure><h2 id="将当前用户加入-docker-组:"><a href="#将当前用户加入-docker-组:" class="headerlink" title="将当前用户加入 docker 组:"></a>将当前用户加入 docker 组:</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">sudo usermod -aG docker <span class="hljs-variable">$USER</span><br></code></pre></td></tr></table></figure><p>退出当前终端并重新登录,进行如下测试。</p><h2 id="测试-Docker-是否安装正确"><a href="#测试-Docker-是否安装正确" class="headerlink" title="测试 Docker 是否安装正确"></a>测试 Docker 是否安装正确</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">docker run hello-world<br></code></pre></td></tr></table></figure><figure class="highlight livecodeserver"><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></pre></td><td class="code"><pre><code class="hljs livecodeserver">Unable <span class="hljs-built_in">to</span> find image <span class="hljs-string">'hello-world:latest'</span> locally<br>latest: Pulling <span class="hljs-built_in">from</span> library/hello-world<br>d1725b59e92d: Pull complete<br>Digest: sha256:<span class="hljs-number">0</span>add3ace90ecb4adbf7777e9aacf18357296e799f81cabc9fde470971e499788<br>Status: Downloaded newer image <span class="hljs-keyword">for</span> hello-world:latest<br><br>Hello <span class="hljs-built_in">from</span> Docker!<br>This message shows that your installation appears <span class="hljs-built_in">to</span> be working correctly.<br><br>To generate this message, Docker took <span class="hljs-keyword">the</span> following steps:<br> <span class="hljs-number">1.</span> The Docker client contacted <span class="hljs-keyword">the</span> Docker daemon.<br> <span class="hljs-number">2.</span> The Docker daemon pulled <span class="hljs-keyword">the</span> <span class="hljs-string">"hello-world"</span> image <span class="hljs-built_in">from</span> <span class="hljs-keyword">the</span> Docker Hub.<br> (amd64)<br> <span class="hljs-number">3.</span> The Docker daemon created <span class="hljs-keyword">a</span> <span class="hljs-built_in">new</span> container <span class="hljs-built_in">from</span> that image which runs <span class="hljs-keyword">the</span><br> executable that produces <span class="hljs-keyword">the</span> output you are currently reading.<br> <span class="hljs-number">4.</span> The Docker daemon streamed that output <span class="hljs-built_in">to</span> <span class="hljs-keyword">the</span> Docker client, which sent <span class="hljs-keyword">it</span><br> <span class="hljs-built_in">to</span> your terminal.<br><br>To <span class="hljs-keyword">try</span> something more ambitious, you can run <span class="hljs-keyword">an</span> Ubuntu container <span class="hljs-keyword">with</span>:<br> $ docker run -<span class="hljs-keyword">it</span> ubuntu bash<br><br>Share images, automate workflows, <span class="hljs-keyword">and</span> more <span class="hljs-keyword">with</span> <span class="hljs-keyword">a</span> free Docker ID:<br> <span class="hljs-keyword">https</span>://hub.docker.com/<br><br>For more examples <span class="hljs-keyword">and</span> ideas, visit:<br> <span class="hljs-keyword">https</span>://docs.docker.com/<span class="hljs-built_in">get</span>-started/<br></code></pre></td></tr></table></figure><p>若能正常输出以上信息,则说明安装成功。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://yeasy.gitbooks.io/docker_practice/install/debian.html">Debian 安装 Docker CE</a><br><a href="https://docs.docker.com/engine/install/debian/">Install Docker Engine on Debian</a> (<strong>这个是官网</strong>)</p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Docker</tag>
</tags>
</entry>
<entry>
<title>python虚拟环境的使用</title>
<link href="/python%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E7%9A%84%E4%BD%BF%E7%94%A8/"/>
<url>/python%E8%99%9A%E6%8B%9F%E7%8E%AF%E5%A2%83%E7%9A%84%E4%BD%BF%E7%94%A8/</url>
<content type="html"><![CDATA[<p>为了开发的方便,所以得每个项目都有自己的库</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在开发的时候,有些项目之间的依赖项冲突,有的用的是老版,有的用的是新版。为了解决这问题,最好在开发的时候就针对每一个项目搞一个自己环境,互相之间隔离起来。这样会方便很多。</p><h1 id="创建虚拟环境"><a href="#创建虚拟环境" class="headerlink" title="创建虚拟环境"></a>创建虚拟环境</h1><p>在你喜欢的位置(最好是你的项目的根目录下),输入以下的指令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python -m venv ProjectEnv<br></code></pre></td></tr></table></figure><p>这会新建一个叫<code>ProjectEnv</code>的目录,并且在里面配置好对应版本的Python解释器。如果你需要其他的版本,就用对应的版本来创建,如下便是创建了应用Python3.8的虚拟环境。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python3.8 -m venv ProjectEnv<br></code></pre></td></tr></table></figure><h1 id="激活虚拟环境"><a href="#激活虚拟环境" class="headerlink" title="激活虚拟环境"></a>激活虚拟环境</h1><p>在刚才的目录下,输入以下的指令来激活虚拟环境</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">source</span> ProjectEnv/bin/activate<br></code></pre></td></tr></table></figure><h1 id="退出虚拟环境"><a href="#退出虚拟环境" class="headerlink" title="退出虚拟环境"></a>退出虚拟环境</h1><p>直接输入以下指令就可以退出虚拟环境了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">deactivate<br></code></pre></td></tr></table></figure><h1 id="在虚拟环境中安装包"><a href="#在虚拟环境中安装包" class="headerlink" title="在虚拟环境中安装包"></a>在虚拟环境中安装包</h1><p>和在外面一样,直接用pip就可以了。</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://docs.python.org/zh-cn/3/tutorial/venv.html#virtual-environments-and-packages">12. 虚拟环境和包 ——Python 3.8.2 文档</a></p>]]></content>
<categories>
<category>学习</category>
<category>Python</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Python</tag>
<tag>虚拟环境</tag>
</tags>
</entry>
<entry>
<title>pip的requirements.txt怎么用</title>
<link href="/pip%E7%9A%84requirements-txt%E6%80%8E%E4%B9%88%E7%94%A8/"/>
<url>/pip%E7%9A%84requirements-txt%E6%80%8E%E4%B9%88%E7%94%A8/</url>
<content type="html"><![CDATA[<p>这是我第一个全靠看官方文档搞懂的问题</p><span id="more"></span><h1 id="前言"><a href="#前言" class="headerlink" title="前言"></a>前言</h1><p>在从git上运行一些Python开源项目时,会发现有<code>requirements.txt</code>这样的文件。这个一般都存放着这个项目所需要的依赖项。通过这个文件,我们可以快速的搭建所需要的环境。</p><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><p>其实很简单,到有<code>requirements.txt</code>这个文件的文件夹下,输入以下的指令就可以安装好了</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">pip install -r requirements.txt<br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://pip.pypa.io/en/stable/user_guide/">pip的官方说明书</a></p>]]></content>
<categories>
<category>学习</category>
</categories>
<tags>
<tag>Python</tag>
<tag>pip</tag>
</tags>
</entry>
<entry>
<title>debian10自己编译python3.8</title>
<link href="/debian10%E8%87%AA%E5%B7%B1%E7%BC%96%E8%AF%91python3-8/"/>
<url>/debian10%E8%87%AA%E5%B7%B1%E7%BC%96%E8%AF%91python3-8/</url>
<content type="html"><![CDATA[<p>apt仓库罪大恶极,搞得民众怨声载道。</p><span id="more"></span><h1 id="闲聊"><a href="#闲聊" class="headerlink" title="闲聊"></a>闲聊</h1><p>之所以会要这么干,主要就是因为apt仓库不提供python3.8的源。而我自己利用开源的<a href="https://github.com/simonsmh/telegram-group-easyauth">telegrambot</a>自己搞的一个入群验证Bot发现要求Python版本在3.8以上。所以想了想,还是把这个搞定吧。</p><h1 id="环境"><a href="#环境" class="headerlink" title="环境"></a>环境</h1><p>我的环境是</p><ol><li>系统版本 debian10</li></ol><h1 id="安装编译依赖包"><a href="#安装编译依赖包" class="headerlink" title="安装编译依赖包"></a>安装编译依赖包</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">apt update<br>apt-get install -y build-essential tk-dev libncurses5-dev libncursesw5-dev libreadline6-dev libdb5.3-dev libgdbm-dev libsqlite3-dev libssl-dev libbz2-dev libexpat1-dev liblzma-dev zlib1g-dev libffi-dev tar wget vim<br></code></pre></td></tr></table></figure><h1 id="下载Python3-8源代码"><a href="#下载Python3-8源代码" class="headerlink" title="下载Python3.8源代码"></a>下载Python3.8源代码</h1><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-built_in">mkdir</span> download<br><span class="hljs-built_in">cd</span> download<br>wget https://www.python.org/ftp/python/3.8.2/Python-3.8.2.tgz<br>tar -zxf Python-3.8.0.tgz<br><span class="hljs-built_in">cd</span> Python-3.8.0<br></code></pre></td></tr></table></figure><h1 id="编译并安装Python3-8"><a href="#编译并安装Python3-8" class="headerlink" title="编译并安装Python3.8"></a>编译并安装Python3.8</h1><figure class="highlight bash"><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><code class="hljs bash">./configure --enable-optimizations<br>make -j 4 <span class="hljs-comment">#如果你的系统有8核,可以使用-j 8</span><br>make altinstall<br></code></pre></td></tr></table></figure><p>这里要查看系统核心数量的话,可以参考我的这篇博客<a href="https://www.yikakia.com/linux%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E6%A0%B8%E5%BF%83%E6%95%B0.html">linux 查看系统核心数</a></p><h1 id="确认安装成功"><a href="#确认安装成功" class="headerlink" title="确认安装成功"></a>确认安装成功</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python3.8 --version<br></code></pre></td></tr></table></figure><h1 id="设置Python默认版本"><a href="#设置Python默认版本" class="headerlink" title="设置Python默认版本"></a>设置Python默认版本</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">rm</span> -rf /usr/bin/python<br><span class="hljs-built_in">ln</span> -s /usr/local/bin/python3.8 /usr/bin/python<br></code></pre></td></tr></table></figure><p>现在就可以用</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">python --version<br></code></pre></td></tr></table></figure><p>看看是不是设置好了。<br>之后如果pip出现问题可以看我参考链接的第二个和第三个</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.itgeeker.net/ubuntu-debian-raspbian-install-python3-8-use-source-code-complier/">Ubuntu/Debian/Raspbian源码编译安装Python3.8 及默认版本选择配置</a><br><a href="https://blog.csdn.net/White_Idiot/article/details/78240298">【Python】Ubuntu修改默认Python版本</a><br><a href="https://www.cnblogs.com/phpper/p/10887602.html">Python3 安装pip 提示ModuleNotFoundError: No module named ‘distutils.util’</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>Python</tag>
<tag>编译</tag>
</tags>
</entry>
<entry>
<title>linux查看系统核心数</title>
<link href="/linux%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E6%A0%B8%E5%BF%83%E6%95%B0/"/>
<url>/linux%E6%9F%A5%E7%9C%8B%E7%B3%BB%E7%BB%9F%E6%A0%B8%E5%BF%83%E6%95%B0/</url>
<content type="html"><![CDATA[<p>主要是vps上编译软件的时候需要这个参数。</p><span id="more"></span><h1 id="查看物理CPU个数"><a href="#查看物理CPU个数" class="headerlink" title="查看物理CPU个数"></a>查看物理CPU个数</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cat</span> /proc/cpuinfo| grep <span class="hljs-string">"physical id"</span>| <span class="hljs-built_in">sort</span>| <span class="hljs-built_in">uniq</span>| <span class="hljs-built_in">wc</span> -l<br></code></pre></td></tr></table></figure><h1 id="查看每个物理CPU中core的个数-即核数"><a href="#查看每个物理CPU中core的个数-即核数" class="headerlink" title="查看每个物理CPU中core的个数(即核数)"></a>查看每个物理CPU中core的个数(即核数)</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cat</span> /proc/cpuinfo| grep <span class="hljs-string">"cpu cores"</span>| <span class="hljs-built_in">uniq</span><br></code></pre></td></tr></table></figure><h1 id="查看逻辑CPU的个数"><a href="#查看逻辑CPU的个数" class="headerlink" title="查看逻辑CPU的个数"></a>查看逻辑CPU的个数</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cat</span> /proc/cpuinfo| grep <span class="hljs-string">"processor"</span>| <span class="hljs-built_in">wc</span> -l<br></code></pre></td></tr></table></figure><p>系统的总核数 = 物理CPU个数 * 每颗物理CPU的核数<br>总逻辑CPU数 = 物理CPU个数 * 每颗物理CPU的核数 * 超线程数</p><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.cnblogs.com/emanlee/p/3587571.html">Linux查看物理CPU个数、核数、逻辑CPU个数</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>tmux安装及简单的使用指南</title>
<link href="/tmux%E5%AE%89%E8%A3%85%E5%8F%8A%E7%AE%80%E5%8D%95%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/"/>
<url>/tmux%E5%AE%89%E8%A3%85%E5%8F%8A%E7%AE%80%E5%8D%95%E7%9A%84%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/</url>
<content type="html"><![CDATA[<p>需要后台运行程序时,就可以用到tmux了。</p><span id="more"></span><h1 id="什么是tmux"><a href="#什么是tmux" class="headerlink" title="什么是tmux"></a>什么是tmux</h1><p>简单的说tmux就是终端复用工具。使用的场景是你有希望跑在Linux服务器上的程序,而且这个程序不会因为你退出而结束。</p><h1 id="tmux的安装"><a href="#tmux的安装" class="headerlink" title="tmux的安装"></a>tmux的安装</h1><p>我的环境是debian10,安装的话用下面的语句就行</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">apt install tmux<br></code></pre></td></tr></table></figure><p>这样就安装好了tmux</p><h1 id="tmux的启动与退出"><a href="#tmux的启动与退出" class="headerlink" title="tmux的启动与退出"></a>tmux的启动与退出</h1><h2 id="启动"><a href="#启动" class="headerlink" title="启动"></a>启动</h2><p>在终端输入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">tmux<br></code></pre></td></tr></table></figure><p>即可进入tmux界面。你会进入一个新的界面,下面有一行关于tmux使用的信息。</p><h2 id="退出"><a href="#退出" class="headerlink" title="退出"></a>退出</h2><p>在tmux的界面,按下<code>Ctrl+D</code>或者直接输入<code>exit</code>即可退出tmux。</p><h1 id="tmux查看所有会话"><a href="#tmux查看所有会话" class="headerlink" title="tmux查看所有会话"></a>tmux查看所有会话</h1><p>进入tmux以后,其实就开启了一个新的会话,你可以输入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">tmux <span class="hljs-built_in">ls</span><br></code></pre></td></tr></table></figure><p>来查看正在运行的tmux会话。如果不出意外的话,大概会显示下面这样的结果。</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">0</span>: <span class="hljs-number">1</span> windows (created Wed Apr <span class="hljs-number">8</span> <span class="hljs-number">06</span>:<span class="hljs-number">41</span>:<span class="hljs-number">21</span> <span class="hljs-number">2020</span>)<span class="hljs-meta"> [134x37] (attached)</span><br></code></pre></td></tr></table></figure><p>这里的<code>0</code>就是一个会话的名字,现在也就是当前这个会话的名字。当然也可以更改这个会话的名字。</p><h1 id="tmux更改对应会话的名字"><a href="#tmux更改对应会话的名字" class="headerlink" title="tmux更改对应会话的名字"></a>tmux更改对应会话的名字</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">tmux rename-session -t 0 new-session<br>tmux <span class="hljs-built_in">ls</span><br></code></pre></td></tr></table></figure><p>这样就可以看到如下的结果,把原来叫<code>0</code>的窗口的名字改成了<code>new-session</code></p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">new</span>-session: <span class="hljs-number">1</span> windows (created Wed Apr <span class="hljs-number">8</span> <span class="hljs-number">06</span>:<span class="hljs-number">43</span>:<span class="hljs-number">51</span> <span class="hljs-number">2020</span>)<span class="hljs-meta"> [134x37] (attached)</span><br></code></pre></td></tr></table></figure><h1 id="tmux将当前会话放入后台"><a href="#tmux将当前会话放入后台" class="headerlink" title="tmux将当前会话放入后台"></a>tmux将当前会话放入后台</h1><p>这个操作很简单,先按下<code>Ctrl+B</code>,然后按下<code>D</code>,这样就可以把当前的会话放入后台了。<br>退出来了之后看看那个会话在不在后台运行,可以输入</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">tmux <span class="hljs-built_in">ls</span><br></code></pre></td></tr></table></figure><p>来查看。没有意外的话,会返回类似于这样的信息</p><figure class="highlight apache"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs apache"><span class="hljs-attribute">new</span>-session: <span class="hljs-number">1</span> windows (created Wed Apr <span class="hljs-number">8</span> <span class="hljs-number">06</span>:<span class="hljs-number">43</span>:<span class="hljs-number">51</span> <span class="hljs-number">2020</span>)<span class="hljs-meta"> [134x37]</span><br></code></pre></td></tr></table></figure><p>现在的话你就可以做到退出SSH,而程序依然在后台跑了。</p><h1 id="tmux-attach命令用于重新接入某个已存在的会话。"><a href="#tmux-attach命令用于重新接入某个已存在的会话。" class="headerlink" title="tmux attach命令用于重新接入某个已存在的会话。"></a>tmux attach命令用于重新接入某个已存在的会话。</h1><figure class="highlight bash"><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><code class="hljs bash"><span class="hljs-comment"># 使用会话编号</span><br>tmux attach -t 0<br><br><span class="hljs-comment"># 使用会话名称</span><br>tmux attach -t <session-name><br></code></pre></td></tr></table></figure><h1 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h1><p><a href="https://www.ruanyifeng.com/blog/2019/10/tmux.html">Tmux 使用教程</a><br><a href="https://www.jianshu.com/p/c3e1ed08f029">tmux–后台运行利器</a></p>]]></content>
<categories>
<category>折腾</category>
</categories>
<tags>
<tag>Linux</tag>
</tags>
</entry>
<entry>
<title>vsftp配置</title>
<link href="/vsftp%E9%85%8D%E7%BD%AE/"/>
<url>/vsftp%E9%85%8D%E7%BD%AE/</url>
<content type="html"><![CDATA[<p>主要是想从vps上拖文件下来</p><span id="more"></span><p>我的环境</p><ul><li>debian10</li></ul><h1 id="安装vsftp"><a href="#安装vsftp" class="headerlink" title="安装vsftp"></a>安装vsftp</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">apt install vsftp<br></code></pre></td></tr></table></figure><h1 id="配置vsftp"><a href="#配置vsftp" class="headerlink" title="配置vsftp"></a>配置vsftp</h1><p>输入以下命令</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash"><span class="hljs-built_in">cp</span> /etc/vsftpd.conf /etc/vsftpd.conf.bak <span class="hljs-comment">#备份配置文件</span><br>nano /etc/vsftpd.conf <span class="hljs-comment">#编辑配置文件</span><br></code></pre></td></tr></table></figure><p>按照下面的填法,把对应的项修改了</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><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></pre></td><td class="code"><pre><code class="hljs conf"><br>listen=NO<br><br>listen_ipv6=YES<br><br>anonymous_enable=NO<br><br>#允许本地用户登录(就是你主机上本来的账户)<br>local_enable=YES<br><br>dirmessage_enable=YES<br><br>use_localtime=YES<br><br>xferlog_enable=YES<br><br>connect_from_port_20=YES<br><br>secure_chroot_dir=/var/run/vsftpd/empty<br><br>pam_service_name=vsftpd<br><br>ssl_enable=NO<br><br>#这里表示你的ftp服务器的根目录<br>local_root=/download<br></code></pre></td></tr></table></figure><p>一般来说把我注释的这两项改了就行。</p><p>改完以后保存并退出,然后重启vsftp服务。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">service vsftpd restart<br></code></pre></td></tr></table></figure><p>如果没有报错,那就正常运行了。现在你可以试试登录看。<br>在浏览器这样输入</p><figure class="highlight awk"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs awk">ftp:<span class="hljs-regexp">//</span>你的IP地址<br></code></pre></td></tr></table></figure><p>一般就可以了。登录的账户就是你主机上可以登录的账户,而密码就是你用的那个密码。<br>为了安全起见还是应该开一个虚拟账户,专门用于登录FTP,并且禁止本地用户登录,不过我就偷懒没这么做啦。直接禁止了用密码SSH登录上主机。</p><p>想和我一样直接禁止用密码SSH登陆上主机的话,可以参考我的这篇博客👉<a href="https://www.yikakia.com/%E9%85%8D%E7%BD%AESSH%E5%8F%AA%E8%83%BD%E4%BD%BF%E7%94%A8%E5%AF%86%E9%92%A5%E7%99%BB%E5%BD%95.html">配置 SSH 只能使用密钥登录</a></p>]]></content>
<categories>
<category>建站</category>
</categories>
<tags>
<tag>Linux</tag>
<tag>FTP</tag>