-
Notifications
You must be signed in to change notification settings - Fork 1
/
inspector.eve
946 lines (683 loc) · 24.6 KB
/
inspector.eve
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
# Inspector
The inspector ("don't panic" button) is Eve's interactive debugging tool. It acts as a go between to help the Analyzer understand what's wrong based on your input. It handles the subset of issues that Eve can't know about a priori, where the program is valid and reasonable but not behaving as you intend; e.g.:
- *"I shouldn't be able to see this button when I'm not logged in."*
- *"The student attendance list is missing."*
- *"Too many emails were sent to each client."*
- *"The clock hand in the wrong position."*
- *"This program slow."*
Once Eve understands what the issue is, it provides a set of structured questions to work backwards through the symptoms to the source. Just telling you "the block labelled 'draw a sign out button when logged in' drew the sign out button" is worse than useless. However, with a little help from you ("that user shouldn't have the tag `#logged-in` right now), Eve can work backwards and say "the `#logged-in` tag was never removed from the user because she did not have an email attribute.
When you've arrived at the root of the problem, the inspector provides tools to figure out why it happened. If, instead a missing attribute, the issue involved incorrect values (perhaps the result of mathematical error), Eve can show you intermediates to find where the breakdown occurs. When too many or too few rows match a pattern, Eve can show you the cardinality of the actions in a block to get a sense of why the numbers don't add up. Some issues the inspector can help diagnose can be found in the **Example Scenarios** section.
## Events
Clean the events we care about up.
~~~
search @event
event = if e = [#inspector #inspect] then e
if e = [#inspector #clear] then e
commit @event
event := none
~~~
### Inspect
When the inspect event comes in, open a new inspector targeted to the inspected element/record/span.
If an inspector is already open, close it and nuke its state.
~~~
search @event
[#inspector #inspect]
search @inspector
inspector = [#inspector]
bind @event
[#inspector #clear inspector]
~~~
When an element is targeted, inspect it.
~~~
search @event
event = [#inspector #inspect #direct-target target: element type: "element" x y]
commit @inspector
[#inspector element state: ("popout", "annotate-blocks") | x y]
commit @event
event := none
~~~
When the document root is targeted, inspect it.
~~~
search @event
event = [#inspector #inspect #direct-target type: "root" x y]
commit @inspector
[#inspector root: "true" state: "popout" | x y]
commit @event
event := none
~~~
When a block is targeted, inspect it.
~~~
search @event
event = [#inspector #inspect target: block type: "code_block" x y]
commit @inspector
[#inspector block state: ("block-popout") | x y]
commit @event
event := none
~~~
### Focus/Unfocus Current
When inspecting, the navigator will reveal a button which can be clicked to elide everything but the annotated sections of the document.
~~~
search @event
event = [#inspector #focus-current]
search @inspector
inspector = [#inspector state]
focus-states = if state = "annotate-blocks" then "focus-blocks"
if state = "annotate-affectors" then "focus-affectors"
if state = "annotate-failures" then "focus-failures"
if state = "annotate-performance" then "focus-performance"
commit @inspector
inspector.state += focus-states
commit @event
event := none
~~~
~~~
search @event
event = [#inspector #unfocus-current]
search @inspector
inspector = [#inspector state]
focus-states = if state = "annotate-blocks" then "focus-blocks"
if state = "annotate-affectors" then "focus-affectors"
if state = "annotate-failures" then "focus-failures"
if state = "annotate-performance" then "focus-performance"
commit @inspector
inspector.state -= focus-states
commit @event
event := none
~~~
### Clear
When an inspector clear event comes in, remove open inspectors and all their state.
~~~
search @event @inspector
event = [#inspector #clear]
inspector = if event.inspector then event.inspector
else [#inspector]
commit @inspector
inspector := none
inspector.state := none
inspector.data := none
~~~
### Click Option
When an inspector button is pressed, activate any new states we want to transition into.
~~~
search @event
[#click #direct-target element]
search @browser
element = [#button inspector activate]
commit @inspector
inspector.state += activate
~~~
When an inspector button is pressed, deactivate any old states we may have been in that want to leave.
~~~
search @event
[#click #direct-target element]
search @browser
element = [#button inspector deactivate]
commit @inspector
inspector.state -= deactivate
~~~
### Click Attribute Table
When a row in the attribute table is clicked, find the source of that particular attribute.
~~~
search @event
[#click element]
// If we're clicking on an entity value, we'll handle that elsewhere
[#click element: value-elem]
search @browser
not(value-elem = [#value is-entity: true])
element = [#kv-row key]
[#kv-table inspector children: element]
commit @inspector
inspector.attribute := key
~~~
When we click a value in the attribute table, if it's an entity navigate to it.
~~~
search @event
[#click element]
[#click element: value-elem]
search @browser
value-elem = [#value is-entity: true text: entity]
element = [#kv-row key]
[#kv-table inspector children: element]
search @inspector
x = inspector.x
y = inspector.y
bind @event
[#inspector #inspect #direct-target target: entity type: "element" x y]
~~~
### Click Elsewhere
Any click that is entirely outside of the inspector will close it.
~~~
search @inspector
inspector = [#inspector]
search @event
event = [#click]
not([#click element: inspector])
commit @inspector
inspector := none
~~~
While the inspector is open on an element, update its avs to that element's avs. This will persist until it's no longer potentially relevant.
@NOTE: This is kind of weird and it may be better to have multiple targets instead.
~~~
search @inspector
inspector = [#inspector element]
search @browser
lookup[record: element, attribute, value]
commit @inspector
inspector.avs := [attribute value]
~~~
## Data
As the inspector states change, it will need to gather different data from the editor and language service. Data requests will be added to the `data` attribute and requests for that data will be bound for so long as those values exist. By gathering all the data in a separate pass, UI to display it can share the same data and be written immediate-mode style.
Certain kinds of data depend on other data.
~~~
commit @inspector
[#data data: "sources"]
[#data data: "source-sections", requires: "sources"]
[#data data: "related" requires: "sources"]
[#data data: "cardinalities" requires: "related"]
[#data data: "values" requires: "related"]
[#data data: "all-values" requires: "related"]
[#data data: "affectors"]
[#data data: "affector-failures" requires: "affectors"]
[#data data: "performance-stats"]
~~~
If we need data that has a dependency, make sure we're fetching that too.
~~~
search @inspector
inspector = [#inspector data]
[#data data requires]
bind @inspector
inspector.data += requires
~~~
### Sources
Find source(s) for the current record.
~~~
search @inspector
[#inspector data: "sources" element: record not(attribute)]
bind @editor
[#find-source record]
~~~
Find source(s) for a specific attribute of the current record.
~~~
search @inspector
[#inspector data: "sources" element: record attribute]
bind @editor
[#find-source record attribute]
~~~
### Source Sections
Find the section(s) containing the found source(s).
~~~
search @inspector
[#inspector data: "source-sections" element: record]
search @editor
[#source record block]
bind @editor
[#find-section span: block]
~~~
### Related
Find related(s) for the current record's source action(s).
~~~
search @inspector
inspector = [#inspector data: "related" element: record]
search @editor
[#source record span]
bind @editor
[#find-related inspector | span]
~~~
### Values
Find the intermediate values that contribute to the currently targeted record.
~~~
search @inspector
inspector = [#inspector data: "values" element avs: [attribute value]]
search @editor
[#source record: element block span]
[#related span variable]
bind @editor
[#find-value inspector | variable given: [attribute value]]
~~~
### All Values
Find all intermediate values for the current target's related variable(s).
~~~
search @inspector
(inspector, element) = if i = [#inspector data: "all-values" element] then (i, element)
else if i = [#inspector data: "values" element not(avs)] then (i, element)
search @editor
[#source record: element block span]
[#related span variable]
bind @editor
[#find-value inspector | variable]
~~~
### Cardinalities
Find cardinalities for the current target's related variable(s).
~~~
search @inspector
inspector = [#inspector data: "cardinalities" element]
search @editor
[#source record: element block span]
[#related span variable]
bind @editor
[#find-cardinality inspector | variable]
~~~
### Affectors
Find the set of blocks that could affect the currently targeted element.
~~~
search @inspector
inspector = [#inspector data: "affectors" element]
bind @editor
[#find-affector record: element attribute: "children"]
~~~
Find the set of blocks that could draw into the document root
~~~
search @inspector
inspector = [#inspector data: "affectors" root]
bind @editor
[#find-root-drawers]
~~~
### Affector Failures
Find the reasons why affectors of the current target failed.
~~~
search @inspector
inspector = [#inspector data: "affector-failures" element]
search @editor
[#affector record: element block]
bind @editor
[#find-failure block]
~~~
### Block Failure
Find the reason why the targeted block failed.
~~~
search @inspector
inspector = [#inspector data: "block-failure" block]
bind @editor
[#find-failure block]
~~~
### Performance Stats
~~~
search @inspector
inspector = [#inspector data: "performance-stats"]
bind @editor
[#find-performance]
~~~
## States
Inspector states control how the inspector interacts with the editor and presents itself to the user.
Certain states require data to be fetched.
~~~
commit @inspector
// Element States
[#state state: "focus-blocks" requires: "sources"]
[#state state: "annotate-blocks" requires: "sources"]
[#state state: "highlight-related" requires: "related"]
[#state state: "show-values-inline" requires: "values"]
[#state state: "show-values-table" requires: "values"]
[#state state: "show-cardinalities-inline" requires: "cardinalities"]
[#state state: "focus-affectors" requires: "affectors"]
[#state state: "annotate-affectors" requires: "affectors"]
[#state state: "focus-failures" requires: "affector-failures"]
[#state state: "annotate-failures" requires: "affector-failures"]
[#state state: "highlight-failures" requires: "affector-failures"]
// Block States
[#state state: "highlight-block-failure" requires: "block-failure"]
[#state state: "annotate-performance" requires: "performance-stats"]
[#state state: "focus-performance" requires: "performance-stats"]
~~~
When the inspector is in a state that requires data, request that data.
~~~
search @inspector
[#state state requires]
inspector = [#inspector state]
bind @inspector
inspector.data += requires
~~~
### Focus Blocks
When the `"focus-blocks"` state is active, elide everything but the originating blocks for the current target.
~~~
search @inspector
inspector = [#inspector state: "focus-blocks" element]
search @editor
[#source record: element block]
bind @editor
[#elide-between-sections inspector | span: block]
[#jump-to position: 0]
~~~
### Annotate Blocks
When the `"annotate-blocks"` state is active, annotate each source block for the current target.
~~~
search @inspector
inspector = [#inspector state: "annotate-blocks" element]
search @editor
[#source record: element block]
bind @editor
[#mark-span inspector type: "block_annotation" span: block kind: "source" message: "This block provides the inspected value."]
[#jump-to span: block]
~~~
### Highlight Related
When the `"highlight-related"` state is active, mark all related spans highlighted.
~~~
search @inspector
inspector = [#inspector state: "highlight-related" element]
search @editor
[#source record: element span]
[#related span variable]
bind @editor
[#mark-span inspector type: "highlight" | span: variable]
~~~
### Show Values Inline
When the `"show-values-inline"` state is active, badge any found intermediate values.
~~~
search @inspector
inspector = [#inspector state: "show-values-inline" element]
search @editor
[#source record: element block span]
[#related span variable]
[#value variable value row: 1]
bind @editor
[#mark-span inspector type: "badge" kind: "intermediate" target: element message: value span: variable]
~~~
### Show Values Table
When the `"show-values-table"` state is active, embed a table of found intermediate values.
~~~
search @inspector
inspector = [#inspector state: "show-values-table" element]
search @editor
[#source record: element block span]
[#related span variable]
[#value variable value row name]
bind @view
row-guy = [row]
lookup[record: row-guy attribute: name value]
table = [#table inspector | field: name row: row-guy]
bind @browser
table.span := block
~~~
### Show Cardinalities Inline
When the `"show-cardinalities-inline"` state is active, badge any found cardinalities.
~~~
search @inspector
inspector = [#inspector state: "show-cardinalities-inline" element]
search @editor
[#source record: element block span]
[#related span variable]
[#cardinality variable cardinality]
bind @editor
[#mark-span inspector type: "badge" kind: "cardinality" target: element message: cardinality | span: variable]
~~~
### Focus Affectors
When the `"focus-affectors"` state is active, elide everything but the blocks which could impact the target.
~~~
search @inspector
inspector = [#inspector state: "focus-affectors" element]
search @editor
[#affector record: element block action]
bind @editor
[#elide-between-sections inspector | span: block]
[#jump-to position: 0]
[#mark-span inspector type: "highlight" | span: action]
~~~
### Annotate Affectors
When the `"annotate-affectors"` state is active, annotate blocks which could impact the target element.
~~~
search @inspector
inspector = [#inspector state: "annotate-affectors" element]
search @editor
[#affector record: element block action]
bind @editor
[#mark-span inspector type: "block_annotation" span: block kind: "affector" message: "This block affects the inspected value."]
[#jump-to span: block]
~~~
When the `"annotate-affectors"` state is active, annotate blocks which could draw to the document root.
~~~
search @inspector
inspector = [#inspector state: "annotate-affectors" root]
search @editor
[#root-drawer span start stop]
bind @editor
[#mark-range inspector type: "annotation" span start stop kind: "affector" message: "This block could draw to the document root."]
[#jump-to position: start]
~~~
### Focus Failures
When the `"focus-failures"` state is active, elide everything but the blocks which could impact the target but did not.
~~~
search @inspector
inspector = [#inspector state: "focus-failures" element]
search @editor
[#affector record: element block action]
[#failure block]
bind @editor
[#elide-between-sections inspector | span: block]
[#jump-to position: 0]
[#mark-span inspector type: "highlight" | span: action]
~~~
### Annotate Failures
When the `"annotate-failures"` state is active, annotate the blocks which could impact the target.
~~~
search @inspector
inspector = [#inspector state: "annotate-failures" element]
search @editor
[#affector record: element block action]
[#failure block]
bind @editor
[#mark-span inspector type: "block_annotation" span: block kind: "failure" message: "This block could affect the inspected value but failed."]
[#jump-to span: block]
~~~
### Highlight Failures
When the `"highlight-failures"` state is active, show the failing reasons for blocks that impact the target.
~~~
search @inspector
inspector = [#inspector state: "highlight-failures" element]
search @editor
[#affector record: element block]
[#failure block start stop]
bind @editor
[#mark-range type: "cause-of-failure" start stop]
~~~
### Highlight Block Failure
When the `"highlight-block-failure"` state is active, show the failing reason for the targeted block.
~~~
search @inspector
inspector = [#inspector state: "highlight-block-failure" block]
search @editor
[#failure block start stop]
bind @editor
[#mark-range type: "cause-of-failure" start stop]
~~~
### Annotate Performance
~~~
search @inspector
inspector = [#inspector state: "annotate-performance"]
search @editor
[#performance block color]
color != "green"
bind @editor
[#mark-span inspector type: "block_annotation" span: block kind: "performance-{{color}}" message: "This block has performance issues."]
~~~
~~~
search @inspector
inspector = [#inspector state: "annotate-performance"]
search @editor
perf = [#performance block color]
total-percent = to-fixed[value: perf.percent, places: 2]
average-time = to-fixed[value: perf.average, places: 2]
max-time = to-fixed[value: perf.max, places: 2]
bind @editor
[#mark-span inspector type: "document_widget" span: block kind: "performance-{{color}}" message: "{{total-percent}}% of total | average {{average-time}}ms | max {{max-time}}ms"]
~~~
### Focus Performance
~~~
search @inspector
inspector = [#inspector state: "focus-performance"]
search @editor
[#performance block color != "green"]
bind @editor
[#elide-between-sections inspector | span: block]
[#jump-to position: 0]
~~~
## Drawing
While we have an inspector, notify the editor about its existence.
~~~
search @inspector
inspector = [#inspector x y]
bind @browser
inspector <- [#editor #inspector x y: y + 15]
~~~
When an `#inspector` is open targeted to an element, show the element popout.
~~~
search @inspector
inspector = [#inspector state: "popout" element]
bind (@view, @browser)
attributes = [#attribute-table inspector entity: element]
bind @browser
inspector <-
[#div element class: "inspector-pane" children:
[#div #attributes-panel inspector children: attributes]
[#div #options-panel inspector class: "buttons" children:
[#button inspector text: "Find events" activate: "focus-blocks", deactivate: "popout"]
[#button inspector text: "Why this?" activate: "show-values-table" deactivate: "popout"]
[#button inspector text: "Too few? Too many?" activate: "show-cardinalities-inline" deactivate: "popout"]
[#button inspector text: "Not drawing?" activate: ("annotate-affectors", "highlight-failures") deactivate: ("annotate-blocks", "popout")]]]
~~~
When an `#inspector` is open targeted to the document root, show the root popout.
~~~
search @inspector
inspector = [#inspector state: "popout" root]
bind @browser
inspector <- [#div class: "inspector-pane" children:
[#div #options-panel inspector class: "buttons" children:
[#button inspector text: "Not drawing?" activate: ("annotate-affectors", "highlight-failures") deactivate: "popout"]]]
~~~
When an `#inspector` is open targeted to a block, show the block popout.
@TODO: Just make this the popout for blocks.
~~~
search @inspector
inspector = [#inspector state: "block-popout" block]
bind @browser
inspector <- [#div in-editor: true class: "inspector-pane" children:
[#div #options-panel inspector class: "buttons" children:
[#button inspector text: "Did this fail?" activate: "highlight-block-failure" deactivate: "block-popout"]
[#button inspector text: "Why is this slow?" activate: "annotate-performance" deactivate: "block-popout"]]]
~~~
## Debug
### Inspector Debugger
~~~
search @view
wrapper = [#inspector-debugger inspector]
lookup[record: wrapper, attribute: "tag", value: "inspector-debugger", node]
search (@session, @browser, @inspector)
lookup[record: inspector attribute: key value]
bind @view @browser
wrapper.node := node
wrapper.tag += "kv-table"
wrapper.kvs := [key value]
~~~
## Example Scenarios
### Missing Attribute
*"I shouldn't be able to see this button when I'm not logged in."*
1. Click the investigate button.
2. Click the logout button.
- Should this not show up right now?
- Are there too many or few of these?
- Does this have an incorrect value?
- List of attributes
3. This should not show up right now.
- Filter code to blocks which create the logout button.
- Show a timeline of events creating the button.
- The `[#button #log-out]` is drawn because `app.user` is tagged `#logged-in`.
- The `app.user` is tagged `#logged-in` because the `[#button #login]` was clicked.
- List blocks which could cause it to stop drawing.
- The `app.user` `#logged-in` tag was not removed when `[#button #logout]` was clicked because `app.user` did not have an `email` attribute.
### Bad Join
*"The student attendance list is missing."*
1. Click the investigate button.
2. Click where the attendance list belongs.
- Qs
3. This should contain something.
- Filter code to blocks which can create children for this element.
- Highlight the bailing reason for each block.
- Summary
- [this block](#) can insert here, but `[#app page: not(grades)]`
- [this block](#) can insert here, but `[#app page: not(syllabus)]`
- [this block](#) can insert here, but `teacher.students` is empty
4. Click `teacher.students`
- Filter code to the blocks affecting `teacher.students`
- [this block](#) creates `teacher.students`, but `not(student.name = school.name)`
### Wrong Cardinality
*"Too many emails were sent to each client."*
1. Click the investigate button.
2. Click an email to a client.
- Should this not show up right now?
- Are there too many or few of these?
- Does this have an incorrect value?
- List of attributes
3. There are too many of these.
- Filter code to the block which created the emails.
- Gray out the patterns that do not contribute to the cardinality of the emails.
- Embed a cardinality badge for each relevant pattern.
- Summary
- an email was created for each `[#client email]` (721) X `[#promo message]` (1) X `[#admin email]` (5).
- Click a pattern to see its values.
4. Click `[#admin email]`.
- There are 5 `[#admin]`s, each with one `email`. These are: ...
### Wrong Value
*"The clock hand in the wrong position."*
1. Click the investigate button.
2. Click the clock hand.
- Should this not show up right now?
- Are there too many or few of these?
- Does this have an incorrect value?
- List of attributes
3. Click the `x2` attribute.
- Filter code to the blocks affecting the `x2` attribute of the entity.
- Gray out the patterns that do not contribute to the `x2` attribute.
- Embed value badges for each relevant variable.
- Summary
- `[#clock-hand degrees` (70) `length` (30) `]`.
- `x2` (78.19) `= 50 + (length` (30) `* sin[degrees` (70) `]` (0.94) `)`.
- `hand <- [#line x1: 50, y1: 50, x2` (78.19) `y2]`.
4. Click the `degrees` attribute.
- Filter code to the blocks affecting the `degrees` attribute of the `[#clock-hand]`
- Gray out the patterns that do not contribute to the `degrees attribute`.
- Embed value badges for each relevant variable.
- Summary
- `[#clock-hand #hour-hand degrees` (900)`: 60 * hours` (15) `, length: 30, stroke: "#023963"]`
### Performance
*"This program slow."*
1. Click the investigate button.
2. ???
3. Color-code blocks by total time spent.
4. Click a block.
- Display total percentage of time spent.
- Display total number of rows run.
- Display average/max/min time per row.
### Exploration
*"What has this block done?"*
1. Click the investigate button.
2. Click the block
- What does this depend on?
- What does this create?
- What depends on this?
3. What does this create?
- List patterns and cardinalities created by this node
- Highlight visible side effects (e.g. ui)
*"What created this?"*
1. Click the investigate button.
2. Click the element or pattern
- What created this?
3. What created this?
- Filter code to blocks affecting this.
- Highlight the specific actions impacting this.
## Inspector views
- Element
- Variable
- Action
- Scan
- Block
- Active element
- Something's wrong
- Are there too many/few of these?
- Is a value wrong?
- Is something missing?
- Should this not be here? (?)
- Exploration
- source
- dependents
- Active variable
- Something's wrong
- Are there too many/few of these?