-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.xml
757 lines (558 loc) · 162 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
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>Сорок лет - это те же двадцать</title>
<link>https://platoff.github.io/index.xml</link>
<description>Recent content on Сорок лет - это те же двадцать</description>
<generator>Hugo -- gohugo.io</generator>
<language>ru-RU</language>
<lastBuildDate>Sun, 22 Jan 2017 11:51:09 +0100</lastBuildDate>
<atom:link href="https://platoff.github.io/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Осознавая Ярило</title>
<link>https://platoff.github.io/blog/%D0%BE%D1%81%D0%BE%D0%B7%D0%BD%D0%B0%D0%B2%D0%B0%D1%8F-%D1%8F%D1%80%D0%B8%D0%BB%D0%BE/</link>
<pubDate>Sun, 22 Jan 2017 11:51:09 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BE%D1%81%D0%BE%D0%B7%D0%BD%D0%B0%D0%B2%D0%B0%D1%8F-%D1%8F%D1%80%D0%B8%D0%BB%D0%BE/</guid>
<description>
<p>Две недели пытался в муках родить <a href="https://platoff.github.io/blog/%D1%8F%D1%80%D0%B8%D0%BB%D0%BE/">Ярило</a>. Хоть я и обещал себе сделать все проще, схематично, и &ldquo;прототипично&rdquo;, но руки не слушались. Выкинув несколько вариантов модели данных, я даже потратил несколько дней портируя на Nim замечательную реализацию языка <a href="http://wren.io">Wren</a>, от <a href="http://journal.stuffwithstuff.com">Bob Nystrom</a> - мне показалось что Ярило хорошо ляжет на его модель, но, потратив эти дни, я почувствовал что опять двигаюсь в какую-то неправильную сторону.</p>
<p>В результате я возвращаюсь примерно к тому же, что уже имел прошедшим летом в качестве прообраза <a href="https://github.com/pragmagic/yarilo">Ярило</a>, но за эти две недели я родил одну важную мысль. Мысль кажется простой и с первого взгляда туповатой, но мне, по крайней мере в данный момент, она мне кажется важнейшей и ключевой: <strong>сборщика мусора не будет!</strong>.</p>
<p>Эта мысль у меня в голове расставила все на свои места. Чего я хочу? <a href="https://platoff.github.io/blog/%D1%85%D0%BE%D1%87%D1%83-%D0%B4%D0%B5%D0%BB%D0%B0%D1%82%D1%8C-%D0%B2%D0%B5%D0%B1-%D0%BF%D1%80%D0%B8%D0%BB%D0%BE%D0%B6%D0%B5%D0%BD%D0%B8%D1%8F/">Я хочу делать Web-приложения</a>, и под веб-приложениями я в первую очередь понимаю UI. Что такое UI? Это дерево. <strong>Дерево, блять!</strong> Де-ре-во, а дерево &ndash; это не граф. Какое замечательное свойство есть у дерева? В нем нет циклов, в нем (концептуально) на каждый элемент есть только <strong>одна ссылка</strong>.</p>
<p>Что такое state приложения в понимании большинства современных фреймворков? Это <strong>дерево</strong>. Его так и называют - дерево состояния. Что такое UI приложение - это преобразование одного дерева в другое. Грубо говоря это то, чем пытается заниматься <a href="https://facebook.github.io/react/">React.js</a> и его друзья. Этот фундаментальный взгляд на UI приложение я не буду оспаривать, я с ним согласен на 100%. Но я хочу <a href="https://platoff.github.io/blog/%D0%B0-%D0%BD%D1%83%D0%B6%D0%B5%D0%BD-%D0%BB%D0%B8-%D1%8F%D0%B7%D1%8B%D0%BA-self-adjusting-computation/">большего</a></p>
<p>Мне нужен механизм (это может быть язык программирования) описания того как одни части дерева преобразуются в другие части. В моих фантазиях, такие преобразования могут зависить друг от друга. Например новая нода в дереве состояний порождает новую ноду в дом), а та, в свою очередь порождает еще одну ноду DOM (например с переводом текста, в случае если в некотором месте дерева состояния включена опция трансляции). И так далее.</p>
<p>Разницы между типами узлов дерева быть не должно. В том смысле что ноды состояния приложения, ноды описывающие DOM, или ноды хранящие трансиентные данные выглядят для приложения единообразно и я могу преобразовать что хочу во что хочу. Никто не мешает мне породить из UI некоторое состояние а потом его опять трансформировать в UI.</p>
<p>И самое важное: <strong>я не хочу задумываться о деталях</strong>. Состояние может быть огромным (по размеру), но я как пользователь должен иметь единообразый доступ к нему всему. Точно так же UI - я даже не должен знать что некоторая нода - это UI элемент. Я лишь хочу описать правила транформации и запустить приложение.</p>
<h1 id="сборка-мусора-и-linear-types">Сборка мусора и Linear Types</h1>
<p>Итак, мысль о том что сборка мусора не нужна и что наше приложение &ndash; дерево, упорядочила все у меня в голове и несколько повлияло на дизайн языка. К сожалению, или к счастью, это не будет язык общего назначения. Концептуально &ndash; все данные храняться в дереве, и только в дереве. Это значит, что если нода A и нода B не может иметь общего ребенка C. Даже если С ноды B создается из C ноды A в процессе трансформации &ndash; то создасться копия C. Несомненно надо предусмотреть оптимизацию для immutable данных - в этом случае копия не имеет смысла, но опять же концептуально пользователь работает с деревом и только с деревом &ndash; копируются ли immutable данные под капотом или нет &ndash; не должно волновать пользователя.</p>
<p>Я конечно погуглил на тему этой деревянной идеи - ничего толком не нашел, кроме <a href="https://en.wikipedia.org/wiki/Substructural_type_system#Linear_type_systems">Linear Types</a> - это не совсем мой случай, а более общий, когда на объект может существовать одна и только одна ссылка. По теме не так много статей, и в основном недоступная мне математика о Linear Logic, но есть очень интересные стайки от <a href="http://www.pipeline.com/~hbaker1/home.html">Henry Baker</a>, например о <a href="http://www.pipeline.com/~hbaker1/LinearLisp.html">Linear Lisp</a> и стековых машинах в этом контексте <a href="http://www.pipeline.com/~hbaker1/ForthStack.html">Linear Logic and Permutation Stacks</a>.</p>
<p>Этот путь (в Linear Logic) слишком умный для меня, я лишь буду руководствоваться правилом дерева. Технически, на ноду придется ссылаться не только из родительской ноды но и из обработчиков событий, процессов транформации, и так далее. Но еще раз: такие ссылки &ndash; это забота движка. Концептуально данные &ndash; дерево. Убили ноду &ndash; все, кирдык, если кто-то ее слушал и во что-то трансформировал, то и ему кирдык &ndash; трансформировался в ноль (хотя теоретически он может трансформировать &ldquo;нулевую&rdquo; ноду во что-то осмысленное).</p>
</description>
</item>
<item>
<title>А нужен ли язык? (Self-adjusting Computation)</title>
<link>https://platoff.github.io/blog/%D0%B0-%D0%BD%D1%83%D0%B6%D0%B5%D0%BD-%D0%BB%D0%B8-%D1%8F%D0%B7%D1%8B%D0%BA-self-adjusting-computation/</link>
<pubDate>Thu, 12 Jan 2017 17:28:05 +0200</pubDate>
<guid>https://platoff.github.io/blog/%D0%B0-%D0%BD%D1%83%D0%B6%D0%B5%D0%BD-%D0%BB%D0%B8-%D1%8F%D0%B7%D1%8B%D0%BA-self-adjusting-computation/</guid>
<description><p>Зачем мне свой язык? Я не собираюсь делать язык ради языка, возможно я смогу обойтись без самодельного языка - и это было бы хорошо. Но пока не очень получается.</p>
<p>Много думая об управлении состоянием приложения (в общем про то что делают ваши всякие flux/redux и так далее, в которые я тоже не вдупляю) я все чаще и чаще попаю на статьи о self-adjusted или incremental computations. Сейчас у вас популярны всяческие RxJS и подобные, и честно скажу я сам зафанател от ориниального Rx (Microsoft) в году так 2008, но все же по этому пути я не пойду: Erich, создатель Rx сделал выдающуюся вещь показав реактивные (асинхронные) counterparts синхронным примитивам типа Enumeration, которые мы пользовали всю жизнь, и он гений.</p>
<p>Но говорить о том что мои приложения будут основаны на Observables это то же что и говорить что мои приложения будут основаны на Enumerables - если первое звучит только модно, не более, то и первое и второе по сути - хуйня и не о чем. Это не отменяет возможность использования мной реактивных паттернов, но еще раз скажу что сам по себе Rx никаких фундаментальных проблем не решит.</p>
<p>Для тех кто впервые слышит о self-adjusting computation, го на сайт Umut Acar - <a href="http://www.umut-acar.org/self-adjusting-computation">сайт Umut Acar</a>, это чувак много лет занимающийся этим вопросом, там же можно найти некоторые статьи по теме.</p>
<blockquote>
<p>Self-adjusting computation refers to a model of computing where computations can automatically respond to changes in their data</p>
</blockquote>
<p>Я пролистал довольно много статей о self-adjusting computations, штука эта действительно выглядит мощно для UI приложений и не только, но и с первого взгляда не нова - грань между FRP и self-adjusted computation довольно тонка: и то и другое можно применять, и применяется для одних и тех же целей - декларативно описать вычисления и пойти курить оставив компьютер заниматься персчетом результатов при изменении входных данных (я сейчас очень грубо).</p>
<p>И если мы стараемся не углубляться в разницу между тем и другим, то в мире JavaScript было и есть несколько продуктов близких к тому что мне хочется:</p>
<ul>
<li>Жемчужина - это, конечно, <a href="http://www.flapjax-lang.org">Flapjax</a>. Как это часто бывает с жемчужинами - они опережают время (готовность масс понять и принять), и умирают раньше чем стать тем, что пользует весь мир. Так было с объектно-ориентированными базами данных, да и много с чем. В общем очень достойная вещь и на пейпер flapjax есть много ссылок из вполне себе научных статек, жаль только то что самого flapjax уже нет.</li>
<li>Есть на первый взгляд хороший выходец из практических кругов <a href="https://github.com/mobxjs/mobx">MobX</a> - они себя называют TFRP (transparent functional reactive programming), пусть будет так - о терминах я спорить не буду.</li>
</ul>
<p>Ну и куча других проектов на различных языках, которые гуглятся по словам reactive и functional, но так легко докатиться до <a href="http://elm-lang.org">Elm</a>. Я сознательно не упоминал Elm упоминая FRP. Elm - фантастическая вещь, лично для меня понятная и приятная тем, что у меня очень быстро получилось написать и запустить простенькую программу на Elm, чего я не смог сделать с помощю довольно мейнстримовых React, Cycle.js и подобное - количество пиздеца которое у меня не работает и количество обращений к гуглу бъет по моим нервам так что я бросаю это дело.</p>
<p>Так, Elm можно считать эталоном FRP в вебе на данный момент. У проекта есть все - и сильный теоретический бекграунд (ссылок на <a href="http://people.seas.harvard.edu/~chong/pubs/pldi13-elm.pdf">Elm папер</a> не меньше чем на flapjax) и прекрасная реализация. Все же, несморя на то что я часто говорю о теоретических основах, я чел необразованный &ndash; просто практик. Со всем уважением относясь к мотивации создателя Elm не делать first-class сигналы (ее невозможно оспорить, по крайней мере такому неспециалисту как я) - я чувствую, что на практике мне Elm не хватит. Мне хочется решения, которое позволит мне сколь угодно сложно менять граф вычислений во время исполнения, а это как я понимаю - главная проблема всех FRP решений на данный момент. Поэтому мне очень хочется выйти за рамки FRP (в понимании Elm) и я хочу посмотреть в какие-то другие стороны. Отсюда MobX и self-adjusting computation.</p>
</description>
</item>
<item>
<title>Ярило</title>
<link>https://platoff.github.io/blog/%D1%8F%D1%80%D0%B8%D0%BB%D0%BE/</link>
<pubDate>Wed, 11 Jan 2017 12:47:07 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D1%8F%D1%80%D0%B8%D0%BB%D0%BE/</guid>
<description>
<p>Итак, <a href="https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE-%D1%85%D0%BE%D1%80%D0%BE%D1%88%D0%B8%D1%85-%D0%B8-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B7%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82%D0%BE%D0%B2/">я возвращаюсь к Ярило</a>. Как я уже писал - мне не нужны инновации, мне нужен некоторый скриптинг язык, требования к которому я уточню по ходу. Но часть требований уже сейчас понятна.</p>
<h1 id="минимальные-требования">Минимальные требования</h1>
<ul>
<li><p>Я бы хотел <a href="https://en.wikipedia.org/wiki/Homoiconicity">Homoiconic Language</a>. Язык, который хорошо подходит для создания DSL-ей. В этом случае на ум сразу приходит LISP. Современным чуавкам еще придет на ум Julia, но ее корни тоже в LISP, вернее в Scheme. Кому то придет в голову TCL, и так далее. В общем Lisp &ndash; очевидный выбор, но ни одна моя попытка научиться легко программировать на Lisp не увенчалась успехом. Вместо Lisp я буду черпать вдохновение в <a href="https://en.wikipedia.org/wiki/Rebol">REBOL</a>, который так же похож на Lisp как и не похож. Этих сходств и различий достаточно для того чтобы я (лично) мог программировать на Rebol не испытывая сложностей, одновоременно чувствуя всю &ldquo;мощь&rdquo; Lisp.</p></li>
<li><p>REPL-oriented. Хороший пример REPL-ориентированного языка &ndash; <a href="https://en.wikipedia.org/wiki/PowerShell">Microsoft PowerShell</a>, но и TCL, да и вообще все Homoiconic языки достаточно неполхи для REPL. Что нужно сделать с Rebol, чтобы добавить удобства как REPL инструмента, я посмотрю в процессе.</p></li>
</ul>
<h1 id="поехали">Поехали</h1>
<p>Постараюсь обойтись без прошлых ошибок и достигнуть полезного результата с минимальными усилиями. Соответственно:</p>
<p>Отказываюсь от собственного GC и эффективного представления данных. Буду пользоваться GC предоставленным Nim, а соответственно структуры данных должны быть понимаемыми Nim. Значит отказываемся от тегирования указателей и прочих фишек - наша память должна выглядить для Nim как родная. В этом есть свой плюс - interoperability с Nim, но и минус в потере эффективности из за некоторой несовместимости моделей (у меня динамическая, и, возможно, слабая типизация).</p>
</description>
</item>
<item>
<title>Про хороших и полезных программистов</title>
<link>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE-%D1%85%D0%BE%D1%80%D0%BE%D1%88%D0%B8%D1%85-%D0%B8-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B7%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82%D0%BE%D0%B2/</link>
<pubDate>Tue, 10 Jan 2017 09:00:57 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE-%D1%85%D0%BE%D1%80%D0%BE%D1%88%D0%B8%D1%85-%D0%B8-%D0%BF%D0%BE%D0%BB%D0%B5%D0%B7%D0%BD%D1%8B%D1%85-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%81%D1%82%D0%BE%D0%B2/</guid>
<description>
<p>Последние несколько дней увлекся чтением про искусственный интеллект, но про ИИ я напишу отдельно. Сейчас же время вернуться к реальному программированию. Пора мне начать соединять точки.</p>
<h2 id="ярило">Ярило</h2>
<p>Летом 2016 я провел замечательною неделю на балконе в Новосибирске (а там можно это делать только летом, и то не всегда) в попытках вернуться к программированию. Результатом этой недели были наброски реализации языка программирования с временным названием <a href="https://github.com/pragmagic/yarilo">YARILO</a>. Yet Another Rebol Inspired Language, Obviously!</p>
<p>Язык не претендует на инновации, собственно инноваций там не задумывалось <em>вообще (совсем)</em>. Но я интуитивно чувствую что без своего языка для скиптинга мне точки не соеденить. Поэтому я возвращаюсь к написанию языка.</p>
<p>Прошедшим летом я накидал штук 5 вариантов и попался на обычную ошибку начинающего программиста - которая называется <em>делай сразу хорошо</em>. Частный случай этой ошибки &ndash; преждевременная оптимизация. Хотя почему ошибка начинающего? Есть дохуя программистов страдающих этим всю жизнь, старающихся делать хорошие программы, не делая при этом практически никакой <em>полезной работы</em>.</p>
<p>Такие программисты может быть и хорошие (тут вся соль в определении термина &ldquo;хороший программист&rdquo;), но к сожалению бесполезные. Это то, что назвывется программированием ради программирования, и я действительно соскучившись по программированию все время потратил на разнообразную хуету, ничуть не приблизившись к полезному результату.</p>
<p>В те дни Ярило, мне захотелось эффективно использовать память, из чего следовал собственный GC, трансляция в эффективный байт-код и так далее. Несколько часов я оптимизировал цикл интерпретатора, добивался возможности компилятора Nim/C использовать tail calls, а потом переписывал этот цикл к хуям, аннигилируя часы работы, и так далее. В общем я <em>программировал</em>, но не <em>работал</em>. Что естественно для человека который соскучился по программированию.</p>
<h2 id="хорошие-программисты">Хорошие программисты</h2>
<p>В общем я делал все то, что делают многие &ldquo;хорошие&rdquo; программисты. &ldquo;Хороший&rdquo; программист &ndash; это программист, который программирует ради программирования, и их немало. Еще они за это получают деньги. Если бы это был реальный проект, и у меня был типичный менеджер, а я был бы на хорошем, счету как программист, то у нас бы случился match in heaven. Я бы каждый день показывал ему какой у нас охуенный прогресс (как мы ускорилсь тут или там, как у нас появился байткод и так далее), и объяснял бы что свой язык - сложная тема, и все эти вещи жизненно необходимы, чтобы взлетело (что безусловно правда).</p>
<p>Правда через годик мы бы с этим менеджером соснули хуйца, по десятку причин, но мне как &ldquo;хорошему&rdquo; программисту нашлась бы другая задача. Так происходит у многих. Чтобы так не было - программист должен быть <em>полезным</em>. Но типична и другая крайность - &ldquo;Полезный&rdquo; программист. И чем хуже программист как программист - тем он больше старается быть полезным (иначе нахуй он вообще нужен).</p>
<h2 id="полезные-программисты">Полезные программисты</h2>
<p>&ldquo;Полезных&rdquo; программистов не волнуют вопросы оптимизации (ни преждевременной ни последующей), дизайна, и прочих вещей - они слабо представляют себе каким должна быть архитектура проекта, чтобы взлетело. От таких программистов выходит то, что &ldquo;хорошие&rdquo; программисты называют словом <em>говнокод</em> (я ненавижу это слово, и дальше объясню почему).</p>
<p>&ldquo;Полезные&rdquo; программисты, обычно, тоже отсасывают хуйца, но по причинам отличным от тех по которым отсасывают &ldquo;хорошие&rdquo; программисты. Полезные программисты погружаются в пучину <em>технического долга</em>, который они не в состоянии гасить, и перестают быть полезными.</p>
<p>Разговор &ldquo;полезного&rdquo; программиста с &ldquo;хорошим&rdquo; программистом &ndash; это разговор слепого с глухим. Один лепит другому про технический долг, про так нельзя, тут у нас будут проблемы, надо вот так; второй отвечает про планы, сроки, задачи бизнеса, кастомеров и так далее. Часто &ldquo;хорошим&rdquo; программистам дают в помощь &ldquo;полезного&rdquo; менеджера &ndash; и следствие тех же разговоров слепого с глухим мы видим в недовольстве программистов своим &ldquo;тупым&rdquo; менеджером, а менеджеров жалующихся на программистов.</p>
<h1 id="отличные-программисты">Отличные программисты</h1>
<p>Мне интересны и &ldquo;хорошие&rdquo; и &ldquo;полезные&rdquo; программисты, два в одном, назовем их &ldquo;отличные&rdquo;. Таких немного и их надо искать. Такой программист должен уметь хорошо мыслить и технически, и с точки зрения бизнеса, одновременно в нескольких временных масштабах, оптимизируя и полезность и качество работы &ndash; типичный tradeoff в разработке. Причем если мыслить в одном масштабе (например текущего релиза), то оптимальное решение одно, а если мыслим более глобально, то оптимальное решение - другое. Отличный же программист может выбрать третье решение, которое может быть не оптимально ни для первого масштаба ни для второго, но позволит получить максимальную полезность и в первом и во втором масштабе, с минимальным техническим долгом во обоих случаях.</p>
<p>Быть таким программистом &ndash; значит уметь пройти между струй дождя на всем долгом цикле проекта. Таких немного и только такие могут быть успешными руководителями проекта. Слепые с глухими редко могут быть успешными в долгосрочных и сложных историях.</p>
<h1 id="говнокод">Говнокод</h1>
<p>Когда я слышу от программиста слово &ldquo;говнокод&rdquo;, ну например на собесе в ответ на вопрос про его прошлые места работы &ndash; у меня сразу вколючается маячок: с этим человеком скорее всего что-то не так. Вероятнее всего передо мной &ldquo;хороший программист&rdquo;. Скорее всего я его не возьму на работу, а если и возьму, то мы скоро расстанемся. Мне не нужны &ldquo;хорошие&rdquo; программисты (с ними сложно добится <em>полезного</em> результата), мне так же неинтересны &ldquo;полезные&rdquo; программисты &ndash; с нимим невозможно достигать больших целей, да и не решить сложных задач.</p>
<p>Люди, часто употребляющие слово &ldquo;говнокод&rdquo;, обычно &ldquo;хорошие&rdquo; программисты, и могут найти этот &ldquo;говнокод&rdquo; везде, даже в очень мной уважаемых проектах, достойных восхищения. Один мне как-то показывал &ldquo;говонокод&rdquo; от Erich Gamma. Еб твою мать, дружище, я и сам такое могу найти везде. но как ты можешь знать об условиях в которых находились люди написавшие этот код? Ты же как &ldquo;хороший&rdquo;, но &ldquo;бесполезный&rdquo; программист не думаешь об обратной совместимости, о текущих пользователях этого кода, о задачах бизнеса, о сроках, о тех кто ждет этого &ldquo;фикса&rdquo;, о том насколько это важно и так далее. А применимо к данному коду ты об этом ничего не знаешь.</p>
<p>Я более чем уверен, что если бы тебя погрузили в ту ситуацию, и попросили найти оптимальное решение <em>всех</em> стоящих задач &ndash; ты бы не справился. В жизни часто бывает, что написать &ldquo;хороший&rdquo; код это не оптимальное, а часто губительное в долгосрочной перспективе решение для проекта. Да и не факт что твой код был бы лучше (хотя тут мы опять уходим в определение &ldquo;хорошего&rdquo;).</p>
<p>К чему я все это написал? Ах, да, пора мне вернуться к Ярило, и все таки написать этот язычок, и поскольку теперь у меня есть <a href="https://platoff.github.io/about/">цель</a>, то в этот раз работа моя должна быть полезной.</p>
</description>
</item>
<item>
<title>Балуюсь с запросами</title>
<link>https://platoff.github.io/blog/%D0%B1%D0%B0%D0%BB%D1%83%D1%8E%D1%81%D1%8C-%D1%81-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0%D0%BC%D0%B8/</link>
<pubDate>Wed, 04 Jan 2017 10:48:40 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%B1%D0%B0%D0%BB%D1%83%D1%8E%D1%81%D1%8C-%D1%81-%D0%B7%D0%B0%D0%BF%D1%80%D0%BE%D1%81%D0%B0%D0%BC%D0%B8/</guid>
<description><p>Отвелекусь немного на сами данные. Сейчас отношения примитивно и неоптимально со всех точек зрения. Пока я предполагаю что весь <code>state</code> (и persistent и transient) будет валятся в таких структурах. Хочется проверить насколько это все реально, соответственно хочу померить уже известную мне dbmonster модель. Захуярю-ка я ее в &ldquo;базу&rdquo;.</p>
<p>В datomic (или RDF-alike) модель запихать монстра оказалось даже быстрее чем в объекты конкретных классов: вот весь код создания базы:</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span><span class="k">const</span>
<span class="n">DatabaseName</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">Elapsed</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">Waiting</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span>
<span class="n">SQL</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span>
<span class="n">Queries</span> <span class="o">=</span> <span class="n">A</span><span class="p">(</span><span class="mi">5</span><span class="p">)</span>
<span class="k">proc </span><span class="nf">genQuery</span><span class="p">(</span><span class="n">db</span><span class="p">:</span> <span class="n">DB</span><span class="p">):</span> <span class="n">E</span> <span class="o">=</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">getId</span><span class="p">()</span>
<span class="n">db</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">Elapsed</span><span class="p">,</span> <span class="n">random</span><span class="p">(</span><span class="mi">1500</span><span class="p">))</span>
<span class="n">db</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">Waiting</span><span class="p">,</span> <span class="n">random</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span>
<span class="kd">var</span> <span class="n">query</span><span class="p">:</span> <span class="kt">string</span>
<span class="k">case</span> <span class="n">random</span><span class="p">(</span><span class="mi">10</span><span class="p">)</span>
<span class="k">of</span> <span class="mi">0</span><span class="p">:</span> <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;vacuum&quot;</span>
<span class="k">of</span> <span class="mf">1</span><span class="p">..</span><span class="mi">2</span><span class="p">:</span> <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;&lt;IDLE&gt; in transaction&quot;</span>
<span class="k">else</span><span class="p">:</span> <span class="n">query</span> <span class="o">=</span> <span class="s">&quot;SELECT blah FROM something&quot;</span>
<span class="n">db</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">SQL</span><span class="p">,</span> <span class="n">query</span><span class="p">)</span>
<span class="k">proc </span><span class="nf">genDatabase</span><span class="p">(</span><span class="n">db</span><span class="p">:</span> <span class="n">DB</span><span class="p">,</span> <span class="n">name</span><span class="p">:</span> <span class="kt">string</span><span class="p">):</span> <span class="n">E</span> <span class="o">=</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">getId</span><span class="p">()</span>
<span class="n">db</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">DatabaseName</span><span class="p">,</span> <span class="n">name</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="mf">0</span><span class="p">..</span><span class="n">random</span><span class="p">(</span><span class="mi">10</span><span class="p">):</span>
<span class="n">db</span><span class="p">.</span><span class="n">add</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">Queries</span><span class="p">,</span> <span class="n">db</span><span class="p">.</span><span class="n">genQuery</span><span class="p">())</span>
<span class="k">proc </span><span class="nf">getData</span><span class="o">*</span><span class="p">():</span> <span class="n">Db</span> <span class="o">=</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">newDB</span><span class="p">(</span><span class="o">[</span><span class="n">sizeof</span> <span class="n">E</span><span class="p">,</span> <span class="n">sizeof</span> <span class="n">A</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">]</span><span class="p">,</span> <span class="o">[</span><span class="n">Order</span><span class="p">(</span><span class="mh">0x123</span><span class="p">)</span><span class="o">]</span><span class="p">)</span>
<span class="k">for</span> <span class="n">i</span> <span class="ow">in</span> <span class="mf">1</span><span class="p">..</span><span class="n">ROWS</span><span class="p">:</span>
<span class="k">discard</span> <span class="n">result</span><span class="p">.</span><span class="n">genDatabase</span><span class="p">(</span><span class="s">&quot;cluster&quot;</span> <span class="o">&amp;</span> <span class="o">$</span><span class="n">i</span><span class="p">)</span>
<span class="k">discard</span> <span class="n">result</span><span class="p">.</span><span class="n">genDatabase</span><span class="p">(</span><span class="s">&quot;cluster&quot;</span> <span class="o">&amp;</span> <span class="o">$</span><span class="n">i</span> <span class="o">&amp;</span> <span class="s">&quot; slave&quot;</span><span class="p">)</span>
</code></pre></div>
<p>Запускаем, и видим ожидаемую жопу: <code>1.8ms</code> на генерацию для 200 монстробаз. Это нативно. Напомню что оригинал генерировал данные за <code>0.36ms</code> нативно. Интересно, что уменьшая количество данных в 2 раза, время построения уменьшается линейно до 0.9ms, что говорит о том что неэффктивность где-то в сериализации тупла, а не в уебищной структуре данных (можно было ожидать что тормозит вставка с сортировкой, но походу нет).</p>
<p>Пробую V8. Оригинал &ndash; <code>1ms</code>. &ldquo;База данных&rdquo; &ndash; полная сракотень <code>18.9ms</code>. С другой стороны, на V8 уменьшив объем данных в 10 раз получаю ускорение в 20 раз, до 0.8ms. Что нам это говорит? Видимо то что emscripten и движки JS пока далеки от генерации чего-то похожего на нативный код. Думаю что <code>memcpy</code> реализован циклом по массиву HEAP&hellip; Или чота типа того. Safari как всегда впереди всех - 14.7ms но тоже не торт. Возможно корень зла в emscripten и webassembly отожгет.</p>
<p>Ладно, хер с ним переживать - все это можно оптимизировать в разы. Продолжу с сутью и давайте попробуем выбрать все запросы где <code>Waiting == true</code>. Для этого добавлю AVE индекс: <code>var monster = newDB([sizeof E, sizeof A, -1], [Order(0x123), Order(0x231)])</code></p>
<p>Ха-ха-Ха ебать, и вот она - пизда! 10ms на итерацию в нативном коде. Ну конечно, идентификаторы триплов я генерировал последовательно, и они (триплы) добавлялись в конец, а с индексом понеслась пизда по кочкам, все таки структура данных (тупо массив) - откровенное гавно, но это меня не остановит.</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span> <span class="kd">var</span> <span class="n">q</span> <span class="o">=</span> <span class="n">newQuery</span><span class="p">()</span>
<span class="n">q</span><span class="p">.</span><span class="n">pred</span><span class="p">(</span><span class="n">monster</span><span class="p">,</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?e&quot;</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="n">Waiting</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="kp">true</span><span class="p">))</span>
<span class="n">q</span><span class="p">.</span><span class="n">select</span><span class="p">(</span><span class="s">&quot;?e&quot;</span><span class="p">)</span>
<span class="n">q</span><span class="p">.</span><span class="n">prepare</span>
<span class="n">q</span><span class="p">.</span><span class="n">execute</span>
</code></pre></div>
<p>ОК, соснул, построились кривые итераторы не из того места&hellip; Починил, включая поддержку 32 бит. Осталось поправить багу (iter.up/iter.open должен перематывать итератор в начало), но бага мешает толко для &ldquo;плохих&rdquo; планов (так то нехуй ничо перематывать).</p>
<p>А вот с запросами двигло работет побыстрее. Поиск монстробаз где <code>Waiting == true</code> &ndash; <code>5.5ms</code> на V8:</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span> <span class="n">q</span><span class="p">.</span><span class="n">pred</span><span class="p">(</span><span class="n">monster</span><span class="p">,</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?q&quot;</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="n">Waiting</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="kp">true</span><span class="p">))</span>
<span class="n">q</span><span class="p">.</span><span class="n">pred</span><span class="p">(</span><span class="n">monster</span><span class="p">,</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?db&quot;</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="n">Queries</span><span class="p">),</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?q&quot;</span><span class="p">))</span>
<span class="n">q</span><span class="p">.</span><span class="n">pred</span><span class="p">(</span><span class="n">monster</span><span class="p">,</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?db&quot;</span><span class="p">),</span> <span class="n">constant</span><span class="p">(</span><span class="n">DatabaseName</span><span class="p">),</span> <span class="n">variable</span><span class="p">(</span><span class="s">&quot;?name&quot;</span><span class="p">))</span>
<span class="n">q</span><span class="p">.</span><span class="n">select</span><span class="p">(</span><span class="s">&quot;?name&quot;</span><span class="p">)</span>
<span class="n">q</span><span class="p">.</span><span class="n">prepare</span>
<span class="n">q</span><span class="p">.</span><span class="n">execute</span>
</code></pre></div>
<p>На сегодня с программированием завязал, надо подумать что со всем этим делать дальше. Код под тегом <code>day-170104</code>.</p>
</description>
</item>
<item>
<title>Leapfrog Triejoin</title>
<link>https://platoff.github.io/blog/leapfrog-triejoin/</link>
<pubDate>Tue, 03 Jan 2017 15:51:49 +0100</pubDate>
<guid>https://platoff.github.io/blog/leapfrog-triejoin/</guid>
<description><p>Итак, <a href="https://platoff.github.io/blog/%D0%B7%D0%B0%D1%85%D0%BE%D0%B6%D1%83-%D1%81-%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B9-%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%8B/">из вчерашнего</a> мы узнали, что сердце моего движка запросов - <a href="https://arxiv.org/abs/1210.0481">Leapfrog Triejoin</a> алгоритм. Надо закончить с выбором плана и построением соответствующих итераторов.</p>
<p>В общем, после всей ебаты на 300 строк, оно заработало. Сам join проще простого:</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span> <span class="kd">var</span> <span class="n">join</span><span class="p">:</span> <span class="n">TrieJoin</span><span class="o">[</span><span class="n">TrieIter</span><span class="o">]</span>
<span class="n">join</span><span class="p">.</span><span class="n">init</span><span class="p">(</span><span class="n">plan</span><span class="p">)</span>
<span class="k">proc </span><span class="nf">joinOn</span><span class="p">(</span><span class="n">v</span><span class="p">:</span> <span class="kt">int</span><span class="p">)</span> <span class="o">=</span>
<span class="kd">var</span> <span class="n">leapfrog</span> <span class="o">=</span> <span class="n">join</span><span class="p">.</span><span class="n">open</span>
<span class="k">while</span> <span class="ow">not</span> <span class="n">leapfrog</span><span class="p">.</span><span class="n">atEnd</span><span class="p">:</span>
<span class="n">echo</span> <span class="n">q</span><span class="p">.</span><span class="n">vars</span><span class="o">[</span><span class="n">v</span><span class="o">]</span><span class="p">.</span><span class="n">name</span><span class="p">,</span> <span class="s">&quot; &lt;- &quot;</span><span class="p">,</span> <span class="n">leapfrog</span><span class="p">.</span><span class="n">key</span><span class="p">.</span><span class="n">key</span>
<span class="k">if</span> <span class="n">v</span> <span class="o">&lt;</span> <span class="n">q</span><span class="p">.</span><span class="n">vars</span><span class="p">.</span><span class="n">len</span> <span class="o">-</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">joinOn</span><span class="p">(</span><span class="n">v</span> <span class="o">+</span> <span class="mi">1</span><span class="p">)</span>
<span class="n">leapfrog</span><span class="p">.</span><span class="n">next</span>
<span class="n">join</span><span class="p">.</span><span class="n">up</span>
<span class="n">joinOn</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
</code></pre></div>
<p>Результат под тегом <a href="https://github.com/platoff/wafer/tree/day-170103"><code>day-170103</code></a>.</p>
</description>
</item>
<item>
<title>Захожу с другой стороны</title>
<link>https://platoff.github.io/blog/%D0%B7%D0%B0%D1%85%D0%BE%D0%B6%D1%83-%D1%81-%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B9-%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%8B/</link>
<pubDate>Mon, 02 Jan 2017 10:19:40 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%B7%D0%B0%D1%85%D0%BE%D0%B6%D1%83-%D1%81-%D0%B4%D1%80%D1%83%D0%B3%D0%BE%D0%B9-%D1%81%D1%82%D0%BE%D1%80%D0%BE%D0%BD%D1%8B/</guid>
<description>
<p>Итак, 2 января 2017го. Декабрьская поездка в Прагу и Новосибирск поломала только начинавшеюся практику ежедневного программирования, суета конца года в бизнесе усугубила, но пару дней в конце года я уделил для кода.</p>
<p>Что я имею: какой то жалкий прототип dom diff &ndash; это даже нельзя назвать virtual dom, поскольку DOM как таковой у меня отсутствует (даже виртуальный). Чтобы двинуться дальше надо увидеть всю картину, поэтому я зайду с другой стороны - со стороны модели.</p>
<p>Я - старый фанат <a href="http://www.datomic.com">datomic</a>. Настолько старый, что вы не поверите, но что не удивительно, учитывая мой вечный, берущий начало в прошлом веке интерес к архтектурам БД, и чему есть <a href="https://twitter.com/platoff/statuses/281250841401389056">документальные подтверждения из 2012-го</a>.</p>
<p>Несколько лет назад <a href="http://tonsky.me">Никита Прокопов</a> сделал довольно известное в некоторых кругах архитектурное подобие Datomic под названием <a href="https://github.com/tonsky/datascript">DataScript</a>, а буквально месяц назад кто-то твитнул о том что Mozilla тоже делает нечно похожее. Вот оно: <a href="https://github.com/mozilla/datomish">Datomish</a>.</p>
<p>В каком направлении идет Mozilla я не смотрел, но пару лет назад встречался с Никитой и говорил что для платформы моей мечты я хочу сделать полноценный datomic на стороне браузера. Тогда Никита сказал что это пиздец и на такое не готов сам Rich Hickey (не знаю поменял Никита свою точку зрения к этому моменту или нет), но тогда он подкинул мне интересных ребят, и хоть я на них уже натыкался, ребят стоит читать и внимательно смотреть - они очень интересные, спасибо Никите. Вот ребята: <a href="http://witheve.com">Eve: Programming designed for humans</a>&hellip; Нашел письмо от Никиты, встречались мы в октябре 2014го.</p>
<p>В общем я не буду ждать ни Никиту ни Mozilla, а просто попытаюсь сделать для себя полноценный Datomic-alike database, с клиентом (peer, в терминологии datomic) на стороне браузера. Задача эта интересна еще и тем, что с 2000-х годов в мире возникло столько структур данных и алгоритмов, что прям крышу сносит. Это в основном succint и cache-oblivious data structures, который интересно было бы с большой пользой применить в БД.</p>
<p>Но начну я с очень простой, скажем так, схематичной реализации хранилища и выполнения запросов.</p>
<h1 id="прототип">Прототип</h1>
<p>В моем прототипе основная часть &ndash; это выполнение запросов. В своей прошлой жизни я никогда до этого момента не доходил (выполнение любого запроса от пользователя). Ибо, если ты делаешь какое то свое хранилище вместо БД общего назначения &ndash; то оно <em>специализированное</em> под конкретную задачу. Это имеет смысл, поскольку в этом случае ты имеешь шанс уделать любую базу данных общего назначения (по памяти, производительности и т.д.). Это предполагает и выполнение конкретных запросов супротив оптимизированной структуры.</p>
<p>Но жизнь показывает, что большинство программистов мыслят стереотипом: если есть данные и есть запросы к данным надо взять БД. Вы не поверите насколько много программистов так мыслят, и даже очень хороших. Работал у нас один мужчина - очень неплохой, и в какой-то момент он занимался эксклюзивно <a href="http://eclipse.org/dltk">DLTK</a>. DLTK это грубо говоря средство разработки, а в средстве разработке задача поиска разнообразной информации - вещь необходимая. Так вот: этот программист всандалил туда <a href="http://www.h2database.com/html/main.html">H2 Database</a>, чем вызвал мое полное недоумение и неприязнь.</p>
<p>Ладно бы он засунул какую-нить BerkeleyDB, но полнценную, реляционную БД с SQL фронт-эндом &ndash; это полный пиздец. А больший пиздец в том, что это <a href="http://spektom.blogspot.fr/2009/07/new-dltk-indexing-is-promising.html">мало кого удивило</a> за исключением реально думащих чуваков, как, например известный в мире PHP Seva (Wsevolod) Lapsha, который буквально снял мои слова с языка:</p>
<pre><code>As I already mentioned, you would probably like to try the Berkeley DB. I assume you do not use non-trivial table joints and filtering, in the queries, so seemless Map interface provided by Berkeley would be easier to use. Also the statement parsing, compilation and optimization is told to be a certain overhead.
Anyway, it would be interesting to perform a clean performance comparison between H2 and B., since I did not found an existing one over the Internets.
</code></pre>
<p>Я не знаю выпилили ли они H2 из DLTK на данный момент (хоть я вроде и оставался формальным Project Lead этого проекта долгое время), но беглый поиск по сети говорит что <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=454867">еблись ребята долго</a>.</p>
<p>Но мы не ищем легких путей (сарказм), хотя можно было бы сейчас скомпилячить <code>sqllite</code> emscripten-ом и подрачить на то, что у меня уже есть БД в браузере, рассазать вам что у меня есть реляционная &ldquo;альтернатива&rdquo; datomic, настроить хуеты вокруг и жидко обосраться в конце.</p>
<h1 id="что-есть-на-данный-момент">Что есть на данный момент</h1>
<p>Практически нихуя. Как я писал выше, моя первая задача - выполнить запрос. В архитектуре datomic любой запрос - это большое количество джойнов, про архитектуру, если не хотите рыться в сети можно почитать выжимку у Никиты: <a href="http://tonsky.me/blog/unofficial-guide-to-datomic-internals/">Unofficial guide to Datomic internals</a>.</p>
<p>Поскольку я интересуюсь БД давно то есть у меня в загашнике знание об одном замечательном алгоритме, который называется <a href="https://arxiv.org/abs/1210.0481">Leapfrog Triejoin</a>. Его я и попользую, поскольку 1) реализация алгоритма тривиальна 2) есть подозрение что он будет работать быстрее чем у Никиты, а у него в DataScript, как я понимаю из <a href="http://tonsky.me/blog/datascript-internals/">A shallow dive into DataScript internals</a> Hash Join.</p>
<h1 id="новый-репозиторий">Новый репозиторий</h1>
<p>Самое время во второй день нового года сделать новую репу, и залить туда всю гавнину. Тем более что старая <a href="https://github.com/platoff/faxma">faxma</a> уже неактуальна ни своим названием ни сутью (<a href="https://platoff.github.io/blog/virtual-dom-%D0%B4%D0%B5%D0%BD%D1%8C-2/">объясняю почему я - дебил</a>). Встречаем свежак: <a href="https://github.com/platoff/wafer">https://github.com/platoff/wafer</a>. Web Application Framework (Elegant and Reactive).</p>
<p><code>leapfrog.nim</code> реализация Leapfrog Triejoin. <code>rel.nim</code> простое хранилище отношений. Отношение это набор tuples вида <code>[a b c ...]</code>, и я предполгаю что все переменные в тупле фиксированной длинны, за исключением одной, которая может быть переменной длинны (этого допущения мне явно не хватит, но пусть пока так).</p>
<p><code>db.nim</code> &ndash; не законченная реализация запросов (из данных, лежащих в rel с помощью leapfrog). Поскольку leapfrog все за меня делает, мне остается лишь построить какой-то план выполнения запроса, итераторы соответствующие этому плану и отдать все это дело в leapfrog. План запроса - не что иное как порядок вычисления переменных участвующих в запросе. Я мог бы сейчас взять их в любом порядке, но хочется посмотреть как согласуются части программы, поэтому я все же делаю какой-то алгоритм выбора эффективного плана (который, в силу своей примитивности, легко сможет &ldquo;выбрать&rdquo; хуевый план).</p>
<h1 id="хуярю">Хуярю</h1>
<p>Надо доделать сам join, сейчас у меня есть только план выполнения запроса. Но перед этим надо навести порядок с ебучей матрицей, которая у меня вдруг возникла. Последний раз я матрицу пользовал в школе, когда программировал пиксельную графику (и не для аффинных преобразований &ndash; я про них не знал ни тогда ни сейчас), а для того чтобы хранить пиксели. А из университета меня выгнали, так что матрицы я не программировал, и всегда считал что для программиста достаточно одномерного массива. Но все же в данном месте мне очень хочется ее засунуть.</p>
<p>&hellip;В общем хер с ним &ndash; делать полноценное построение всех планов это подзаебаться, завтра сделаю чтобы работало в моих частных случаях. <a href="https://github.com/platoff/wafer/commit/4bd155da9c37fa54cfeaad4ac5dce8d97d821371">Коммит</a></p>
</description>
</item>
<item>
<title>Про софтваре чуваков и проблемы реального мира</title>
<link>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE-%D1%81%D0%BE%D1%84%D1%82%D0%B2%D0%B0%D1%80%D0%B5-%D1%87%D1%83%D0%B2%D0%B0%D0%BA%D0%BE%D0%B2-%D0%B8-%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BC%D0%B8%D1%80%D0%B0/</link>
<pubDate>Sun, 01 Jan 2017 14:15:35 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE-%D1%81%D0%BE%D1%84%D1%82%D0%B2%D0%B0%D1%80%D0%B5-%D1%87%D1%83%D0%B2%D0%B0%D0%BA%D0%BE%D0%B2-%D0%B8-%D0%BF%D1%80%D0%BE%D0%B1%D0%BB%D0%B5%D0%BC%D1%8B-%D1%80%D0%B5%D0%B0%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE-%D0%BC%D0%B8%D1%80%D0%B0/</guid>
<description>
<p>Здравствуй 2017, и мой анонимный читатель с псевдонимом George. Я еще никому не сказал про этот блог, но George его уже как-то нарыл, что приятно.</p>
<p>Наверное в первый день нового года стоит написать о том, что я планирую сделать в этом году. Поддамся стереотипам и попробую. Сделать это будет несколько сложно, ведь суть этого блога &ndash; показать ход мысли. Не только что я делаю/хочу/&hellip;, а как я дошел до это, в том числе через огромное количество ошибок. Для этого придется дампить некоторое содержимое из башки в текст, свзяать же все в одну кучу в тексте будет стоить много времени, но думаю, что к концу года все свяжется.</p>
<p>Начну издалека, и параллельно выдам себе комплиментов:</p>
<h1 id="про-софтваре-чуваков-и-решение-проблем">Про софтваре-чуваков и решение проблем</h1>
<p>Я можно сказать с рождения был software-чувак. Сходу я не смог найти оригинальны пост про то, что я имею ввиду под софтваре-чуваком, но если кратко, то софтваре-чел &ndash; это чел, который видя какую-либо проблему в реальном мире, пытается решить ее в софте. Пытается - это не значит что он садится за компьютер и напрягается, я про способ мышления - есть проблема, есть фантазии на тему решения проблемы с помощью &ndash;зонта&ndash; софта.</p>
<p>Если порытся в сети, можно найти разнобразные проекции этой мысли, например вот здесь: <a href="http://codemanship.co.uk/parlezuml/blog/?sectionid=39">The Best Software Developers Know It&rsquo;s Not All &lsquo;Hacking&rsquo;</a> это первое попавшееся, но от себя я сразу уточню что быть софтваре-чуваком - это необходимое, но не достаточное условие для того, чтобы быть Best Software Developer.</p>
<p>Решать реальные проблемы с помощью софта - это не сначит делать софт самому, большая часть проблем решается сущуствующими инструментами. Будучи и программистом и софтваре чуваком, существенная часть реальных проблем, с которыми я встречался в жизни были связаны, как это не удивительно (сарказм), с программированием, и разработкой ПО.</p>
<p>Первая очевидная мне проблема встала в моей первой команде (в году так 1995, мне тогда было 19 лет) - проблема версионинга исходных файлов, и проблема &ldquo;учета проблем&rdquo; :). Смешно это писать в первый день 2017 года, когда даже начинающий программист удивится: ведь есть куча инструментов версионинга, и баг трекеры. Но гораздо смешнее то, что и в далеком 1995 годе большинство программистов жили без версионинга и багтрекинга и <em>проблемы не видели</em>. Перед ними стояли <em>задачи</em> синхронизировать кодебазу, которую они успешно решали передачей файлов на дискетах, через файловый сервер (у кого была локальная сеть), или самые продвинутые через электронную почту (у кого была и локальный сервер был не доступен). Вышак был воздвигнуть FTP.</p>
<p>Блять! Я вам скажу 95% программистов считало что таскать файлы на дискете - это <em>нормально</em>. Что у них <em>нет проблем</em>. Для учета проблем в самых продвинутых и жестких организциях была тетрадка учета проблем, а наиболее компьютеризированные (и имеющие локальные сети) записывали проблемы в текстовом (или вордовом!) файле (тем самым <em>усугубляя</em> проблему версионирования. Так делали не только в отсталой России, но и во всем мире.</p>
<p>Ребята, еб вашу мать! Так быть не должно, вы же понимаете что это пиздец, вы понимаете что вы теряетесь в версиях ваших файлов, вы понимаете, что вы тратите безумное количество времени чтобы синхронизироваться и огромное количество ошибок мы ловим потоуму что кто-то что-то собрал хуй пойми их каких версий, непонятно откудо взятых файлов??? (а это случалось постоянно). Но восклицать было бесполезно. 19 из 20 программистов смотрели на тебя как на долбоеба, типа что-ты тут орешь &ndash; такова жизнь и все так делают &ndash; разработка ПО - это боль.</p>
<p>Тогда, более 20 лет назад, я понял что программист != софтваре-чел. Это разные, случайно пересекающиеся множества. Большинство программистов <em>не видят проблем</em>, там где они есть. Они не видят проблем даже в том, чем непосредственно занимаются. Точно так же они не видят проблем ни в своих решениях, ни в той области в которую они призваны (наняты) решать проблемы.</p>
<p>Но мне то, как софтваре-челу проблема была очевидна, и я начал искать. В те времена я не думал что пацан из Сибири имеет право сам решать мировые проблемы, и я просто искал решение. На компакт дисках, устанавливая горы шлака имеющее хоть какое-то отношение к разработке, в интернете (на скоросте 500 байт в секунду), и эй! Google в то время отсутствовал, не думайте что найти что-либо релевантное в сети тогда было так просто.</p>
<p>И вот оно, оказалось под носом. Только что вышедший Delphi Client/Server версии 2.0 включал в себя некий комонент под названием PVCS. Как эта хуета работала и как ей пользоваться было решительно непонятно - я вам скажу этот PVCS был еще тот пиздец, но я радовался безумно: оказалось что я не один ебанутый, а есть люди, которые понимают проблему, и даже предлагают решения.</p>
<p>Для молодежи скажу что тогда, естественно, не было никакого git, и даже SVN. Уже был CVS: <em>On November 19, 1990, CVS version 1.0 was submitted to the Free Software Foundation for development and distribution</em>, но я его успешно пропустил - у меня не было машины с юниксом - сеть наша бегала на Novell Netware, и мой поиск к сожалению был нацелен на винду. Кстати, как бы там не было - CVS в то время был свежак - прям хипстерская технология не для масс. Хер его знает в каком он был состоянии в 1995 (активно пользовать сам я его начал примерно в 2002), так вот тогда SVN которому уже было пару лет отроду был полный пиздец, пользовать его можно было начинать только после 2006 - а там уже git подтягивался.</p>
<p>Long story short, я наконец нашел его: <a href="https://en.wikipedia.org/wiki/StarTeam">StarTeam</a> от компании StarBase, чуть ли ни бету версии 2.0, то ли на треш-CD куда сливали весь warez мира без разбору и продавали в ларьках за деньги, толи еще где. Это была песня. Это был кайф, и не только versioning файлов, но и интегрированный баг-трекер. Чуть позже мы нарыли StarTeam Server и просидели на этом волшебном продукте до того как команда наебнулась в самом начале 1999.</p>
<p>Тогда я, кстати, думал что Borland - дураки, и должны были купить StarTeam, что они, кстати и сделали в 2003-м. Borland вообще единственная контора на моей памяти, покупки которой согласовались с моим наивным представлением о том, кто и что должен купить. В какой то момент смотря на уебищный Midas от Borland (такое же уебанство как PVCS), разочарованно думал, еб вашу мать, зачем вам это гавно - есть же прекрасный VisiORB. И Borland покупает VisiGenic. Наивный я был конечно в том, что думал компании и продукты покупаются чтобы сделать свою линейку еще более удобной и привлекательной для пользователя, но, во-первых и зачастую это не так, а во-вторых, даже когда это так - топ-менеджмент компаний нихуя не понимает в том, что на самом деле надо людям.</p>
<p>В 1999 я пришел в небезызвестный Novosoft. Я был 105-й, а через год там работало что-то около 500 человек. Так вот, большинство этих программистов не пользовалость ни version control, ни багтрекерами, и не парились по этому поводу. Были люди, которые прям насаждали CVS или StarTeam в отдельно взятых командах, но багтрекерами большинство так и не воспользовалось (Jira кстати тогда тоже не было), про Wiki даже не говорите, и хоть Ward Cunningham уже сделал WikiWikiWeb - знали о значении этого слова их четырех букв только избранные.</p>
<p>Хехе CruiseControl я тоже пользовал - но это уже лишнее для данного поста.</p>
<h1 id="резумируя">Резумируя</h1>
<p>Большинство диалогов начинающихся с фразы: &ldquo;ты же программист, реши нам проблему (сделай софт)&rdquo; заканчивается <em>двумя</em> проблемами: оригинальной проблемой, которая до сих пор нормально не решена и тем решением, с которым как то приходится жить и мириться. Это происходит потому что mindset большинства программистов (как впрочем и непрограммистов) не заточен на решение real-world пробелем. Они не видят проблем (да же тех, которые у них перед носом) и так же не видят решений.</p>
<p>То есть если им объяснить проблему (показать) - они смогут <em>придумать</em> некоторое решение, которое будет далеко не идеальным. У меня нет объяснения почему так, но я думаю объяснение лежит в области слепоты: человек не <em>видящий</em> проблему не может <em>увидеть</em> решение. Тут важно заметить что я говорю не про знание а про видение: даже самый глазастый визионер не будучи <em>знаком</em> с предметом никаих проблем там не увидит. Речь идет о том когда человек знаком с проблемным предметом.</p>
<p>В общем так, ребятишки - если бы вас научили программированию где-нибудь на необитаемых островах и заставили писать софт, то только на одном из 20 таких островов нашлись бы люди, которые сделали бы себе систему контороля версий и прочее, остальные бы херачили как получится. Я это видел - и это медицинский факт.</p>
<p>Что интересно, если бы вас научили программировать на ассемблере и оставили на острове, то только на одном из 20 появилось бы некоторое подобие Си. Остальные так бы и херачили на ассемблере, <em>не видя в этом никаких проблем</em>. Я привожу примеры из области программирования только потому что блог как бы про программирование, к сожалению (или к счастью) то же самое верно для любой области деятельности и в любом разрезе.</p>
<p>На сегодня хватит писанины, надо бы еще попрограммировать. Завтра продожу подводить к планам на 2017, и после этого расскажу что там с программированием. Последние несколько дней 2016 я чо то поделал, и сейчас буду продолжать.</p>
</description>
</item>
<item>
<title>Прошел месяц</title>
<link>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE%D1%88%D0%B5%D0%BB-%D0%BC%D0%B5%D1%81%D1%8F%D1%86/</link>
<pubDate>Mon, 19 Dec 2016 10:12:21 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BF%D1%80%D0%BE%D1%88%D0%B5%D0%BB-%D0%BC%D0%B5%D1%81%D1%8F%D1%86/</guid>
<description>
<p>Прошел месяц с моего решения ежедневно программировать и так же ежедневно писать. В результате я програмиировал 4.5 дня. Писал немного чаще, но в основном в чукотском стиле (что вижу - то пою). А это уже некоторые цифирки, помогающие мне понять чем я на самом деле занимаюсь, и в какую из труб вылетает все мое время.</p>
<h2 id="заканчиваю-с-dbmonster">Заканчиваю с dbmonster</h2>
<p>Прежде чем идти дальше, приду к какому-то законченному варианту с dbmonster. Мне не нравится что выглядит он не так, как остальные dbmonster в сети: толи я накосячил со стилями, то-ли в html, непорядок. Попробую найти проблему.</p>
<blockquote>
<p>Ебать же в сраку вашу мать</p>
</blockquote>
<p>Сравнил все что мог, мистика, HTML и CSS идентичны, но у чувачков размер фонта поменьше и количество запросов выровнено по вертикали, в отличии от меня. Ебана в рот, оказывается дело в том что у меня нет вот этой прекрасной директивы <code>&lt;!DOCTYPE html&gt;</code>, которая, кто бы мог подумать, имеет значение.</p>
<p>Определенно, Web продвинулся очень далеко с 1999 года, и мне придется многое изучить, ну а мой dbmonster теперь выглядит как все.</p>
<h2 id="заканчиваю-с-dom-diff">Заканчиваю с DOM diff</h2>
<p>В общем DOM diff вещь, которая безусловно пригодится но я пока не вижу всей картины. Как должно выглядить полноценное приложение мне совсем не понятно. Как я буду управлять состоянием, на чем буду писать презентацию и ее логику? Будет ли это Nim или собственный язык (если так то будет это компилятор или интерпретатор на Nim). Язык общего назначения или &ldquo;шаблоны&rdquo;?</p>
<p>Чтобы закончить на позитивной ноте, решил еще померять скорость того, что есть. Имеется ввиду полный цикл (построение модели, рендер в HTML, diff с предыдущей и применение diff к DOM браузера). Основная просадка по времени была не у меня а в 2-х местах
* Реализация random в Nim модуле random жутко медленная. Заменил на модуль mersenne.
* Форматирование при выводе float в строку так же съедает большую часть времени, заменил на int в модели.</p>
<p>После этих двух нехитрых изменений:</p>
<ul>
<li>Нативно: Render: 0.3ms, Diff: 0.35ms, Model + Render + Diff: <strong>1ms</strong></li>
<li>V8 (node.js v4.1.1): Render: 1.2ms, Diff: 1.8ms, Model + Render + Diff: <strong>4.3ms</strong></li>
</ul>
<p>Качнул свежак node - v7.3.0, в душе не ебу как у них с версиями и старая ли моя 4.1.1.</p>
<ul>
<li>V8 (node.js v7.3.0): Model + Render + Diff: <strong>4.8ms</strong> - эта гавнина еще медленнее, похоже я не умею ее готовить&hellip;</li>
</ul>
<p>Нашел гарную тему: <code>node --v8-options</code>, включаю некий TurboFan <code>--turbo</code></p>
<ul>
<li>V8 (node.js v7.3.0): Model + Render + Diff: <strong>6.2ms</strong> начинаю ржать :).</li>
<li>V8 (node.js v7.3.0 &ndash;turbo_asm): Model + Render + Diff: <strong>4.3ms</strong> походу эта муля была включена в 4.1.1 по умолчанию.</li>
</ul>
<p>В общем с настройками V8 интересно баловаться, но оставлю на потом.</p>
<h2 id="посмотреть">Посмотреть</h2>
<p>Потыкать в dbmonster (200 строк) можно здесь: <a href="https://platoff.github.io/dbmonster/200/dbmonster.html">https://platoff.github.io/dbmonster/200/dbmonster.html</a>. Постмотреть как оно должно быть (с точки зрения производительности) можно здесь: <a href="https://platoff.github.io/dbmonster/20/dbmonster.html">https://platoff.github.io/dbmonster/20/dbmonster.html</a>.</p>
<p>Код здесь: <a href="https://github.com/platoff/faxma/tree/day-161219">https://github.com/platoff/faxma/tree/day-161219</a></p>
</description>
</item>
<item>
<title>Выхожу из тени</title>
<link>https://platoff.github.io/blog/%D0%B2%D1%8B%D1%85%D0%BE%D0%B6%D1%83-%D0%B8%D0%B7-%D1%82%D0%B5%D0%BD%D0%B8/</link>
<pubDate>Wed, 14 Dec 2016 12:12:47 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%B2%D1%8B%D1%85%D0%BE%D0%B6%D1%83-%D0%B8%D0%B7-%D1%82%D0%B5%D0%BD%D0%B8/</guid>
<description><p>Если вы это читаете, то да, этот блог вышел в сеть. Большую часть дня я потратил на поиск движка для блога. Остановился на <a href="https://gohugo.io">hugo</a>, поиск &ldquo;темы&rdquo;, ее подхачивание, редактирование и форматирование контента, выкладывание сайта и артефактов от предыдущих постов.</p>
<p>Такой день&hellip; Завтра с утра бюрократия, но вторую половину дня надеюсь посвятить программированию.</p>
</description>
</item>
<item>
<title>Рекрутер</title>
<link>https://platoff.github.io/blog/%D1%80%D0%B5%D0%BA%D1%80%D1%83%D1%82%D0%B5%D1%80/</link>
<pubDate>Tue, 13 Dec 2016 18:17:52 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D1%80%D0%B5%D0%BA%D1%80%D1%83%D1%82%D0%B5%D1%80/</guid>
<description><p>Сегодня не программировал, но день прошел не без мелких программистских &ldquo;радостей&rdquo;. Рекрутеры не контачили со мной много лет. Я думаю это потому, что мой GitHub пуст, а в резюме нет интересующих их слов типа JavaScript. Но стоило мне начать программировать, какая-то особо чувствительная особа унюхала свежее мясо и доебалась.</p>
<p>Я честно говоря был рад: ведь общение с рекрутером &ndash; это уже признак того, что я становлюсь интересен как программист. Уверен, что для практикующих программистов такие диалоги &ndash; рутина, но для меня &ndash; нечто новое. Вот что получилось:</p>
<blockquote>
<p>&ndash; Андрей, добрый день. Спешно ищем Лида в Webgames. Давайте пообщаемся?<br />
&ndash; Давайте пообщаемся<br />
&ndash; Давайте ))<br />
&ndash; Начинайте<br />
&ndash; Андрей, добрый день. Что скажете про описание? Разработку игр и Godot?<br />
&ndash; Godot - отличная вещь, слежу за ним уже пару лет. Что вам интересно про описание? Описание достойное, не хватает пункта о компенсации<br />
&ndash; Вы занимаетесь разработкой игр сейчас ?<br />
&ndash; Ага<br />
&ndash; Компенсацию готовы обсуждать, тут сложно сказать точную ставку<br />
&ndash; А в чем сложность?<br />
&ndash; Зависит от кандидата, явно человек не будет рассматривать уровень меньше, чем сейчас. Есть ли у вас резюме? Или где-то информация о вас?<br />
&ndash; Конечно есть <a href="https://lmgtfy.com/?q=андрей+платов">https://lmgtfy.com/?q=андрей+платов</a> а почему вы думаете что человек не будет рассматривать уровень меньше чем сейчас? это очень частый случай. Нашли резюме?<br />
&ndash; Неа, поможите)))<br />
&ndash; Как не нашли? а что google выдает? И я использую ненормативную лексику, это проблема?<br />
&ndash; Нет)))) Главное Любовь к годот )))<br />
&ndash; так и какие действия? резюме не нашли? годот - молодцы, хорошие ребята, не скажу что у меня к ним любовь, скорее уважение<br />
&ndash; Не, линкедин не открывается( закрыли его. Надо искать через что открыть<br />
&ndash; А, забыл что закрыли, а как же вы людей-то ищете без linkedin? получается? Слушайте, а что, в Москву надо переезжать, чтобы с вами работать?<br />
&ndash; А где вы?<br />
&ndash; я во Франции<br />
&ndash; Да, надо. Вы не поедете 😂<br />
&ndash; почему вы так уверены? вы же обратились ко мне, значит какое-то уникальное предложение. Я конечно Москву не терплю но ради интересного дела могу потерпеть<br />
&ndash; ))))) серьёзно ? Мне кажется, место жительство это важный аспект, тем более это же не из Нижнего Новгорода в Москву, а почти наоборот 😂<br />
&ndash; Ну я же езжу в Новосибирск, и надолго - у нас там главный офис. В Москве тоже провожу около месяца в году, хоть и не люблю ее. Дело то важнее, так же?<br />
&ndash; Да) хорошо, я открою ваш профиль через Линк, отправлю нашему технич гуру )<br />
&ndash; А он точно гуру? Как зовут? Я в России всех гуру знаю, или слышал<br />
&ndash; Яша Боревич<br />
&ndash; Не слышал. Гляну сейчас. Понял. Чувак любитель годота <a href="https://moikrug.ru/borevich-yakov">https://moikrug.ru/borevich-yakov</a><br />
&ndash; Да ))) Но он уходит, ищем ему смену<br />
&ndash; Слушайте, а что он готов к предложениям за 200 тыщ? Может я его найму? Но я то за 200 тыщ не готов как он<br />
&ndash; А за сколько? И как вы к unity3d относитесь ?<br />
&ndash; Отрицательно. Скажу вам Unity гавно.<br />
&ndash; Хорошо, я вас поняла. У нас 2 позиции и ещё одна unity lead<br />
&ndash; На кой вам Юнити лид? Вы много игр делаете? Слушайте, а вот эти прекрасные отзывы - это правда? <a href="http://job-interview.ru/company/review/4391">http://job-interview.ru/company/review/4391</a><br />
&ndash; Это же все старьё. Старый HR<br />
&ndash; Ну а сейчас как дела? И причём здесь HR. Кидает то не HR. И что новый не подчистил интернет?<br />
&ndash; Все хорошо, не кидают никого<br />
&ndash; А чо Яша уходит? Денег мало или перспектив нет?<br />
&ndash; И то и то наверное, он давно работает. Я ищу для веб Геймс, не работаю у них в штате<br />
&ndash; то есть вы меня хотите продать вместо Яши, которому мало платят и у которого нет перспектив? Ладно, черт с ними, с зарплатой и перспективами. Так то мне 40 лет, не стар для программиста?<br />
&ndash; [тишина&hellip;]</p>
</blockquote>
<p>В общем разговор не состоялся, где-то я накосячил и до офера не дошел. Но почувствовал себя востребованным программистом. Хотя&hellip; может действительно возраст испугал. Завтра утром продолжу доказывать что в сорок лет не поздно начинать конкурировать с молодежью на их территории.</p>
</description>
</item>
<item>
<title>Russian Business</title>
<link>https://platoff.github.io/blog/russian-business/</link>
<pubDate>Mon, 12 Dec 2016 17:22:58 +0100</pubDate>
<guid>https://platoff.github.io/blog/russian-business/</guid>
<description>
<p>Тег <code>проебал</code> не совсем верен. За последние две недели я проебал только программирование - с годами мне стало сложно переключаться, вернее невозможно. Впрочем, попробую научиться, дело в практике.</p>
<p>Все дни был занят бытовухой в Праге и Новосибирске. Ребята молодцы! Юра К. для меня - открытие года. Прага вроде начала активный поиск сотрудников. Академовский офис переезжает в новое большое помещение (не помню размер, но что то около 1500 квадратов). Ну и не обошлось без трений с российским бизнесом.</p>
<h1 id="бессмысленный-и-беспощадный">Бессмысленный и беспощадный</h1>
<p>Сталкиваясь с &ldquo;бессмысленным и беспощадным&rdquo; российским бизнесом, сразу понимаешь: вот он, родимый. За редким исключением, российский бизнес, идущий на конфликт с желанием что-либо выторговать для себя, так же, как и российская внешняя политика, использует только два инструмента: <code>блеф</code> и <code>шантаж</code>. Обычно в паре, поскольку шантаж без блефа это сложно.</p>
<p>Пиздеть они могут на любую тему, и как правило, все, что они очень убедительно излагают, не соответствует действительности. &ldquo;Факты&rdquo; на которые они опираются не существуют в природе, а законы, на которые ссылаются, говорят обратное.</p>
<p>По возможности избегайте, но встретившись - поймите где блеф, выкиньте его из поля зрения, и пошлите товарищей нахуй.</p>
</description>
</item>
<item>
<title>Посмотреть на Монстра</title>
<link>https://platoff.github.io/blog/%D0%BF%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C-%D0%BD%D0%B0-%D0%BC%D0%BE%D0%BD%D1%81%D1%82%D1%80%D0%B0/</link>
<pubDate>Sun, 27 Nov 2016 12:43:21 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BF%D0%BE%D1%81%D0%BC%D0%BE%D1%82%D1%80%D0%B5%D1%82%D1%8C-%D0%BD%D0%B0-%D0%BC%D0%BE%D0%BD%D1%81%D1%82%D1%80%D0%B0/</guid>
<description>
<p>Сегодня хочу получить полноценный dbmonster - с бегущими циферками по экрану. До текущего момента я генерировал экраны в цикле, не передавая управление браузеру, и это надо исправить. Для этого мне надо по-честному воткнуться в message loop. Замечательный emscripten все сделал, пользую <code>emscripten_set_main_loop</code>.</p>
<p>Итак, все оказалось очень просто:</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span><span class="k">proc </span><span class="nf">loop</span><span class="p">()</span> <span class="p">{.</span><span class="n">cdecl</span><span class="p">.}</span> <span class="o">=</span>
<span class="n">patch</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
<span class="k">let</span> <span class="n">data</span> <span class="o">=</span> <span class="n">getData</span><span class="p">()</span>
<span class="k">if</span> <span class="n">i</span> <span class="ow">mod</span> <span class="mi">2</span> <span class="o">==</span> <span class="mi">1</span><span class="p">:</span>
<span class="n">b</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">data</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="n">b</span><span class="p">)</span>
<span class="n">patch</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">current</span><span class="p">,</span> <span class="n">a</span><span class="p">.</span><span class="n">current</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">a</span><span class="p">.</span><span class="n">clear</span><span class="p">()</span>
<span class="n">data</span><span class="p">.</span><span class="n">render</span><span class="p">(</span><span class="n">a</span><span class="p">)</span>
<span class="n">patch</span><span class="p">.</span><span class="n">diff</span><span class="p">(</span><span class="n">a</span><span class="p">.</span><span class="n">current</span><span class="p">,</span> <span class="n">b</span><span class="p">.</span><span class="n">current</span><span class="p">)</span>
<span class="n">patch</span><span class="p">.</span><span class="n">done</span><span class="p">()</span>
<span class="n">JSrender</span><span class="p">(</span><span class="n">patch</span><span class="p">.</span><span class="n">data</span><span class="p">.</span><span class="n">head</span><span class="p">)</span>
<span class="n">inc</span> <span class="n">i</span>
<span class="n">emscripten_set_main_loop</span><span class="p">(</span><span class="n">loop</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="mi">0</span><span class="p">)</span>
</code></pre></div>
<p>Safari: 18-19 FPS. В разы медленнее inferno. Через некоторое время падает с out of memory - не мудрено, я же отключил GC. Для начала попробую как то врубить GC: безопасно это только в main loop, и добиться стабильности:</p>
<div class="highlight"><pre><code class="language-Nimrod" data-lang="Nimrod"><span></span> <span class="n">GC_enable</span><span class="p">()</span>
<span class="k">let</span> <span class="n">x</span> <span class="o">=</span> <span class="n">newString</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
<span class="n">GC_disable</span><span class="p">()</span>
</code></pre></div>
<p>17-18 FPS. Медленнее, чем большинство фреймворков. В Chrome вообще пиздец: 9-10 FPS. Утешаю себя тем, что я только начал и дело не в скорости, а в первую очередь в продуктивности и нежелании писать на JavaScript. Пока по всем параметрам я проигрываю.</p>
<h1 id="посмотреть-на-монстра">Посмотреть на Монстра</h1>
<p>Посмотреть на монстра в деле можно здесь: <a href="https://platoff.github.io/dbmonster">https://platoff.github.io/dbmonster</a>.
Код под тегом <code>day-10</code> <a href="https://github.com/platoff/faxma/tree/day-10">https://github.com/platoff/faxma/tree/day-10</a>.</p>
</description>
</item>
<item>
<title>Уехал в Прагу</title>
<link>https://platoff.github.io/blog/%D1%83%D0%B5%D1%85%D0%B0%D0%BB-%D0%B2-%D0%BF%D1%80%D0%B0%D0%B3%D1%83/</link>
<pubDate>Sat, 26 Nov 2016 22:38:16 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D1%83%D0%B5%D1%85%D0%B0%D0%BB-%D0%B2-%D0%BF%D1%80%D0%B0%D0%B3%D1%83/</guid>
<description><p>Все таки вести этот журнал была хорошая идея &ndash; сразу видно сколько дней я проебываю в никуда. В четверг улетел в Прагу. Пятница зашел в офис - поговорили с коллегами. Суббота &ndash; тупо проебал, сходил пообедать, поужинать. Для моего программирования польза нулевая. Попробую что-нибудь сделать завтра.</p>
</description>
</item>
<item>
<title>Пора запуститься в браузере</title>
<link>https://platoff.github.io/blog/%D0%BF%D0%BE%D1%80%D0%B0-%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D1%82%D0%B8%D1%82%D1%8C%D1%81%D1%8F-%D0%B2-%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80%D0%B5/</link>
<pubDate>Wed, 23 Nov 2016 11:30:59 +0100</pubDate>
<guid>https://platoff.github.io/blog/%D0%BF%D0%BE%D1%80%D0%B0-%D0%B7%D0%B0%D0%BF%D1%83%D1%81%D1%82%D0%B8%D1%82%D1%8C%D1%81%D1%8F-%D0%B2-%D0%B1%D1%80%D0%B0%D1%83%D0%B7%D0%B5%D1%80%D0%B5/</guid>
<description>
<p>Сегодня, наконец, хочу увидеть что-нибудь в браузере.</p>
<h1 id="moй-первый-javascript">Moй первый JavaScript</h1>
<p>Для начала, могу сказать что я вообще не знаю как работают scopes в JavaScript (и моя предыдущая проблема с переменной цикла без var тому пример), я решил для начала вывести DOM в консоль, и для этого погуглил функцию вывода n пробелов (я уже веду себя как настоящий JS-разработчик, не начав программировать). Реализация вылезла следующая:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span></span><span class="kd">function</span> <span class="nx">space</span><span class="p">(</span><span class="nx">num</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nb">Array</span><span class="p">(</span><span class="nx">num</span> <span class="o">+</span> <span class="mi">1</span><span class="p">).</span><span class="nx">join</span><span class="p">(</span><span class="s2">&quot; &quot;</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div>
<p>Тут я полностью охуел и понял, что JS-программистом мне не быть никогда. Я просто не смогу такое придумать - в прошлом я не протоптал ни одной тропинки в мозгу, которая могла бы привести к такому решению задачи. И, честно говоря, протаптывать такие тропинки (учиться) мне пока не хочется. Поэтому в пизду - будем сразу вываливать DOM.</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span></span><span class="nx">mergeInto</span><span class="p">(</span><span class="nx">LibraryManager</span><span class="p">.</span><span class="nx">library</span><span class="p">,</span> <span class="p">{</span>
<span class="nx">$renderElement</span><span class="o">:</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">p</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">p</span> <span class="o">=</span> <span class="nx">p</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="kr">const</span> <span class="nx">tags</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;DOCUMENT_ROOT&quot;</span><span class="p">,</span> <span class="s2">&quot;TEXT&quot;</span><span class="p">,</span> <span class="s2">&quot;a&quot;</span><span class="p">,</span> <span class="s2">&quot;button&quot;</span><span class="p">,</span> <span class="s2">&quot;div&quot;</span><span class="p">,</span> <span class="s2">&quot;h1&quot;</span><span class="p">,</span> <span class="s2">&quot;header&quot;</span><span class="p">,</span> <span class="s2">&quot;hr&quot;</span><span class="p">,</span> <span class="s2">&quot;input&quot;</span><span class="p">,</span>
<span class="s2">&quot;label&quot;</span><span class="p">,</span> <span class="s2">&quot;li&quot;</span><span class="p">,</span> <span class="s2">&quot;p&quot;</span><span class="p">,</span> <span class="s2">&quot;section&quot;</span><span class="p">,</span> <span class="s2">&quot;span&quot;</span><span class="p">,</span> <span class="s2">&quot;table&quot;</span><span class="p">,</span> <span class="s2">&quot;tbody&quot;</span><span class="p">,</span> <span class="s2">&quot;td&quot;</span><span class="p">,</span> <span class="s2">&quot;tr&quot;</span><span class="p">,</span> <span class="s2">&quot;ul&quot;</span>
<span class="p">];</span>
<span class="kr">const</span> <span class="nx">A</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;TEXT&quot;</span><span class="p">,</span> <span class="s2">&quot;class&quot;</span><span class="p">,</span> <span class="s2">&quot;for&quot;</span><span class="p">,</span> <span class="s2">&quot;placeholder&quot;</span><span class="p">,</span> <span class="s2">&quot;type&quot;</span><span class="p">,</span> <span class="s2">&quot;value&quot;</span><span class="p">,</span> <span class="s2">&quot;width&quot;</span><span class="p">,</span> <span class="s2">&quot;title&quot;</span><span class="p">];</span>
<span class="kd">var</span> <span class="nx">t</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">kids</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">attrs</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">e</span><span class="p">;</span>
<span class="k">switch</span><span class="p">(</span><span class="nx">t</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="mi">0</span><span class="o">:</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;render DOCUMENT_ROOT&quot;</span><span class="p">);</span>
<span class="nx">e</span> <span class="o">=</span> <span class="nx">createTextNode</span><span class="p">(</span><span class="s2">&quot;error: DOCUMENT ROOT HERE&quot;</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">1</span><span class="o">:</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span> <span class="c1">//attrid == text</span>
<span class="nx">e</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createTextNode</span><span class="p">(</span><span class="nx">Pointer_stringify</span><span class="p">(</span><span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]));</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="nx">e</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">createElement</span><span class="p">(</span><span class="nx">tags</span><span class="p">[</span><span class="nx">t</span><span class="p">]);</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span><span class="nx">attrs</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">a</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">v</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">e</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="nx">A</span><span class="p">[</span><span class="nx">a</span><span class="p">],</span> <span class="nx">Pointer_stringify</span><span class="p">(</span><span class="nx">v</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">for</span> <span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span><span class="o">&lt;</span><span class="nx">kids</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">kid</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)];</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">e</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span> <span class="nx">renderElement</span><span class="p">(</span><span class="nx">kid</span><span class="p">)</span> <span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">e</span><span class="p">;</span>
<span class="p">},</span>
<span class="nx">JSrender</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">p</span> <span class="o">=</span> <span class="nx">p</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">root</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;app&quot;</span><span class="p">);</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;Hello from emscripten: &quot;</span><span class="p">,</span> <span class="nx">root</span><span class="p">.</span><span class="nx">childElementCount</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">app</span> <span class="o">=</span> <span class="nx">renderElement</span><span class="p">(</span><span class="nx">p</span><span class="p">,</span> <span class="mi">0</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">root</span><span class="p">.</span><span class="nx">childElementCount</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">root</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span> <span class="nx">app</span> <span class="p">);</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="nx">JSrender__deps</span><span class="o">:</span> <span class="p">[</span><span class="s2">&quot;$renderElement&quot;</span><span class="p">],</span>
<span class="p">})</span>
</code></pre></div>
<p>Я намеренно вываливаю DOM на экран лишь один раз - хочу замерить генерацию JS DOM off-screen. Ну что-ж: 18.5 ms на итерацию в Safari (это притом что asm.js часть справилась за 4.2ms). Chrome: хром вообще охуел от того что я ему сунул, пришлось считать на 250 итерациях - 75ms на итерацию. Это вообще ни в какие ворота, но как бы радует что asm.js часть все делает за 7.5ms.</p>
<p>Из &ldquo;тяжелого&rdquo; у меня в цикле только <code>Pointer_stringify</code>, который работает с UTF-8, пробую заменить на более быстрый <code>AsciiToString</code>, что, впрочем не совсем верно, но надо посмотреть. Safari - 17.1ms. Выйграл миллисекунду, и понятно, что дело не в &ldquo;математике&rdquo;, а в большом количестве создаваемых и собираемых сборщиком мусора нод. Вот он корень зла, и подтверждение того, что вроде бы Virtual DOM - нужная вещь. Для проверки, отключил все операции с JS DOM - 6.9ms на итерацию.</p>
<p>Ну что-ж остался основной ингридиент - diff/patch, и наступит момент истины.</p>
<h1 id="момент-истины">Момент истины</h1>
<p>Итак, примитивный (не значит что медленный) diff реализован, запускаю без UI. На, нахуй! 1.3ms на итерацию нативный код, 7.8ms на итерацию в V8 (node.js). Это генерация модели + посторение DOM + простроение Diff. Какой-то запас еще есть. Осталось патчить DOM в браузере.</p>
<h3 id="21-54-центрально-европейского-времени">21:54 центрально-европейского времени</h3>
<p>Готово применение патча в браузере - <code>9.8ms</code> на итерацию! в Safari. Рано радоваться, поскольку итерация не отрисовывается (я не передаю управление в main loop), отрисовывается только результат последней. Но время обнадеживает: думаю что до 8ms эта история оптимизируется, 8ms оставим на отрисовку, и здравствуй 60 FPS. Правда Chrome дает <code>14ms</code>, но будем смотреть - сейчас все довольно схематично.</p>
<p>Выглядит примерно так:</p>
<div class="highlight"><pre><code class="language-js" data-lang="js"><span></span> <span class="nx">JSrender</span><span class="o">:</span> <span class="kd">function</span><span class="p">(</span><span class="nx">p</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">p</span> <span class="o">=</span> <span class="nx">p</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">element</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="s2">&quot;app&quot;</span><span class="p">);</span>
<span class="c1">//console.log(&quot;RENDER: &quot;, p);</span>
<span class="c1">// p is PATCH address</span>
<span class="k">while</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">cmd</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="c1">//console.log(&quot;cmd: &quot;, cmd);</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">switch</span><span class="p">(</span><span class="nx">cmd</span><span class="p">)</span> <span class="p">{</span>
<span class="k">case</span> <span class="mi">0</span><span class="o">:</span> <span class="c1">// HALT</span>
<span class="k">return</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">1</span><span class="o">:</span> <span class="c1">// NAV_UP</span>
<span class="kd">var</span> <span class="nx">times</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">times</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">2</span><span class="o">:</span> <span class="c1">// NAV_KID</span>
<span class="kd">var</span> <span class="nx">nkid</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">children</span><span class="p">[</span><span class="nx">nkid</span><span class="p">];</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">3</span><span class="o">:</span> <span class="c1">// NAV_PARENT</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">4</span><span class="o">:</span> <span class="c1">// NAV_GRAND_PARENT</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">parentNode</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">5</span><span class="o">:</span> <span class="c1">// NAV_FIRST_CHILD</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">firstChild</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">6</span><span class="o">:</span> <span class="c1">// NAV_SECOND_CHILD</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">firstChild</span><span class="p">.</span><span class="nx">nextSibling</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">7</span><span class="o">:</span> <span class="c1">// NAV_NEXT_SIBLING</span>
<span class="nx">element</span> <span class="o">=</span> <span class="nx">element</span><span class="p">.</span><span class="nx">nextSibling</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">8</span><span class="o">:</span> <span class="c1">// APPEND</span>
<span class="kd">var</span> <span class="nx">e</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">appendChild</span><span class="p">(</span><span class="nx">renderElement</span><span class="p">(</span><span class="nx">e</span><span class="p">));</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">9</span><span class="o">:</span> <span class="c1">// REMOVE_LAST</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">lastChild</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">10</span><span class="o">:</span> <span class="c1">// REMOVE_LAST_MANY</span>
<span class="kd">var</span> <span class="nx">times</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span><span class="nx">i</span><span class="o">&lt;</span><span class="nx">times</span><span class="p">;</span><span class="nx">i</span><span class="o">++</span><span class="p">)</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">removeChild</span><span class="p">(</span><span class="nx">element</span><span class="p">.</span><span class="nx">lastChild</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">11</span><span class="o">:</span> <span class="c1">// ATTR_SET</span>
<span class="kd">var</span> <span class="nx">attr</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">AsciiToString</span><span class="p">(</span><span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]);</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="k">if</span><span class="p">(</span><span class="nx">attr</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">//console.log(&quot;current value: &quot;, element.nodeValue);</span>
<span class="c1">//console.log(&quot;text: &quot;, value);</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">nodeValue</span> <span class="o">=</span> <span class="nx">value</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">setAttribute</span><span class="p">(</span><span class="nx">attributeNames</span><span class="p">[</span><span class="nx">attr</span><span class="p">],</span> <span class="nx">value</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">case</span> <span class="mi">12</span><span class="o">:</span> <span class="c1">// ATTR_REMOVE</span>
<span class="kd">var</span> <span class="nx">attr</span> <span class="o">=</span> <span class="nx">HEAP32</span><span class="p">[((</span><span class="nx">p</span><span class="p">)</span><span class="o">&gt;&gt;</span><span class="mi">2</span><span class="p">)]</span> <span class="o">|</span> <span class="mi">0</span><span class="p">;</span>
<span class="nx">p</span> <span class="o">+=</span> <span class="mi">4</span><span class="p">;</span>
<span class="nx">element</span><span class="p">.</span><span class="nx">removeAttribute</span><span class="p">(</span><span class="nx">attributeNames</span><span class="p">[</span><span class="nx">attr</span><span class="p">]);</span>
<span class="k">break</span><span class="p">;</span>
<span class="k">default</span><span class="o">:</span>
<span class="nx">console</span><span class="p">.</span><span class="nx">log</span><span class="p">(</span><span class="s2">&quot;SHIT HAPPENS&quot;</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<p>Завтра лечу в Прагу, а в дороге пока не получается работать. А пока результаты под тегом <code>day-6</code> <a href="https://github.com/platoff/faxma/tree/day-6">https://github.com/platoff/faxma/tree/day-6</a>.</p>
</description>
</item>
</channel>
</rss>