summaryrefslogblamecommitdiffstats
path: root/2021/captions/emacsconf-2021-dashboard--productivity-dashboards-with-emacs-and-kindle--mehmet-tekman--main.vtt
blob: 4f0147b2b7250bf0def68028eda35124135a86b2 (plain) (tree)
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


















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































                                            
WEBVTT

00:00.000 --> 00:01.567
Hi everyone! I'm Mehmet Tekman,

00:01.567 --> 00:02.483
and I'm here to talk to you

00:02.483 --> 00:03.700
about using Amazon Kindles

00:03.700 --> 00:05.040
as a productivity dashboard for

00:05.040 --> 00:07.359
your various projects.

00:07.359 --> 00:09.519
In a nutshell, you describe your machines,

00:09.519 --> 00:11.317
your commands, and your schedules

00:11.317 --> 00:13.120
in an Org-Mode file,

00:13.120 --> 00:14.933
and then you just initialize

00:14.933 --> 00:16.960
your Kindle devices.

00:16.960 --> 00:18.367
These devices are asleep

00:18.367 --> 00:19.117
most of the time,

00:19.117 --> 00:20.720
but they wake up at scheduled times

00:20.720 --> 00:22.033
to retrieve content

00:22.033 --> 00:24.800
from the centralized server.

00:24.800 --> 00:27.599
Content can be Org mode and Emacs-based,

00:27.599 --> 00:29.500
or it can be from Web content,

00:29.500 --> 00:42.840
or it can just be static images and WAV.

00:42.840 --> 00:45.600
If you, like me, struggle to

00:45.600 --> 00:46.833
keep your life under tabs,

00:46.833 --> 00:48.300
or find it very hard to separate

00:48.300 --> 00:49.417
your work life from your home life,

00:49.417 --> 00:51.283
then you, like me, likely need

00:51.283 --> 00:52.917
some kind of passive background service

00:52.917 --> 00:54.083
that reminds you of where you are

00:54.083 --> 00:55.267
and what you are supposed to be doing.

00:55.267 --> 00:56.960
Even if it's just a sign saying,

00:56.960 --> 00:58.640
"You're at home! Relax!"

00:58.640 --> 01:00.400
An Amazon Kindle is perfect for this.

01:00.400 --> 01:01.717
In a nutshell, it's a cheap

01:01.717 --> 01:03.117
black and white e-ink device

01:03.117 --> 01:03.800
that can go for weeks

01:03.800 --> 01:05.033
without needing a single charge.

01:05.033 --> 01:06.767
Every year, Amazon brings out

01:06.767 --> 01:07.983
an incrementally better model,

01:07.983 --> 01:09.333
which makes the old devices obsolete,

01:09.333 --> 01:11.067
and you can find these older models

01:11.067 --> 01:13.360
for 5 euros on second-hand websites.

01:13.360 --> 01:15.360
Plus it runs Linux, has WiFi networking,

01:15.360 --> 01:16.987
and has a dedicated forum of hackers

01:16.987 --> 01:19.200
for getting the most out of the device.

01:19.200 --> 01:20.366
Some drawbacks of this is that

01:20.366 --> 01:22.799
the device often comes with unwanted bloat:

01:22.799 --> 01:24.050
over-the-air updates,

01:24.050 --> 01:25.833
it phones home to Amazon regularly,

01:25.833 --> 01:27.033
it has a secret microphone

01:27.033 --> 01:27.983
embedded in the device,

01:27.983 --> 01:29.433
and it has a bunch of creepy

01:29.433 --> 01:30.633
seemingly interdependent

01:30.633 --> 01:31.439
background processes,

01:31.439 --> 01:34.083
where killing one kind of kills the others

01:34.083 --> 01:36.560
risking that you will break the device.

01:36.560 --> 01:37.799
But this is where the community

01:37.799 --> 01:38.883
really shines through,

01:38.883 --> 01:40.483
since the friendly (and not-so-friendly)

01:40.483 --> 01:41.583
users (and developers)

01:41.583 --> 01:43.200
from the MobileRead forums have pretty much

01:43.200 --> 01:44.560
scraped out a good portion of the

01:44.560 --> 01:46.960
harmful Amazon scripts from the device.

01:46.960 --> 01:48.550
Some of the devices even use

01:48.550 --> 01:49.483
Awesome Window Manager,

01:49.483 --> 01:50.800
meaning you can really play around

01:50.800 --> 01:51.620
with the existing system

01:51.620 --> 01:52.633
without having to create

01:52.633 --> 01:54.233
your own X11 server.

01:54.233 --> 01:55.377
This then empowers users

01:55.377 --> 01:57.600
to display whatever they want on the device.

01:57.600 --> 01:59.040
One project that really got this going

01:59.040 --> 02:00.560
was the Kindle-Dash dashboard from

02:00.560 --> 02:02.320
Pascal Widdershoven, who really refined a

02:02.320 --> 02:03.483
lot of the internal scripts

02:03.483 --> 02:05.439
to stabilize the device.

02:05.439 --> 02:06.600
However, the project then

02:06.600 --> 02:07.650
puts the onus on the device

02:07.650 --> 02:08.560
to retrieve the data from

02:08.560 --> 02:09.950
somewhere else over the internet,

02:09.950 --> 02:10.753
and so you still need to 

02:10.753 --> 02:11.440
generate the content

02:11.440 --> 02:13.200
and place it on the web somewhere.

02:13.200 --> 02:14.640
Plus you need to do this and manage it

02:14.640 --> 02:17.360
for every Kindle device that you have.

02:17.360 --> 02:18.500
Kindle-Sync, however,

02:18.500 --> 02:19.867
is an entirely different beast,

02:19.867 --> 02:21.800
albeit one that builds off of the works

02:21.800 --> 02:23.440
of the aforementioned projects.

02:23.440 --> 02:24.800
It assumes that instead of just having

02:24.800 --> 02:26.050
one Kindle device around

02:26.050 --> 02:27.133
that you wish to re-purpose

02:27.133 --> 02:28.080
for productivity purposes,

02:28.080 --> 02:28.983
that you actually have

02:28.983 --> 02:30.117
multiple Kindle devices

02:30.117 --> 02:30.794
that you want to manage

02:30.794 --> 02:32.720
and configure in tandem.

02:32.720 --> 02:33.633
Everything is managed

02:33.633 --> 02:35.667
from a dedicated server (or a raspberry pi)

02:35.667 --> 02:37.440
which distributes jobs to multiple Kindles,

02:37.440 --> 02:39.519
running on different update timers.

02:39.519 --> 02:40.786
These timers are all managed

02:40.786 --> 02:41.486
from the server,

02:41.486 --> 02:43.017
and all the Kindle device has to do is:

02:43.017 --> 02:45.200
to wake up, power on the WiFi,

02:45.200 --> 02:47.280
receive some media, display the media, and

02:47.280 --> 02:49.680
receive a barebones RTC sleep request.

02:49.680 --> 02:51.040
Then it sleeps for the requested time,

02:51.040 --> 02:52.800
consuming no power, whilst displaying the

02:52.800 --> 02:55.200
desired media. That is maybe 10 seconds

02:55.200 --> 02:57.599
of awake time between each request.

02:57.599 --> 02:58.933
Cron does not actually run

02:58.933 --> 02:59.933
on the Kindle device itself,

02:59.933 --> 03:01.600
simply because it does not reliably work.

03:01.600 --> 03:04.050
All of this is handled by the server.

03:04.050 --> 03:05.599
With the server-client model,

03:05.599 --> 03:08.000
it also tries to restrict Amazon access.

03:08.000 --> 03:09.517
SSH keys are shared

03:09.517 --> 03:11.217
only from the client to the server,

03:11.217 --> 03:12.517
but not from the server to the client,

03:12.517 --> 03:13.920
so the Kindle cannot connect

03:13.920 --> 03:16.319
to the Raspberry Pi without a password.

03:16.319 --> 03:18.033
IPtables rules are also set

03:18.033 --> 03:19.483
so that the Kindle cannot phone home

03:19.483 --> 03:20.667
to Amazon, and the connections

03:20.667 --> 03:23.200
are restricted to just the LAN.

03:23.200 --> 03:24.820
So I got very curious at one point

03:24.820 --> 03:26.133
and decided to see how long

03:26.133 --> 03:27.599
a Kindle could last on a single charge

03:27.599 --> 03:28.560
in such an arrangement,

03:28.560 --> 03:30.640
so that every 15 minutes for 18 hours,

03:30.640 --> 03:31.599
I tested the device

03:31.599 --> 03:32.959
by sending a media item

03:32.959 --> 03:35.200
and recording the battery level.

03:35.200 --> 03:36.159
The Kindle doesn't seem to

03:36.159 --> 03:36.959
report the battery level

03:36.959 --> 03:37.760
very continuously,

03:37.760 --> 03:39.040
but at discrete percentages,

03:39.040 --> 03:39.840
so that you could end up with

03:39.840 --> 03:42.159
a graph that looks like this.

03:42.159 --> 03:43.617
Assuming you have half the charge,

03:43.617 --> 03:45.200
and use it once every hour -

03:45.200 --> 03:48.319
it will drop by 10% battery in 76 hours,

03:48.319 --> 03:49.760
which is roughly three days.

03:49.760 --> 03:50.640
It's hard to extrapolate

03:50.640 --> 03:52.400
with only three good summarized data points,

03:52.400 --> 03:53.519
of which the number of requests

03:53.519 --> 03:54.879
per battery level appear to diminish

03:54.879 --> 03:56.640
as shown in the table below,

03:56.640 --> 03:58.560
but the final result yields 76 requests

03:58.560 --> 04:00.799
with an average loss of 0.5% battery life

04:00.799 --> 04:02.273
per request. Which is not bad!

04:02.273 --> 04:04.400
Assuming you do a request every 2 hours

04:04.400 --> 04:06.000
from 8am to 8pm,

04:06.000 --> 04:07.040
and let it sleep at night,

04:07.040 --> 04:09.040
then that's approximately 6 requests a day,

04:09.040 --> 04:10.400
which could easily last a device

04:10.400 --> 04:11.280
for a month.

04:11.280 --> 04:12.586
The ksync script does

04:12.586 --> 04:13.200
essentially everything:

04:13.200 --> 04:14.799
from generating and fetching the media,

04:14.799 --> 04:16.720
to initializing all Kindle devices,

04:16.720 --> 04:18.160
generating the server cronjobs,

04:18.160 --> 04:19.199
log report summaries,

04:19.199 --> 04:20.400
editing the config tables,

04:20.400 --> 04:21.199
and much more.

04:21.199 --> 04:22.880
The media operations are comparatively

04:22.880 --> 04:23.680
much more complex

04:23.680 --> 04:25.280
and encompass a few media use cases

04:25.280 --> 04:26.400
such as fetching the weather

04:26.400 --> 04:28.560
(though only from Open Weather Maps)

04:28.560 --> 04:30.000
and retrieving Google Calendar views

04:30.000 --> 04:32.000
by week, month, agenda, and four day view.

04:32.000 --> 04:33.199
You can retrieve Org-Mode data

04:33.199 --> 04:34.639
from an Emacs instance on the server,

04:34.639 --> 04:35.360
which in my case

04:35.360 --> 04:36.720
I produce views for an agenda

04:36.720 --> 04:39.360
or a sparse tree of my main projects file.

04:39.360 --> 04:41.120
Finally we have gallery and wavfile,

04:41.120 --> 04:42.240
which are static resources

04:42.240 --> 04:44.000
which will never change once generated.

04:44.000 --> 04:45.199
The idea is that you feed it

04:45.199 --> 04:46.400
text and an image location,

04:46.400 --> 04:47.040
and it generates

04:47.040 --> 04:48.720
a Kindle-compatible image

04:48.720 --> 04:51.280
using imagemagick as a backend for it.

04:51.280 --> 04:52.240
In the case of the wavfile,

04:52.240 --> 04:54.160
it uses espeak on the backend.

04:54.160 --> 04:55.280
The below is summarized

04:55.280 --> 04:56.317
from the help-me text

04:56.317 --> 04:57.199
in the main ksync file,

04:57.199 --> 04:58.160
but essentially, you need to

04:58.160 --> 04:59.919
define your config in the CSV files,

04:59.919 --> 05:01.440
which we talk about in the next section;

05:01.440 --> 05:03.120
initialize all your Kindle devices,

05:03.120 --> 05:04.720
i.e. copy over SSH keys,

05:04.720 --> 05:06.160
kill all the unnecessary services,

05:06.160 --> 05:07.840
and prime them for media collection;

05:07.840 --> 05:08.720
and ensure that you have

05:08.720 --> 05:10.080
all your static media generated

05:10.080 --> 05:11.440
and fetchable; and finally

05:11.440 --> 05:12.720
you then refresh the scheduling

05:12.720 --> 05:14.240
on the server.

05:14.240 --> 05:15.759
Okay, so this is all good and well,

05:15.759 --> 05:17.039
and we now know what the server does

05:17.039 --> 05:18.400
and how to probe and inspect it -

05:18.400 --> 05:19.759
but how does the server generate

05:19.759 --> 05:21.120
much of the content?

05:21.120 --> 05:22.080
So a lot of the content

05:22.080 --> 05:23.360
will be dynamically generated,

05:23.360 --> 05:24.639
meaning it cannot be cached

05:24.639 --> 05:26.720
and is likely to change from hour to hour.

05:26.720 --> 05:28.400
The media content that is generated here

05:28.400 --> 05:29.759
are mostly PNG images

05:29.759 --> 05:30.567
and have a timestamp

05:30.567 --> 05:32.320
embedded in their filenames.

05:32.320 --> 05:33.520
The Emacs-specific content

05:33.520 --> 05:34.560
consists of a few views,

05:34.560 --> 05:36.000
namely the org-gcal views,

05:36.000 --> 05:37.600
org-agenda, and org-calories --

05:37.600 --> 05:39.520
essentially anything that Emacs can display

05:39.520 --> 05:42.000
and that you want to capture into an image.

05:42.000 --> 05:43.360
Emacs can't (as far as I know)

05:43.360 --> 05:44.639
render graphics in a headless way,

05:44.639 --> 05:45.600
so what we do instead

05:45.600 --> 05:48.240
is run Emacs in a dummy minimal X11 session

05:48.240 --> 05:50.080
via "xvrb-run."

05:50.080 --> 05:51.680
From inside, you can take screenshots

05:51.680 --> 05:52.233
as you would in 

05:52.233 --> 05:53.440
a normal desktop environment,

05:53.440 --> 05:54.400
but with the benefit that

05:54.400 --> 05:56.479
you don't actually need to invoke a desktop

05:56.479 --> 05:58.560
or interfere with an existing one.

05:58.560 --> 05:59.840
The minimal elisp shown here

05:59.840 --> 06:00.720
is all that is required

06:00.720 --> 06:02.400
to output your desired image from Emacs

06:02.400 --> 06:04.479
and configure it for the Kindle environment.

06:04.479 --> 06:05.360
On the web side of things,

06:05.360 --> 06:06.400
we don't really need to invoke

06:06.400 --> 06:07.520
a dummy X11 session

06:07.520 --> 06:09.120
because Chromium can run headless

06:09.120 --> 06:09.919
and can be controlled

06:09.919 --> 06:11.600
by the node library "puppeteer"

06:11.600 --> 06:13.039
to render dynamic content,

06:13.039 --> 06:14.560
focus on regions of the webpage,

06:14.560 --> 06:16.080
and take snapshots.

06:16.080 --> 06:17.600
The static content comprises

06:17.600 --> 06:19.600
of two types: images and audio.

06:19.600 --> 06:21.520
The content is accessed by a key,

06:21.520 --> 06:22.560
in this case Batman,

06:22.560 --> 06:23.600
and the content information

06:23.600 --> 06:25.199
is given by the "--extra" parameter

06:25.199 --> 06:26.960
which describes either or both

06:26.960 --> 06:30.880
an image and text.

06:30.880 --> 06:32.248
Okay, so now we have content,

06:32.248 --> 06:33.600
how do we schedule this content

06:33.600 --> 06:34.960
to appear on our desired machines

06:34.960 --> 06:36.400
at desired times?

06:36.400 --> 06:37.759
Everything is run via cron.

06:37.759 --> 06:38.720
So previously we saw that

06:38.720 --> 06:40.880
we only needed the tables MACHINES.csv,

06:40.880 --> 06:43.440
COMMANDS.csv, and multiple TIME_*.csv tables

06:43.440 --> 06:44.880
for the shell script to work.

06:44.880 --> 06:46.479
But Org-Mode does this far easier,

06:46.479 --> 06:47.919
since you can just have everything

06:47.919 --> 06:49.039
in the same file,

06:49.039 --> 06:50.720
and with the helper minor-mode,

06:50.720 --> 06:51.360
manage everything

06:51.360 --> 06:53.120
from a single Org-Mode document.

06:53.120 --> 06:55.120
Here I have 4 kindles and their shortnames.

06:55.120 --> 06:56.160
Yes, I even have a Kindle

06:56.160 --> 06:57.520
hanging outside my door.

06:57.520 --> 06:58.960
I have 11 defined commands

06:58.960 --> 07:00.800
which represent the views I want to see,

07:00.800 --> 07:02.319
and there are 4 timetables I use,

07:02.319 --> 07:02.800
but you can have

07:02.800 --> 07:04.319
everything on one, if you like.

07:04.319 --> 07:05.360
Rows are machine names,

07:05.360 --> 07:06.800
and columns are corresponding hours

07:06.800 --> 07:07.840
at which they run.

07:07.840 --> 07:09.440
Trust me, it's easier to configure

07:09.440 --> 07:10.960
repeating tasks just by repeating them

07:10.960 --> 07:12.720
multiple times, because at least this way,

07:12.720 --> 07:13.680
it's human readable,

07:13.680 --> 07:14.880
and the script which converts these

07:14.880 --> 07:15.759
to a cronjob

07:15.759 --> 07:18.800
collapses the repeating tasks by itself.

07:18.800 --> 07:20.560
The ksync script can be called

07:20.560 --> 07:23.120
from within the config.org file

07:23.120 --> 07:24.683
using this convenient 

07:24.683 --> 07:26.960
use-package declaration.

07:26.960 --> 07:28.319
All that one needs to do

07:28.319 --> 07:30.560
is to configure the ENVIRONMENT_VARIABLES

07:30.560 --> 07:32.880
by setting them in this table

07:32.880 --> 07:34.479
where you set the repo name,

07:34.479 --> 07:36.160
the config directory,

07:36.160 --> 07:37.599
where the media shall go,

07:37.599 --> 07:38.960
and the server IP,

07:38.960 --> 07:39.919
although this can be

07:39.919 --> 07:41.360
automatically detected.

07:41.360 --> 07:42.240
The package allows you

07:42.240 --> 07:43.440
to export your tables

07:43.440 --> 07:46.720
by running C-c C-c on them,

07:46.720 --> 07:49.199
and allows you to update all the jobs

07:49.199 --> 07:52.319
related to each of your clients.

07:52.319 --> 07:53.759
You can also initialize clients

07:53.759 --> 07:55.120
using this package --

07:55.120 --> 07:56.479
for either all of them

07:56.479 --> 07:58.479
or individual clients --

07:58.479 --> 07:59.599
and the package comes with

07:59.599 --> 08:01.120
some convenience functions

08:01.120 --> 08:02.720
to do this automatically

08:02.720 --> 08:06.720
for all tables in the buffer.

08:06.720 --> 08:08.319
With this, I want to say a big thank you

08:08.319 --> 08:09.840
to Takaaki Ishikawa

08:09.840 --> 08:11.520
for his fantastic "org-tree-slide"

08:11.520 --> 08:12.879
presentation package.

08:12.879 --> 08:14.136
To Pascal Widdershoven

08:14.136 --> 08:15.803
and David Hamp-Gonsalves,

08:15.803 --> 08:16.633
for their fantastic 

08:16.633 --> 08:17.840
kindle-dash repositories,

08:17.840 --> 08:19.903
for which some of my internal Kindle scripts

08:19.903 --> 08:20.720
are derived from.

08:20.720 --> 08:22.160
Also a big thanks to the friendly

08:22.160 --> 08:23.520
and not-so-friendly users and hackers

08:23.520 --> 08:24.960
in the MobileRead forums.

08:24.960 --> 08:25.919
And finally, a big thanks

08:25.919 --> 08:26.960
to the Emacs community

08:26.960 --> 08:28.270
and the conference organizers.

08:28.270 --> 08:31.120
Thank you! [captions by Mehmet]