-
Notifications
You must be signed in to change notification settings - Fork 3
/
README.html
828 lines (735 loc) · 75.4 KB
/
README.html
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
<!doctype html>
<html>
<head>
<meta charset='UTF-8'><meta name='viewport' content='width=device-width initial-scale=1'>
<title>README</title><link href='https://fonts.loli.net/css?family=PT+Serif:400,400italic,700,700italic&subset=latin,cyrillic-ext,cyrillic,latin-ext' rel='stylesheet' type='text/css' /><style type='text/css'>html {overflow-x: initial !important;}:root { --bg-color:#ffffff; --text-color:#333333; --select-text-bg-color:#B5D6FC; --select-text-font-color:auto; --monospace:"Lucida Console",Consolas,"Courier",monospace; --title-bar-height:20px; }
.mac-os-11 { --title-bar-height:28px; }
html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; tab-size: 4; }
iframe { margin: auto; }
a.url { word-break: break-all; }
a:active, a:hover { outline: 0px; }
.in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); }
#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; overflow-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; }
#write.first-line-indent p { text-indent: 2em; }
#write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; }
#write.first-line-indent li { margin-left: 2em; }
.for-image #write { padding-left: 8px; padding-right: 8px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
.typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; }
.typora-export .task-list-item input { pointer-events: none; }
@media screen and (max-width: 500px) {
body.typora-export { padding-left: 0px; padding-right: 0px; }
#write { padding-left: 20px; padding-right: 20px; }
.CodeMirror-sizer { margin-left: 0px !important; }
.CodeMirror-gutters { display: none !important; }
}
#write li > figure:last-child { margin-bottom: 0.5rem; }
#write ol, #write ul { position: relative; }
img { max-width: 100%; vertical-align: middle; image-orientation: from-image; }
button, input, select, textarea { color: inherit; font: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
*, ::after, ::before { box-sizing: border-box; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; }
#write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; }
p { line-height: inherit; }
h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; }
p { orphans: 4; }
h1 { font-size: 2rem; }
h2 { font-size: 1.8rem; }
h3 { font-size: 1.6rem; }
h4 { font-size: 1.4rem; }
h5 { font-size: 1.2rem; }
h6 { font-size: 1rem; }
.md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; }
a { cursor: pointer; }
sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-radius: 4px; cursor: pointer; }
sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; }
figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; }
figure > table { margin: 0px; }
tr { break-inside: avoid; break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }
table.md-table td { min-width: 32px; }
.CodeMirror-gutters { border-right: 0px; background-color: inherit; }
.CodeMirror-linenumber { user-select: none; }
.CodeMirror { text-align: left; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror pre { padding: 0px 4px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
#write pre { white-space: pre-wrap; }
#write.fences-no-line-wrapping pre { white-space: pre; }
#write pre.ty-contain-cm { white-space: normal; }
.CodeMirror-gutters { margin-right: 4px; }
.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }
.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }
#write .md-fences.mock-cm { white-space: pre-wrap; }
.md-fences.md-fences-with-lineno { padding-left: 0px; }
#write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; }
.md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; }
.CodeMirror-line, twitterwidget { break-inside: avoid; }
.footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; }
.footnotes + .footnotes { margin-top: 0px; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: 0px 0px; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li .mathjax-block, li p { margin: 0.5rem 0px; }
li blockquote { margin: 1rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child, li > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; }
#write .footnote-line { white-space: pre-wrap; }
@media print {
body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; }
#write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; }
.typora-export * { -webkit-print-color-adjust: exact; }
.typora-export #write { break-after: avoid; }
.typora-export #write::after { height: 0px; }
.is-mac table { break-inside: avoid; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }
p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; }
#write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; }
p > .md-image:only-child { display: inline-block; width: 100%; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.md-math-block { width: 100%; }
.md-math-block:not(:empty)::after { display: none; }
.MathJax_ref { fill: currentcolor; }
[contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; }
.md-task-list-item { position: relative; list-style-type: none; }
.task-list-item.md-task-list-item { padding-left: 0px; }
.md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc-content::after, .md-toc::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); }
.md-toc-item a { text-decoration: none; }
.md-toc-inner:hover { text-decoration: underline; }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h6 .md-toc-inner { margin-left: 8em; }
}
a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: "."; }
code, pre, samp, tt { font-family: var(--monospace); }
kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; }
.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); }
code { text-align: left; vertical-align: initial; }
a.md-print-anchor { white-space: pre !important; border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; background: 0px 0px !important; text-decoration: initial !important; text-shadow: initial !important; }
.md-inline-math .MathJax_SVG .noError { display: none !important; }
.html-for-mac .inline-math-svg .MathJax_SVG { vertical-align: 0.2px; }
.md-math-block .MathJax_SVG_Display { text-align: center; margin: 0px; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; overflow-y: hidden; display: block !important; }
.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }
.MathJax_SVG .MJX-monospace { font-family: var(--monospace); }
.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }
.MathJax_SVG { display: inline; font-style: normal; font-weight: 400; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; overflow-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }
.MathJax_SVG * { transition: none 0s ease 0s; }
.MathJax_SVG_Display svg { vertical-align: middle !important; margin-bottom: 0px !important; margin-top: 0px !important; }
.os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; }
.md-diagram-panel > svg { max-width: 100%; }
[lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; }
[lang="mermaid"] .node text { font-size: 1rem; }
table tr th { border-bottom: 0px; }
video { max-width: 100%; display: block; margin: 0px auto; }
iframe { max-width: 100%; width: 100%; border: none; }
.highlight td, .highlight tr { border: 0px; }
mark { background: rgb(255, 255, 0); color: rgb(0, 0, 0); }
.md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; }
mark .md-meta { color: rgb(0, 0, 0); opacity: 0.3 !important; }
@media print {
.typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; }
}
.md-diagram-panel .messageText { stroke: none !important; }
.md-diagram-panel .start-state { fill: var(--node-fill); }
.md-diagram-panel .edgeLabel rect { opacity: 1 !important; }
.md-require-zoom-fix foreignobject { font-size: var(--mermaid-font-zoom); }
.CodeMirror { height: auto; }
.CodeMirror.cm-s-inner { background: inherit; }
.CodeMirror-scroll { overflow: auto hidden; z-index: 3; }
.CodeMirror-gutter-filler, .CodeMirror-scrollbar-filler { background-color: rgb(255, 255, 255); }
.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background: inherit; white-space: nowrap; }
.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }
.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }
.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }
.cm-s-inner .cm-number { color: rgb(17, 102, 68); }
.cm-s-inner .cm-def { color: rgb(0, 0, 255); }
.cm-s-inner .cm-variable { color: rgb(0, 0, 0); }
.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }
.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }
.cm-s-inner .cm-string { color: rgb(170, 17, 17); }
.cm-s-inner .cm-property { color: rgb(0, 0, 0); }
.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }
.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }
.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }
.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }
.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }
.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }
.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }
.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }
.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }
.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: rgb(0, 0, 255); }
.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }
.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }
.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }
.cm-negative { color: rgb(221, 68, 68); }
.cm-positive { color: rgb(34, 153, 34); }
.cm-header, .cm-strong { font-weight: 700; }
.cm-del { text-decoration: line-through; }
.cm-em { font-style: italic; }
.cm-link { text-decoration: underline; }
.cm-error { color: red; }
.cm-invalidchar { color: red; }
.cm-constant { color: rgb(38, 139, 210); }
.cm-defined { color: rgb(181, 137, 0); }
div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }
div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }
.cm-s-inner .CodeMirror-activeline-background { background: inherit; }
.CodeMirror { position: relative; overflow: hidden; }
.CodeMirror-scroll { height: 100%; outline: 0px; position: relative; box-sizing: content-box; background: inherit; }
.CodeMirror-sizer { position: relative; }
.CodeMirror-gutter-filler, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-vscrollbar { position: absolute; z-index: 6; display: none; }
.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow: hidden; }
.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow: hidden; }
.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }
.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }
.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }
.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }
.CodeMirror-gutter-wrapper { position: absolute; z-index: 4; background: 0px 0px !important; border: none !important; }
.CodeMirror-gutter-background { position: absolute; top: 0px; bottom: 0px; z-index: 4; }
.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }
.CodeMirror-lines { cursor: text; }
.CodeMirror pre { border-radius: 0px; border-width: 0px; background: 0px 0px; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; overflow-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }
.CodeMirror-wrap pre { overflow-wrap: break-word; white-space: pre-wrap; word-break: normal; }
.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }
.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }
.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }
.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }
.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }
.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }
.CodeMirror-measure pre { position: static; }
.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }
.cm-searching { background: rgba(255, 255, 0, 0.4); }
@media print {
.CodeMirror div.CodeMirror-cursor { visibility: hidden; }
}
/* meyer reset -- http://meyerweb.com/eric/tools/css/reset/ , v2.0 | 20110126 | License: none (public domain) */
@include-when-export url(https://fonts.loli.net/css?family=PT+Serif:400,400italic,700,700italic&subset=latin,cyrillic-ext,cyrillic,latin-ext);
/* =========== */
/* pt-serif-regular - latin */
/* pt-serif-italic - latin */
/* pt-serif-700 - latin */
/* pt-serif-700italic - latin */
:root {
--active-file-bg-color: #dadada;
--active-file-bg-color: rgba(32, 43, 51, 0.63);
--active-file-text-color: white;
--bg-color: #f3f2ee;
--text-color: #1f0909;
--control-text-color: #444;
--rawblock-edit-panel-bd: #e5e5e5;
--select-text-bg-color: rgba(32, 43, 51, 0.63);
--select-text-font-color: white;
}
pre {
--select-text-bg-color: #36284e;
--select-text-font-color: #fff;
}
html {
font-size: 16px;
}
html, body {
background-color: #f3f2ee;
font-family: "PT Serif", 'Times New Roman', Times, serif;
color: #1f0909;
line-height: 1.5em;
}
/*#write {
overflow-x: auto;
max-width: initial;
padding-left: calc(50% - 17em);
padding-right: calc(50% - 17em);
}
@media (max-width: 36em) {
#write {
padding-left: 1em;
padding-right: 1em;
}
}*/
#write {
max-width: 40em;
}
@media only screen and (min-width: 1400px) {
#write {
max-width: 914px;
}
}
ol li {
list-style-type: decimal;
list-style-position: outside;
}
ul li {
list-style-type: disc;
list-style-position: outside;
}
ol,
ul {
list-style: none;
}
blockquote,
q {
quotes: none;
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
content: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/* styles */
/* ====== */
/* headings */
h1,
h2,
h3,
h4,
h5,
h6 {
font-weight: bold;
}
h1 {
font-size: 1.875em;
/*30 / 16*/
line-height: 1.6em;
/* 48 / 30*/
margin-top: 2em;
}
h2,
h3 {
font-size: 1.3125em;
/*21 / 16*/
line-height: 1.15;
/*24 / 21*/
margin-top: 2.285714em;
/*48 / 21*/
margin-bottom: 1.15em;
/*24 / 21*/
}
h3 {
font-weight: normal;
}
h4 {
font-size: 1.125em;
/*18 / 16*/
margin-top: 2.67em;
/*48 / 18*/
}
h5,
h6 {
font-size: 1em;
/*16*/
}
h1 {
border-bottom: 1px solid;
margin-bottom: 1.875em;
padding-bottom: 0.8125em;
}
/* links */
a {
text-decoration: none;
color: #065588;
}
a:hover,
a:active {
text-decoration: underline;
}
/* block spacing */
p,
blockquote,
.md-fences {
margin-bottom: 1.5em;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin-bottom: 1.5em;
}
/* blockquote */
blockquote {
font-style: italic;
border-left: 5px solid;
margin-left: 2em;
padding-left: 1em;
}
/* lists */
ul,
ol {
margin: 0 0 1.5em 1.5em;
}
/* tables */
.md-meta,.md-before, .md-after {
color:#999;
}
table {
margin-bottom: 1.5em;
/*24 / 16*/
font-size: 1em;
/* width: 100%; */
}
thead th,
tfoot th {
padding: .25em .25em .25em .4em;
text-transform: uppercase;
}
th {
text-align: left;
}
td {
vertical-align: top;
padding: .25em .25em .25em .4em;
}
code,
.md-fences {
background-color: #dadada;
}
code {
padding-left: 2px;
padding-right: 2px;
}
.md-fences {
margin-left: 2em;
margin-bottom: 3em;
padding-left: 1ch;
padding-right: 1ch;
}
pre,
code,
tt {
font-size: .875em;
line-height: 1.714285em;
}
/* some fixes */
h1 {
line-height: 1.3em;
font-weight: normal;
margin-bottom: 0.5em;
}
p + ul,
p + ol{
margin-top: .5em;
}
h3 + ul,
h4 + ul,
h5 + ul,
h6 + ul,
h3 + ol,
h4 + ol,
h5 + ol,
h6 + ol {
margin-top: .5em;
}
li > ul,
li > ol {
margin-top: inherit;
margin-bottom: 0;
}
li ol>li {
list-style-type: lower-alpha;
}
li li ol>li{
list-style-type: lower-roman;
}
h2,
h3 {
margin-bottom: .75em;
}
hr {
border-top: none;
border-right: none;
border-bottom: 1px solid;
border-left: none;
}
h1 {
border-color: #c5c5c5;
}
blockquote {
border-color: #bababa;
color: #656565;
}
blockquote ul,
blockquote ol {
margin-left:0;
}
.ty-table-edit {
background-color: transparent;
}
thead {
background-color: #dadada;
}
tr:nth-child(even) {
background: #e8e7e7;
}
hr {
border-color: #c5c5c5;
}
.task-list{
padding-left: 1rem;
}
.md-task-list-item {
padding-left: 1.5rem;
list-style-type: none;
}
.md-task-list-item > input:before {
content: '\221A';
display: inline-block;
width: 1.25rem;
height: 1.6rem;
vertical-align: middle;
text-align: center;
color: #ddd;
background-color: #F3F2EE;
}
.md-task-list-item > input:checked:before,
.md-task-list-item > input[checked]:before{
color: inherit;
}
#write pre.md-meta-block {
min-height: 1.875rem;
color: #555;
border: 0px;
background: transparent;
margin-top: -4px;
margin-left: 1em;
margin-top: 1em;
}
.md-image>.md-meta {
color: #9B5146;
}
.md-image>.md-meta{
font-family: Menlo, 'Ubuntu Mono', Consolas, 'Courier New', 'Microsoft Yahei', 'Hiragino Sans GB', 'WenQuanYi Micro Hei', serif;
}
#write>h3.md-focus:before{
left: -1.5rem;
color:#999;
border-color:#999;
}
#write>h4.md-focus:before{
left: -1.5rem;
top: .25rem;
color:#999;
border-color:#999;
}
#write>h5.md-focus:before{
left: -1.5rem;
top: .0.3125rem;
color:#999;
border-color:#999;
}
#write>h6.md-focus:before{
left: -1.5rem;
top: 0.3125rem;
color:#999;
border-color:#999;
}
.md-toc:focus .md-toc-content{
margin-top: 19px;
}
.md-toc-content:empty:before{
color: #065588;
}
.md-toc-item {
color: #065588;
}
#write div.md-toc-tooltip {
background-color: #f3f2ee;
}
#typora-sidebar {
background-color: #f3f2ee;
-webkit-box-shadow: 0 6px 12px rgba(0, 0, 0, 0.375);
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.375);
}
.pin-outline #typora-sidebar {
background: inherit;
box-shadow: none;
border-right: 1px dashed;
}
.pin-outline #typora-sidebar:hover .outline-title-wrapper {
border-left:1px dashed;
}
.outline-item:hover {
background-color: #dadada;
border-left: 28px solid #dadada;
border-right: 18px solid #dadada;
}
.typora-node .outline-item:hover {
border-right: 28px solid #dadada;
}
.outline-expander:before {
content: "\f0da";
font-family: FontAwesome;
font-size:14px;
top: 1px;
}
.outline-expander:hover:before,
.outline-item-open>.outline-item>.outline-expander:before {
content: "\f0d7";
}
.modal-content {
background-color: #f3f2ee;
}
.auto-suggest-container ul li {
list-style-type: none;
}
/** UI for electron */
.megamenu-menu,
#top-titlebar, #top-titlebar *,
.megamenu-content {
background: #f3f2ee;
color: #1f0909;
}
.megamenu-menu-header {
border-bottom: 1px dashed #202B33;
}
.megamenu-menu {
box-shadow: none;
border-right: 1px dashed;
}
header, .context-menu, .megamenu-content, footer {
font-family: "PT Serif", 'Times New Roman', Times, serif;
color: #1f0909;
}
#megamenu-back-btn {
color: #1f0909;
border-color: #1f0909;
}
.megamenu-menu-header #megamenu-menu-header-title:before {
color: #1f0909;
}
.megamenu-menu-list li a:hover, .megamenu-menu-list li a.active {
color: inherit;
background-color: #e8e7df;
}
.long-btn:hover {
background-color: #e8e7df;
}
#recent-file-panel tbody tr:nth-child(2n-1) {
background-color: transparent !important;
}
.megamenu-menu-panel tbody tr:hover td:nth-child(2) {
color: inherit;
}
.megamenu-menu-panel .btn {
background-color: #D2D1D1;
}
.btn-default {
background-color: transparent;
}
.typora-sourceview-on #toggle-sourceview-btn,
.ty-show-word-count #footer-word-count {
background: #c7c5c5;
}
#typora-quick-open {
background-color: inherit;
}
.md-diagram-panel {
margin-top: 8px;
}
.file-list-item-file-name {
font-weight: initial;
}
.file-list-item-summary {
opacity: 1;
}
.file-list-item {
color: #777;
}
.file-list-item.active {
background-color: inherit;
color: black;
}
.ty-side-sort-btn.active {
background-color: inherit;
}
.file-list-item.active .file-list-item-file-name {
font-weight: bold;
}
.file-list-item{
opacity:1 !important;
}
.file-library-node.active>.file-node-background{
background-color: rgba(32, 43, 51, 0.63);
background-color: var(--active-file-bg-color);
}
.file-tree-node.active>.file-node-content{
color: white;
color: var(--active-file-text-color);
}
.md-task-list-item>input {
margin-left: -1.7em;
margin-top: calc(1rem - 12px);
}
input {
border: 1px solid #aaa;
}
.megamenu-menu-header #megamenu-menu-header-title,
.megamenu-menu-header:hover,
.megamenu-menu-header:focus {
color: inherit;
}
.dropdown-menu .divider {
border-color: #e5e5e5;
}
/* https://github.com/typora/typora-issues/issues/2046 */
.os-windows-7 strong,
.os-windows-7 strong {
font-weight: 760;
}
.ty-preferences .btn-default {
background: transparent;
}
.ty-preferences .window-header {
border-bottom: 1px dashed #202B33;
box-shadow: none;
}
#sidebar-loading-template, #sidebar-loading-template.file-list-item {
color: #777;
}
.searchpanel-search-option-btn.active {
background: #777;
color: white;
}
:root {--mermaid-font-zoom:1.5em ;}
</style>
</head>
<body class='typora-export os-windows'>
<div id='write' class=''><p><img src="https://img.shields.io/badge/TL;DR-Free and secure remote access with NAT & firewall traversal, using Git as backend-blue.svg" referrerpolicy="no-referrer" alt="Generic badge"><span> </span></p><p><a href='https://doi.org/10.5281/zenodo.4673010'><img src="https://zenodo.org/badge/DOI/10.5281/zenodo.4673010.svg" referrerpolicy="no-referrer" alt="DOI"></a><span> </span></p><p><a href='https://www.gnu.org/software/bash/'><img src="https://img.shields.io/badge/Made%20with-Bash-green.svg" referrerpolicy="no-referrer" alt="made-with-bash"></a><span> </span><a href='https://www.gnu.org/licenses/gpl-3.0'><img src="https://img.shields.io/badge/License-GPLv3-blue.svg" referrerpolicy="no-referrer" alt="License: GPL v3"></a><span> </span><img src="https://img.shields.io/badge/Dependency-Git, Bash, cURL-blue.svg" referrerpolicy="no-referrer" alt="Generic badge"><span> </span><img src="https://img.shields.io/badge/Tested on-Ubuntu 12.04, 16.04, 20.04 and Debian 10-blue.svg" referrerpolicy="no-referrer" alt="Generic badge"><span> </span></p><p><a href='https://github.com/SomajitDey/gibberish'><img src="https://img.shields.io/badge/Repository-SomajitDey/gibberish-blue.svg" referrerpolicy="no-referrer" alt="Generic badge"></a><span> </span><a href='https://github.com/SomajitDey/gibberish/graphs/commit-activity'><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" referrerpolicy="no-referrer" alt="Maintenance"></a><span> </span><a href='https://www.researchgate.net/profile/Somajit-Dey'><img src="https://img.shields.io/badge/maintainer-Somajit Dey-blue" referrerpolicy="no-referrer" alt="Maintaner"></a></p><p> </p><h1><a name="what-is-gibberish" class="md-header-anchor"></a><span>What is GiBBERISh</span></h1><p><strong><span>GiBBERISh</span></strong><span> stands for </span><strong><em><span>Git and Bash Based Encrypted Remote Interactive Shell</span></em></strong><span>. It is a </span><em><span>free</span></em><span>, </span><em><span>easy</span></em><span> and </span><em><span>portable</span></em><span> solution to </span><em><span>securely</span></em><span> access your </span><em><span>Linux</span></em><span> computer from another </span><em><span>Linux</span></em><span> box over the internet, when none of the machines has a public IP address. You can also transfer files to and fro the remote host, with end-to-end encryption.</span></p><p><span>GiBBERISh consists of only a short </span><em><span>Bash</span></em><span> </span><em><span>script</span></em><span>, to be run on both the hosts (viz. </span><em><span>client</span></em><span> and </span><em><span>server</span></em><span>), and an </span><em><span>online</span></em><span> </span><em><span>Git</span></em><span> </span><em><span>repository</span></em><span> owned and controlled by the user, such as a </span><em><span>free</span></em><span> repository at any of </span><a href='https://github.com/'><span>GitHub</span></a><span>, </span><a href='https://gitlab.com/'><span>GitLab</span></a><span>, </span><a href='https://bitbucket.org/'><span>Bitbucket</span></a><span>, </span><a href='https://sourceforge.net/'><span>SourceForge</span></a><span> etc.</span></p><h1><a name="why-gibberish" class="md-header-anchor"></a><span>Why GiBBERISh</span></h1><p><span>The standard way to remote access a Linux computer is Secure Shell (SSH). But, in order to connect to the remote host over internet, it has to have a public IP address -- something most personal and work PCs do not have. You can, however, beat this in the following ways:</span></p><ol start='' ><li><span>SSH port forwarding at a server with public IP/URL (for some free services with a new URL per session see </span><a href='https://gist.github.com/SomajitDey/a8ce8af891f753307019f52fd45ca200'><span>this</span></a><span> and </span><a href='https://gist.github.com/SomajitDey/efd8f449a349bcd918c120f37e67ac00'><span>this</span></a><span>)</span></li><li><span>Virtual Private Network or VPN</span></li></ol><p><span>If you can afford any of the above, then GiBBERISh is not for you. However, if you are like me, who doesn't want to pay for a VPN or port-forwarding service with static URL, you are probably out of luck with SSH. Also, some corporate firewalls block non-web traffic entirely, hence SSH is not even an option there.</span></p><p><span>However, you can still manage fine with a freemium remote access app, such as TeamViewer or Anydesk. If you are happily using such Virtual Network Computing (VNC) tools, then too you won't have any use for GiBBERISh. However, VNC apps have their </span><a href='https://www.comparitech.com/vpn/what-is-a-vnc-and-how-does-it-differ-from-a-vpn/#:~:text=phones%2C%20these%20days.-,Cons%20of%20VNC,the%20color%20depth%20to%20use.'><span>cons</span></a><span>. They consume a lot of bandwidth. If you want to access just the shell of your remote host, why would you need to import the entire screen! The remote computer also need to be online all the time. Another common problem is </span><a href='https://www.tek-tools.com/itsm/teamviewer-alternatives'><span>version incompatibility</span></a><span>. For TeamViewer, for example, every machine needs to have the same version of the app installed on it, or else it won’t work. In addition, being freemium, what they offer for free is limited and you never know how long they would keep offering those free services. To top it all of, you can do nothing but trust these service providers when they say that using their services is completely safe for </span><a href='http://www.remoteaccess.org/what-is-a-vnc/#:~:text=Some%20Cons%20in%20Using%20a%20Virtual%20Network%20Computing%20Program&text=Security%20issues%20can%20quickly%20become,possibly%20compromise%20your%20entire%20network.'><span>your systems</span></a><span> and </span><a href='https://www.bbc.com/news/technology-36459015'><span>your data</span></a><span>.</span></p><p><span>Anyways, I needed a light-weight, portable, easy-to-install and completely free yet reliable platform to access my remote machine securely over the internet. I didn't mind the latency, as long as my main purpose of submitting jobs to the remote host was served. Hence, my DIY solution - GiBBERISh.</span></p><h1><a name="how-it-works" class="md-header-anchor"></a><span>How it works</span></h1><p><em><span>An interactive shell is nothing but the user chatting with the operating system (OS), occasionally poking the OS with interrupts or job-control signals</span></em><span>. For GiBBERISh, the user's local machine is the </span><strong><span>client</span></strong><span>, and the OS in the remote host is the </span><strong><span>server</span></strong><span>. Correspondence between the two is managed by an automated </span><em><span>Git</span></em><span> workflow.</span></p><p><em><a href='https://git-scm.com/book/en/v2'><span>Git</span></a></em><span>, if you don't know about it already, is a widely-used, fast, lightweight, distributed version-control system or content-tracker. Because it is distributed, widely available, and easy to use, you can use it to synchronize two machines quite easily. If you </span><em><span>push commits</span></em><span> (i.e. make some changes) to a Git </span><em><span>repository</span></em><span> (i.e. a directory with </span><em><span>history</span></em><span>) in one machine, you can synchronize or update its </span><em><span>clone</span></em><span> in another machine simply by </span><em><span>fetching</span></em><span> those new commits from the former repository (called </span><em><span>upstream</span></em><span> in Git-speak).</span></p><p><span>Git can connect two machines over the internet for push/fetch only if at least one of them has a public IP address or URL. However, one can have a free, if not private, online Git repository with a public URL hosted in any of the popular Git-servers, such as </span><a href='https://github.com/'><span>GitHub</span></a><span>, </span><a href='https://gitlab.com/'><span>GitLab</span></a><span>, </span><a href='https://bitbucket.org/'><span>Bitbucket</span></a><span> or </span><a href='https://sourceforge.net/'><span>SourceForge</span></a><span>. Although anyone can view (and fetch) the contents of your online repository, you remain in control of who can make changes to your repository. This is because all push access is protected by your password or an access-token generated by you.</span></p><h4><a name="how-gibberish-connects-two-hosts-client-and-server-over-the-internet-without-any-of-them-having-a-public-ip-address" class="md-header-anchor"></a><span>How GiBBERISh connects two hosts (client and server) over the internet without any of them having a public IP address </span></h4><p><span>Whenever the user enters a command at client, the GiBBERISh script encrypts it with your Git credentials using a state-of-the-art, yet free, cryptography service called GNU Privacy Guard (GPG). It then commits this encrypted text to the user's local repository and pushes the same to the user's upstream repository (say, at GitHub). Server's script then fetches this commit from upstream, decrypts and pipes the user's command to an interactive Bash. The output emitted by Bash is again encrypted, committed and pushed to GitHub, which the client fetches, decrypts and shows to the user. ( For an original implementation of a similar Git-based chat, see </span><a href='https://github.com/ephigabay/GIC' target='_blank' class='url'>https://github.com/ephigabay/GIC</a><span> ).</span></p><p><strong><span>Note</span></strong><span>: Because only encrypted text goes to GitHub, the public cannot see what commands the user is running, or their outputs.</span></p><h1><a name="latency" class="md-header-anchor"></a><span>Latency:</span></h1><p><span>Because of the dependence on an online Git repository, the time between entering a command and getting its output back is not insignificant. This is because </span><code>git-push</code><span> is slow. From multiple measurements with upstream at GitHub, I found the latency varies between 6 to 9 seconds. However, using GitHub's REST API, the </span><code>git-push</code><span> can be avoided and </span><a href='https://gist.github.com/SomajitDey/3a438669bd00bdf3b80e4471c2c41a98'><span>performance improved</span></a><span>. When using the API, the latency decreases to 3-4 seconds.</span></p><h1><a name="features" class="md-header-anchor"></a><span>Features:</span></h1><ol start='' ><li><span>Doesn't require a public IP address. Both machines can be behind multiple NATs.</span></li><li><span>Doesn't care about firewalls and blocked ports.</span></li><li><span>Secure (everything public is encrypted with your password / access-token).</span></li><li><span>Interactive. Unlike SSH, however, the raw user input is not streamed to server. The user can type, edit, erase as many times as necessary, with zero-lag, before pressing the </span><code>Enter</code><span> key.</span></li><li><span>Secure (encryption using AES256) file transfer from client to server and vice-versa.</span></li><li><span>Easy and fast switching between local and remote environments without interrupting the remote session in any way. See </span><em><span>brb</span></em><span> in the </span><em><span>Keywords</span></em><span> section below.</span></li><li><span>Relays user's keyboard-generated signals, such as Ctrl-c; Ctrl-z to server.</span></li><li><span>Monitorability and overrides: If you grant someone else access to your local machine, for remote diagnostics for example, you can see all the commands she is executing from your terminal. You can also override those executions with Ctrl-c, Ctrl-z, Ctrl-\ etc., if necessary.</span></li><li><span>Forever free. Given the popularity of Git in DevOps, freemium services such as GitHub are here to stay and they probably will continue hosting small public repositories for free for years to come. GiBBERISh is careful about keeping the repository size as small as possible. So, the size limit of the free-tier plans should never be an issue.</span></li><li><span>Lightweight: CPU usage is minimal. Polling and busy-waits are avoided wherever possible in favor of event-driven triggers.</span></li><li><span>Reliable: If any of your machines goes offline, it automatically gets connected once its internet connection is restored. No data is lost. Just make sure your remote host stays up even when there is power-outage.</span></li><li><span>Hassle-free installation, portability and flexibility: GiBBERISh only runs Git, and some basic Unix commands, all from a short, simple, stupid (KISS) Bash script. Most current Linux distributions ship with Git and Bash both. Hence, GiBBERISh should run readily on those. No superuser or admin privilege is required to install or run GiBBERISh. You also hold the perpetual right to adapt the source-code to your needs.</span></li><li><span>Everything is under your control. You are free to modify the single Bash script that GiBBERISh runs from. You own and manage the upstream repository. If you are connecting to your work computer from your home machine or vice versa, you control both the machines. You also choose who can access your machine, should you ever be granting someone else remote access for purposes of diagnostics, instructions etc.</span></li><li><span>Because Git and Bash are the only main ingredients, GiBBERISh (in an implementation that doesn't use </span><code>flock</code><span>) maybe run easily on </span><a href='https://gitforwindows.org/'><span>Git-Bash</span></a><span> from the Git for Windows package. However, that might be unnecessary, given that Windows 10 now ships with a subsystem for Linux (</span><a href='https://docs.microsoft.com/en-us/windows/wsl/install-win10'><span>WSL</span></a><span>).</span></li><li><span>Stores command history for the session. Use the Up, Down arrow keys or Ctrl-p and Ctrl-n to access history as usual.</span></li></ol><h1><a name="how-to-install--run" class="md-header-anchor"></a><span>How to install / run</span></h1><p><span>First, </span><a href='https://docs.github.com/en/github/getting-started-with-github/create-a-repo'><span>create a dedicated repository</span></a><span> at any free Git hosting service such as </span><a href='https://github.com/' target='_blank' class='url'>https://github.com/</a><span>, </span><a href='https://gitlab.com/' target='_blank' class='url'>https://gitlab.com/</a><span>, </span><a href='https://bitbucket.org/' target='_blank' class='url'>https://bitbucket.org/</a><span> or </span><a href='https://sourceforge.net/' target='_blank' class='url'>https://sourceforge.net/</a><span>. I recommend using GitHub, as GiBBERISh can speed itself up using their content API. The repository can be completely empty, i.e. without any commits. </span></p><p><strong><span>Tip</span></strong><span>: Also </span><a href='https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token'><span>generate a personal access-token (PAT)</span></a><span> with write-access to your repository. This makes GiBBERISh even more secure.</span></p><p><strong><span>Tip:</span></strong><span> If you have created the repository at GitHub, then install </span><a href='https://stedolan.github.io/jq/download/'><code>jq</code></a><span> and </span><code>base64</code><span> to experience the lowest latency (3-4s) with GiBBERISh. However, you can also run GiBBERISh without these, albeit with double latency.</span></p><p><span>At the Linux machine that you want to use as server, run the </span><em><span>installer</span></em><span> script (no superuser or admin privilege required): </span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">./installer</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 25px;"></div><div class="CodeMirror-gutters" style="display: none; height: 25px;"></div></div></div></pre><p><span>Then, simply follow the on-screen instructions.</span></p><p><span>To start the server, run: </span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">gibberish-server</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 25px;"></div><div class="CodeMirror-gutters" style="display: none; height: 25px;"></div></div></div></pre><p><span>At the client machine, install GiBBERISh similarly as above.</span></p><p><span>To access the remote server, simply run:</span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">gibberish</span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 25px;"></div><div class="CodeMirror-gutters" style="display: none; height: 25px;"></div></div></div></pre><p><strong><span>Note</span></strong><span>: GiBBERISh allows, possibly unnecessarily, upstream repositories that are on your local disk or NFS.</span></p><h1><a name="keywords-or-built-in-commands" class="md-header-anchor"></a><span>Keywords or built-in commands</span></h1><p><span>GiBBERISh recognizes a few keywords as listed below.</span></p><p><strong><span>ping</span></strong><span> </span><span>|</span><span> </span><strong><span>hello</span></strong><span> </span><span>|</span><span> </span><strong><span>hey</span></strong><span> </span><span>|</span><span> </span><strong><span>hi</span></strong></p><p><span>To test if the server is still connected. Consider the following situation. You are running a foreground process on the server, which outputs infrequently. Because it is in foreground, you do not have the command prompt and hence cannot execute a short command such as </span><a href='https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html'><code>echo</code></a><span> to see if the server is still responding. Just enter any of these keywords, and the server will send you a 'hello' if it can hear you, without interrupting that foreground process in any way. However, you can also do a simple </span><code>Ctrl-<spacebar></code><span> or </span><code>Ctrl-z</code><span> to get back the prompt, at the expense of stopping the foreground process. </span><strong><span>Note</span></strong><span>: You can use any of these commands anytime, even if a foreground process is running at the server and you do not have a prompt.</span></p><p><strong><span>exit</span></strong><span> </span><span>|</span><span> </span><strong><span>quit</span></strong><span> </span><span>|</span><span> </span><strong><span>logout</span></strong><span> </span><span>|</span><span> </span><strong><span>hup</span></strong><span> </span><span>|</span><span> </span><strong><span>bye</span></strong></p><p><span>To end the session, and disconnect or hangup. When you do this, the current interactive shell in the server is closed and a new, fresh shell is launched ready for the next session. You therefore, would lose any environment variable you had set or function definitions you had sourced during the last session. Beware that this should also close any process running on the server that the exiting shell sends SIGHUP to, unless the process has a handler installed for HUP. Start processes in background with </span><a href='https://man7.org/linux/man-pages/man1/nohup.1.html'><code>nohup</code></a><span> if you intend to keep them running even after you logout using these keywords. </span></p><p><strong><span>brb</span></strong></p><p><span>Be right back, viz. to quickly switch to your local environment for a short while, without ending or interrupting the remote session. Any foreground process running in the server, keeps running uninterrupted. With this keyword, you simply get back your local command prompt, whenever you need to run commands locally during a remote session. To return to the remote session, just enter </span><code>gibberish</code><span> again. You will be shown all the server output since the time you did </span><code>brb</code><span>, so you miss nothing.</span></p><p><strong><span>local</span></strong></p><p><span>Run commands locally, i.e. at the client, inside a sub-shell. The syntax is:</span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation" style=""><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">local <commands></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text=""></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># To run codes from a file</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">local . <path to script></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span cm-text=""></span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment"># To see current working directory at client</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">local <span class="cm-comment"># equivalent to: local pwd</span></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 173px;"></div><div class="CodeMirror-gutters" style="display: none; height: 173px;"></div></div></div></pre><p><strong><span>rc</span></strong></p><p><span>Run commands. This is akin to the </span><code>.</code><span> or </span><a href='https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html'><code>source</code></a><span> built-in of Bash. Whereas </span><code>source</code><span> reads commands from a local file and executes them in the current shell, </span><code>rc</code><span> takes commands from a client-side file and executes them in the server-side shell that the user is currently interacting with. The syntax is: </span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">rc <local path to script></span></pre></div></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 25px;"></div><div class="CodeMirror-gutters" style="display: none; height: 25px;"></div></div></div></pre><p><span>All the commands in the given script are passed to upstream in one Git-push. Hence, use of this keyword helps with latency issues.</span></p><p><strong><span>take</span></strong><span> </span><span>|</span><span> </span><strong><span>push</span></strong></p><p><span>See next section</span></p><p><strong><span>bring</span></strong><span> </span><span>|</span><span> </span><strong><span>pull</span></strong></p><p><span>See next section</span></p><p><strong><span>help</span></strong><span> </span><span>|</span><span> </span><strong><span>tutorial</span></strong></p><p><span>Gives the link to this section</span></p><p><strong><span>latency</span></strong><span> </span><span>|</span><strong><span>rtt</span></strong></p><p><span>Gives the latency or round-trip-time for the current connection in seconds. </span><strong><span>Note</span></strong><span>: You can use any of these commands anytime, even if a foreground process is running at the server and you do not have a prompt.</span></p><hr /><p><strong><span>Tip</span></strong><span>: If you need to run a command that matches any of the keywords described above, use the </span><strong><a href='https://www.gnu.org/software/bash/manual/html_node/Bash-Builtins.html'><code>command</code></a></strong><span> built-in of Bash.</span></p><h1><a name="file-and-directory-transfer" class="md-header-anchor"></a><span>File and directory transfer</span></h1><p><strong><span>Copying file from client to server:</span></strong></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">take <local path> <remote path> </span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">#### or</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">push <local path> <remote path></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 74px;"></div><div class="CodeMirror-gutters" style="display: none; height: 74px;"></div></div></div></pre><p><strong><span>Copying file from server to client:</span></strong></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">bring <remote path> <local path></span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-comment">#### or</span></span></pre><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">pull <remote path> <local path></span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 74px;"></div><div class="CodeMirror-gutters" style="display: none; height: 74px;"></div></div></div></pre><p><span>File transfer is atomic, which guarantees you never end up with a corrupt file, even if the transfer operation gets interrupted or terminated prematurely. If the destination file is existing, it will be overwritten after backup. If the destination path is a directory, the file would be put inside it. The paths can be absolute or relative. As should be intuitive, any relative path would be interpreted with PWD at the corresponding host as its base, i.e. relative local (remote) path would be relative to the client-side (server-side) working directory. Similarly, tilde and shell-variable expansion in the path specifications, are done with respect to the corresponding host.</span></p><p><strong><span>Tip</span></strong><span>: To transfer directories or a collection of files, archive them first, with </span><a href='https://man7.org/linux/man-pages/man1/tar.1.html'><code>tar</code></a><span> for example, and then use the above commands to exchange that single archive file.</span></p><p><strong><span>Tip</span></strong><span>: To transfer a file from the Windows filesystem in WSL, first change its path to Unix path using the command: </span><code>wslpath</code><span>.</span></p><p><strong><span>Note</span></strong><span>: File transfer is end-to-end encrypted with your Git credentials. To keep your Git repository size small, the files are transferred using free, public file-hosting servers.</span></p><h1><a name="keyboard-generated-job-control-signals" class="md-header-anchor"></a><span>Keyboard-generated job-control signals</span></h1><p><span>All the familiar Ctrl key generated signals are supported except </span><code>Ctrl-\</code><span>, which has been replaced by </span><code>Ctrl-e</code><span> (mnemonic: 'e' for exit). Because the user doesn't have the liberty to open a second terminal to control a runaway foreground process that ignores SIGTSTP (as generated with </span><code>Ctrl-z</code><span>), GiBBERISh provides </span><code>Ctrl-<spacebar></code><span> key-binding to force pause a foreground process with SIGSTOP - which cannot be ignored or handled.</span></p><h1><a name="try-gibberish-at-localhost" class="md-header-anchor"></a><span>Try GiBBERISh at localhost</span></h1><p><span>If you are a first-time user, you may want to get familiar with GiBBERISh at your local machine. To do that, install GiBBERISh twice, once as server and then as client. Now, open a terminal and run: </span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">export</span> <span class="cm-def">GIBBERISH</span><span class="cm-operator">=</span>server</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">gibberish-server</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 49px;"></div><div class="CodeMirror-gutters" style="display: none; height: 49px;"></div></div></div></pre><p><span>Then, open another terminal and run: </span></p><pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="bash"><div class="CodeMirror cm-s-inner CodeMirror-wrap" lang="bash"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 0px; left: 4px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" tabindex="0" style="position: absolute; bottom: -1em; padding: 0px; width: 1000px; height: 1em; outline: none;"></textarea></div><div class="CodeMirror-scrollbar-filler" cm-not-content="true"></div><div class="CodeMirror-gutter-filler" cm-not-content="true"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="margin-left: 0px; margin-bottom: 0px; border-right-width: 0px; padding-right: 0px; padding-bottom: 0px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines" role="presentation"><div role="presentation" style="position: relative; outline: none;"><div class="CodeMirror-measure"><pre><span>xxxxxxxxxx</span></pre></div><div class="CodeMirror-measure"></div><div style="position: relative; z-index: 1;"></div><div class="CodeMirror-code" role="presentation"><div class="CodeMirror-activeline" style="position: relative;"><div class="CodeMirror-activeline-background CodeMirror-linebackground"></div><div class="CodeMirror-gutter-background CodeMirror-activeline-gutter" style="left: 0px; width: 0px;"></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;"><span class="cm-keyword">export</span> <span class="cm-def">GIBBERISH</span><span class="cm-operator">=</span>client</span></pre></div><pre class=" CodeMirror-line " role="presentation"><span role="presentation" style="padding-right: 0.1px;">gibberish</span></pre></div></div></div></div></div><div style="position: absolute; height: 0px; width: 1px; border-bottom: 0px solid transparent; top: 49px;"></div><div class="CodeMirror-gutters" style="display: none; height: 49px;"></div></div></div></pre><h1><a name="granting-remote-access-while-you-monitor" class="md-header-anchor"></a><span>Granting remote-access while you monitor</span></h1><p><span>There might be desperate situations where you need to grant access to your local machine to someone else. To do that safely, do the following.</span></p><ol start='' ><li><span>If your machine is not already configured as server, install GiBBERISh to run as server.</span></li><li><a href='https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token'><span>Create a temporary access-token</span></a><span> at your upstream account.</span></li><li><span>Send the access-token to the person you are granting remote access to and ask her to install GiBBERISh as client with the given token as password/PAT. [If she already has GiBBERISh client configured with a different password, ask her to backup her </span><code>~/.gibberish</code><span> directory before reinstallation. After the session, she can simply restore the backup.]</span></li><li><span>Run: </span><code>gibberish-server <access-token></code></li><li><span>Ask the other person to run: </span><code>gibberish</code></li><li><span>Monitor everything on-screen. Whenever you feel you need to interrupt any command the remote client is running on your machine, use </span><code>Ctrl-c</code><span>, </span><code>Ctrl-z</code><span> or </span><code>Ctrl-\</code><span> as usual. In the worst case, simply close the terminal. It would kill all processes spawned in that session.</span></li><li><span>After the session is over, close your terminal to kill the server.</span></li><li><span>Revoke the access-token from your upstream account.</span></li></ol><h1><a name="library-not-executable" class="md-header-anchor"></a><span>Library, not executable</span></h1><p><span>The Bash script for GiBBERISh, viz. </span><em><span>gibberish_rc.bash</span></em><span>, is a library rather than an executable. On startup, your interactive Bash sources this script. The </span><em><span>installer</span></em><span> puts the corresponding run-command in .bashrc. </span></p><p><span>The </span><em><span>installer</span></em><span>, on the other hand, is an executable script. Hence, do a </span><em><span>chmod +x</span></em><span> on it, if necessary.</span></p><h1><a name="internals-pointers-to-understand-the-code" class="md-header-anchor"></a><span>Internals (pointers to understand the code)</span></h1><p><span>The client-side and server-side codes are almost the same structurally. This is why a single shell-script suffices for both. There are two types of events:</span></p><p><span>1) Internal events: User@client or Bash@server creates new data to push</span></p><p><span>2) External events: Git-fetch brings new data from outside to display or process </span></p><p><span>Internal events are mostly waited for, while external ones need to be polled for continuously. Everything else is mostly triggered by these events. For example, upon creation, the data to be pushed is first siloed and an encrypt-commit-push pipeline is triggered.</span></p><p><span>The Git repository for GiBBERISh has two linear branches, viz. server-branch and client-branch. Server fetches from server-branch, but pushes to client-branch. Client does the converse. Every user-command@client or Bash-output@server, is committed to the proper outgoing branch as a single text file. As new commands or outputs become available, this file is simply revised to hold the same. The Git-worktree, therefore, always contains only a single file, and all the commands/outputs can always be tracked from its revision history. Every time a commit happens, it triggers a post-commit hook that pushes the commit automatically.</span></p><p><span>Every iteration of Git-fetch triggers a checkout sequence that tracks all the new commits chronologically, restoring the corresponding version of the abovementioned text file for decryption. Upon successful decryption, the checkout function pushes the data down a pipeline to user (@client) or Bash (@server), before moving on to the next commit in the git-revision-list.</span></p><p><span>Note that if every user-command was passed using that single text file alone, then all the commands would end up in the queue for Bash@server. To relay a user-generated signal (SIGINT, SIGTSTP, SIGQUIT) to a foreground process on demand, however, we need to route </span><a href='https://man7.org/linux/man-pages/man1/kill.1.html'><code>kill</code></a><span> commands to a second, parallel shell in the server. We, therefore, need a way to commit commands in the repository other than the single text file mentioned before. GiBBERISh exploits Git's commit-message field for this purpose. Only those commits that carry the user-generated control signals, or any other command that is to be executed by the parallel shell only, would have commit-messages which hold the commands themselves. All other commits have empty commit-messages. Whether the commit is meant for the main shell or the parallel, can therefore be ascertained simply by checking whether the commit-message is empty or not. </span></p><p><span>Such commit-message commands, meant for the parallel shell, are mostly kill(@server) and file-download(@client) commands. Hence, they do not contain any sensitive data and are consequently not encrypted to save on time. These commands are called </span><strong><span>hook</span></strong><span>s. Both server and client share this hook-execution architecture. Hooks are the only way server can make client do some work, such as required during file transfer from server to client.</span></p><p><span>In contrast to SSH, GiBBERISh does not stream every keystroke made by the user to the server in real-time. Rather, it first lets the user enter the complete command, then reads it, checks for keywords, and only then decides what to do. If the command-line is not a keyword, it is pushed to the server as is for execution. To generate signals at server from particular key-sequences entered at the client, key-binding is done at the client-terminal such that it commits and pushes the appropriate hook to be executed by the parallel shell at server, whenever those keys are pressed by the user.</span></p><p><span>The current prompt at the server-side terminal is appended to the text file in the repository below the PGP message block containing the output of Bash@server. When a foreground process is running in that terminal, only a newline is appended instead. Client extracts this appendix to remain informed about the current state of the dynamic server-side prompt, and displays the same at the client-side terminal as required. This feature is strictly designed for adding to the user experience and is in no way a necessary part of the GiBBERISh engine.</span></p><p><a href='https://gist.github.com/SomajitDey/3a438669bd00bdf3b80e4471c2c41a98'><em><span>Strategy to decrease latency</span></em></a></p><p><code>git-push</code><span> is the most obvious way to transfer a file to upstream. However, it is slow (~3s). Using a file-update API, if provided by the upstream host, can make file-transfer faster (~1s). GiBBERISh uses the REST </span><a href='https://docs.github.com/en/rest/reference/repos#create-or-update-file-contents'><span>API</span></a><span> of GitHub for this purpose. The speed up is significant:</span></p><p><span>Using API: 3-4s | Using git-push: 6-9s</span></p><h1><a name="bug-reports-feature-requests-comments" class="md-header-anchor"></a><span>Bug-reports, Feature-requests, Comments</span></h1><p><span>Create issue(s) and comment at </span><a href='https://github.com/SomajitDey/gibberish' target='_blank' class='url'>https://github.com/SomajitDey/gibberish</a></p><p><span>You can also contact me directly at </span><a href='mailto:dey.somajit@gmail.com' target='_blank' class='url'>dey.somajit@gmail.com</a></p><h1><a name="legal" class="md-header-anchor"></a><span>Legal</span></h1><p><a href='https://github.com/SomajitDey/gibberish'><span>GiBBERISh-- Git and Bash Based Encrypted Remote Interactive Shell</span></a></p><p><span>Copyright (C) 2021 </span><a href='https://www.researchgate.net/profile/Somajit-Dey'><span>Somajit Dey</span></a><span>, </span><a href='https://orcid.org/0000-0002-6102-9777'><span>ORCID ID: 0000-0002-6102-9777</span></a></p><p><span>You are free to modify and distribute the code under GPL-3.0-or-later </span><a href='https://www.gnu.org/licenses/' target='_blank' class='url'>https://www.gnu.org/licenses/</a></p><p><em><span>GiBBERISh comes with ABSOLUTELY NO WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Use it at your own risk. The developer or copyright holder won't be liable for any damage done by or done using this software.</span></em></p><h1><a name="acknowledgements" class="md-header-anchor"></a><span>Acknowledgements</span></h1><p><span>Soumalya Bhowmik contributed by testing this software thoroughly.</span></p><p><span>Thanks to </span><a href='https://pbedat.de/'><span>Patrick Bedat</span></a><span> and Seth Kenlon for encouragement and discussions.</span></p><h1><a name="future-directions" class="md-header-anchor"></a><span>Future directions</span></h1><p><a href='https://github.com/SomajitDey/gibberish/projects/1' target='_blank' class='url'>https://github.com/SomajitDey/gibberish/projects/1</a></p><p> </p></div>
</body>
</html>