-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path2006_02_06-control_break_reporting.html
1378 lines (1341 loc) · 63.5 KB
/
2006_02_06-control_break_reporting.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en" prefix="og: http://ogp.me/ns# fb: https://www.facebook.com/2008/fbml">
<head>
<title>Control Break Reporting - S.Lott -- Software Architect</title>
<!-- Using the latest rendering mode for IE -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="canonical" href="https://slott56.github.io/2006_02_06-control_break_reporting.html">
<meta name="author" content="S.Lott" />
<meta name="keywords" content="building skills,python,data analysis,summarizing" />
<meta name="description" content="Note This referred to the old Active State Programmers Network, ASPN, Python Cookbook. The code has been moved to the ActiveState Code site. Likely, the fact that it's Python 2 means it is no longer online. Control Break Reporting is a design pattern that has been around since the earliest …" />
<meta property="og:site_name" content="S.Lott -- Software Architect" />
<meta property="og:type" content="article"/>
<meta property="og:title" content="Control Break Reporting"/>
<meta property="og:url" content="https://slott56.github.io/2006_02_06-control_break_reporting.html"/>
<meta property="og:description" content="Note This referred to the old Active State Programmers Network, ASPN, Python Cookbook. The code has been moved to the ActiveState Code site. Likely, the fact that it's Python 2 means it is no longer online. Control Break Reporting is a design pattern that has been around since the earliest …"/>
<meta property="article:published_time" content="2006-02-06" />
<meta property="article:section" content="Books" />
<meta property="article:tag" content="building skills" />
<meta property="article:tag" content="python" />
<meta property="article:tag" content="data analysis" />
<meta property="article:tag" content="summarizing" />
<meta property="article:author" content="S.Lott" />
<!-- Bootstrap -->
<link rel="stylesheet" href="https://slott56.github.io/theme/css/bootstrap.min.css" type="text/css"/>
<link href="https://slott56.github.io/theme/css/font-awesome.min.css" rel="stylesheet">
<link href="https://slott56.github.io/theme/css/pygments/native.css" rel="stylesheet">
<link href="https://slott56.github.io/theme/css/html4css1.css" rel="stylesheet">
<link rel="stylesheet" href="https://slott56.github.io/theme/css/style.css" type="text/css"/>
<link href="https://slott56.github.io/feeds/all.atom.xml" type="application/atom+xml" rel="alternate"
title="S.Lott -- Software Architect ATOM Feed"/>
<link href="https://slott56.github.io/feeds/all.rss.xml" type="application/rss+xml" rel="alternate"
title="S.Lott -- Software Architect RSS Feed"/>
<link href="https://slott56.github.io/feeds/books.atom.xml" type="application/atom+xml" rel="alternate"
title="S.Lott -- Software Architect Books ATOM Feed"/>
</head>
<body>
<div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-ex1-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="https://slott56.github.io/" class="navbar-brand">
S.Lott -- Software Architect </a>
</div>
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav">
<li><a href="https://slott56.github.io/pages/other-articles.html">
Other Articles
</a></li>
<li><a href="https://slott56.github.io/pages/publications.html">
Publications
</a></li>
<li><a href="https://slott56.github.io/pages/slott-biography.html">
S.Lott Biography
</a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
</ul>
</div>
<!-- /.navbar-collapse -->
</div>
</div> <!-- /.navbar -->
<!-- Banner -->
<!-- End Banner -->
<!-- Content Container -->
<div class="container">
<div class="row">
<div class="col-sm-9">
<section id="content">
<article>
<header class="page-header">
<h1>
<a href="https://slott56.github.io/2006_02_06-control_break_reporting.html"
rel="bookmark"
title="Permalink to Control Break Reporting">
Control Break Reporting
</a>
</h1>
</header>
<div class="entry-content">
<div class="panel">
<div class="panel-body">
<footer class="post-info">
<span class="label label-default">Date</span>
<span class="published">
<i class="fa fa-calendar"></i><time datetime="2006-02-06T23:49:00-05:00"> Mon 06 February 2006</time>
</span>
<span class="label label-default">Tags</span>
<a href="https://slott56.github.io/tag/building-skills.html">building skills</a>
/
<a href="https://slott56.github.io/tag/python.html">python</a>
/
<a href="https://slott56.github.io/tag/data-analysis.html">data analysis</a>
/
<a href="https://slott56.github.io/tag/summarizing.html">summarizing</a>
</footer><!-- /.post-info --> </div>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">This referred to the old Active State Programmers Network, ASPN,
Python Cookbook.
The code has been moved to the ActiveState Code site.
Likely, the fact that it's Python 2 means it is no longer online.</p>
</div>
<p>Control Break Reporting is a design pattern that
has been around since the earliest days of business applications. It solves the
problem of producing a report on nested (or hierarchical) data, the kind often
found in a chart of accounts.</p>
<p>The result of "control break" reporting is a properly nested set of reports, each of
which has localized subtotals. The details add up to a deeply nested subtotal.
The subtotals add up to higher and higher level totals, and the top-level totals
add to a grand total.</p>
<p>When the hierarchical key values change from one record to the next,
this is called a "break" in the controlling keys for a subsection.
At this break in control, emit a sub-total appropriate to the level of the keys showing the change.</p>
<p>The classical algorithm for "control break" reporting, however, tends to hide the basic
hierarchy under a welter of details about keys and totals and subtotals. It
can't produce "heading" totals or counts, only footing totals or counts. As
soon as you want additional features, you may as well ditch the classical
algorithm.</p>
<div class="section" id="the-problem-is-the-sort">
<h2>The Problem is the Sort</h2>
<p>The most important thing I
dislike about the classical "control break" algorithm is the sort that's required.
Sorting is an expensive operation. Rarely does a "control break" report show all
of the detail with all of the nested totals, so why should I sort all that data
only to produce higher-level
subtotals?</p>
<p>The sorting seems so logical
and necessary. Often our data isn't in the desired order, so sorting it makes
superficial sense. More to the point, however, is that no one wants all the
data in a single report. Even if I did produce a PDF file with all 21,000
accounts in the general ledger, people only want their little section of
details, or they want a slice down to a depth of 3 from where their ownership of
the finances starts.</p>
<p>The CFO wants
the top-most totals. The manager of production wants her costs, and the next
few levels of summary data. Her shift supervisors want the details for their
specific times and production areas. No one wants ALL of the data. If no one
wants all of the data, why sort all of
it?</p>
</div>
<div class="section" id="the-data-is-dimensional">
<h2>The Data is Dimensional</h2>
<p>Most of the interesting
reporting problems have a combination of two features: dimensions and
hierarchies. The basic numeric measurements (dollars, hours, pounds, pallets,
and the like) are the facts on which we are reporting. Each fact has a number
of relevant dimensions along which that fact is measured. We might, for
example, have sales dollars by product, by fiscal period, by sales person; this
is a three-dimensional analysis. We could group these three dimensions in any
of 6 different orders, and produce a number of hierarchies with different kinds
of totals.</p>
<p>In additional to the
independent dimensions of a fact, each dimension may be a hierarchical grouping
of data. Time, for example, has groupings of days, weeks, months, quarters and
years. Sales people may be organized into territories, regions and countries.
Products may be organized into lines and
families.</p>
<p>In the Cookbook example from
ASPN, they have one dimension: the sales organization. This is broken into
branches and sales people. This forms a tidy hierarchy, good for a simple
example.</p>
<p>In most kinds of reporting,
however, there are often a large number of dimensions. Worse, there may be
complex relationships within a dimension. For example, the calendar has weeks
and months, but months don't fall on nice weekly boundaries. Similarly, our USA
office may have many regions in a single country, but our European office may
combine several countries in a region.</p>
</div>
<div class="section" id="the-solution-is-a-mapping">
<h2>The Solution is a Mapping</h2>
<p>The right way to handle "Control Break" reporting in Python is through a design pattern that is a
variation on the Index or the Inverted Database. I prefer to call it the
Dimensional Map, because that's a better clue as to how it
works.</p>
<p>Let's look at the data we have in the ASPN example:</p>
<pre class="literal-block">
records = [("branch1", "sales1", 100),
("branch1", "sales1", 50),
("branch1", "sales2", 10),
("branch2", "sales1", 104),
("branch2", "sales2", 56),
("branch2", "sales2", 156)]
</pre>
<p>In this case, we have two keys (branch
and sales person), and one fact (the sales dollars). What we will make is a Map
of the branches. Each entry in the branch-level Map is a Map of the sales
people. Each entry in the person-level map is a list of their detailed sales
dollars. We can then traverse these nested maps to write the report we want to
see, correctly labeled with headers and footers. We can, without too much extra
work. have totals in the header as well as the footer. I'll leave that as an
exercise.</p>
<p>It works like this:</p>
<pre class="literal-block">
branchMap= {}
for branch, person, dollars in records:
branchMap.setdefault( branch, {} )
personMap= branchMap[ branch ]
personMap.setdefault( person, 0 )
personMap[person].append( dollars )
branchList= branchMap.keys()
branchList.sort()
for branch in branchList:
print "header Branch", branch
personMap= branchMap[branch]
personList= personMap.keys()
personList.sort()
for person in personList:
print "header Person", person
for data in personMap[person]
print data
print "footer Person"
print "footer Branch"
print "grand Total"
</pre>
<p>This little script is essentially
hard-wired for this simple two-dimensional analysis. It doesn't take too much
cut-and-paste to expand this to the desired number of levels. It isn't,
however, the most general solution. For that, we need a better class
design.</p>
</div>
<div class="section" id="expanding-on-the-pattern">
<h2>Expanding On The Pattern</h2>
<p>The real problem with Control Break reporting is the recursion. Any level of the report (except the
numeric facts) is a recursive structure: it contains a Map of the next lower
level of detail. We can define a class, Dimension, which does two things for
us.</p>
<ul class="simple">
<li>Dimension carries the data elements for
that Dimension, the key and the next lower level Dimension object with the
details. A Dimension's key may contains a Fact object which has a simple
unkeyed list of values.</li>
<li>Dimension handles the recursive structure
implied by the hierarchy. We have methods which process data recursively,
treating each subsidiary Dimension (or Fact) in a uniform
way.</li>
</ul>
<p>A simple tail recursion technique
assures that each Dimension contains subsidiary Dimensions, and the most
deeply-nested item is the basic Fact. This leads to programs that fit the
recursive model of a number of dimensions, terminated by a single
fact.</p>
<p>To keep the classes polymorphic,
both Dimension and Fact must implement an <tt class="docutils literal">append()</tt> method
that loads data and a <tt class="docutils literal">report()</tt> method
that produces the final report on the data.</p>
<p>Further, to keep this example simple,
we'll make each object a combination of data and meta-data. The data is the
mapping of key to details or the list of facts. The metadata is the column name
and the relationship with the lower-level dimensions. The metadata is a
universal truth about the data.</p>
<p>We have multiple instances of each object: there are multiple branches and multiple
people. We'll need to create additional collections to hold the data. We'll do
this by cloning the object definition. There's a better way to do this by
separating the metadata from the actual detailed numeric data, but that is a
more complex solution, not a simple recipe.</p>
<pre class="literal-block">
import copy
class Fact( object ):
"""A Fact is a measurable quantity."""
def __init__ ( self, name ):
self.name= name
self.data= []
self.total= 0
def append( self, item ):
self.data.append( item[0] )
self.total += item[0]
def values( self ):
return self.data
def report( self, depth=0 ):
for d in self.data:
print depth*' ', d
class Dimension( object ):
"""A Dimension is a value to group Facts or Dimensions."""
def __init__( self, name, child=None ):
self.name= name
self.map= {}
self.child= child
self.total= 0
def append( self, row ):
"""The first value is the key for this dimension.
The remaining values are other dimension keys or the fact value.""
key= row[0]
values= row[1:]
self.map.setdefault( key, copy.deepcopy(self.child) )
self.map[key].append( values )
def keys( self ):
keyList= self.map.keys()
keyList.sort()
return keyList
def get( self, value ):
return self.map.get( value )
def report( self, depth=0 ):
"""Report this dimension, relying on other Dimensions or Facts."""
self.total= 0
for k in self.keys():
print depth*' ', self.name, k, 'header'
self.map[k].report( depth+1 )
self.total += self.map[k].total
print depth*' ', k, 'total', self.map[k].total
</pre>
<p>Loading this structure with data is
pleasantly simple. We define the nested structure of our Dimensions and the
Fact which they contain. This same recursive structure can then be used to
break up each record into a key and the data associated with that
key.</p>
<pre class="literal-block">
analysis= Dimension( "branch", Dimension( "person", Fact( "dollars" ) ) )
for row in records:
analysis.append( row )
</pre>
<p>Reporting, similarly, relies on the
recursive structure of Dimension objects nested within Dimension objects.</p>
<pre class="literal-block">
analysis.report()
print analysis.total
</pre>
</div>
<div class="section" id="more-generalization">
<h2>More Generalization</h2>
<p>Since some people
are uncomfortable with the recursion, and would prefer this to use a flat list
of Dimension and Fact objects. This flat list can be used with explicit
for-loops to parse the input and assign an appropriate structure. We'll post
this solution in the future,
perhaps.</p>
<p>Additionally, it would be nice
to allow for multiple Facts and not force the file to be kept with the columns
in order from most general to most specific. The first improvement (multiple
facts for reporting) is a pretty simple generalization. The second, however, is
a matter of a simple map to switch the order in which the columns are examined
to create the various levels of
detail.</p>
<p>Finally, the separation of
meta-data from the real application data would shift the complexity around. It
would make some of this simpler, but it would introduce more classes into the
solution.</p>
</div>
</div>
<!-- /.entry-content -->
</article>
</section>
</div>
<div class="col-sm-3" id="sidebar">
<aside>
<!-- Sidebar -->
<section class="well well-sm">
<ul class="list-group list-group-flush">
<!-- Sidebar/Social -->
<li class="list-group-item">
<h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Social</span></h4>
<ul class="list-group" id="social">
<li class="list-group-item"><a href="https://fosstodon.org/@slott56"><i class="fa fa-mastodon-square fa-lg"></i> Mastodon</a></li>
<li class="list-group-item"><a href="https://github.com/slott56"><i class="fa fa-github-square fa-lg"></i> Github</a></li>
<li class="list-group-item"><a href="https://stackoverflow.com/users/10661/s-lott"><i class="fa fa-stackoverflow-square fa-lg"></i> StackOverflow</a></li>
<li class="list-group-item"><a href="https://www.linkedin.com/in/steven-lott-029835/"><i class="fa fa-linkedin-square fa-lg"></i> LinkedIn</a></li>
<li class="list-group-item"><a href="https://www.oreilly.com/pub/au/6277"><i class="fa fa-o'reilly-square fa-lg"></i> O'Reilly</a></li>
<li class="list-group-item"><a href="https://www.amazon.com/stores/Steven-Lott/author/B00HNRSLEK"><i class="fa fa-amazon-square fa-lg"></i> Amazon</a></li>
</ul>
</li>
<!-- End Sidebar/Social -->
<!-- Sidebar/Categories -->
<li class="list-group-item">
<h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Categories</span></h4>
<ul class="list-group" id="categories">
<li class="list-group-item">
<a href="https://slott56.github.io/category/architecture-design.html"><i class="fa fa-folder-open fa-lg"></i>Architecture & Design</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/books.html"><i class="fa fa-folder-open fa-lg"></i>Books</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/foss.html"><i class="fa fa-folder-open fa-lg"></i>FOSS</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/management.html"><i class="fa fa-folder-open fa-lg"></i>Management</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/news.html"><i class="fa fa-folder-open fa-lg"></i>News</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/python.html"><i class="fa fa-folder-open fa-lg"></i>Python</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/category/technologies.html"><i class="fa fa-folder-open fa-lg"></i>Technologies</a>
</li>
</ul>
</li>
<!-- End Sidebar/Categories -->
<!-- Sidebar/Links -->
<li class="list-group-item">
<h4><i class="fa fa-external-link-square fa-lg"></i><span class="icon-label">Links</span></h4>
<ul class="list-group" id="links">
<li class="list-group-item">
<a href="https://getpelican.com/" target="_blank">Pelican</a>
</li>
<li class="list-group-item">
<a href="https://www.python.org/" target="_blank">Python.org</a>
</li>
<li class="list-group-item">
<a href="https://palletsprojects.com/p/jinja/" target="_blank">Jinja2</a>
</li>
</ul>
</li>
<!-- End Sidebar/Links -->
<!-- Sidebar/Archive -->
<li class="list-group-item">
<h4><i class="fa fa-home fa-lg"></i><span class="icon-label">Archive</span></h4>
<ul class="list-group" id="archive">
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2025/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2025 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2024 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2024 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2024 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2024 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2024 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2024 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2024 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2024 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2024/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2024 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2023 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2023 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2023 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2023 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2023 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2023 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2023 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2023 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2023 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2023 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2023 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2023/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2023 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2022 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2022 (8)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2022 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2022 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2022 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2022 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2022 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2022 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2022 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2022 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2022 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2022/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2022 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2021 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2021 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2021 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2021 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2021 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2021 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2021 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2021 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2021 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2021 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2021 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2021/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2021 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2020 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2020 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2020 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2020 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2020 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2020 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2020 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2020 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2020 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2020 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2020 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2020/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2020 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2019 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2019 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2019 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2019 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2019 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2019 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2019 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2019 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2019 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2019 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2019 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2019/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2019 (7)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2018 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2018 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2018 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2018 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2018 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2018 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2018 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2018 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2018 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2018/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2018 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2017 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2017 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2017 (6)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2017 (6)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2017 (6)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2017 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2017/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2017 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2016 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2016 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2016 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2016 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2016 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2016 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2016 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2016 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2016 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2016 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2016 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2016/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2016 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2015 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2015 (6)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2015 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2015 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2015 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2015 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2015/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2015 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2014 (7)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2014 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2014 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2014 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2014 (1)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2014 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2014 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2014 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2014 (3)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Mar/index.html"><i class="fa fa-calendar fa-lg"></i>March 2014 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Feb/index.html"><i class="fa fa-calendar fa-lg"></i>February 2014 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2014/Jan/index.html"><i class="fa fa-calendar fa-lg"></i>January 2014 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Dec/index.html"><i class="fa fa-calendar fa-lg"></i>December 2013 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Nov/index.html"><i class="fa fa-calendar fa-lg"></i>November 2013 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Oct/index.html"><i class="fa fa-calendar fa-lg"></i>October 2013 (5)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2013 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2013 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Jul/index.html"><i class="fa fa-calendar fa-lg"></i>July 2013 (4)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Jun/index.html"><i class="fa fa-calendar fa-lg"></i>June 2013 (12)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/May/index.html"><i class="fa fa-calendar fa-lg"></i>May 2013 (8)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2013/Apr/index.html"><i class="fa fa-calendar fa-lg"></i>April 2013 (6)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2012/Sep/index.html"><i class="fa fa-calendar fa-lg"></i>September 2012 (2)
</a>
</li>
<li class="list-group-item">
<a href="https://slott56.github.io/posts/2012/Aug/index.html"><i class="fa fa-calendar fa-lg"></i>August 2012 (1)