-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
1112 lines (1086 loc) · 138 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>Random forest</title>
<link>http://sarg.org.ru/index.xml</link>
<description>Recent content on Random forest</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<managingEditor>[email protected] (Sergey Trofimov)</managingEditor>
<webMaster>[email protected] (Sergey Trofimov)</webMaster>
<lastBuildDate>Wed, 15 Mar 2023 00:00:00 +0100</lastBuildDate><atom:link href="http://sarg.org.ru/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Reprovisioning Guix on a new machine</title>
<link>http://sarg.org.ru/blog/guix-restore-drill/</link>
<pubDate>Wed, 15 Mar 2023 00:00:00 +0100</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/guix-restore-drill/</guid>
<description><style>
.src-block-number {
display: none;
}
.src-block-caption {
text-align: center;
}
</style>
<p>No matter how often you backup, if you never test your recovery procedures -
you&rsquo;d be surprised when it comes to it. So let&rsquo;s make a recovery plan and give
it a test.</p>
<h2 id="back-up-user-files">Back up user files</h2>
<p>Having <a href="https://github.com/sarg/dotfiles/blob/483e71b4ecf5aef17a102a31dded84c8697703a8/backup/.config/borgmatic/config.yaml">~/.config/borgmatic/config.yaml</a> in place it&rsquo;s just one command:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>borgmatic create
</span></span></code></pre></div><h2 id="disaster-happens">Disaster happens</h2>
<p>I see two options:</p>
<ol>
<li>I just need to move my digital stuff to a new machine.</li>
<li>I&rsquo;ve lost access to my current machine.</li>
</ol>
<p>Let&rsquo;s follow the first option for now and prepare everything to migrate smoothly.</p>
<h2 id="make-a-raw-disk-image">Make a raw disk image</h2>
<p>That&rsquo;s as simple as running <code>guix system image</code>.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>guix system image --volatile --image-type<span style="color:#666">=</span>efi-raw ~/.dotfiles/guix/system.scm
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>The following derivations will be built:
</span></span><span style="display:flex;"><span> /gnu/store/q0gvw0s79wkjlanfq4yjjyf2f9ddk4iq-disk-image.drv
</span></span><span style="display:flex;"><span> /gnu/store/dp0p01bzgb9aarzx040iv7k5w1r7z5xx-genimage.cfg.drv
</span></span><span style="display:flex;"><span> /gnu/store/kr39hrsyvwp17ny5hcrj6ynfn56i2cq8-partition.img.drv
</span></span><span style="display:flex;"><span> /gnu/store/758yrvd3m7016i5vflzjyg9232j75k2r-system.drv
</span></span><span style="display:flex;"><span> /gnu/store/58xsyrsaqaqh3dsxzb7zc0h72v7ha3as-etc.drv
</span></span><span style="display:flex;"><span> /gnu/store/5kifgf0yqnki7k9wg0a8jlviqibirmxy-activate.scm.drv
</span></span><span style="display:flex;"><span> /gnu/store/rqyl2kcj5q84daw4qriza38l0vkrax0m-activate-service.scm.drv
</span></span><span style="display:flex;"><span> /gnu/store/5lnmmgrgpy58nnkcpy8z22a0kf54yv0k-boot.drv
</span></span><span style="display:flex;"><span> /gnu/store/ri65rz6rgh5kv6ff8g2q313fr9fjd5ac-provenance.drv
</span></span><span style="display:flex;"><span> /gnu/store/z62g9qwy9k65awaaxg2f3jzdadsk5iha-grub.cfg.drv
</span></span><span style="display:flex;"><span> /gnu/store/x1zyd14c5xnpd51ql6bcfdv0q06nla8a-partition.img.drv
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>building /gnu/store/ri65rz6rgh5kv6ff8g2q313fr9fjd5ac-provenance.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/58xsyrsaqaqh3dsxzb7zc0h72v7ha3as-etc.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/rqyl2kcj5q84daw4qriza38l0vkrax0m-activate-service.scm.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/5kifgf0yqnki7k9wg0a8jlviqibirmxy-activate.scm.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/5lnmmgrgpy58nnkcpy8z22a0kf54yv0k-boot.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/758yrvd3m7016i5vflzjyg9232j75k2r-system.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/z62g9qwy9k65awaaxg2f3jzdadsk5iha-grub.cfg.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/kr39hrsyvwp17ny5hcrj6ynfn56i2cq8-partition.img.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/x1zyd14c5xnpd51ql6bcfdv0q06nla8a-partition.img.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/dp0p01bzgb9aarzx040iv7k5w1r7z5xx-genimage.cfg.drv...
</span></span><span style="display:flex;"><span>building /gnu/store/q0gvw0s79wkjlanfq4yjjyf2f9ddk4iq-disk-image.drv...
</span></span></code></pre></div><p>And the disk image is: <code>/gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image</code></p>
<p>Let&rsquo;s check its partition table:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>fdisk -l <span style="color:#b8860b">$disk_image</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>Disk /gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image: 2.32 GiB, 2488737792 bytes, 4860816 sectors
</span></span><span style="display:flex;"><span>Units: sectors of 1 * 512 = 512 bytes
</span></span><span style="display:flex;"><span>Sector size (logical/physical): 512 bytes / 512 bytes
</span></span><span style="display:flex;"><span>I/O size (minimum/optimal): 512 bytes / 512 bytes
</span></span><span style="display:flex;"><span>Disklabel type: gpt
</span></span><span style="display:flex;"><span>Disk identifier: 389B45C2-0EC7-42EC-9D96-49B40F820311
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>Device Start End Sectors Size Type
</span></span><span style="display:flex;"><span>/gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image1 2048 83967 81920 40M EFI System
</span></span><span style="display:flex;"><span>/gnu/store/rj2i98lw7vjj0k48dbwfs0q9aqnd9nxk-disk-image2 83968 4860775 4776808 2.3G Linux filesystem
</span></span></code></pre></div><p>And filesystems labels are:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#a2f">alias</span> <span style="color:#b8860b">kpartx</span><span style="color:#666">=</span><span style="color:#a2f;font-weight:bold">$(</span>guix build multipath-tools<span style="color:#a2f;font-weight:bold">)</span>/sbin/kpartx
</span></span><span style="display:flex;"><span>kpartx -av <span style="color:#b8860b">$disk_image</span> &gt;/dev/null
</span></span><span style="display:flex;"><span>lsblk -o NAME,FSTYPE,FSVER,LABEL,UUID /dev/loop0
</span></span><span style="display:flex;"><span>kpartx -d <span style="color:#b8860b">$disk_image</span>
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>NAME FSTYPE FSVER LABEL UUID
</span></span><span style="display:flex;"><span>loop0
</span></span><span style="display:flex;"><span>|-loop0p1 vfat FAT16 GNU-ESP 572A-DDF3
</span></span><span style="display:flex;"><span>`-loop0p2 ext4 1.0 Guix_image f6bc8ad8-ff1a-1754-eb2b-35d0f6bc8ad8
</span></span></code></pre></div><p>Note that the partition labels chosen by <code>guix system image</code> are not taken from
the <code>operating-system</code> definition. They&rsquo;re hardcoded in the <code>guix</code> sources and
therefore I have to hardcode the same values in my <code>operating-system</code>. Without
matching labels the system would just refuse to boot as they&rsquo;re used in the EFI
loader to find the boot partition and also in the <code>fstab</code>.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>LABEL=Guix_image / ext4 defaults
</span></span><span style="display:flex;"><span>LABEL=GNU-ESP /boot vfat defaults
</span></span></code></pre></div><h2 id="putting-disk-image-on-a-real-machine">Putting disk image on a real machine</h2>
<p>I have a <a href="https://www.ventoy.net/en/index.html">Ventoy</a> USB stick with <a href="https://lubuntu.me/downloads/">Lubuntu Live CD</a> on it. Let&rsquo;s just copy the
resulting image to the stick. Note, you might need to follow this recipe: <a href="https://github.com/ventoy/Ventoy/issues/79">Access
USB stick on live ISO</a> as by default the USB drive will not be accessible.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#a2f">eval</span> <span style="color:#a2f;font-weight:bold">$(</span>lsblk -P -o LABEL,MOUNTPOINT | grep Ventoy<span style="color:#a2f;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span>cp <span style="color:#b8860b">$disk_image</span> <span style="color:#b8860b">$MOUNTPOINT</span>/guixdisk.img
</span></span><span style="display:flex;"><span>eject <span style="color:#b8860b">$MOUNTPOINT</span>
</span></span></code></pre></div><p>And then reboot to the Live CD environment and run the following provisioning script.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>dd /media/lubuntu/Ventoy/guixdisk.img <span style="color:#b8860b">of</span><span style="color:#666">=</span>/dev/sda <span style="color:#b8860b">status</span><span style="color:#666">=</span>progress
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>parted /dev/sda print
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># Warning: Not all of the space available to /dev/sda appears to be used, you</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># can fix the GPT to use all of the space (an extra 346740088 blocks) or</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># continue with the current setting?</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># Fix/Ignore? fix</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>parted -s /dev/sda resizepart <span style="color:#666">2</span> 100%
</span></span><span style="display:flex;"><span>fsck -y -f /dev/sda2
</span></span><span style="display:flex;"><span>resize2fs /dev/sda2
</span></span></code></pre></div><div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>reboot
</span></span></code></pre></div><h2 id="restoring-backup">Restoring backup</h2>
<p>Log in as root (password is empty)</p>
<p><code>borgmatic</code> and <code>borg</code> are baked in the disk image, use it to restore <code>/storage</code></p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>mkdir -m <span style="color:#666">0700</span> /storage <span style="color:#666">&amp;&amp;</span> chown sarg:users /storage
</span></span><span style="display:flex;"><span>mount /dev/sdb1 /mnt
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">cd</span> /
</span></span><span style="display:flex;"><span><span style="color:#b8860b">latest</span><span style="color:#666">=</span><span style="color:#a2f;font-weight:bold">$(</span>borg list --last <span style="color:#666">1</span> --short /mnt<span style="color:#a2f;font-weight:bold">)</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># borg manual recommends using the same user which made the backup</span>
</span></span><span style="display:flex;"><span>su sarg -c <span style="color:#b44">&#34;borg extract /mnt::</span><span style="color:#b8860b">$latest</span><span style="color:#b44">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">exit</span>
</span></span></code></pre></div><h2 id="revitalising-guix">Revitalising Guix</h2>
<p><code>guix-home</code> profile is already in the image and it&rsquo;s activated using a one-off
shepherd service. It takes some time, so don&rsquo;t rush to log in under your user.
Check <code>herd status guix-home-sarg</code> first and <code>/var/log/messages</code>.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span><span style="color:#a2f">echo</span> <span style="color:#b44">&#34;Wait guix-home-sarg to complete&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">until</span> herd status guix-home-sarg | grep <span style="color:#b44">&#39;It is stopped&#39;</span>; <span style="color:#a2f;font-weight:bold">do</span> <span style="color:#a2f">echo</span> -n .; sleep 1; <span style="color:#a2f;font-weight:bold">done</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>passwd root
</span></span><span style="display:flex;"><span>passwd sarg
</span></span><span style="display:flex;"><span>login sarg
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">cd</span> /storage/devel/dotfiles/guix
</span></span><span style="display:flex;"><span>guix pull -C /run/current-system/channels.scm
</span></span><span style="display:flex;"><span>sudo guix system reconfigure system.scm
</span></span><span style="display:flex;"><span>guix home reconfigure home.scm
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># app-specific restore commands</span>
</span></span><span style="display:flex;"><span>doom sync
</span></span><span style="display:flex;"><span>mu init -m ~/.mail
</span></span><span style="display:flex;"><span>mu index
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">logout</span> <span style="color:#080;font-style:italic"># sarg</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">logout</span> <span style="color:#080;font-style:italic"># root</span>
</span></span></code></pre></div></description>
</item>
<item>
<title>wpa-manager.el and torrent-mode.el</title>
<link>http://sarg.org.ru/blog/wifi-and-torrent/</link>
<pubDate>Sun, 12 Mar 2023 00:00:00 +0100</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/wifi-and-torrent/</guid>
<description><p>There is a nice <a href="https://elpa.gnu.org/packages/bluetooth.html">bluetooth-mode</a> to scan and connect to bluetooth devices, but no
such mode for wifi. It&rsquo;s time to fix that. I&rsquo;ve started implementing <a href="https://github.com/sarg/wpa-manager.el">wpa-manager</a>
which controls <a href="https://w1.fi/wpa_supplicant/">wpa_supplicant</a> over its D-Bus interface. Currently the manager
supports scanning and connecting using WPA PSK. It already solves most of my
use cases.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span>SSID BSSID Freq Signal▼
</span></span><span style="display:flex;"><span>SARG 5B:32:C6:8F:55:03 5180 -47
</span></span><span style="display:flex;"><span>FRITZ!Box 7362 SL 7D:3D:12:D4:C1:1C 2417 -53
</span></span><span style="display:flex;"><span>ZYXEL-795 65:18:77:8E:6B:0C 2412 -56
</span></span><span style="display:flex;"><span>WLAN-123488 27:49:1B:71:5D:F7 2412 -62
</span></span><span style="display:flex;"><span>FRITZ!Box 7530 IG F0:B4:4A:AB:B4:9F 2462 -63
</span></span><span style="display:flex;"><span>WLAN-WWAAAB 83:F9:C3:23:C1:1C 2462 -65
</span></span><span style="display:flex;"><span>FRITZ!Box 7430 DR 63:E7:BC:09:16:C0 2462 -73
</span></span><span style="display:flex;"><span>WLAN-123488 B2:8A:27:3B:C7:39 5500 -75
</span></span></code></pre></div><p>Another package is <a href="https://github.com/sarg/torrent-mode.el">torrent-mode</a> which provides a tabulated view of a torrent
file content. An example of how it looks like.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span> Idx ▼Size Name
</span></span><span style="display:flex;"><span> 000 2.1k dumpruninfo.txt
</span></span><span style="display:flex;"><span> 001 4.8G enwiki-20170220-abstract.xml
</span></span><span style="display:flex;"><span> 002 741M enwiki-20170220-abstract1.xml
</span></span><span style="display:flex;"><span> 003 353M enwiki-20170220-abstract2.xml
</span></span><span style="display:flex;"><span> 004 259M enwiki-20170220-abstract3.xml
</span></span><span style="display:flex;"><span> 005 202M enwiki-20170220-abstract4.xml
</span></span><span style="display:flex;"><span>* 006 168M enwiki-20170220-abstract5.xml
</span></span><span style="display:flex;"><span>* 007 161M enwiki-20170220-abstract6.xml
</span></span><span style="display:flex;"><span>* 008 183M enwiki-20170220-abstract7.xml
</span></span><span style="display:flex;"><span>* 009 161M enwiki-20170220-abstract8.xml
</span></span><span style="display:flex;"><span>* 010 133M enwiki-20170220-abstract9.xml
</span></span></code></pre></div><p>This mode supports selecting individual files which could then be fed into <a href="https://github.com/ukaszg/aria2">aria2</a>
using a small defun:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elisp" data-lang="elisp"><span style="display:flex;"><span>(<span style="color:#a2f">defun</span> <span style="color:#b8860b">torrent-mode-download-selected</span> (<span style="color:#b8860b">dest-dir</span>)
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Download ARG entries.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">interactive</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">list</span> (<span style="color:#b8860b">read-directory-name</span>
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Directory: &#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">or</span> (<span style="color:#b8860b">dired-dwim-target-directory</span>)
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">aria2-download-directory</span>)
</span></span><span style="display:flex;"><span> <span style="color:#800">nil</span>
</span></span><span style="display:flex;"><span> <span style="color:#800">t</span>))
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">&#39;torrent-mode</span>)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic">;; aria2.addTorrent([secret, ]torrent[, uris[, options[, position]]])</span>
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">make-request</span>
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">aria2--cc</span> <span style="color:#b44">&#34;aria2.addTorrent&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">aria2--base64-encode-file</span> <span style="color:#00a000">buffer-file-name</span>)
</span></span><span style="display:flex;"><span> []
</span></span><span style="display:flex;"><span> <span style="color:#666">`</span>(<span style="color:#a2f">:select-file</span> <span style="color:#666">,</span>(<span style="color:#b8860b">seq-map</span> <span style="color:#00a000">#&#39;car</span> (<span style="color:#b8860b">tablist-get-marked-items</span>))
</span></span><span style="display:flex;"><span> <span style="color:#a2f">:dir</span> <span style="color:#666">,</span>(<span style="color:#00a000">expand-file-name</span> <span style="color:#b8860b">dest-dir</span>))))
</span></span></code></pre></div></description>
</item>
<item>
<title>Making org-mode movie diary</title>
<link>http://sarg.org.ru/blog/org-watchlist/</link>
<pubDate>Sun, 05 Mar 2023 00:00:00 +0100</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/org-watchlist/</guid>
<description><p>End result is here: <a href="http://sarg.org.ru/movies/">Movies</a></p>
<h2 id="putting-it-in-org-mode">Putting it in org-mode</h2>
<p>Small demo of my flow:</p>
<p><video controls><source src="http://sarg.org.ru/ox-hugo/demo-org-movies.mp4" type="video/mp4">
Your browser does not support the video tag.</video></p>
<p>File organisation:</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-org" data-lang="org"><span style="display:flex;"><span><span style="color:#080;font-weight:bold">#+STARTUP</span><span style="color:#080;font-style:italic">: logdrawer</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-weight:bold">#+TODO</span><span style="color:#080;font-style:italic">: TODO(t) NEXT(n) | DONE(d!) DROPPED(c@)</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#000080;font-weight:bold">*</span><span style="color:#b68"> DONE</span><span style="font-weight:bold"> La Jetée (1962) :romance:scifi:</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080;font-weight:bold">:rating: 4
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-weight:bold">:imdb: tt0056119
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-weight:bold"></span><span style="color:#080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">:LOGBOOK:
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080;font-weight:bold">- State &#34;DONE&#34; from [2022-07-11 Mon]
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-weight:bold"></span><span style="color:#080;font-style:italic">:END:</span>
</span></span><span style="display:flex;"><span><span style="color:#000080;font-weight:bold">*</span><span style="font-weight:bold"> Watch List [0/1]</span>
</span></span><span style="display:flex;"><span><span style="color:#800080;font-weight:bold">**</span><span style=""> TODO</span> Big Buck Bunny (2008) :animation:short:comedy:
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic">:PROPERTIES:
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"></span><span style="color:#080;font-weight:bold">:imdb: tt1254207
</span></span></span><span style="display:flex;"><span><span style="color:#080;font-weight:bold"></span><span style="color:#080;font-style:italic">:END:</span>
</span></span></code></pre></div><p>And here is a minor mode to automate inserting new entries.</p>
<p><a id="code-snippet--api"></a></p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elisp" data-lang="elisp"><span style="display:flex;"><span>(<span style="color:#a2f">define-minor-mode</span> <span style="color:#b8860b">org-movies-mode</span>
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Helper functions for movies.org&#34;</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f">:keymap</span> (<span style="color:#00a000">list</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">cons</span> (<span style="color:#b8860b">kbd</span> <span style="color:#b44">&#34;C-c C-i&#34;</span>) <span style="color:#00a000">#&#39;</span><span style="color:#b8860b">org-movies-template</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">cons</span> (<span style="color:#b8860b">kbd</span> <span style="color:#b44">&#34;C-c C-o&#34;</span>) <span style="color:#00a000">#&#39;</span><span style="color:#b8860b">org-movies-open-letterboxd</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#a2f">defun</span> <span style="color:#b8860b">org-movies-open-letterboxd</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Open letterboxd for current entry.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">interactive</span> <span style="color:#800">nil</span> <span style="color:#b8860b">&#39;org-movies-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">browse-url</span> (<span style="color:#00a000">format</span> <span style="color:#b44">&#34;https://letterboxd.com/imdb/%s&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">cdar</span> (<span style="color:#b8860b">org-entry-properties</span> <span style="color:#800">nil</span> <span style="color:#b44">&#34;imdb&#34;</span>)))))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#a2f">defun</span> <span style="color:#b8860b">org-movies-template</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Convert imdb url at point to a diary entry.&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">interactive</span> <span style="color:#800">nil</span> <span style="color:#b8860b">&#39;org-movies-mode</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">let*</span> ((<span style="color:#b8860b">ctx</span> (<span style="color:#b8860b">org-element-context</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">link</span> (<span style="color:#a2f">if</span> (<span style="color:#00a000">eq</span> (<span style="color:#00a000">car</span> <span style="color:#b8860b">ctx</span>) <span style="color:#b8860b">&#39;link</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">plist-get</span> (<span style="color:#b8860b">cadr</span> <span style="color:#b8860b">ctx</span>) <span style="color:#a2f">:raw-link</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#b44">&#34;Not an org link&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">imdb</span> (<span style="color:#a2f">or</span> (<span style="color:#00a000">nth</span> <span style="color:#666">1</span> (<span style="color:#b8860b">s-match</span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">rx</span> <span style="color:#b44">&#34;imdb.com/title/&#34;</span> (<span style="color:#b8860b">group</span> <span style="color:#b44">&#34;tt&#34;</span> (<span style="color:#00a000">+</span> <span style="color:#b8860b">digit</span>)))
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">link</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#d2413a;font-weight:bold">error</span> <span style="color:#b44">&#34;Not an imdb link&#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">apikey</span> (<span style="color:#b8860b">auth-source-pass-get</span> <span style="color:#b8860b">&#39;secret</span> <span style="color:#b44">&#34;Sites/omdbapi.com&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">movie</span> (<span style="color:#a2f">with-current-buffer</span>
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">url-retrieve-synchronously</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">concat</span> <span style="color:#b44">&#34;http://omdbapi.com/?apikey=&#34;</span> <span style="color:#b8860b">apikey</span> <span style="color:#b44">&#34;&amp;i=&#34;</span> <span style="color:#b8860b">imdb</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">goto-char</span> <span style="color:#b8860b">url-http-end-of-headers</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">json-read-from-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">decode-coding-string</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">buffer-substring</span> (<span style="color:#00a000">point</span>) (<span style="color:#00a000">point-max</span>)) <span style="color:#b8860b">&#39;utf-8</span>))))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">genres-str</span> (<span style="color:#b8860b">alist-get</span> <span style="color:#b44">&#34;Genre&#34;</span> <span style="color:#b8860b">movie</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00a000">#&#39;</span><span style="color:#b8860b">string=</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">genres</span> (<span style="color:#b8860b">-map</span> (<span style="color:#a2f">lambda</span> (<span style="color:#b8860b">el</span>) (<span style="color:#00a000">downcase</span> (<span style="color:#b8860b">s-replace</span> <span style="color:#b44">&#34;-&#34;</span> <span style="color:#b44">&#34;&#34;</span> <span style="color:#b8860b">el</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">string-split</span> <span style="color:#b8860b">genres-str</span> <span style="color:#b44">&#34;, &#34;</span>)))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">title</span> (<span style="color:#b8860b">alist-get</span> <span style="color:#b44">&#34;Title&#34;</span> <span style="color:#b8860b">movie</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00a000">#&#39;</span><span style="color:#b8860b">string=</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">year</span> (<span style="color:#b8860b">alist-get</span> <span style="color:#b44">&#34;Year&#34;</span> <span style="color:#b8860b">movie</span> <span style="color:#800">nil</span> <span style="color:#800">nil</span> <span style="color:#00a000">#&#39;</span><span style="color:#b8860b">string=</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#a2f">pcase</span> (<span style="color:#b8860b">org-element-type</span> (<span style="color:#b8860b">org-element-at-point</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">&#39;headline</span> (<span style="color:#b8860b">ignore</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">_</span> (<span style="color:#00a000">beginning-of-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">kill-line</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">org-insert-heading</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">org-edit-headline</span> (<span style="color:#00a000">concat</span> <span style="color:#b8860b">title</span> <span style="color:#b44">&#34; (&#34;</span> <span style="color:#b8860b">year</span> <span style="color:#b44">&#34;)&#34;</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">org-set-tags</span> <span style="color:#b8860b">genres</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">org-todo</span> <span style="color:#b44">&#34;TODO&#34;</span>)
</span></span><span style="display:flex;"><span> (<span style="color:#b8860b">org-set-property</span> <span style="color:#b44">&#34;imdb&#34;</span> <span style="color:#b8860b">imdb</span>)))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#b8860b">org-movies-mode</span> <span style="color:#666">1</span>)
</span></span></code></pre></div><div class="src-block-caption">
<span class="src-block-number"><a href="#code-snippet--api">Code Snippet 1</a>:</span>
Minor mode with useful helpers
</div>
<!--more-->
<h2 id="letterboxd-export">Letterboxd export</h2>
<p>I&rsquo;ve fallen into this trap again&hellip; I&rsquo;ve relied on a 3rd party website to manage
my data. Yes, it looks good and it&rsquo;s UX friendly, it&rsquo;s easy to fall prey. This
time it was <a href="https://letterboxd.com">Letterboxd</a>. I imported my <a href="https://themoviedb.org">TheMovieDB</a> watchlist there and used it as
a film diary for a couple of years. One day I finally found some time to sort my
movie collection with <a href="https://www.tinymediamanager.org">tinyMediaManager</a> and the icing on the cake was to add my
ratings to the NFO files. To my disappointment, Letterboxd doesn&rsquo;t include the
imdb id in the export files, so I had to write a script to fetch all their short
urls one by one and extract the imdb ids from the html.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">re</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">requests</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">fileinput</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#080;font-style:italic"># takes file with https://boxd.it/71O short links</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">for</span> row <span style="color:#a2f;font-weight:bold">in</span> fileinput<span style="color:#666">.</span>input():
</span></span><span style="display:flex;"><span> row <span style="color:#666">=</span> row<span style="color:#666">.</span>strip()
</span></span><span style="display:flex;"><span> d <span style="color:#666">=</span> requests<span style="color:#666">.</span>get(row)
</span></span><span style="display:flex;"><span> imdb <span style="color:#666">=</span> re<span style="color:#666">.</span>findall(<span style="color:#b44">&#39;(?&lt;=imdb.com/title/)tt[^/]+&#39;</span>, d<span style="color:#666">.</span>text)[<span style="color:#666">0</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a2f">print</span>(row, imdb, sep<span style="color:#666">=</span><span style="color:#b44">&#39;,&#39;</span>, flush<span style="color:#666">=</span><span style="color:#a2f;font-weight:bold">True</span>)
</span></span></code></pre></div><h2 id="importing-ratings-in-nfo-files">Importing ratings in NFO files</h2>
<p>Then another script to put the ratings in the NFO files.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">re</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">sys</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">csv</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">glob</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>r <span style="color:#666">=</span> csv<span style="color:#666">.</span>reader(<span style="color:#a2f">open</span>(<span style="color:#b44">&#34;/home/sarg/rated.csv&#34;</span>))
</span></span><span style="display:flex;"><span>rates <span style="color:#666">=</span> {}
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">for</span> n <span style="color:#a2f;font-weight:bold">in</span> glob<span style="color:#666">.</span>glob(<span style="color:#b44">&#39;/media/sarg/2TB/Movies/**/**/*.nfo&#39;</span>):
</span></span><span style="display:flex;"><span> imdb <span style="color:#666">=</span> re<span style="color:#666">.</span>findall(<span style="color:#b44">&#39;(?&lt;=&lt;id&gt;)tt\d+&#39;</span>, <span style="color:#a2f">open</span>(n)<span style="color:#666">.</span>read())[<span style="color:#666">0</span>]
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> imdb <span style="color:#a2f;font-weight:bold">in</span> rates:
</span></span><span style="display:flex;"><span> rates<span style="color:#666">.</span>pop(imdb)
</span></span><span style="display:flex;"><span> d <span style="color:#666">=</span> re<span style="color:#666">.</span>sub(<span style="color:#b44">&#39;&lt;userrating&gt;0.0&#39;</span>, <span style="color:#b44">&#39;&lt;userrating&gt;&#39;</span> <span style="color:#666">+</span> <span style="color:#a2f">str</span>(rates[imdb]), d)
</span></span><span style="display:flex;"><span> f <span style="color:#666">=</span> <span style="color:#a2f">open</span>(n <span style="color:#666">+</span> <span style="color:#b44">&#39;.new&#39;</span>, <span style="color:#b44">&#39;w&#39;</span>)
</span></span><span style="display:flex;"><span> f<span style="color:#666">.</span>write(d)
</span></span><span style="display:flex;"><span> f<span style="color:#666">.</span>close()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">print</span>(<span style="color:#b44">&#34;High rated movies I don&#39;t have:&#34;</span>)
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">for</span> imdb <span style="color:#a2f;font-weight:bold">in</span> rates:
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> rates[imdb]<span style="color:#666">&gt;</span><span style="color:#666">7</span>:
</span></span><span style="display:flex;"><span> <span style="color:#a2f">print</span>(<span style="color:#b44">f</span><span style="color:#b44">&#34;https://imdb.com/title/</span><span style="color:#b68;font-weight:bold">{</span>imdb<span style="color:#b68;font-weight:bold">}</span><span style="color:#b44">&#34;</span>)
</span></span></code></pre></div></description>
</item>
<item>
<title>Exporting Liked Videos from Youtube</title>
<link>http://sarg.org.ru/blog/export-youtube-liked/</link>
<pubDate>Sun, 26 Feb 2023 00:00:00 +0100</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/export-youtube-liked/</guid>
<description><p>Over the years I&rsquo;ve collected ~300 favourite videos and unfortunately some of
them have been taken down. I have spent some time re-watching the old videos and
still enjoy them. Few are just for laughs, some are educational and others are
just art. As there are not too many of them, I can just download them all to my
archives. 14 videos that were missing on Youtube I&rsquo;ve recovered from
<a href="https://web.archive.org">https://web.archive.org</a></p>
<p>The resulting archive weighs in at just 13G, so it really is a no-brainer to keep it offline.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#080;font-style:italic"># https://gist.github.com/guidocella/a272b6e68f9c44532b011f6596e95c61</span>
</span></span><span style="display:flex;"><span><span style="color:#666">{</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f">echo</span> <span style="color:#b44">&#39;# Netscape HTTP Cookie File&#39;</span> <span style="color:#080;font-style:italic"># needed by youtube-dl</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#b8860b">QUERY</span><span style="color:#666">=</span><span style="color:#b44">&#34;SELECT
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> host_key,
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> IIF(host_key LIKE &#39;.%&#39;, &#39;TRUE&#39;, &#39;FALSE&#39;),
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> path,
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> IIF(is_secure, &#39;TRUE&#39;, &#39;FALSE&#39;),
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> IIF(expires_utc == 0, 0, expires_utc / 1000000 - 11644473600),
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> name,
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> value
</span></span></span><span style="display:flex;"><span><span style="color:#b44"> FROM cookies;&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic"># There is no attempt to url encode $1, but SQLite already handles</span>
</span></span><span style="display:flex;"><span> <span style="color:#080;font-style:italic"># characters like spaces, so only ? % and # should cause issues.</span>
</span></span><span style="display:flex;"><span> sqlite3 -readonly -separator <span style="color:#b44">$&#39;\t&#39;</span> <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> <span style="color:#b44">&#34;file:</span><span style="color:#b68;font-weight:bold">${</span><span style="color:#b8860b">1</span><span style="color:#a2f;font-weight:bold">:-</span><span style="color:#b8860b">$HOME</span>/.local/share/qutebrowser<span style="color:#b68;font-weight:bold">}</span><span style="color:#b44">/webengine/Cookies?nolock=1&#34;</span> <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> <span style="color:#b44">&#34;</span><span style="color:#b8860b">$QUERY</span><span style="color:#b44">&#34;</span>
</span></span><span style="display:flex;"><span><span style="color:#666">}</span> &gt; cookies.txt
</span></span></code></pre></div><div class="src-block-caption">
<span class="src-block-number">Code Snippet 1:</span>
Export <code>qutebrowser</code> cookies for <code>yt-dlp</code>
</div>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>yt-dlp --ignore-errors <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> --download-archive archive.txt <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> --cookies cookies.txt <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> <span style="color:#b44">&#39;https://www.youtube.com/playlist?list=LL&#39;</span>
</span></span></code></pre></div><div class="src-block-caption">
<span class="src-block-number">Code Snippet 2:</span>
Download everything from the Liked Videos playlist
</div>
</description>
</item>
<item>
<title>📖 Cracking The Code To A Successful Interview</title>
<link>http://sarg.org.ru/blog/cracking-interview/</link>
<pubDate>Thu, 28 May 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/cracking-interview/</guid>
<description><p><a href="https://www.goodreads.com/book/show/32794226-cracking-the-code-to-a-successful-interview">Goodreads</a> - 3/5.</p>
<p>First impression:
Overall the tone of the book is slightly arrogant. The author&rsquo;s ego is soaking from every page.</p>
<p>After the read:
The book is best suited for a sales position in corporate America.
Overall the message of the book is: <strong>Be prepared, know what&rsquo;s expected of you and give it to the inverviewer in advance.</strong>
In chapter 9 there is a summary of REAPRICH method. Chapter 10-12,15 are unrelated to hiring process.</p>
<h2 id="chapter-1-dot">Chapter 1.</h2>
<p>Hiring managers could be of 4 types:</p>
<ul>
<li>the power tripper - tries to prove his own intellectual prowess</li>
<li>the defensive crouhcer - feels unsafe with poeple they fear could do their jobs better</li>
<li>method man - follows script and expects valid answers</li>
<li>rogue agent - not fitting in 3 types above, dark horse</li>
</ul>
<p>REAPRICH - 8 step plan to win the interview.
results / energy / attitude / process / relationships / interview the interviewer / close the interviewer / humanity</p>
<h2 id="chapter-2">Chapter 2</h2>
<ul>
<li>research the company</li>
<li>polish resume</li>
<li>be tenacious</li>
</ul>
<p>On the day of interview - be on time, dress well, shine your shoes, bring hard copy of your resume, give a firm handshake, look into the eye.</p>
<p>Don&rsquo;t discuss personal problems, family, bad experiences with past employers.</p>
<h2 id="chapter-3-dot-rea">Chapter 3. REA</h2>
<p>Be enthusiastic (E - energy) and have positive A (attitude).</p>
<h2 id="chapter-4-dot-p-spotlight-on-creativity">Chapter 4. P - Spotlight on creativity</h2>
<p>You’re in great shape if the manager ends up saying, “I want you on board so you can do this for me or my team. I want this to be a part of our skill set and our arsenal as we move forward as an organization.”</p>
<h2 id="chapter-5-dot-r-relationships">Chapter 5. R - Relationships</h2>
<p>One of the biggest fears of hiring managers is having a personality conflict on their team. Showing that you have the ability to create and maintain relationships alleviates this fear.</p>
<p>Exercise:
Write down two long-term relationships such as bosses, coaches, mentors, or friends (one which affected your career). Answer the following questions in writing for each: How did you secure this relationship? Was it through performance? How did this person become interested in you? How did he or she see positive qualities in you? How did you build and nurture this connection?</p>
<h2 id="chapter-6-dot-i-interview-the-interviewer">Chapter 6. I - interview the interviewer</h2>
<p>Ask something that you can&rsquo;t find in public sources.</p>
<ul>
<li>Tell me about some of your most successful people. What’s made them great?</li>
<li>How can I help your team? What is the best way my skills could add value?</li>
<li>If you hired me today, what would you have me help you and your team with in the first three months?</li>
</ul>
<h2 id="chapter-7-dot-close-the-interview">Chapter 7. Close the interview</h2>
<p>Like in sales - try to close the deal.</p>
<h2 id="chapter-8-dot-humanity">Chapter 8. Humanity</h2>
<p>Small talk in the end. Author suggests to directly ask if you&rsquo;re recommended for hire.</p>
<h2 id="chapter-9-dot-recap-dot">Chapter 9. Recap.</h2>
<p>The most successful interview candidates aren’t necessarily the most experienced, the most educated, or the most qualified for the job. They are the best prepared.</p>
<h2 id="chapter-14-dot-tough-questions">Chapter 14. Tough questions</h2>
<ol>
<li>Who are you?</li>
<li>Why should I hire you?</li>
<li>Give an example of a time you tried your best and failed.</li>
<li>Who was the worst boss (or employee) you ever worked with?</li>
<li>What four words would someone close to you use to describe you?</li>
<li>Who was your best mentor?</li>
<li>What do you feel you will bring to this organization?</li>
<li>Where do you want to be in five years?</li>
<li>What is your greatest weakness?</li>
<li>What is your ninety-day plan to be successful here?</li>
<li>Give me an example of where you took a difficult customer or situation and turned it into a win.</li>
</ol>
</description>
</item>
<item>
<title>📖 Growing Object-Oriented Softwared, Guided by Tests.</title>
<link>http://sarg.org.ru/blog/tdd-freeman/</link>
<pubDate>Tue, 19 May 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/tdd-freeman/</guid>
<description><p>I&rsquo;ve finished reading <a href="https://www.goodreads.com/book/show/4268826-growing-object-oriented-software-guided-by-tests">Growing Object-Oriented Softwared, Guided by Tests</a> by
Steve Freeman and Nat Pryce. The book is a good introduction into TDD. First it
goes through core concepts and then demonstrates how to implement TDD on a simple project.</p>
<p>My takeouts throughout the reading:</p>
<ul>
<li>TDD is a core practice of XP. TDD is not about keeping defects from the users, but helping the team to understand the features and to deliver them reliably and predictably.</li>
<li>Making code accessible for testing often drives it towards being cleaner and more modular.</li>
<li>TDD cycle: red/green/refactor</li>
<li>Different kinds of tests:
<ul>
<li><strong>acceptance</strong> - exercises the functionality we want to build. Does the whole system work? Whenever possible should be end-to-end without directly calling internal code.</li>
<li><strong>integration</strong> - does our code work against code we can&rsquo;t change?</li>
<li><strong>unit</strong> - do our objects do the right thing, are they convenient to work with?</li>
</ul>
</li>
<li>External/internal quality: customer facing or developer/admin facing</li>
<li>OOP focuses more on the communication between objects than on the objects themselves. An object has a method of handling every type of message that it understands and in encapsulates some internal state.</li>
<li>Objects could have different semantics:<br />
<ul>
<li><strong>values</strong> model unchanging quantities</li>
<li><strong>objects</strong> have identity that may change over time and model computational process</li>
</ul>
</li>
</ul>
<p>TDD best practices:</p>
<ul>
<li>First make a minimal &ldquo;skeleton&rdquo; of an app and set up deployment infrastructure. E.g. for a web app it would be a one page site which shows a field in database.</li>
<li>Develop from outer boundary. E.g. write end-to-end acceptance test and start unrolling the logic from the incoming external message.</li>
<li>The development cycle goes like this. When implementing an object, we discover that it needs a service to be provided by another object. We give the new service a name and mock it out in the client object’s unit tests, to clarify the relationship between the two. Then we write an object to provide that service and, in doing so, discover what services that object needs. We follow this chain (or perhaps a directed graph) of collaborator relationships until we connect up to existing objects, either our own or from a third-party API. We think of this as “on-demand” design: we “pull” interfaces and their implementations into existence from the needs of the client, rather than “pushing” out the features that we think a class should provide.</li>
</ul>
</description>
</item>
<item>
<title>Exporting watch list from TMDb</title>
<link>http://sarg.org.ru/blog/tmdb-export/</link>
<pubDate>Sun, 26 Apr 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/tmdb-export/</guid>
<description><p>I keep list of movies I&rsquo;ve watched on <a href="https://www.themoviedb.org/u/sarg/ratings">TheMovieDB</a>. The service is great and I&rsquo;ve
used it for quite a long time (&gt;700 movies in my list). I was using another
service before, which unfortunately had closed without giving me a chance to
export the data and I had to scrape my watchlist from the google cache.</p>
<p>To prevent that from happening again, I&rsquo;ve exported my watchlist from TMDb and
will use the service only as a secondary source with a nice UI.</p>
<p>TMDb has a decent API and there are several python wrappers for it. The script
for export is pretty straightforward. Retrieve <code>request_token</code>, open a session
(login) for your account and retrieve the list of rated movies from a paginated
endpoint.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">tmdbsimple</span> <span style="color:#a2f;font-weight:bold">as</span> <span style="color:#00f;font-weight:bold">tmdb</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">json</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">subprocess</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>tmdb<span style="color:#666">.</span>API_KEY <span style="color:#666">=</span> <span style="color:#b44">&#34;bafca4e813ca8fc43b3c9f1e32d1932b&#34;</span>
</span></span><span style="display:flex;"><span>res <span style="color:#666">=</span> subprocess<span style="color:#666">.</span>run(
</span></span><span style="display:flex;"><span> [<span style="color:#b44">&#34;pass&#34;</span>, <span style="color:#b44">&#34;show&#34;</span>, <span style="color:#b44">&#34;Sites/themoviedb.org&#34;</span>], capture_output<span style="color:#666">=</span><span style="color:#a2f;font-weight:bold">True</span>, check<span style="color:#666">=</span><span style="color:#a2f;font-weight:bold">True</span>
</span></span><span style="display:flex;"><span>)
</span></span><span style="display:flex;"><span>password <span style="color:#666">=</span> res<span style="color:#666">.</span>stdout<span style="color:#666">.</span>splitlines()[<span style="color:#666">0</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>auth <span style="color:#666">=</span> tmdb<span style="color:#666">.</span>Authentication()
</span></span><span style="display:flex;"><span>token <span style="color:#666">=</span> auth<span style="color:#666">.</span>token_new()[<span style="color:#b44">&#34;request_token&#34;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>auth<span style="color:#666">.</span>token_validate_with_login(request_token<span style="color:#666">=</span>token, username<span style="color:#666">=</span><span style="color:#b44">&#34;sarg&#34;</span>, password<span style="color:#666">=</span>password)
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>session_id <span style="color:#666">=</span> auth<span style="color:#666">.</span>session_new(request_token<span style="color:#666">=</span>token)[<span style="color:#b44">&#34;session_id&#34;</span>]
</span></span><span style="display:flex;"><span>acc <span style="color:#666">=</span> tmdb<span style="color:#666">.</span>Account(session_id)
</span></span><span style="display:flex;"><span>acc<span style="color:#666">.</span>info()
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>movies <span style="color:#666">=</span> []
</span></span><span style="display:flex;"><span>idx <span style="color:#666">=</span> <span style="color:#666">1</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">while</span> <span style="color:#a2f;font-weight:bold">True</span>:
</span></span><span style="display:flex;"><span> res <span style="color:#666">=</span> acc<span style="color:#666">.</span>rated_movies(page<span style="color:#666">=</span>idx)
</span></span><span style="display:flex;"><span> movies <span style="color:#666">=</span> movies <span style="color:#666">+</span> res[<span style="color:#b44">&#34;results&#34;</span>]
</span></span><span style="display:flex;"><span> idx <span style="color:#666">=</span> idx <span style="color:#666">+</span> <span style="color:#666">1</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> idx <span style="color:#666">&gt;</span> res[<span style="color:#b44">&#34;total_pages&#34;</span>]:
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>idx <span style="color:#666">=</span> <span style="color:#666">1</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">while</span> <span style="color:#a2f;font-weight:bold">True</span>:
</span></span><span style="display:flex;"><span> res <span style="color:#666">=</span> acc<span style="color:#666">.</span>watchlist_movies(page<span style="color:#666">=</span>idx)
</span></span><span style="display:flex;"><span> movies <span style="color:#666">=</span> movies <span style="color:#666">+</span> res[<span style="color:#b44">&#34;results&#34;</span>]
</span></span><span style="display:flex;"><span> idx <span style="color:#666">=</span> idx <span style="color:#666">+</span> <span style="color:#666">1</span>
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> idx <span style="color:#666">&gt;</span> res[<span style="color:#b44">&#34;total_pages&#34;</span>]:
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">break</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">print</span>(json<span style="color:#666">.</span>dumps(movies, indent<span style="color:#666">=</span><span style="color:#666">2</span>))
</span></span></code></pre></div><p>Unfortunately TMDb does not expose <code>Rated Date</code> via API. It could be extracted
from the CSV export though. Request the CSV export on the &ldquo;My Ratings&rdquo;
page (under three dots icon). It would be sent by email. Download the file and
use the following script to merge the json and csv.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-python" data-lang="python"><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">csv</span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">import</span> <span style="color:#00f;font-weight:bold">json</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>rates <span style="color:#666">=</span> { row[<span style="color:#b44">&#34;TMDb ID&#34;</span>]: row <span style="color:#a2f;font-weight:bold">for</span> row <span style="color:#a2f;font-weight:bold">in</span> csv<span style="color:#666">.</span>DictReader(<span style="color:#a2f">open</span>(<span style="color:#b44">&#34;ratings.csv&#34;</span>)) }
</span></span><span style="display:flex;"><span>films <span style="color:#666">=</span> json<span style="color:#666">.</span>load(<span style="color:#a2f">open</span>(<span style="color:#b44">&#34;movies.json&#34;</span>))
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f;font-weight:bold">for</span> film <span style="color:#a2f;font-weight:bold">in</span> films:
</span></span><span style="display:flex;"><span> <span style="color:#a2f;font-weight:bold">if</span> <span style="color:#a2f">str</span>(film[<span style="color:#b44">&#39;id&#39;</span>]) <span style="color:#a2f;font-weight:bold">in</span> rates:
</span></span><span style="display:flex;"><span> film[<span style="color:#b44">&#39;rated_date&#39;</span>] <span style="color:#666">=</span> rates[<span style="color:#a2f">str</span>(film[<span style="color:#b44">&#39;id&#39;</span>])][<span style="color:#b44">&#39;Date Rated&#39;</span>]
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#a2f">print</span>(json<span style="color:#666">.</span>dumps(films, indent<span style="color:#666">=</span><span style="color:#666">2</span>))
</span></span></code></pre></div></description>
</item>
<item>
<title>Android apps that I use</title>
<link>http://sarg.org.ru/blog/android-apps/</link>
<pubDate>Fri, 24 Apr 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/android-apps/</guid>
<description><p>My phone is running <a href="https://github.com/phhusson/treble_experimentations">AOSP</a> without google services and almost all of the
applications I use come from <a href="https://f-droid.org">F-Droid</a>. Few exceptions are the apps for paid
services that I use and they are installed from Aurora Store.</p>
<ul>
<li>I use <a href="https://github.com/mvdan/fdroidcl">fdroidcl</a> to install and update applications.</li>
<li>Backup is covered in the post &ldquo;<a href="http://sarg.org.ru/blog/android-backup/">Backing up an Android phone</a>&rdquo;.</li>
<li>I use syncthing to share a directory between my laptops and the phone.</li>
<li>I have &ldquo;Password Store&rdquo; files in the shared directory in case I need access to
passwords on the phone (rarely).</li>
<li>In AFWall+ I whitelist only selected apps. All others are denied to access the net.</li>
</ul>
<h2 id="f-droid-apps">F-Droid apps</h2>
<p><a id="table--fdroid-apps"></a></p>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://f-droid.org/packages/com.ichi2.anki">AnkiDroid</a></td>
<td>A flashcard-based study aid</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.danoeh.antennapod">AntennaPod</a></td>
<td>Easy-to-use, flexible and open-source podcast manager and player</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.aurora.store">Aurora Store</a></td>
<td>Play store alternative</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.markusfisch.android.binaryeye">BinaryEye</a></td>
<td>Yet another barcode scanner for Android. Free, no ads and open source.</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.solovyev.android.calculator">Calculator++</a></td>
<td>Scientific calculator with sleek interface and powerful capabilities</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.mozilla.fennec_fdroid">Fennec F-Droid</a></td>
<td>Browse the web</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.apps.adrcotfas.goodtime">Goodtime</a></td>
<td>Minimalist Pomodoro Timer</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.fsck.k9">K-9 Mail</a></td>
<td>Full-featured email client</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.mm20.launcher2.release">Kvaesitso</a></td>
<td>A search-focused, free and open source launcher for Android</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.koreader.launcher.fdroid">KOReader</a></td>
<td>Ebook reader supporting multiple formats like PDF, DjVu, EPUB, FB2</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.linphone">LinPhone</a></td>
<td>SIP (VOIP) phone</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.secuso.privacyfriendlymemory">Memo Game</a></td>
<td>Find pairs of cards</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.artifex.mupdf.viewer.app">MuPDF viewer</a></td>
<td>Lightweight document viewer</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.polymorphicshade.newpipe">NewPipe x SponsorBlock</a></td>
<td>A free lightweight YouTube frontend for Android with SponsorBlock capabilities</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.schildbach.oeffi">Offi Stations</a></td>
<td>King of public transit planning!</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.sufficientlysecure.keychain">OpenKeychain</a></td>
<td>Encrypt your Files and Communications. Compatible with the OpenPGP Standard.</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.blinkt.openvpn">OpenVPN for Android</a></td>
<td>OpenVPN without root</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.orgzlyrevived">Orgzly Revived</a></td>
<td>Outliner for taking notes and managing to-do lists in Org-mode format</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/net.osmand.plus">OsmAnd~</a></td>
<td>Global Mobile Map Viewing &amp; Navigation for Offline and Online OSM Maps</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.ligi.passandroid">PassAndroid</a></td>
<td>View Passbook files</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/dev.msfjarvis.aps">Password Store</a></td>
<td>Manage your passwords</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.olgsoft.apipepanic">PipePanic</a></td>
<td>A plumbers favorite game</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/name.boyle.chris.sgtpuzzles">Puzzles</a></td>
<td>39 single-player logic games</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.moez.QKSMS">QKSMS</a></td>
<td>Messaging app</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.reimardoeffinger.quickdic">QuickDic</a></td>
<td>Offline translation dictionary</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/xyz.deepdaikon.quinb">Quinb</a></td>
<td>A multiplayer reaction game: train your mind and your reflexes while having fun.</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.vonglasow.michael.satstat">SatStat</a></td>
<td>GPS, sensor and network status</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.galexander.sshd">SimpleSSHD</a></td>
<td>Easy to use SSH server</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.nutomic.syncthingandroid">Syncthing</a></td>
<td>File synchronization</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.telegram.messenger">Telegram</a></td>
<td>Telegram is a messaging app with a focus on speed and security.</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.videolan.vlc">VLC</a></td>
<td>The best video and music player. Fast and “just works”, plays any file</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.ph1b.audiobook">Voice</a></td>
<td>Simple audiobook player</td>
</tr>
</tbody>
</table>
<h2 id="archive">Archive</h2>
<table>
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="https://f-droid.org/packages/fr.neamar.kiss">KISS launcher</a></td>
<td>Custom launcher</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/dev.ukanth.ufirewall">AFWall+</a></td>
<td>Control network traffic</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.menny.android.anysoftkeyboard">AnySoftKeyboard</a></td>
<td>Keyboard</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.amaze.filemanager">Amaze</a></td>
<td>Manage local files</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.shadowice.flocke.andotp">andOTP</a></td>
<td>Time-based One-time Passwords (TOTP) from QR codes for two-factor authentication</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.simplemobiletools.clock">Clock</a></td>
<td>A combination of a clock, alarm, stopwatch and timer.</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.isoron.uhabits">Loop Habit Tracker</a></td>
<td>Track your habits and long-term goals</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.github.axet.binauralbeats">Binaural Beats</a></td>
<td>Meditation helper</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.ligi.survivalmanual">Survival Manual</a></td>
<td>Learn how to survive</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/de.meonwax.soundboard">Soundboard</a></td>
<td>Play short sound samples on touch</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.jmstudios.redmoon">Red Moon</a></td>
<td>Filter blue light from your screen for a better sleep</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.mendhak.gpslogger">GPSLogger</a></td>
<td>Lightweight GPS Logging</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.spitslide.derdiedas">Der Die Das</a></td>
<td>learning genders of German nouns</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/net.sourceforge.opencamera">Open Camera</a></td>
<td>Camera App</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.google.android.gms">UnifiedNlp (no GAPPS)</a></td>
<td>Location provider middleware (UnifiedNlp)</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/com.nicue.onetwo">OneTwo</a></td>
<td>Provides you with dices, counter and timers</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/sh.ftp.rocketninelabs.meditationassistant.opensource">Meditation Assistant</a></td>
<td>Feature packed meditation session timer and recorder</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.fitchfamily.android.gsmlocation">LocalGsmNlpBackend</a></td>
<td>UnifiedNlp location provider (local GSM database)</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/saschpe.poker">Planning Poker</a></td>
<td>Planning Poker for phone, tablet and wear devices</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.microg.nlp.backend.nominatim">NominatimNlpBackend</a></td>
<td>UnifiedNlp geocoding provider (MapQuest Nominatim)</td>
</tr>
<tr>
<td><a href="https://f-droid.org/packages/org.openbmap">RadioBeacon</a></td>
<td>Contribute to coverage maps</td>
</tr>
</tbody>
</table>
</description>
</item>
<item>
<title>Backing up an Android phone</title>
<link>http://sarg.org.ru/blog/android-backup/</link>
<pubDate>Fri, 24 Apr 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/android-backup/</guid>
<description><p>One day my wife asked me to help her backup about 30Gb of photos from her
android phone. At first we had tried to copy files over MTP (in Win10). This
idea quickly showed its incapacity. You see, Win10 wants to be nice and tries
to calculate ETA. But 30Gb is a lot of files and over MTP it takes one request
per file to get its size. So, we waited half an hour while Win10 was preparing
to start the transfer and I had aborted this madness.</p>
<p>Here is a sane approach to do the job.</p>
<ol>
<li>
<p>Install <a href="https://f-droid.org/packages/org.galexander.sshd/">SimpleSSHD</a> on the phone.
Set <code>&quot;Start on Open&quot;</code> in app settings.</p>
</li>
<li>
<p>Grab <a href="https://github.com/google/adb-sync#adb-channel"><code>adb-channel</code></a> script and add this snippet to <code>~/.ssh/config</code></p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-text" data-lang="text"><span style="display:flex;"><span> Host sshelper
</span></span><span style="display:flex;"><span> Port 2222
</span></span><span style="display:flex;"><span> ProxyCommand adb-channel tcp:%p org.galexander.sshd/.SimpleSSHD 1
</span></span></code></pre></div></li>
<li>
<p>Copy your public key to the phone.</p>
<p>Please note that <code>ssh-copy-id</code> won&rsquo;t work. Just <code>ssh sshelper</code> and then paste
the key from <code>ssh-add -L</code> into <code>authorized_keys</code>. Details <a href="http://www.galexander.org/software/simplesshd/">here</a>.</p>
</li>
<li>
<p>Now backup with rsync as usual.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span> rsync -e ssh -av sshelper:/sdcard/DCIM .
</span></span></code></pre></div></li>
<li>
<p>Optional</p>
<p>This setup assumes that you copy files over USB. But nothing stops you from
starting SimpleSSHD manually and copy files over WiFi.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span> rsync -e <span style="color:#b44">&#39;ssh -p 2222&#39;</span> -av 192.168.178.42:/sdcard/DCIM .
</span></span></code></pre></div></li>
</ol>
<p>Now that newer Android versions (newer than 12 I believe) don&rsquo;t allow apps to
access files of other apps, I had to revisit my backup solution.</p>
<p>Now I simply use the <code>adb-sync</code> script, but I also do <code>adb root</code> to give the
script full access to any files. The script is pretty smart and it works kind of
like rsync, downloading only newer files. It fits perfect the use case.</p>
</description>
</item>
<item>
<title>Making a hugo powered blog in emacs</title>
<link>http://sarg.org.ru/blog/emacs-hugo/</link>
<pubDate>Wed, 22 Apr 2020 00:00:00 +0200</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/emacs-hugo/</guid>
<description><p>Starting a blog this days couldn&rsquo;t be easier. Ten simple steps to get started.</p>
<ol>
<li>
<p><a href="https://help.github.com/en/github/working-with-github-pages/creating-a-github-pages-site">Create a github pages repo</a>.</p>
<p>Check it out locally, e.g. to <code>~/blog</code>. Every file you put in the repo will
be published <a href="https://help.github.com/en/github/working-with-github-pages/about-github-pages-and-jekyll#configuring-jekyll-in-your-github-pages-site">automatically</a>:</p>
<blockquote>
<p>By default, Jekyll doesn&rsquo;t build files or folders that:</p>
<ul>
<li>are located in a folder called <code>/node_modules</code> or <code>/vendor</code></li>
<li>start with <code>_</code>, <code>.</code>, or <code>#</code></li>
<li>end with <code>~</code></li>
<li>are excluded by the exclude setting in your configuration file</li>
</ul>
</blockquote>
</li>
<li>
<p><a href="https://help.github.com/en/github/working-with-github-pages/configuring-a-custom-domain-for-your-github-pages-site">Configure</a> custom domain or just use the default <code>&lt;repo&gt;.github.io</code>.</p>
</li>
<li>
<p>Create <code>~/blog/_hugo/config.toml</code></p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span> baseURL = <span style="color:#b44">&#34;http://sarg.org.ru/&#34;</span>
</span></span><span style="display:flex;"><span> languageCode = <span style="color:#b44">&#34;en-us&#34;</span>
</span></span><span style="display:flex;"><span> title = <span style="color:#b44">&#34;Random forest&#34;</span>
</span></span><span style="display:flex;"><span> theme = <span style="color:#b44">&#34;anubis&#34;</span> <span style="color:#080;font-style:italic"># see the next step</span>
</span></span><span style="display:flex;"><span> publishDir = <span style="color:#b44">&#34;../&#34;</span> <span style="color:#080;font-style:italic"># github pages look in the root folder by default</span>
</span></span></code></pre></div></li>
<li>
<p>Checkout some <a href="https://themes.gohugo.io/">theme</a>.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span> git submodule add <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> https://github.com/Mitrichius/hugo-theme-anubis.git <span style="color:#b62;font-weight:bold">\
</span></span></span><span style="display:flex;"><span><span style="color:#b62;font-weight:bold"></span> _hugo/themes/anubis
</span></span></code></pre></div></li>
<li>
<p>Add <code>_hugo/content</code> to <code>.gitignore</code>.</p>
<p>This directory will be generated by <code>ox-hugo</code>, no need to store it in git.</p>
</li>
<li>
<p>Create <code>org-mode</code> file where all the content would be placed.</p>
<p>Use the <a href="https://ox-hugo.scripter.co/#screenshot-one-post-per-subtree">instruction</a> from <code>ox-hugo</code> documentation. But make sure that
<code>#+HUGO_BASE_DIR</code> points to <code>_hugo</code> directory. You can put the file whenever
you want, not strictly necessary in the repository.</p>
</li>
<li>
<p>Export the file with <code>ox-hugo</code>.</p>
<p>Press <code>C-c C-e H A</code> to export everything. Now <code>_hugo/content</code> should be
populated. You might want to enable <a href="https://ox-hugo.scripter.co/doc/auto-export-on-saving/">auto export on saving</a>.</p>
</li>
<li>
<p>Check that your blog works locally.</p>
<p>Go to <code>_hugo/</code> and run <code>hugo server -D</code>. Hugo should start on <a href="http://localhost:1313">http://localhost:1313</a></p>
</li>
<li>
<p>Generate html for github pages.</p>
<p>Run <code>hugo</code> and it&rsquo;ll create all the files in <code>publishDir</code>.</p>
</li>
<li>
<p>Commit and push all the changes. You&rsquo;re done! 🎉</p>
</li>
</ol></description>
</item>
<item>
<title>Advent of Code 2019</title>
<link>http://sarg.org.ru/blog/aoc2019/</link>
<pubDate>Wed, 01 Jan 2020 00:00:00 +0100</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/aoc2019/</guid>
<description><p>For the first time I&rsquo;ve participated in <a href="https://adventofcode.com/2019">&ldquo;Advent of Code&rdquo;</a> contest. It promised to
be a fun time and a good opportunity to learn a new programming language. I&rsquo;ve
taken Clojure from my bucket list and dived head first into the contest.</p>
<p>The first few tasks are deliberately very easy, so that participants firstly
would get into the mood and would not detract by the bar raised too high, and
secondly to let one to get acquainted with the platform and rules, set up the
coding environment and get hands-on with the new language (if you one uses
such).</p>
<p>The problems were of varying complexity and some of them required prior
knowledge of algorithms. The hardest one were about searching a path in a maze.
The cool twist was the addition of the IntCode virtual machine. Over the course
of a few days the problems were shaping the definition of the IndCode VM.
Participants were expected to implement and to debug it in order to solve the
problem.</p>
<p>Clojure has shown strong and I&rsquo;ve rarely struggled with the language. Debugging
tools could be better though. All the solutions could be found <a href="https://github.com/sarg/advent2019">here on Github</a>.</p>
<p>For an additional fun I&rsquo;ve produced animations for some of the problems. For
that I&rsquo;ve used awesome <a href="https://github.com/quil/quil">Quil</a> library which implements <a href="https://processing.org/reference">Processing.org API</a>.</p>
<h2 id="problem-13-care-package"><a href="https://adventofcode.com/2019/day/13">Problem 13 - Care Package</a></h2>
<p>Arkanoid AI should be implemented in IntCode. Each block in the game has its own
unique value and the answer of the problem is the end score.</p>
<p><video controls><source src="https://raw.githubusercontent.com/sarg/advent2019/master/resources/day13.mp4"></video></p>
<h2 id="problem-15-oxygen-system"><a href="https://adventofcode.com/2019/day/15">Problem 15 - Oxygen System</a></h2>
<p>A robot have been deployed to a maze of unknown structure. By issuing movement
and observation commands the maze should be fully explored and a marked cell
should be found. Then the time to fill the maze with air should be calculated,
given that the air is injected in the bottome left corner and it spreads each
tick to the adjacent cells.</p>
<p><video controls><source src="https://raw.githubusercontent.com/sarg/advent2019/master/resources/day15.mp4"></video></p>
</description>
</item>
<item>
<title> "Parental control" for emacs
</title>
<link>http://sarg.org.ru/blog/telega-otp/</link>
<pubDate>Fri, 21 Sep 2018 00:00:00 +0000</pubDate>
<author>[email protected] (Sergey Trofimov)</author>
<guid>http://sarg.org.ru/blog/telega-otp/</guid>
<description><p>It easily becomes automatic to check for notifications/new messages/new emails
etc. To give my rational self some time to intercept compulsive behaviour I have
made this elisp snippet.</p>
<div class="highlight"><pre tabindex="0" style="background-color:#f8f8f8;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-elisp" data-lang="elisp"><span style="display:flex;"><span>(<span style="color:#a2f">defun</span> <span style="color:#b8860b">sarg/otp-for-confirm</span> ()
</span></span><span style="display:flex;"><span> <span style="color:#b44">&#34;Generates random hex string&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">format</span> <span style="color:#b44">&#34;%06x%06x%06x&#34;</span>
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">random</span> (<span style="color:#00a000">expt</span> <span style="color:#666">16</span> <span style="color:#666">6</span>))
</span></span><span style="display:flex;"><span> (<span style="color:#00a000">random</span> (<span style="color:#00a000">expt</span> <span style="color:#666">16</span> <span style="color:#666">6</span>))