-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
1330 lines (1261 loc) · 120 KB
/
index.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" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>A Technical Blog</title>
<link>https://www.gagua.xyz/</link>
<description>Recent content on A Technical Blog</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<lastBuildDate>Tue, 11 May 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://www.gagua.xyz/index.xml" rel="self" type="application/rss+xml" /><item>
<title>Uvicorn ANSI Color Error In Pycharm Terminal</title>
<link>https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/</link>
<pubDate>Tue, 11 May 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/</guid>
<description><h1 id="origin">Origin</h1>
<p>Recently I&rsquo;m learning <a class="link" href="https://fastapi.tiangolo.com/" target="_blank" rel="noopener"
>FastAPI</a> wanting to develop a JSON API based backend server which using Uvicorn
as ASGI server. Previously I usually used VSCode to writing python script, but this time I&rsquo;d like to build a slightly bigger project
so I turned to <a class="link" href="https://www.jetbrains.com/zh-cn/pycharm/" target="_blank" rel="noopener"
>Pycharm</a> to build FastAPI application.</p>
<h2 id="uvicorn">Uvicorn</h2>
<p><a class="link" href="https://github.com/encode/uvicorn" target="_blank" rel="noopener"
>Uvicorn</a> is a lightning-fast ASGI server implementation, using uvloop and httptools.</p>
<h3 id="error">ERROR</h3>
<p>When I ran FastAPI application with <code>uvicorn.exe sql_app.main:app</code> I got into a weird trouble:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">$ uvicorn.exe sql_app.main:app
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Started server process <span class="o">[</span>?<span class="o">[</span>36m15204?<span class="o">[</span>0m<span class="o">]</span>
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Waiting <span class="k">for</span> application startup.
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Application startup complete.
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Uvicorn running on ?<span class="o">[</span>1mhttp://127.0.0.1:8000?<span class="o">[</span>0m <span class="o">(</span>Press CTRL+C to quit<span class="o">)</span>
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Shutting down
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Waiting <span class="k">for</span> application shutdown.
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Application shutdown complete.
?<span class="o">[</span>32mINFO?<span class="o">[</span>0m: Finished server process <span class="o">[</span>?<span class="o">[</span>36m15204?<span class="o">[</span>0m<span class="o">]</span>
</code></pre></div><p>There are some unexpected code in Uvicorn starting log. Then I opened the same folder with VScode, the
results looks like:</p>
<blockquote>
<p><span style="color: green;">INFO:</span> Started server process [<span style="color: Cyan;">5536</span>]</p>
</blockquote>
<p>It makes me feel puzzled, then searched the Pycharm settings about color and terminal but didn&rsquo;t get any result.</p>
<h3 id="different-shells">Different Shells</h3>
<p>Maybe I chose the wrong shell for Pycharm so that I tested Different Shells. Importantly, I&rsquo;m using Windows platform.</p>
<dl>
<dt><strong>Git-bash.exe</strong>:</dt>
<dd>render colors correctly but need to open a new window</dd>
<dt><strong>bin\bash.exe:</strong></dt>
<dd>render error code in Pycharm terminal</dd>
<dt><strong>PowerShell</strong>:</dt>
<dd>render error code in Pycharm terminal</dd>
</dl>
<p>Now, I&rsquo;m suspicious of Pycharm terminal. So I opened them independently (out of Pycharm) and run Uvicorn command.</p>
<p>bash.exe:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">$ uvicorn.exe sql_app.main:app
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Started server process <span class="o">[[</span>36m15060<span class="o">[</span>0m<span class="o">]</span>
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Waiting <span class="k">for</span> application startup.
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Application startup complete.
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Uvicorn running on <span class="o">[</span>1mhttp://127.0.0.1:8000<span class="o">[</span>0m <span class="o">(</span>Press CTRL+C to quit<span class="o">)</span>
</code></pre></div><p>PowerShell:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">$ uvicorn.exe sql_app.main:app
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Started server process <span class="o">[[</span>36m13668<span class="o">[</span>0m<span class="o">]</span>
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Waiting <span class="k">for</span> application startup.
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Application startup complete.
<span class="o">[</span>32mINFO<span class="o">[</span>0m: Uvicorn running on <span class="o">[</span>1mhttp://127.0.0.1:8000<span class="o">[</span>0m <span class="o">(</span>Press CTRL+C to quit<span class="o">)</span>
</code></pre></div><p><strong>Git-bash.exe</strong> runs without error code however it&rsquo;s just plain text without colors</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">$ uvicorn.exe sql_app.main:app
INFO: Started server process <span class="o">[</span>12864<span class="o">]</span>
INFO: Waiting <span class="k">for</span> application startup.
INFO: Application startup complete.
INFO: Uvicorn running on http://127.0.0.1:8000 <span class="o">(</span>Press CTRL+C to quit<span class="o">)</span>
</code></pre></div><h3 id="uvicorns-issue">Uvicorn&rsquo;s Issue</h3>
<p>After Googled for this kind of strange behavior, I found an <a class="link" href="https://github.com/tiangolo/fastapi/issues/815" target="_blank" rel="noopener"
>issue opened on FastAPI page</a> which is related to <a class="link" href="https://github.com/encode/uvicorn/pull/542" target="_blank" rel="noopener"
>uvicorn&rsquo;s bug</a>.</p>
<p>That bug seems caused by color escaping error on windows, and <em>euri10</em> created a pull request which add <code>click.clear()</code> on <strong>logging.py</strong> to fix the bug. However, this line disappeared at official Uvicorn repository and the package I downloaded. Despite it actually <em>works</em>, I think modify the package hardcode by myself is not an elegant solution.</p>
<h2 id="ansi-escape-code">ANSI Escape Code</h2>
<p>After spending a lot of time searching for that issue, I finally got some clues about it.</p>
<p>ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font styling, and other options on video text terminals and <strong>terminal emulators</strong>.
<code>[32mINFO[0m:</code> is equivalent to <code>\e[32mINFO\e[0m</code> which will display <span style="color: green;">INFO</span> on terminal. <code>\e</code> means <em>escaping</em>, <code>[32m</code> means green foreground and <code>[0m</code> reset the escape color code.</p>
<h3 id="windows-terminalhttpsdocsmicrosoftcomzh-cnwindowsterminalget-started"><a class="link" href="https://docs.microsoft.com/zh-cn/windows/terminal/get-started" target="_blank" rel="noopener"
>Windows Terminal</a></h3>
<p>Installed Windows terminal at Microsoft store, then I tried launching Uvicorn with windows terminal. To my surprise, <strong>both powershell and gitbash</strong> rendered colorful Uvicorn&rsquo;s starting log on terminal.</p>
<p><figure style="flex-grow: 368; flex-basis: 884px">
<a href="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/Gitbash_uvicorn.png" data-size="722x196"><img src="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/Gitbash_uvicorn.png"
srcset="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/Gitbash_uvicorn_hud52419d6d550249d073264309dccc3e4_24068_480x0_resize_box_2.png 480w, https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/Gitbash_uvicorn_hud52419d6d550249d073264309dccc3e4_24068_1024x0_resize_box_2.png 1024w"
width="722"
height="196"
loading="lazy"
alt="run Uvicorn with git-bash.exe on windows terminal ">
</a>
<figcaption>run Uvicorn with git-bash.exe on windows terminal</figcaption>
</figure></p>
<h3 id="strange-behavior">Strange Behavior</h3>
<p>then I tried running <code>echo -e &quot;\e[37;44;3;1mLYL\e[0m&quot;</code> on different terminal with different shell, this code expected white italic &ldquo;LYL&rdquo; text with blue background looks like: <span style="color: white;font-style: italic; background: blue">LYL<span></p>
<p>On windows terminal platform print with correct format:
<figure style="flex-grow: 1174; flex-basis: 2818px">
<a href="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/windows_terminal_gitbash.png" data-size="728x62"><img src="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/windows_terminal_gitbash.png"
srcset="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/windows_terminal_gitbash_hu9b02bfbabace5483a6895d7cdda2c428_3030_480x0_resize_box_2.png 480w, https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/windows_terminal_gitbash_hu9b02bfbabace5483a6895d7cdda2c428_3030_1024x0_resize_box_2.png 1024w"
width="728"
height="62"
loading="lazy"
alt="render escape code on windows terminal">
</a>
<figcaption>render escape code on windows terminal</figcaption>
</figure></p>
<p>but bash.exe can&rsquo;t render italic text:
<figure style="flex-grow: 736; flex-basis: 1768px">
<a href="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/bash_alone.png" data-size="339x46"><img src="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/bash_alone.png"
srcset="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/bash_alone_hubcf7dd4b31479c27d9b3b276f3467630_1133_480x0_resize_box_2.png 480w, https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/bash_alone_hubcf7dd4b31479c27d9b3b276f3467630_1133_1024x0_resize_box_2.png 1024w"
width="339"
height="46"
loading="lazy"
alt="bash.exe alone">
</a>
<figcaption>bash.exe alone</figcaption>
</figure></p>
<p>git-bash.exe have completely correct format, and run with <code>--use-colors</code> parameter has colorful log output:
<figure style="flex-grow: 362; flex-basis: 870px">
<a href="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/git-bash-use-color.png" data-size="526x145"><img src="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/git-bash-use-color.png"
srcset="https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/git-bash-use-color_hu07c94afd42171bde551223936c7feafa_12147_480x0_resize_box_2.png 480w, https://www.gagua.xyz/p/uvicorn-ansi-color-error-in-pycharm-terminal/images/git-bash-use-color_hu07c94afd42171bde551223936c7feafa_12147_1024x0_resize_box_2.png 1024w"
width="526"
height="145"
loading="lazy"
alt="git-bash with parameter">
</a>
<figcaption>git-bash with parameter</figcaption>
</figure></p>
<p>And I tried setting Pycharm terminal&rsquo;s shell as <em>git-bash.exe</em> which will have wonderful formatted log, with only one drawback: a seperate window.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Different terminals or terminal emulators have different behaviors, that makes me frustrating, I finally couldn&rsquo;t find a perfect solution about this problem.</p>
<p><a class="link" href="https://www.jetbrains.com/help/pycharm/terminal-emulator.html" target="_blank" rel="noopener"
>Pycharm integrated terminal </a> as an embedded terminal emulator, it has it&rsquo;s own exclusive manifestation. As a non-ANSI-aware terminal it has intrinsic flaw. VsCode might be a better solution?</p>
</description>
</item>
<item>
<title>Axios With Typescript</title>
<link>https://www.gagua.xyz/p/axios-with-typescript/</link>
<pubDate>Sat, 17 Apr 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/axios-with-typescript/</guid>
<description><h1 id="refactor-with-typescript">Refactor With Typescript</h1>
<p>最近跟着b站上的视频用vue构建了一个移动版的商城项目,算是初步了解了vue全家桶的用法。不过这个项目是用javascript写的,所以就想用typescript重构,也算是一次项目实践,不用写ui只用写逻辑应该比较轻松。</p>
<h2 id="typescripthttpswwwtypescriptlangorg"><a class="link" href="https://www.typescriptlang.org/" target="_blank" rel="noopener"
>Typescript</a></h2>
<p>javascript由于某些历史原因,设计上存在着一些糟粕,并且作为弱类型语言常常由于隐式的类型转换而产生一些运行时的bug,在编写过程中难以发觉,错误发生后也难以定位(debug)。没有类型系统的话,对于编辑器来说也不够友好,跳转和定义并不方便。因此微软开发了typescript,完全兼容javascript,没有限定运行时,完全开源,可以将其当作带有类型系统的js。最妙的是ts和js并非是二元对立的选择,而是渐进式的。</p>
<h2 id="axioshttpsgithubcomaxiosaxios"><a class="link" href="https://github.com/axios/axios" target="_blank" rel="noopener"
>Axios</a></h2>
<p>Axios是一个http请求库,是<abbr title="xmlHttpRequest">XHR</abbr>的Promise实现,将其封装后用于网络请求。</p>
<h3 id="axiosresponse">AxiosResponse</h3>
<p>尽管TS已经有官方类型,但是在用TS重构项目时还是发生了问题,
主要在于封装过程中采用响应拦截器封装request请求,使得直接返回了<code>res=&gt;res.data</code>,而在使用封装完毕的请求方法时,</p>
<pre><code class="language-{typescript}" data-lang="{typescript}">Promise().then(res:AxiosResponse&lt;data&gt; =&gt; {
res.filed
})
</code></pre><p>会发现TS报错字段<code>filed</code>不存在,这是因为<em>AxiosResponse</em>的类型定义中并不存在这个字段,而必须在<em>data</em>字段中寻找。而如果采用另外的一种方式,即:</p>
<pre><code class="language-{typescript}" data-lang="{typescript}">Promise().then(res:AxiosResponse&lt;data&gt; =&gt; {
res.data.filed
})
</code></pre><p>却会发现尽管字段不报错,但是TS报错<code>AxiosResponse&lt;data&gt;无法赋值给AxiosResponse&lt;any&gt;</code>。
google搜索后找到了Axios官方库中的一个<a class="link" href="https://github.com/axios/axios/issues/1510" target="_blank" rel="noopener"
>issue</a>,不过个人能力有限,就算看完了这个也没想到什么好的解决方法。因为AxiosResponse的<strong>data</strong>字段本身没有给出特定的接口,而是采用泛型来实现,想在函数调用之前就设定接口,但是这样修改的也只是AxiosPromise,似乎无法在根本上解决问题。</p>
<h3 id="discard-interceptor">Discard interceptor</h3>
<p>最后我决定妥协,即放弃在拦截器中采用<code>res=&gt;res.data</code>的方式,而在调用获取数据后额外加上data字段。虽然麻烦了一点点但是毕竟问题解决了。
仔细一想,其实封装时在拦截器直接返回data似乎并不是一个良好的方式,毕竟返回数据其实还有config,header等重要的元数据信息,如果贸然把这些数据丢弃,对于类型安全并不可靠,也不利于之后功能的扩展。</p>
</description>
</item>
<item>
<title>Vue Router:The Front-End Routing </title>
<link>https://www.gagua.xyz/p/vue-routerthe-front-end-routing/</link>
<pubDate>Fri, 12 Mar 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/vue-routerthe-front-end-routing/</guid>
<description><h1 id="router">Router</h1>
<p>最近在学习<a class="link" href="https://v3.vuejs.org/" target="_blank" rel="noopener"
>Vue</a>这个前端框架<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>,看到Routing这一节时觉得很费解,不明白为什么要弄一套Vue router库。</p>
<p>我认为所谓<strong>路由</strong>,应该就是指URL跳转到对应的页面的一个映射方法。</p>
<h2 id="nginx">Nginx</h2>
<p>在nginx中可以通过配置文件来进行路由设定:</p>
<pre><code>location /path/ {
root xxx;
index xxx.html;
}
</code></pre><p>通过正则匹配来进行路由映射。</p>
<p>既然已经有现成的路由方法了,为什么前端框架还是要自己弄一套新的路由方法呢?</p>
<h2 id="front-end-routing">Front-End Routing</h2>
<p>查阅之后,发现有前端和后端路由的区别,<strong>博客园</strong>上的一篇<a class="link" href="https://www.cnblogs.com/songyao666/p/11470030.html" target="_blank" rel="noopener"
>文章</a>
让我对此稍微有了一点了解。</p>
<p>总而言之,后端路由需要绑定methods,并且随着页面变得复杂,代码耦合性强,难以维护。前端路由应时而出,解决了页面切换白屏和可复用等问题,不过也使得SEO困难。</p>
<p>通过js渲染界面:</p>
<pre><code class="language-{html}" data-lang="{html}">&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Vue&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;div id=&quot;app&quot;&gt;&lt;/div&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;xxxx.xxx.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;yyyy.yyy.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot; src=&quot;zzzz.zzz.js&quot;&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre><p>前端路由有两种方式:</p>
<ol>
<li>Hash模式</li>
<li>History模式</li>
</ol>
<p>Hash模式利用的是浏览器不会对#号后面的路径对服务端发起路由请求,
而History模式利用的是HTML5的History API,所以不能兼容低版本IE。</p>
<h2 id="写在最后">写在最后</h2>
<p>从业经历不足半年在这还真是吃亏,古人说,以史为鉴可以知兴替。没有切身体会过前端的<em>古早</em>时代的我,难以理解一些新的概念。曾经的我<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>无法理解为什么要弄出Composition API,为什么会有IE的兼容问题,为什么要做状态管理,为什么要做前端路由。在ES6之前连模块导入这种概念都没有的Javascript是怎么成为浏览器运行时的事实标准的。</p>
<p>不过这个又回到了一个有点接近哲学的问题,没有亲身体验过,人能了解事物的本质吗?如果说只有实践才能出真知,那么,实践的方法到底有哪些?实践的风险与收益如何平衡?人的有穷和事物的无穷,又该如何选择?</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>或者说Javascript库。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>也许现在我也只是以为我懂了。 <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
</description>
</item>
<item>
<title>Fastx-Toolkit Install</title>
<link>https://www.gagua.xyz/p/fastx-toolkit-install/</link>
<pubDate>Tue, 09 Mar 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/fastx-toolkit-install/</guid>
<description><h1 id="fastx-toolkit">FASTX-Toolkit</h1>
<p>记录一下<a class="link" href="http://hannonlab.cshl.edu/fastx_toolkit/download.html" target="_blank" rel="noopener"
>FASTX-Toolkit</a> 安装时遇到的坑。作为一款FASTQ/A短reads预处理软件,它也算是有些年头了,所以在现在的安装环境下难免会存在一些问题,这里就把遇到的这些问题记录下来,以示后人。</p>
<h2 id="install-libgtextutils">install libgtextutils</h2>
<p>这是一款用C和C++编写的软件,所以安装流程中可以选择通过源码安装,也可以选择通过预编译的二进制包安装。可以在<a class="link" href="http://hannonlab.cshl.edu/fastx_toolkit/download.html" target="_blank" rel="noopener"
>冷泉港hannonlab实验室</a>的官网上找到,不过预编译的二进制包只存在0.0.13的旧版本,所以这里选择通过源码安装。</p>
<p>值得注意的是,FASTX-Toolkit<strong>依赖</strong>于libgtextutils,所以选择先安装libgtextutils。解压后查看<strong>README</strong>文件,然后转到<strong>INSTALL</strong>文件查看安装方法,不过通常来说,C系列的软件安装都是三步走,即:</p>
<ol>
<li><code>./configure</code></li>
<li><code>make</code></li>
<li><code>make install</code></li>
</ol>
<p>对于有些软件来说可能略有不同,比如需要加上<code>make test</code>检验安装是否完成,对于使用Cmake安装的,等以后有空再来研究吧。这里有个问题就是这种方法安装的软件怎么卸载呢?直接把安装文件夹给删了,总觉的很简单粗暴,但是也没见到有<code>make uninstall</code>这个指令呀。</p>
<h3 id="prefix">Prefix</h3>
<p>这里就很奇怪了,明明INSTALL文件夹里提到了默认文件夹可以用以上三个步骤,但我重复之后会发现奇奇怪怪的Bug,显示安装已经完成但是却找不到<em>libgtextutils</em>这个依赖项。后面才发现,手动指定文件夹路径就不会有问题了。<code>./configure --prefix=/PATH/TO/INSTALL</code>,值得注意的是,这里的路径要采用绝对路径,不能用<code>~</code>指代根目录,说实话让人觉得非常不习惯。</p>
<h3 id="heading"></h3>
<p>在<strong>make</strong>步骤中,会发生一些麻烦,比如说</p>
<pre><code>text_line_reader.cpp
...
return input_stream() ;
</code></pre><p>这个是由于GCC版本导致的问题,如果大于4.8.5就会报错</p>
<pre><code>gcc --version
x86_64-conda-linux-gnu-gcc (crosstool-NG 1.24.0.133_b0863d8_dirty) 7.5.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
</code></pre><p>可以考虑降低GCC版本到要求或者修改<code>text_line_reader.cpp</code>文件</p>
<pre><code>return input_stream.good() ;
</code></pre><h2 id="install-fastx-toolkit">install FASTX-Toolkit</h2>
<p>安装完成后用同样的方法尝试安装FASTX-Toolkit,这时会在第一步生成配置文件时就发现问题,不过这个很容易解决,按照错误提示:</p>
<pre><code>vi ~/.bashrc
export PKG_CONFIG_PATH=/PATH/TO/INSTALL/lib/pkgconfig
source ~/.bashrc
</code></pre><p>出现这种问题的原因是,找不到包的依赖路径,不过这个我很不理解为什么安装的时候不会自动添加进环境变量。手动配置总感觉很麻烦。</p>
<p>继续安装,这时候又会在make阶段发生问题</p>
<pre><code>fasta_formatter.cpp: In function 'void parse_command_line(int, char**)':
fasta_formatter.cpp:105:9: error: this statement may fall through [-Werror=implicit-fallthrough=]
usage();
~~~~~^~
fasta_formatter.cpp:107:3: note: here
case 'i':
^~~~
cc1plus: all warnings being treated as errors
make[3]: *** [Makefile:425: fasta_formatter.o] Error 1
make[3]: Leaving directory '/home/wangy/fastx_toolkit-0.0.14/src/fasta_formatter'
make[2]: *** [Makefile:373: all-recursive] Error 1
make[2]: Leaving directory '/home/wangy/fastx_toolkit-0.0.14/src'
make[1]: *** [Makefile:411: all-recursive] Error 1
make[1]: Leaving directory '/home/wangy/fastx_toolkit-0.0.14'
make: *** [Makefile:342: all] Error 2
</code></pre><p>这个报错甚至可以在github中的一个<a class="link" href="https://github.com/agordon/fastx_toolkit/issues/21" target="_blank" rel="noopener"
>issue</a>中看到。解决方法也很简单:</p>
<pre><code>cd /fastx_toolkit-0.0.14/src/fasta_formatter
vi fasta_formatter.cpp
switch(opt) {
case 'h':
usage();
exit(0);//添加一行
</code></pre><p>看起来这个步骤是提供命令行中<code>-h</code>的帮助提示,不过需要添加<code>exit(0)</code>返回,可能是bug又或是就版本的C支持这种语句?不懂。</p>
<h3 id="path">PATH</h3>
<p>最后,为了使用方便,最好还是把安装目录下的bin文件夹添加到$PATH环境变量</p>
<pre><code>export PATH=/PATH/TO/INSTALL/fastx_toolkit-0.0.14/bin
</code></pre><p>可以愉快的使用啦!</p>
</description>
</item>
<item>
<title>Methods for Checking Source Code of R Functions</title>
<link>https://www.gagua.xyz/p/methods-for-checking-source-code-of-r-functions/</link>
<pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/methods-for-checking-source-code-of-r-functions/</guid>
<description>
<div id="r-functions-source-code" class="section level1">
<h1>R function’s source code</h1>
<p>Recently, I found some problems programming with R, and I habitually pressed <kbd>F1</kbd> for document. However, this document can’t figure out these problems. So I finally decided to check the source code of these functions. To be honest, it’s a little bit struggle for me to find source code since some R functions were written by C. Besides, the object oriented programming such as S3 generics make things weird.</p>
<p>Thanks for some answers on <a href="https://www.zhihu.com/question/24586822">Zhihu platform</a>, these problems have been solved already.</p>
<div id="print-funtions-name-immediately" class="section level2">
<h2>print funtion’s name immediately</h2>
<pre class="r"><code>rank</code></pre>
<pre><code>## function (x, na.last = TRUE, ties.method = c(&quot;average&quot;, &quot;first&quot;,
## &quot;last&quot;, &quot;random&quot;, &quot;max&quot;, &quot;min&quot;))
## {
## nas &lt;- is.na(x)
## nm &lt;- names(x)
## ties.method &lt;- match.arg(ties.method)
## if (is.factor(x))
## x &lt;- as.integer(x)
## x &lt;- x[!nas]
## y &lt;- switch(ties.method, average = , min = , max = .Internal(rank(x,
## length(x), ties.method)), first = sort.list(sort.list(x)),
## last = sort.list(rev.default(sort.list(x, decreasing = TRUE))),
## random = sort.list(order(x, stats::runif(sum(!nas)))))
## if (!is.na(na.last) &amp;&amp; any(nas)) {
## yy &lt;- NA
## NAkeep &lt;- (na.last == &quot;keep&quot;)
## if (NAkeep || na.last) {
## yy[!nas] &lt;- y
## if (!NAkeep)
## yy[nas] &lt;- (length(y) + 1L):length(yy)
## }
## else {
## len &lt;- sum(nas)
## yy[!nas] &lt;- y + len
## yy[nas] &lt;- seq_len(len)
## }
## y &lt;- yy
## names(y) &lt;- nm
## }
## else names(y) &lt;- nm[!nas]
## y
## }
## &lt;bytecode: 0x00000000138d6818&gt;
## &lt;environment: namespace:base&gt;</code></pre>
</div>
<div id="call-edit" class="section level2">
<h2>call edit()</h2>
<pre class="r"><code>edit(rank)</code></pre>
<pre><code>## function (x, na.last = TRUE, ties.method = c(&quot;average&quot;, &quot;first&quot;,
## &quot;last&quot;, &quot;random&quot;, &quot;max&quot;, &quot;min&quot;))
## {
## nas &lt;- is.na(x)
## nm &lt;- names(x)
## ties.method &lt;- match.arg(ties.method)
## if (is.factor(x))
## x &lt;- as.integer(x)
## x &lt;- x[!nas]
## y &lt;- switch(ties.method, average = , min = , max = .Internal(rank(x,
## length(x), ties.method)), first = sort.list(sort.list(x)),
## last = sort.list(rev.default(sort.list(x, decreasing = TRUE))),
## random = sort.list(order(x, stats::runif(sum(!nas)))))
## if (!is.na(na.last) &amp;&amp; any(nas)) {
## yy &lt;- NA
## NAkeep &lt;- (na.last == &quot;keep&quot;)
## if (NAkeep || na.last) {
## yy[!nas] &lt;- y
## if (!NAkeep)
## yy[nas] &lt;- (length(y) + 1L):length(yy)
## }
## else {
## len &lt;- sum(nas)
## yy[!nas] &lt;- y + len
## yy[nas] &lt;- seq_len(len)
## }
## y &lt;- yy
## names(y) &lt;- nm
## }
## else names(y) &lt;- nm[!nas]
## y
## }
## &lt;environment: namespace:base&gt;</code></pre>
</div>
<div id="call-page" class="section level2">
<h2>call page()</h2>
<p>It’s similar to ‘edit()’ but open on a new page</p>
<pre class="r"><code>page(rank)</code></pre>
</div>
<div id="methods" class="section level2">
<h2>Methods()</h2>
<p>For some functions, approaches above will not work.</p>
<pre class="r"><code>mean</code></pre>
<pre><code>## function (x, ...)
## UseMethod(&quot;mean&quot;)
## &lt;bytecode: 0x0000000015b73ce8&gt;
## &lt;environment: namespace:base&gt;</code></pre>
<p>Obviously, <code>mean</code> function behave as a <strong>class</strong> like other programming languages. It will call different methods depend on the type of it’s parameters. So that we need call <code>methods()</code> for specific object.</p>
<pre class="r"><code>methods(mean)</code></pre>
<pre><code>## [1] mean.Date mean.default mean.difftime mean.POSIXct mean.POSIXlt
## [6] mean.quosure*
## see &#39;?methods&#39; for accessing help and source code</code></pre>
<pre class="r"><code>mean.default</code></pre>
<pre><code>## function (x, trim = 0, na.rm = FALSE, ...)
## {
## if (!is.numeric(x) &amp;&amp; !is.complex(x) &amp;&amp; !is.logical(x)) {
## warning(&quot;argument is not numeric or logical: returning NA&quot;)
## return(NA_real_)
## }
## if (na.rm)
## x &lt;- x[!is.na(x)]
## if (!is.numeric(trim) || length(trim) != 1L)
## stop(&quot;&#39;trim&#39; must be numeric of length one&quot;)
## n &lt;- length(x)
## if (trim &gt; 0 &amp;&amp; n) {
## if (is.complex(x))
## stop(&quot;trimmed means are not defined for complex data&quot;)
## if (anyNA(x))
## return(NA_real_)
## if (trim &gt;= 0.5)
## return(stats::median(x, na.rm = FALSE))
## lo &lt;- floor(n * trim) + 1
## hi &lt;- n + 1 - lo
## x &lt;- sort.int(x, partial = unique(c(lo, hi)))[lo:hi]
## }
## .Internal(mean(x))
## }
## &lt;bytecode: 0x0000000015304888&gt;
## &lt;environment: namespace:base&gt;</code></pre>
</div>
<div id="getanywhere" class="section level2">
<h2>getAnywhere</h2>
<p>Sometimes there is function with asterisk, which can’t be looking for with <code>methods()</code> because it’s written by C lang.</p>
<pre class="r"><code>methods(mean)</code></pre>
<pre><code>## [1] mean.Date mean.default mean.difftime mean.POSIXct mean.POSIXlt
## [6] mean.quosure*
## see &#39;?methods&#39; for accessing help and source code</code></pre>
<pre class="r"><code>try(methods(mean.quosure))</code></pre>
<pre><code>## Error in methods(mean.quosure) : object &#39;mean.quosure&#39; not found</code></pre>
<p><code>getAnywhere</code> is needed.</p>
<pre class="r"><code>getAnywhere(mean.quosure)</code></pre>
<pre><code>## A single object matching &#39;mean.quosure&#39; was found
## It was found in the following places
## registered S3 method for mean from namespace rlang
## namespace:rlang
## with value
##
## function (x, na.rm = TRUE, ...)
## {
## abort_quosure_op(&quot;Summary&quot;, &quot;mean&quot;)
## }
## &lt;bytecode: 0x0000000013251bc0&gt;
## &lt;environment: namespace:rlang&gt;</code></pre>
</div>
<div id="cran" class="section level2">
<h2>CRAN</h2>
<p>comprehensive R archive network: <a href="https://cran.r-project.org/">CRAN</a></p>
<p>choose <em>packages</em> on the left side and download packages including such function, and source code is available.</p>
</div>
</div>
</description>
</item>
<item>
<title>Google Analytics And SEO</title>
<link>https://www.gagua.xyz/p/google-analytics-and-seo/</link>
<pubDate>Fri, 05 Feb 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/google-analytics-and-seo/</guid>
<description><h1 id="google-analytics">Google Analytics</h1>
<p>Followed <a class="link" href="https://gohugo.io/templates/internal#google-analytics" target="_blank" rel="noopener"
>Hugo documents</a>, I&rsquo;d like to implement some extra features on my blog site such as <abbr title="google analytics">GA</abbr>. Here are description about GA:</p>
<blockquote>
<p>Google Analytics lets you measure your advertising ROI as well as track your Flash, video, and social networking sites and applications.</p>
</blockquote>
<h2 id="registration">Registration</h2>
<p>Google for Google Analytics,<a class="link" href="https://analytics.google.com/" target="_blank" rel="noopener"
>login in</a> using personal google account<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>. Add an user then create an application of website, it would generate a tracking id after choose <strong>data stream</strong>. GA also provide some javascript code adding below the <code>&lt;head&gt;</code> tag of website exactly to achieve analytics. It sounds terrible to add js code on each page of a website, fortunately, Hugo provide an internal template for GA. What I need to do is only to add a <code>{{ template &quot;_internal/google_analytics_async.html&quot; . }}</code> shortcode at custom head file and provide tracking id in configuration file. Remarkably, I choose a asynchronous version, which might have a better performance, at least I hope so.</p>
<h2 id="analytics">Analytics</h2>
<p>It looks like GA has been an integrated marketing platform, however, I gravitate toward feature of visitor statistics such as visitors' numbers<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup> and locations.</p>
<p>example: <figure style="flex-grow: 215; flex-basis: 516px">
<a href="https://www.gagua.xyz/p/google-analytics-and-seo/images/google_analytic.png" data-size="1901x884"><img src="https://www.gagua.xyz/p/google-analytics-and-seo/images/google_analytic.png"
srcset="https://www.gagua.xyz/p/google-analytics-and-seo/images/google_analytic_hue8f6761bdddb8db483171fc90720aa7c_526020_480x0_resize_box_2.png 480w, https://www.gagua.xyz/p/google-analytics-and-seo/images/google_analytic_hue8f6761bdddb8db483171fc90720aa7c_526020_1024x0_resize_box_2.png 1024w"
width="1901"
height="884"
loading="lazy"
alt="google analytic map">
</a>
<figcaption>google analytic map</figcaption>
</figure></p>
<h1 id="seo">SEO</h1>
<p>During learning website technology, I gradually recognized the importance of <abbr title="search engine optimalization">SEO</abbr>. Hugo or theme provides a default <code>sitemap.xml</code> file. In principle, search engines like <em>Google</em> behave like a spider but it won&rsquo;t go inside a deep hierarchy. Sitemap create a more flatten structure of the whole website consequently a better SEO performance.</p>
<h2 id="google-search-console">Google Search Console</h2>
<p><a class="link" href="https://developers.google.com/search" target="_blank" rel="noopener"
>Google Search Console</a>:</p>
<blockquote>
<p>Google Search Central, formerly Google Webmasters, is here to help the right people view your content with resources to make your website discoverable to Google Search.</p>
</blockquote>
<p>It&rsquo;s easy to verify website ownership using method <strong>Google Analytics</strong> on that page. Next, log in <strong>Google Search Console</strong>, after validate web information it will generate a txt token. Switching to DNS provider, add a <strong>txt</strong> type DNS record whose value must be the token above. Besides, server name can be <code>@</code>, might other names are also valid?</p>
<p>In site map index, sitemap can be provided by an URL, of course the sitemap.xml path for my site.</p>
<h1 id="words-in-the-end">Words in the End</h1>
<p>In fact, as a personal tech blog, SEO seems not indispensable, maybe I&rsquo;m so idle at home?</p>
<p>next plan:</p>
<ul>
<li><input disabled="" type="checkbox"> baidu SEO</li>
<li><input disabled="" type="checkbox"> indexes catalog</li>
<li><input disabled="" type="checkbox"> words statistic</li>
</ul>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p>thats what called <em>ecology</em>? <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>a sadly news, it seems no one browse this website except myself. <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
</description>
</item>
<item>
<title>甘雨:梦里韶光</title>
<link>https://www.gagua.xyz/p/index.zh-cn/</link>
<pubDate>Fri, 22 Jan 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/index.zh-cn/</guid>
<description>
<div style="position: relative; width: 100%; height: 0; padding-bottom: 56.25%;">
<iframe src="//player.bilibili.com/player.html?as_wide=1&amp;high_quality=1&amp;page=1&bvid=BV1xT4y1N7Wn"
scrolling="no"
frameborder="no"
framespacing="0"
allowfullscreen="true"
style="position: absolute; width: 100%; height: 100%; left: 0; top: 0;"
>
</iframe>
</div>
<h2 id="可圈可点">可圈可点</h2>
<p><a class="link" href="https://ys.mihoyo.com/" target="_blank" rel="noopener"
>原神</a>,本来以为开放世界探索和氪金抽卡内核的冲突会导致游戏体验撕裂,结果成绩居然意料之外的不错。不过也没办法,毕竟原神作为一款手游可以说对其他游戏是降维打击。因为时间的缘故没法继续玩原神,不过消息还是一直在关注。新角色甘雨的PV实在是太完美了,<a class="link" href="https://www.mihayo.com/" target="_blank" rel="noopener"
>miHoYo</a>不只是美工,连音乐也是神啊!BGM是璃月战斗曲的变奏,与PV画面可以说相当的契合,急促轻缓的节奏变化非常吸引人,不懂如何用专业术语评价,总之就是好听就完事了!<del>甘雨老婆!</del></p>
</description>
</item>
<item>
<title>Integrated R Workflow</title>
<link>https://www.gagua.xyz/p/integrated-r-workflow/</link>
<pubDate>Tue, 19 Jan 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/integrated-r-workflow/</guid>
<description><h2 id="shiny">Shiny</h2>
<p>最近导师觉得找我要图太麻烦了,就让我弄一个网页版的工具来进行可视化。虽然这事之前确实没做过,不过对Shiny还算有所耳闻,初步想了一下,感觉不算什么太难的事情,就答应了<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>。</p>
<p><a class="link" href="https://shiny.rstudio.com/" target="_blank" rel="noopener"
>Shiny</a>也算是Rstudio强推的一个通过R构建交互式网页的工具,不得不感慨一下Rstudio为R的社区生态做出的卓越贡献。Shiny教学看起来还挺完善的,视频版的教学据说内容更丰富,不过说实话这连个自动字幕都没有,就纯练英语听力,实在是太为难我了,果断选择<em>Written</em>版。初学者的教学就7章,花了大概两个小时看完了,顺便跟着做了点练习,教学只提炼出了最基础的部分,不过也覆盖了生成一个完整的网页APP需要的部分,循序渐进好上手,有R的基础整这个还是挺方便的。</p>
<h3 id="deploy">Deploy</h3>
<p>本来想放在自己的服务器的,不过想到我服务器可怜的体量,还是别再开一个web server了。而且,<a class="link" href="https://www.shinyapps.io/" target="_blank" rel="noopener"
>shinyapps</a>可以再Rstudio IDE中自动推送啥的,还不用再去github上整个仓库,感觉自家的工具链是真的爽,难怪有这么多人喜欢用苹果,用的不是手机,而是生态啊。</p>
<p><a class="link" href="https://gagua.shinyapps.io/circadian/" target="_blank" rel="noopener"
>my Shiny app</a>不过感觉在用户体验方面还是有点点小问题,初次打开太慢了,这个也确实没办法,毕竟shiny启动需要加载一堆R包,还得加载数据,而且感觉这种网页不方便进行<abbr title="content distribution network">CDN</abbr>。麻烦的在于,免费版的shinyapp服务每个月只有25小时的活跃(active)时间,也就是,当一段时间无人访问时,服务器会自动进入休眠状态,那再打开网页,就又相当于一次服务重启,相当耗时。如果有思路却要等网页加载,总感觉有点耽误科研效率,嘛,反正我也有本地数据,如果实在觉得性能不行,那就去申请经费整个会员吧。</p>
<h2 id="r-workflow">R workflow</h2>
<p>想想最近的分析工作,大概就是:</p>
<ol>
<li>数据挖掘<sup id="fnref:2"><a href="#fn:2" class="footnote-ref" role="doc-noteref">2</a></sup>
在linux服务器上完成对性能需求较大的mapping, counting等步骤。这步通过基于python编写的<a class="link" href="https://snakemake.readthedocs.io/en/stable/" target="_blank" rel="noopener"
>snakemake</a>完成了流程大体上的自动化。以后最好加个multiqc完成质量控制的可视化。</li>
<li>可视化。在本地服务器上利用R完成数据挖掘和可视化,Rstudio是真的好用,就是字体有点难受,不好区分大小写,视觉上感觉还是更喜欢vscode。之前一直是用Rscript完成分析,这次换成是Rmarkdown。其实本质上没有区别,不过Rmarkdown可以自动生成pptx等展示文档,避免了汇报工作时还得手动插图片的尴尬<sup id="fnref:3"><a href="#fn:3" class="footnote-ref" role="doc-noteref">3</a></sup>。</li>
<li>分享交互。用网页应用进行分享交互可能是最流行的方式了。这里采用Shiny,毕竟基于R,减少了学习成本,部署构建都挺快的,现在也还能满足需求。</li>
</ol>
<p>通过这样一个R-&gt;Rmarkdown-&gt;Shiny的工作流,大体上实现了数据分析工作的自动化,最后的结果看起来也挺美观的。在这里再次感谢R的开源社区提供的强大工具,使得我甚至还有时间在这写blog。然而,还是存在平台的割裂,没有完全实现自动化。如果能把2、3步也放在远程服务器上解决就好了。这里存在的问题就是没钱<sup id="fnref:4"><a href="#fn:4" class="footnote-ref" role="doc-noteref">4</a></sup>,好吧,如果能购买Rstudio的社区版就好了。这样就可以通过snakemake继续调用R脚本,打包成一个完整的流程,不过以后这流程也不一定能再走一遍了。还好,snakemake似乎支持模块化,下次把流程优化重构成一个个单独的模组吧。如果能实现,就可以避免下载文件等一堆繁琐的事情了,也不用非得待在实验室,真好啊真好啊😉。</p>
<section class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1" role="doc-endnote">
<p><strong>朕意已决</strong>? <a href="#fnref:1" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:2" role="doc-endnote">
<p>markdown怎么实现<strong>description list</strong>呀? <a href="#fnref:2" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:3" role="doc-endnote">
<p>就是感觉对ppt的支持还不够完整,当然很大可能是我太菜了。 <a href="#fnref:3" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
<li id="fn:4" role="doc-endnote">
<p>人唯一的病就是穷病? <a href="#fnref:4" class="footnote-backref" role="doc-backlink">&#x21a9;&#xfe0e;</a></p>
</li>
</ol>
</section>
</description>
</item>
<item>
<title>Auto Pull Using Webhook And Nodejs</title>
<link>https://www.gagua.xyz/p/auto-pull-using-webhook-and-nodejs/</link>
<pubDate>Fri, 08 Jan 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/auto-pull-using-webhook-and-nodejs/</guid>
<description><h1 id="purpose">Purpose</h1>
<p>I need to build a webserver using nodejs which listens to a certain port. Besides, writing a simple shell script to implement auto pull is necessary. It&rsquo;s vital to find a approach which is able to parse a json content and execute shell scripts. Considering latent security problem, enable SSL verification and setting secret token is recommended.</p>
<h2 id="install-nodejs">install nodejs</h2>
<p>I first tried <code>conda search node</code> then find the version of nodejs in conda repository is not the latest version.
However, <a class="link" href="https://nodejs.org/en/" target="_blank" rel="noopener"
>nodejs</a> is similar to python that has a active community, and the version iteration of nodejs is frequent. So <strong>using a Node version manager like <a class="link" href="https://github.com/nvm-sh/nvm" target="_blank" rel="noopener"
>nvm</a> to install Node.js and <a class="link" href="https://docs.npmjs.com/" target="_blank" rel="noopener"
>npm</a> is strongly recommend.</strong></p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh <span class="p">|</span> bash
</code></pre></div><p>To verify that nvm has been installed, do:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell"> <span class="nb">command</span> -v nvm
</code></pre></div><p>To download, compile, and install the latest release of node, do this:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">nvm install node <span class="c1"># &#34;node&#34; is an alias for the latest version</span>
</code></pre></div><p>To install a specific version of node:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">nvm install 6.14.4 <span class="c1"># or 10.10.0, 8.9.1, etc</span>
</code></pre></div><p>then check out version of node and <abbr title="nodejs package manager">npm</abbr>:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">npm -v
node -v
</code></pre></div><h2 id="github-webhook-handler">github-webhook-handler</h2>
<p>All fundamental preparation is finished, install a small handle <a class="link" href="https://github.com/rvagg/github-webhook-handler" target="_blank" rel="noopener"
>github-webhook-handler</a> that help with listening for a POST request at certain port.</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">npm i github-webhook-handler
</code></pre></div><p>following the example on that document, I set a <code>.js</code> script which create a server listening for event and execute <strong>shell</strong> script setted previously.</p>
<div class="highlight"><pre class="chroma"><code class="language-javascript" data-lang="javascript"><span class="kd">var</span> <span class="nx">http</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;http&#39;</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">exec</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;child_process&#39;</span><span class="p">).</span><span class="nx">exec</span>
<span class="kd">var</span> <span class="nx">createHandler</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;github-webhook-handler&#39;</span><span class="p">)</span>
<span class="kd">var</span> <span class="nx">handler</span> <span class="o">=</span> <span class="nx">createHandler</span><span class="p">({</span> <span class="nx">path</span><span class="o">:</span> <span class="s1">&#39;$payload/url&#39;</span><span class="p">,</span> <span class="nx">secret</span><span class="o">:</span> <span class="s1">&#39;myxxxxx&#39;</span> <span class="p">})</span><span class="c1">// confirm your path and secret are consistent with those setting on github webserver page.
</span><span class="c1"></span>
<span class="nx">http</span><span class="p">.</span><span class="nx">createServer</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">handler</span><span class="p">(</span><span class="nx">req</span><span class="p">,</span> <span class="nx">res</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">err</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">statusCode</span> <span class="o">=</span> <span class="mi">404</span>
<span class="nx">res</span><span class="p">.</span><span class="nx">end</span><span class="p">(</span><span class="s1">&#39;no such location&#39;</span><span class="p">)</span>
<span class="p">})</span>
<span class="p">}).</span><span class="nx">listen</span><span class="p">(</span><span class="nx">$port</span><span class="p">)</span>
<span class="nx">handler</span><span class="p">.</span><span class="nx">on</span><span class="p">(</span><span class="s1">&#39;push&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">event</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">currentTime</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Date</span><span class="p">();</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;\n--&gt; &#39;</span> <span class="o">+</span> <span class="nx">currentTime</span><span class="p">.</span><span class="nx">toLocaleString</span><span class="p">());</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;Received a push event for %s to %s&#39;</span><span class="p">,</span> <span class="nx">event</span><span class="p">.</span><span class="nx">payload</span><span class="p">.</span><span class="nx">repository</span><span class="p">.</span><span class="nx">name</span><span class="p">,</span> <span class="nx">event</span><span class="p">.</span><span class="nx">payload</span><span class="p">.</span><span class="nx">ref</span><span class="p">);</span>
<span class="nx">exec</span><span class="p">(</span><span class="s1">&#39;sh $path/to/sh&#39;</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">error</span><span class="p">,</span> <span class="nx">stdout</span><span class="p">,</span> <span class="nx">stderr</span><span class="p">)</span> <span class="p">{</span><span class="c1">//execute shell script
</span><span class="c1"></span> <span class="k">if</span><span class="p">(</span><span class="nx">error</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">error</span><span class="p">(</span><span class="s1">&#39;error:\n&#39;</span> <span class="o">+</span> <span class="nx">error</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;stdout:\n&#39;</span> <span class="o">+</span> <span class="nx">stdout</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s1">&#39;stderr:\n&#39;</span> <span class="o">+</span> <span class="nx">stderr</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">})</span>
</code></pre></div><p>using npm install <a class="link" href="https://pm2.keymetrics.io/docs/usage/quick-start/" target="_blank" rel="noopener"
>pm2</a> then call <code>pm2 start .js</code> and <code>pm2 startup</code> directives to keep script lauched.</p>
<h2 id="nginx-reverse-proxy">nginx reverse proxy</h2>
<p>Nodejs lauched sebserver at certain port but reversed proxy to 80 port is convenient for using webhook. rewrite nginx configuration file as followed</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">location /<span class="nv">$payload</span> <span class="o">{</span>
<span class="nb">alias</span> <span class="nv">$path</span>/to/js<span class="p">;</span>
proxy_pass https://<span class="nv">$ip</span>:<span class="nv">$port</span><span class="p">;</span>
<span class="o">}</span>
</code></pre></div><p>open github webhook page and click redeliver, but the same error status code 502 popped up again, it&rsquo;s a little frustrating. Then I scaned the latest nginx error code, finding something different:</p>
<div class="highlight"><pre class="chroma"><code class="language-shell" data-lang="shell">SSL_do_handshake<span class="o">()</span> failed <span class="o">(</span>SSL: error:1408F10B:SSL routines:ssl3_get_record:wrong version number<span class="o">)</span>
</code></pre></div><p>I&rsquo;m definitely a google oriented programmer. By google I find some possible solutions, one is that reversed proxy don&rsquo;t need HTTPS, so just fix <code>proxy_pass https://$ip:$port;</code> as <code>proxy_pass http://$ip:$port;</code> then webhook would work well <code>{&quot;ok&quot;:true}</code>. However, I didn&rsquo;t figure out the reason absolutely, maybe there is no SSL requirement for reversed proxy inside the same host, or nodejs script lauched a server using http protocol.</p>
<ul>
<li><input disabled="" type="checkbox"> waitting for complete solution</li>
</ul>
</description>
</item>
<item>
<title>Deploy A Static Blog Site</title>
<link>https://www.gagua.xyz/p/deploy-a-static-blog-site/</link>
<pubDate>Thu, 07 Jan 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/deploy-a-static-blog-site/</guid>
<description>
<script src="https://www.gagua.xyz/p/deploy-a-static-blog-site/index.en_files/header-attrs/header-attrs.js"></script>
<div id="TOC">
<ul>
<li><a href="#deployment">Deployment</a>
<ul>
<li><a href="#此时需要">此时需要:</a></li>
</ul></li>
<li><a href="#webserver">WebServer</a>
<ul>
<li><a href="#install-nginx">install nginx</a></li>
<li><a href="#domain-name-and-https">domain name and https</a>
<ul>
<li><a href="#https">https</a></li>
</ul></li>
</ul></li>
<li><a href="#webhook">webhook</a>
<ul>
<li><a href="#githook">githook</a></li>
<li><a href="#github-webhook">github webhook</a>
<ul>
<li><a href="#section">405</a></li>
</ul></li>
</ul></li>
</ul>
</div>
<div id="deployment" class="section level1">
<h1>Deployment</h1>
<p>网站如果只运行在local host那还叫啥网站啊,如果部署在一个具有公网ip的服务器,这样就能实现让几乎所有人都能通过浏览器访问自己的网站。<a href="https://bookdown.org/yihui/blogdown/deployment.html">blogdown</a>文档中提供了多种部署方案,但在这里选择部署至一台自己的vps上。</p>
<div id="此时需要" class="section level2">
<h2>此时需要:</h2>
<ul>
<li>能通过互联网访问的主机(host)一台</li>
<li>网站(博客)的文件</li>
<li>client——浏览器</li>
<li>server——webServer</li>
</ul>
<p>云计算,大数据如此火热的现在,主机现在显然不是问题。博客文件已经通过blogdown生成,浏览器也成为了大部分人的应用,接下来就只剩下webServer的问题了。</p>
</div>
</div>
<div id="webserver" class="section level1">
<h1>WebServer</h1>
<p>WebServer可以解析<abbr title="hyper text transfer protocol">HTTP</abbr>,响应(response)一个请求(request),通常都是返回一个html文件来让浏览器进行浏览。在这里我选用的是<a href="http://nginx.org/en/">nginx</a>,一款主要由Igor Sysoev在<em>业余时间</em>开发的HTTP和反向代理的服务器。当然还有其他功能,不过我暂时用上的就只有这两个。webserver当然由很多,如Apache等,甚至可以用python等自己实现一个,但是为什么我会选择nginx?主要是因为nginx内存占用小,并发高(这一点对于我暂时没有什么用处),有着优秀的静态处理性能(关键)。这对于私人博客这样一个静态网站来说,是完美的选择。</p>
<div id="install-nginx" class="section level2">
<h2>install nginx</h2>
<p><a href="http://nginx.org/en/">nginx</a>可以通过源码安装,但是在linux上想到的,果然还是yum优先。抱歉,由权限是真的可以为所欲为。</p>
<pre class="shell"><code>yum install nginx
......
no package nginx available</code></pre>
<p>?居然显示仓库中没有nginx,怎么可能?很好,我选择万能的conda。
安装好miniconda之后,<code>conda search nginx</code>,果然有,完成下载。在浏览器访问主机的ip地址,出现以下的界面:</p>
<div class="figure">
<img src="https://www.gagua.xyz/post/2021-01-07-deploy-a-static-blog-site/index.en_files/b92e58d99fd61d99cac151a5a241feb1.jpg" style="width:80.0%" alt="" />
<p class="caption">nginx 安装成功</p>
</div>
<p>注意,conda 安装的nginx将根目录设置的是conda所在目录。</p>
<pre class="shell"><code>git clone xxx.git</code></pre>
<p>从远程仓库git clone得到静态网页项目文件,之后的就是设置nginx的配置文件了。
<code>nginx -t</code>直接找到配置文件位置</p>
<pre class="shell"><code># nginx -t
nginx: the configuration file $path/to/conf/file syntax is ok
nginx: configuration file $path/to/conf/file test is successful
vi $path/to/conf/file
.
.
.
include sites.d/*.conf;</code></pre>
<p>nginx将<code>sites.d/*.conf</code>中的所有文件包含在了配置文件中。在<code>sites.d/</code>下新建一个<code>.conf</code>文件,</p>
<pre class="shell"><code>server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}</code></pre>
<p>假设网页文件夹的绝对路径为$abl,主机ip为$ip修改</p>
<pre class="shell"><code>server {
listen 80;
server_name $ip;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root $abl;
index index.html index.htm;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}</code></pre>
<p>尝试浏览器访问ip,结果发现403 Forbidden,这个是跟权限有关的状态码。啊这不对劲,难道是conda安装的nginx有问题吗?就想尝试以下系统安装的方法。</p>
<p>之后google一下发现yum无法安装的原因是nginx位于第三方的yum源里面,而不在centos官方yum源里。
那就安装<abbr title="Extra Packages for Enterprise Linux">EPEL</abbr>源好了。</p>
<pre class="shell"><code>yum install epel-release
yum update
yum install -y nginx</code></pre>
<p>应该就可以完成nginx安装了。不过这样会导致,存在两个nginx进程,后面导致监控work process端口出现了一点点麻烦,干脆把yum安装的nginx删除(conda永远滴神!)。</p>
<p>继续访问ip,居然还是403。喵喵喵?百度一下,发现是由于nginx用户和登录用户不一致导致的问题。</p>
<pre class="shell"><code>vi $path/to/conf/file
...
# Run as a unique, less privileged user for security.
user nobody www-data; ## Default: nobody</code></pre>
<p>修改用户(user)和用户组(user group)后,重启nginx<code>nginx -s reload</code>就能通过ip访问。看到网站成功打开还蛮开心的,就像成功把积木玩具拼装好一样。</p>
</div>
<div id="domain-name-and-https" class="section level2">
<h2>domain name and https</h2>
<p>ip难以记忆,也不够cooooool,那必须得采用域名来进行访问。域名很便宜,很多地方都可以购买,烂大街的玩意,不过好的域名还真难找,gagua.com——市场营销精品店公司,gagua.cn(这个貌似有,不过还是想要个.com域名啊啊啊)。这还是,第一次发现<em>gagua</em>这名字,都会有人取呢。最后,还是选了个.xyz域名,虽然可能存在SEO之类的问题,不过对于我这样一个个人博客来说,应该无所谓了。</p>
<ul class="task-list">
<li><input type="checkbox" disabled="" />
其实我还不懂为什么域名还能收费,等以后的答案吧</li>
<li><input type="checkbox" disabled="" />
不知道能不能自己实现DNS解析服务</li>
<li><input type="checkbox" disabled="" />
www和@,CNAME</li>
</ul>
<p>在域名解析服务商解决DNS解析问题,相当于做一个域名到ip的映射,之后就是添加A记录不过这个也不是很懂,以后再看看吧。
这一步需要等待一些时间。</p>
<p>DNS解析成功后,修改<em>server_name</em>为域名</p>
<pre class="shell"><code>server {
listen 80;
server_name domain_name;</code></pre>
<p>然后就可以尝试通过域名访问啦。可惜在浏览器无论是输入<em>domain_name</em> <em><a href="http://domain_name" class="uri">http://domain_name</a></em> 还是 <em><a href="http://domain_name:80" class="uri">http://domain_name:80</a></em> 都无法成功,无法找到服务器。而后,我突然意识到,pc端的谷歌浏览器默认使用<abbr title="hyper text transfer protocol over secure socket layer">https</abbr>,而nginx只监听了80端口。于是乎又将配置文件修改为443,即https的默认端口。
<strong>此时需要确保端口打开</strong><code>firewall-cmd --zone=public --add-port=443/tcp --permanent</code></p>
<p>满怀希望。</p>
<p>结果却是:<code>ERR_SSL_PROTOCOL_ERROR</code>。搜索了一下错误码,发现是因为没有配置ssl协议。</p>
<div id="https" class="section level3">
<h3>https</h3>
<p>https通过加入<abbr title="transfer layer security">TLS</abbr>/<abbr title="secure socket layer">SSL</abbr>协议在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。</p>
<div id="ssl证书申请" class="section level4">
<h4>SSL证书申请</h4>
<p>DNSPod可以直接申请CA证书。不得不说,腾讯还是会做点好事的,免费证书真香,还能自动添加解析记录。一键生成,下载证书后会得到一个与webserver相关的.crt证书文件和.key私钥文件。貌似好像可以自动生成证书,以后研究一下原理。</p>
</div>
<div id="ssl证书部署" class="section level4">
<h4>SSL证书部署</h4>
<p>感谢腾讯云的<a href="https://cloud.tencent.com/document/product/400/4143">悉心指导</a></p>
<pre class="shell"><code>server {
#SSL 访问端口号为 443
listen 443 ssl;
#填写绑定证书的域名
server_name cloud.tencent.com;
#证书文件名称
ssl_certificate 1_cloud.tencent.com_bundle.crt;
#私钥文件名称
ssl_certificate_key 2_cloud.tencent.com.key;
ssl_session_timeout 5m;
#请按照以下协议配置
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
#请按照以下套件配置,配置加密套件,写法遵循 openssl 标准。
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
location / {
#网站主页路径。此路径仅供参考,具体请您按照实际目录操作。
root html;
index index.html index.htm;
}
}</code></pre>
<p>而后还可以将HTTP 请求自动重定向到 HTTPS</p>
<pre class="shell"><code>server {
listen 443 ssl;
#填写绑定证书的域名
server_name cloud.tencent.com;
#证书文件名称
ssl_certificate 1_cloud.tencent.com_bundle.crt;
#私钥文件名称
ssl_certificate_key 2_cloud.tencent.com.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
location / {
#网站主页路径。此路径仅供参考,具体请您按照实际目录操作。
root html;
index index.html index.htm;
}
}
server {
listen 80;
#填写绑定证书的域名
server_name cloud.tencent.com;
#把http的域名请求转成https
return 301 https://$host$request_uri;
}</code></pre>
<p>此后就可通过https://domain_name访问。完美!</p>
<p>就此,网站部署工作已经大体上完成。在<code>git pull</code>时,我突然又懒癌发作。一定有,自动pull的方法吧?虽然ssh登录顺便输个命令并不算多大的工作量,不过这理应是计算机该做的事情吧?!</p>
</div>
</div>
</div>
</div>
<div id="webhook" class="section level1">
<h1>webhook</h1>
<div id="githook" class="section level2">
<h2>githook</h2>
<p>首先看到的是<a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks">githook</a>,提供自定义的脚本,在特定的动作发生后就会执行脚本。提供了client-side和server-side脚本,不过这个好像和我想要的server-web_server有点不同,代表的可能是远程仓库的server。</p>
<p>其实也可以通过在client-side的脚本中设置commit触发ssh链接加git pull,不过总感觉这样的实现不够优雅,而且越过了远程仓库,总感觉会导致一些意料之外的问题。</p>
</div>
<div id="github-webhook" class="section level2">
<h2>github webhook</h2>
<p>github为每个仓库提供了<a href="https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events">webhook</a>,github webhook与githook类似,都是响应动作(response action)。在仓库的setting中可以找到webhook设定,其中必须要添加的是<strong>Payload URL</strong>,webhook会在动作触发后向URL发送一个称为Payload的POST请求(request),请求体(request body)为json,触发动作和发送的文件内容当然也能选择,详情见<a href="https://docs.github.com/en/free-pro-team@latest/developers/webhooks-and-events">文档</a>。</p>
<p>当然,这只是发送了一个POST request,当时的我天真的以为在URL的文件夹下添加<code>git pull</code>的.sh文件就可以实现自动化。
结果当然是,翻车了。</p>
<pre class="html"><code>&lt;html&gt;
&lt;head&gt;&lt;title&gt;405 Not Allowed&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;center&gt;&lt;h1&gt;405 Not Allowed&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<div id="section" class="section level3">
<h3>405</h3>
<blockquote>
<p>请求行中指定的请求方法不能被用于请求相应的资源。该响应必须返回一个Allow 头信息用以表示出当前资源能够接受的请求方法的列表。鉴于 PUT,DELETE 方法会对服务器上的资源进行写操作,因而绝大部分的网页服务器都不支持或者在默认配置下不允许上述请求方法,对于此类请求均会返回405错误。</p>
</blockquote>
<p>nginx作为webserver,不允许静态文件响应POST请求,因此会返回405错误。</p>
<p>在网上找了nginx不响应POST请求的解决方法,不过按结果来看:</p>
<pre class="html"><code>&lt;html&gt;
&lt;head&gt;&lt;title&gt;502 Bad Gateway&lt;/title&gt;&lt;/head&gt;
&lt;body&gt;
&lt;center&gt;&lt;h1&gt;502 Bad Gateway&lt;/h1&gt;&lt;/center&gt;
&lt;hr&gt;&lt;center&gt;nginx&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
<p>查看错误记录发现<code>connect() failed (111: Connection refused) while connecting to upstream</code>,上游是一个.sh文件,怎么可能进行连接。
能response to POST request的,只能是(可以是)<strong>webserver</strong>, 既然现在所用的nginx不允许静态文件响应请求,那就只能再建立一个服务器监听特定端口,大多数现有的方案都是通过PHP来解决,不过我对这门语言实在是不太熟悉,最后还是选择了,<strong>Nodejs</strong></p>
</div>
</div>
</div>
</description>
</item>
<item>
<title>Establish A Website With R Blogdown</title>
<link>https://www.gagua.xyz/p/establish-a-website-by-r-blogdown/</link>
<pubDate>Wed, 06 Jan 2021 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/establish-a-website-by-r-blogdown/</guid>
<description>
<script src="https://www.gagua.xyz/p/establish-a-website-by-r-blogdown/index.en_files/header-attrs/header-attrs.js"></script>
<div id="TOC">
<ul>
<li><a href="#缘起">缘起</a></li>
<li><a href="#选型">选型</a></li>
<li><a href="#blogdown">blogdown</a></li>
</ul>
</div>
<div id="缘起" class="section level1">
<h1>缘起</h1>
<p><a href="https://bookdown.org/yihui/blogdown">Blogdown</a>是由<a href="https://yihui.org">Yihui Xie</a>基于<a href="https://gohugo.io/">Hugo</a>编写的一个R包,用于便捷地进行静态网站的构建。由于Yihui大神和RStudio团队的不懈努力,一个充满活力的R语言社区得以构建。加上之前偶然尝试了Yihui的另一个R包Rmarkdown,不由惊为天人。恰巧最近也学了点web相关的知识,html,css,native js等等,于是就产生了构建一个博客的想法,顺便也能记录一些在探索中遇到的技术问题,分享数据可视化的一些美图,实践《计算机网络,自顶而下方法》,《深入理解计算机系统》。</p>
</div>
<div id="选型" class="section level1">
<h1>选型</h1>
<p>Blogdown下载直接<code>install.packages()</code>,在比较新版本的RStudio IDE中,New Project中可以直接选择website using blogdown,RStudio会自动下载新版本的Hugo,在此也能选择主题(theme github)。在Hugo官网中纠结了很久,最后还是选了<a href="https://themes.gohugo.io/hugo-theme-stack">Stack</a>作为我博客的主题,说实话第一眼还是配图吸引了我,果然人就是肤浅的视觉动物。分类、搜索、评论、无框架,在满足了我基本的需求之后,还能提供相对充裕的自定制空间。毕竟框架虽然强大,但却封装了技术细节,想弄懂又需要花费不少学习成本,好吧,懒癌晚期,if it works, don’t fix it?</p>
</div>
<div id="blogdown" class="section level1">
<h1>blogdown</h1>
<p>在这想稍微详细说一下blogdown。众所周知,hugo是一款以Go开发的强大的静态网站生成器,那为什么还要开发blogdown呢?很简单,因为hugo暂时还没有完成对.Rmd的支持,但rmarkdown直接在网页中同时包含代码和生成的结果实在是太香了(其实还有更多的功能,但我就是个视觉动物)。Yihui因此开发了blogdown(有技术真的可以为所欲为吗),实现了对.Rmd的解析渲染,并且能实现bookdown、rmarkdown的绝大部分特性(yihui怎么又是你,难道这就是推荐式算法吗,信息茧房恐怖如斯),加上<a href="https://shiny.rstudio.com/">Shiny</a>应该可以实现交互式的页面应用,很可惜我暂时还不懂shiny咋用。这里又要吹一波RSstudio了,Addins提供了包括新增post和插入image等操作的快捷方式。</p>
<div class="figure">
<img src="https://www.gagua.xyz/post/2021-01-06-establish-a-website-by-r-blogdown/index.en_files/addins.png" style="width:50.0%" alt="" />
<p class="caption">blogdown addins</p>
</div>
<p>(啊,为什么本地加载图片会失败啊,哦,原来是生成路径的问题,rmd要加入/post/)</p>
<p>总之,<code>blogdown:::serve_site()</code>建立本地服务器用于预览,<code>blogdown::build_site()</code>后能得到一个默认为<strong>public</strong>的文件夹,里面就包含了博客所需要的所有文件。接下来就是github新建仓库, git commit, push remote一气呵成,很快啊。注意要在public文件夹建立仓库,因为建站所需的文件只有这些。</p>
</div>
</description>
</item>
<item>
<title>Chinese Test</title>
<link>https://www.gagua.xyz/p/test-chinese/</link>
<pubDate>Wed, 09 Sep 2020 00:00:00 +0000</pubDate>
<guid>https://www.gagua.xyz/p/test-chinese/</guid>
<description><img src="https://www.gagua.xyz/p/test-chinese/helena-hertz-wWZzXlDpMog-unsplash.jpg" alt="Featured image of post Chinese Test" /><h2 id="正文测试">正文测试</h2>
<p>而这些并不是完全重要,更加重要的问题是, 带着这些问题,我们来审视一下学生会退会。 既然如何, 对我个人而言,学生会退会不仅仅是一个重大的事件,还可能会改变我的人生。 我们不得不面对一个非常尴尬的事实,那就是, 可是,即使是这样,学生会退会的出现仍然代表了一定的意义。 学生会退会,发生了会如何,不发生又会如何。 经过上述讨论, 生活中,若学生会退会出现了,我们就不得不考虑它出现了的事实。 学生会退会,到底应该如何实现。 这样看来, 在这种困难的抉择下,本人思来想去,寝食难安。 对我个人而言,学生会退会不仅仅是一个重大的事件,还可能会改变我的人生。 就我个人来说,学生会退会对我的意义,不能不说非常重大。 莎士比亚曾经提到过,人的一生是短的,但如果卑劣地过这一生,就太长了。这似乎解答了我的疑惑。 莫扎特说过一句富有哲理的话,谁和我一样用功,谁就会和我一样成功。这启发了我, 对我个人而言,学生会退会不仅仅是一个重大的事件,还可能会改变我的人生。 学生会退会,到底应该如何实现。 一般来说, 从这个角度来看, 这种事实对本人来说意义重大,相信对这个世界也是有一定意义的。 在这种困难的抉择下,本人思来想去,寝食难安。 了解清楚学生会退会到底是一种怎么样的存在,是解决一切问题的关键。 一般来说, 生活中,若学生会退会出现了,我们就不得不考虑它出现了的事实。 问题的关键究竟为何? 而这些并不是完全重要,更加重要的问题是。</p>
<p>奥斯特洛夫斯基曾经说过,共同的事业,共同的斗争,可以使人们产生忍受一切的力量。 带着这句话,我们还要更加慎重的审视这个问题: 一般来讲,我们都必须务必慎重的考虑考虑。 既然如此, 这种事实对本人来说意义重大,相信对这个世界也是有一定意义的。 带着这些问题,我们来审视一下学生会退会。 我认为, 我认为, 在这种困难的抉择下,本人思来想去,寝食难安。 问题的关键究竟为何? 每个人都不得不面对这些问题。 在面对这种问题时, 要想清楚,学生会退会,到底是一种怎么样的存在。 我认为, 既然如此, 每个人都不得不面对这些问题。 在面对这种问题时, 那么, 我认为, 学生会退会因何而发生。</p>
<h2 id="引用">引用</h2>
<blockquote>
<p>思念是最暖的忧伤像一双翅膀<br>
让我停不了飞不远在过往游荡<br>
不告而别的你 就算为了我着想<br>
这么沉痛的呵护 我怎么能翱翔</p>
<p><em><a class="link" href="https://www.youtube.com/watch?v=3aypp_YlBzI" target="_blank" rel="noopener"
>最暖的憂傷 - 田馥甄</a></em></p>
</blockquote>
<h2 id="图片">图片</h2>
<p><figure style="flex-grow: 66; flex-basis: 160px">
<a href="https://www.gagua.xyz/p/test-chinese/florian-klauer-nptLmg6jqDo-unsplash.jpg" data-size="667x1000"><img src="https://www.gagua.xyz/p/test-chinese/florian-klauer-nptLmg6jqDo-unsplash.jpg"
srcset="https://www.gagua.xyz/p/test-chinese/florian-klauer-nptLmg6jqDo-unsplash_hu595aaf3b3dbbb41af5aed8d3958cc9f9_13854_480x0_resize_q75_box.jpg 480w, https://www.gagua.xyz/p/test-chinese/florian-klauer-nptLmg6jqDo-unsplash_hu595aaf3b3dbbb41af5aed8d3958cc9f9_13854_1024x0_resize_q75_box.jpg 1024w"
width="667"
height="1000"
loading="lazy"
alt="Photo by Florian Klauer on Unsplash">
</a>