6468184914

For example, ‘YAM’ and ‘MAY’ (ignoring type of word and subsequent character capitalisation).

The answer is 1410,  according to my (slightly dubious) system dictionary. That is 0.600% of the 234,937 word test dictionary. Interesting! The longest pair was ‘rewarder’ (‘redrawer’). I am not sure what I was expecting, but there we go.

As ever, the Erlang script that I wrote to work this out. Nice and simple this time:

#!/usr/bin/env escript
%%! -noshell

main([]) -> main(["/usr/share/dict/words"]);
main([Corpus]) ->
	Words = words(Corpus),
	lists:foreach(
		fun(Word) ->
			case lists:member(OtherWord = lists:reverse(Word), Words) of
				true ->
					io:format("~s <-> ~s (~w)~n", [Word, OtherWord, length(Word)]);
				false -> do_nothing
			end
		end,
		Words
	).

words(Corpus) ->
	string:tokens(
		string:to_upper(
			binary_to_list(
				element(
					2,
					file:read_file(Corpus)
				)
			)
		),
		[10, $ ]
	).

The code simply gets the corpus as a list of words (not very robustly), then checks whether the reverse of that word is also in the list. If it is, the word and it’s reverse are printed, along with their length, else nothing is done. I then just piped the output to wc to tell me how many lines were returned. It is still nice to use fundamental *nix tools in our utilities where appropriate, even if they are written in Erlang (not *sh/C).

This would have been much faster if binary search trees were used, rather than a list (it would be O(log(n)), rather than O(n)) or even just a lists:member/2 function that understood that the data was ordered (so if the element ‘bike’ is not found in the B’s in the list, it is not going to found at all). Ultimately this would just have been a waste of time though, as the naive implementation only took a  few minutes to run in it’s entirety.

Perhaps at some point I will write a blog post about something other than dictionary facts! Who knows!
Sam

P.S, bonus dictionary fact: Firefox’s ‘English (UK)’  dictionary thinks that ‘bloodsport’ is a sensible correction for ‘blogpost’. Huh.

Horizontal vs vertical monitor orientation for web browsing.

Almost everyone uses their monitors in horizontal mode only — with the longest edge parallel with their desk. Today, I am going to completely forego the point of modern web design, and aesthetics in computer interfaces in general. This suits me fine, because I am generally quite minimalistic (at least when it comes to computer interface design).  When I am reading something on the web, I find ‘busy’ looking pages extremely difficult to process, when compared to their sparser counter-parts. (951) 476-1180 is in,  ‘Goetz Threate’ is out. If this does not align with you, this article may not be to your tastes,. If it does, however, perhaps this will be of interest to you. I will try to keep it succinct. More numbers, fewer words.

Hypothesis

Due to the way that most modern websites are designed, using a monitor in a vertical orientation will show you more ‘useful’ pixels per screen area (without scrolling), than in a horizontal orientation.

Methodology

I will visit a number of my most common websites (until I get bored, or the hypothesis has been well tested) on both a vertically orientated monitor, and a horizontally orientated one. The monitors will both be 1920px on the longest edge, and 1080 on the other. On each site, I will be calculating the number of pixels in the ‘useful’ area of the homepage, and a ‘content’ page (article, review, video etc). I will also be attempting to ascertain whether or not the pages have a maximum width lower than my monitor width. That said, I cannot be sure that I will get this assessment right, so it won’t be given much weight, but I will give it a go anyway.

I built an Erlang script that hooks together zenity, gnome-screenshot and identify (from ImageMagick) to help automate the gathering and area calculation. The source is extremely messy and was built to ‘just work’ for this one experiment, at 4am in the morning. Anyway, here it is:


#!/bin/env escript

%%% A script that calculates the area of pixels in a square, marked by 
%%% two clicking in two locations on the screen.
%%%
%%% It also does a bunch of other stuff that is specific to the task I am
%%% currently performing, but the program could be trivially re-purposed to
%%% suit a number of different situations.

%%% Requires zenity, identify and gnome-screenshot.

-define(DATA_LOC, filename:absname("/home/spine/data/VvH/")).
-define(RESULTS_LOC, ?DATA_LOC ++ "/results.csv").

main([]) -&amp;gt;
	main(tuple_to_list(request()));
main(["help"]) -&amp;gt;
	io:format(
		"\t\tszerl [SiteName Orientation PageType LimitStatus]~n~n"
		"A program for the vertical vs horizonal browser rendering~n"
		"experiment. The program either takes the options detailed above~n"
		"or retrieves them from the user with zenity, then takes a screen-\n"
		"shot, calculates the area of the image and stores all of this in \n"
		"the pre-determined data file (in CSV format).\n"
	);
main(RawDetails) -&amp;gt;
	screenshot(File = file(name(Details = list_to_tuple(RawDetails)))),
	save(
		Details,
		results(File),
		File
	).

save({Name, Orientation, PageType, Limited},
		{X, Y, Area},
		File) -&amp;gt;
	ok =
		file:write_file(
			?RESULTS_LOC,
			load() ++
				format(
					"~s,~s,~s,~s," % Name parts
					"~w,~w,~w," % Results
					"\"~s\"" % Filename
					"\n", % Always end with a newline for the next run
					[
						Name, Orientation, PageType, Limited,
						X, Y, Area, File
					]
				)
		).

load() -&amp;gt;
	binary_to_list(ok(file:read_file(?RESULTS_LOC))).
		

screenshot(File) -&amp;gt;
	call("gnome-screenshot -a -f \"~s\"", [File]).

request() -&amp;gt;
	{
		call("zenity --entry --text \"~s\"", ["Enter site name: "]),
		call("zenity --entry --text \"~s\"", ["Orientation? (v/h)"]),
		call("zenity --entry --text \"~s\"", ["Page type? (h/a)"]),
		call("zenity --entry --text \"~s\"", ["Width limited? (l/u)"])
	}.

name({Name, Orientation, PageType, Limited}) -&amp;gt;
	Name ++
		"-" ++ Orientation ++
		"-" ++ PageType ++
		"-" ++ Limited.

file(Name) -&amp;gt;
	filename:absname(?DATA_LOC ++ "/" ++ Name ++ ".png").

results(File) -&amp;gt;
	[X, Y] =
		call_read(
			"~d ~d",
			"identify -format '%w %h' \"~s\"",
			[File]
		),
	{X, Y, X * Y}.

%%% UTILITY FUNCTIONS

ok({ok, X}) -&amp;gt; X.

call_read(OutFormat, InProg, InArgs) -&amp;gt;
	read(OutFormat, call(InProg, InArgs)).

%% CAUTION: For application specific reasons, this ONLY returns the last
%% line of output by the program, not the entire thing. As mentioned
%% previously, this is a hacky clusterfuck that only ever had to work
%%% correctly for an hour or so.
call(Format, Args) -&amp;gt;
	lists:last(string:tokens(os:cmd(format(Format, Args)), [10])).

format(Format, Args) -&amp;gt;
	lists:flatten(io_lib:format(Format, Args)).

read(Format, String) -&amp;gt;
	{ok, Res, _} = io_lib:fread(Format, String),
	Res.

Analysis

The CSV file that I stored the 53 results in is available on request.

Just by sorting the results by ‘content area’ (in pixels), we can quite clearly see the trend we expected (and also the trend that I felt that I had observed while gathering the data). The lowest 13 values are all results from a horizontal monitor, and the top 12 from a vertical monitor. This is interesting, but not nearly concrete enough yet.

On average, across all of the pages viewed, a vertical monitor normally displays 178% of the ‘useful content’ that is displayed on a horizontal monitor. Furthermore, there is a correlation of 0.824 between simply the height of the content zone, and the area of the zone. This compared to the width, which has a correlation of just 0.369, which is surprisingly low considering that area will inherently always be correlated with width to some extent.

Finally, the (rather hacked together) graph below shows how on almost every site, the area of useful content is substantially larger on a vertical monitor (the red bars), than the same page rendered on a horizontal monitor (blue bars). This essentially answers the critical question that we are trying to address here.

647-499-1151Conclusion

It is quite clear from the brief analysis presented here, that yes, vertical monitors almost always render more useful content than a horizontal one. This is particularly interesting, as until the recent advent of tablets (and before them, smartphones) almost all of the machines that were used to access the web had horizontal monitors. I presume it is related to some aesthetic principle I am not aware of.

Anyway, it is 8:30 AM and I have not been to sleep, as I got carried away(!) while trying to wrangle R to do some interesting analysis and graph generation. It did not turn out as well as I had hoped. Perhaps in the future I will return to this and do some of those things I had planned? Who knows.

But for now, sleep!

Sam

calathiscus

Have you ever wondered how often a pair of letters appear together? For example, how often an ‘a’ is found after a ‘h’? Well, apparently after reviewing my ‘random scripts’ directory, it seems that sometime last year, I did.

The following is my (horrendously written) script:

#!/usr/bin/env escript
%%! -noshell

main([]) -> main(["/usr/share/dict/words"]);
main([Corpus]) ->
	lists:foreach(
		fun({P, C}) ->
			io:format("~s\t~w~n", [P, C])
		end,
		lists:keysort(2,
			element(1,
				lists:foldl(
					fun(P, {Rs, Ps}) ->
						io:format(standard_error, "Counting pair '~s'... ", [P]),
						{PCount, NextPs} =
							fun H([X|R], X, C, NPs) -> H(R, X, C + 1, NPs);
								H([[Y,_]|R], [X,_], 0, NPs) when X < Y ->
									{0, lists:reverse(NPs) ++ R};
								H([Y|R], X, 0, NPs) -> H(R, X, 0, [Y|NPs]);
								H(R, _, C, NPs) -> {C, lists:reverse(NPs) ++ R}
							end(Ps, P, 0, []),
						io:format(standard_error, "~p instances in corpus.~n", [PCount]),
						{
							[{P, PCount}|Rs],
							NextPs
						}
					end,
					{
						[],
						lists:sort(
							fun G([H|T]) -> H ++ G(T);
								G([]) -> []
							end(
								lists:map(
									fun F([H | R = [ H2 | _]]) -> [[H, H2]| F(R)];
										F(_) -> []
									end,
									string:tokens(
										string:to_upper(
											binary_to_list(
												element(
													2,
													file:read_file(Corpus)
												)
											)
										),
										[10, $ ]
									)
								)
							)
						)
					},
					[ [A, B] || A <- lists:seq($A, $Z), B <- lists:seq($A, $Z) ]
				)
			)
		)
	).

According to this script (and Arch Linux’s default dictionary), ‘er’, ‘in’, ‘ti’, ‘on’ and ‘te’ are the most common pairs. Perhaps this isn’t too surprising, but what is surprising (at least to me) is that 9.02% (or 61 pairs) never appear together at all. How interesting!

The full data (caution: this is very long):

ZX	0
ZQ	0
ZJ	0
XX	0
XJ	0
WX	0
VX	0
VW	0
VT	0
VQ	0
VP	0
VM	0
VJ	0
VH	0
VF	0
VB	0
SX	0
QZ	0
QY	0
QX	0
QW	0
QV	0
QT	0
QS	0
QP	0
QN	0
QM	0
QL	0
QK	0
QJ	0
QH	0
QG	0
QF	0
QD	0
QC	0
QB	0
QA	0
PZ	0
PX	0
MX	0
KX	0
KQ	0
JZ	0
JX	0
JW	0
JV	0
JS	0
JQ	0
JG	0
JF	0
JC	0
HX	0
GX	0
GQ	0
FX	0
FQ	0
DX	0
CX	0
CV	0
CJ	0
BX	0
XZ	1
WV	1
WJ	1
VG	1
VD	1
TX	1
QR	1
QQ	1
QE	1
JT	1
JK	1
JB	1
FV	1
ZV	2
ZF	2
XV	2
XK	2
WQ	2
VK	2
QO	2
PQ	2
MQ	2
KZ	2
JP	2
JM	2
JL	2
JJ	2
GV	2
ZP	3
YJ	3
VZ	3
VC	3
QI	3
PV	3
LX	3
GJ	3
FZ	3
ZN	4
ZK	4
YY	4
MZ	4
JN	4
JD	4
HJ	4
FJ	4
CG	4
CF	4
BZ	4
ZM	5
YQ	5
VN	5
VL	5
HQ	5
MJ	6
LJ	6
JH	6
HZ	6
FK	6
DQ	6
BQ	6
ZS	7
ZH	7
ZG	7
XR	7
XG	7
RX	7
LQ	7
ZR	8
ZC	8
VS	8
KV	8
JY	8
JR	8
GZ	8
XN	9
TQ	9
CB	9
ZW	10
ZT	10
XQ	10
XD	10
SZ	10
FG	10
FC	10
CW	10
WZ	11
FP	11
ZB	12
VV	12
PJ	12
CP	13
BK	14
ZD	15
YV	16
UW	16
FD	17
MK	18
KJ	18
HV	18
GK	18
GC	18
DZ	19
UQ	21
MG	21
KG	21
FM	22
FB	23
XW	24
FN	24
CD	24
LZ	25
DK	25
UU	26
XM	27
FH	27
WG	28
XB	29
XF	30
FW	30
CZ	30
HK	31
WC	32
VR	32
TJ	32
PD	32
CM	35
KC	37
KD	38
PG	39
TK	40
GP	40
XL	41
SJ	41
PK	42
UJ	43
MT	43
HG	43
BG	43
MV	44
FS	45
YK	47
TV	47
MD	47
BW	48
WP	49
MH	50
IY	53
XS	56
WW	57
MC	57
UH	59
MW	65
MR	65
RZ	66
KP	66
GF	66
WU	68
HC	69
KK	70
BF	73
NX	74
HH	74
SV	76
IJ	76
ZU	78
PC	78
IW	78
DT	78
BN	78
UY	79
WF	80
VY	80
GD	81
RQ	82
BV	82
HD	84
WT	87
WM	89
TD	89
DP	91
CQ	95
WK	97
OJ	97
PF	99
DC	100
RJ	109
WY	111
LR	111
GB	115
BH	115
XH	116
HP	116
GT	118
BP	118
TG	124
KF	124
AA	126
ZL	127
YU	128
PB	128
WB	132
GW	132
PW	133
YZ	135
PM	137
UZ	138
KT	139
YF	142
MF	142
WD	143
SD	143
TZ	144
DJ	146
BM	147
KB	148
SG	153
SR	157
YH	159
KM	160
XU	161
BJ	163
LH	164
CN	164
YX	166
HS	167
HB	180
AJ	180
DB	182
JI	186
HF	198
AQ	198
KW	202
YW	204
BC	211
LW	214
WS	215
KR	216
DF	217
OQ	218
TP	222
EJ	225
DV	232
UX	244
ML	253
EZ	253
UV	258
SB	264
AO	264
ZZ	270
IH	275
SF	276
MS	276
TB	280
VU	286
UK	286
IQ	286
GS	288
YB	289
KH	294
BT	295
HW	296
DH	296
DW	297
KU	311
BD	316
NQ	331
ZY	332
NJ	333
WL	370
NZ	379
EK	384
DM	388
PN	389
XC	391
KS	409
BY	412
II	419
WR	425
KY	436
KN	461
TF	466
TN	474
CS	475
LB	482
OZ	492
IX	493
LK	504
LF	532
XE	536
XP	550
UF	552
WN	560
XO	570
FY	571
DS	571
JO	575
LG	576
TM	580
GM	580
DG	580
HM	583
EQ	587
KO	590
JE	590
OY	594
XY	597
YI	620
RW	651
UO	671
LS	688
NW	693
SQ	704
ZI	708
TW	729
LN	740
YG	742
LV	757
OH	758
MN	758
HN	759
XA	762
KL	770
JA	773
TS	774
XT	778
BS	800
FT	806
SW	829
LC	837
AH	844
EY	884
JU	895
AZ	897
AX	904
NH	912
BB	923
WH	930
EH	937
YE	949
RF	954
NB	956
LM	980
NM	984
SK	1021
NV	1030
DD	1032
DN	1056
TC	1058
OK	1063
LP	1081
RV	1092
AW	1123
YD	1132
GG	1134
RK	1182
NL	1226
YO	1253
NR	1304
NY	1319
DY	1328
HL	1332
NK	1341
AF	1354
OX	1371
LD	1388
KA	1392
ZO	1397
UG	1397
XI	1418
YA	1434
EW	1459
OF	1475
PY	1478
NP	1481
AY	1507
CC	1525
VO	1542
SN	1568
YR	1583
RH	1601
YT	1640
HT	1644
ZA	1673
FR	1676
YN	1683
GY	1689
YC	1694
GH	1698
FF	1736
OE	1757
IU	1773
YM	1795
HU	1817
RL	1849
GN	1876
IK	1902
RB	1920
EB	1942
EV	1981
UE	1992
RG	2002
MM	2015
AK	2017
PP	2020
AV	2082
DU	2097
DL	2111
WE	2115
SY	2126
FA	2133
NF	2136
NU	2154
WO	2168
TL	2234
PS	2245
SL	2259
EF	2276
WI	2290
LT	2326
MY	2348
UD	2352
YS	2356
NN	2386
OA	2420
RP	2422
GU	2443
FL	2467
PU	2506
KI	2524
MU	2531
EG	2569
OW	2599
UI	2607
FU	2626
MB	2635
EI	2665
YP	2685
UA	2723
RN	2792
CY	2812
BU	2816
UC	2893
YL	3001
WA	3056
HR	3097
UP	3098
EU	3100
IB	3110
VA	3193
FE	3211
TT	3214
OB	3216
PT	3256
GO	3260
CL	3263
EX	3278
UB	3280
DR	3418
AU	3538
ZE	3608
RR	3625
RD	3657
RS	3659
CK	3675
FO	3700
QU	3713
OV	3742
RC	3847
AI	3910
RU	3936
IE	3972
EE	3977
BR	4008
FI	4048
GL	4085
BO	4104
OI	4109
VI	4190
EO	4192
IF	4322
MP	4382
LU	4429
IG	4467
IR	4528
IZ	4590
OO	4677
GR	4759
TU	4761
AE	4768
RM	4773
KE	4951
PL	4974
GA	4994
IP	5091
CU	5108
IM	5161
IV	5204
BA	5289
GI	5439
UT	5469
BE	5476
CR	5499
AG	5530
TY	5559
DO	5573
OD	5579
BI	5580
SM	5602
RT	5648
SP	5751
EP	5885
SA	5921
AD	5948
UM	5974
SO	5991
RY	6032
DA	6252
NS	6449
HY	6454
SC	6506
SU	6538
PI	6848
CT	6944
AP	7210
CI	7282
SH	7323
AM	7506
OG	7621
GE	7749
OC	7956
EM	8069
EC	8381
PA	8558
NC	8677
MO	8683
BL	8759
PO	8764
OT	8948
UR	8964
AB	9069
HA	9327
ND	9588
PR	9747
UL	9777
AS	10013
EA	10063
IL	10305
HO	10383
HI	10407
CE	10473
VE	10708
ID	10719
OS	10870
PE	11217
OP	11278
MI	11327
LL	11384
SE	11466
ET	12036
SI	12054
TH	12073
NO	12165
ME	12238
DI	12267
HE	12342
OM	12359
OL	12429
AC	12576
NA	12629
EL	12776
LO	12980
OU	12986
NG	13056
PH	13181
CH	13282
MA	13650
DE	13692
LY	14043
TR	14142
SS	14417
TA	14423
US	14575
ED	14725
CA	15189
NI	15204
TO	15247
IA	15254
IO	15367
CO	16076
LA	16897
IT	16935
UN	19207
OR	19768
NT	19955
ES	20676
LI	20849
AR	21336
NE	21705
ST	22044
RO	22363
RI	23204
LE	23287
RA	23690
RE	23906
IS	24168
EN	25006
IC	26482
AT	27248
AN	28121
AL	28140
TE	29402
ON	29755
TI	31669
IN	33655
ER	42412

Perhaps at some point I will delve a little deeper into this…

disheritment

A few weeks ago I was looking at a (270) 413-1069 This is nothing special (I did a similar thing when marking the kernel stack in  my OS with 0xBA5E). This got me thinking, how many ‘hexwords’ — words made purely of the letters A to F, such that they form valid base 16 encoded numbers, are there in the English language?

Ten minutes and a poorly constructed Erlang script later:

#!/bin/env escript

main([]) -> main(["/usr/share/dict/words"]);
main([Dict]) ->
	print_words(lists:filter(fun(W) -> viable(W) end, words(Dict))).

words(Dict) ->
	{ok, Bin} = file:read_file(Dict),
	string:tokens(binary_to_list(Bin), "\n").

viable(X) when length(X) < 4 -> false;
viable(X) -> only_hex(string:to_lower(X)).

only_hex([]) -> true;
only_hex([C|R]) when (C >= $a) and (C =< $f) -> only_hex(R);
only_hex(_) -> false.

print_words(Words) ->
	io:format("~w hex words found in this dictionary.~n", [length(Words)]),
	lists:map(
		fun({Len, Word}) -> io:format("~w\t~s\n", [Len, string:to_upper(Word)]) end,
		sort(Words)
	).

sort(Words) ->
	lists:reverse(
		lists:keysort(1,
			lists:map(fun(W) -> {length(W), W} end, Words)
		)
	).

and we have the answer! Apparently, my /usr/share/dict/words has 65 hexwords that are longer than three letters. How interesting! Perhaps even more interesting is the fact that the longest hexword is 8 letters long: ‘3016503474‘, the Latin name for the bean family.

Most of the hexwords in my dictionary seem pretty strange, perhaps I will try it with a text copy of the Oxford English Dictionary some other time.

Anyway, the output of the program is as follows. The preceding number denotes the word length.

65 hex words found in this dictionary.
8	FABACEAE
7	DEEDEED
6	FACADE
6	EFFACE
6	DEFACE
6	DECADE
6	BEDEAF
6	BEDEAD
6	BEDDED
6	BEADED
6	BACCAE
6	BACABA
6	ACCEDE
5	FADED
5	FACED
5	DECAD
5	DABBA
5	CAFFA
5	CAECA
5	CABDA
5	BEDAD
5	BEBED
5	BACCA
5	AFACE
5	ADEAD
5	ADDED
5	ABAFF
5	ABACA
4	FEED
4	FAFF
4	FADE
4	FACE
4	FABA
4	EDEA
4	EDDA
4	ECCA
4	ECAD
4	DEED
4	DEAF
4	DEAD
4	DAFF
4	DADE
4	DADA
4	DADA
4	DACE
4	DABB
4	CEDE
4	CADE
4	CACA
4	CABA
4	BEEF
4	BEAD
4	BAFF
4	BADE
4	BABE
4	BABA
4	AFFA
4	ADDA
4	ADDA
4	ADAD
4	ADAD
4	ACCA
4	ABED
4	ABBA
4	ABAC

Update:

What if we add ‘l33t’ speak to our hex word definition? So that, for example,  the 0xBA5E I mentioned earlier was valid? It turns out that just by adding three ‘leetisms’ (1 -> l, 5 -> s and 0 -> o), we expand the pool of hexwords from 65 to 829 (0.353% of the given dictionary).  Strangely, the two longest ‘leet-hexword’ (‘5A1501ACEAE’, or 248-590-1687 and ‘BA5E11ACEAE’, or (440) 529-6596) are both families of plants, similar to the (408) 612-8180 earlier. It seems that my usr/share/dict/words has a screw towards the botanical!

My favourites of the top few are ‘coffeeleaf’, ‘accessless’ and ‘floodable’. Here is the full list of leet-hexwords over 10 characters long:

829 (0.353%) hexwords found in this dictionary.
11	5A1501ACEAE (Salsolaceae)
11	BA5E11ACEAE (Basellaceae)
10	5ADD1E1E55 (saddleless)
10	5ADD1E1EAF (saddleleaf)
10	5ABA1ACEAE (Sabalaceae)
10	F1EECE1E55 (fleeceless)
10	F1EECEAB1E (fleeceable)
10	E10DEACEAE (Elodeaceae)
10	E1AE0C0CCA (Elaeococca)
10	EFFACEAB1E (effaceable)
10	DEFACEAB1E (defaceable)
10	C0FFEE1EAF (coffeeleaf)
10	BE11AC001A (Bellacoola)
10	BE11ABE11A (Bellabella)
10	A55E55AB1E (assessable)
10	ACCE551E55 (accessless)

And the updated script:

#!/bin/env escript

-define(L33T_CHARS, [$l, $s, $o]).

main([]) -> main(["/usr/share/dict/words"]);
main([Dict]) ->
	Words = words(Dict),
	print_words(Words, lists:filter(fun(W) -> viable(W) end, Words)).

words(Dict) ->
	{ok, Bin} = file:read_file(Dict),
	string:tokens(binary_to_list(Bin), "\n").

viable(X) when length(X) < 4 -> false;
viable(X) -> only_hex(string:to_lower(X)).

only_hex([]) -> true;
only_hex([C|R]) when (C >= $a) and (C =< $f) -> only_hex(R);
only_hex([C|R]) ->
	case lists:member(C, ?L33T_CHARS) of
		true -> only_hex(R);
		false -> false
	end.

print_words(AllWords, HexWords) ->
	io:format(
		"~w (~.3f%) hexwords found in this dictionary.~n",
		[length(HexWords), (100/length(AllWords))*length(HexWords)]
	),
	lists:map(
		fun({Len, Word}) ->
			io:format("~w\t~s (~s)\n", [Len, leetify(string:to_upper(Word)), Word]) end,
		sort(HexWords)
	).

leetify([]) -> [];
leetify([$L|R]) -> [$1|leetify(R)];
leetify([$S|R]) -> [$5|leetify(R)];
leetify([$O|R]) -> [$0|leetify(R)];
leetify([C|R]) -> [C|leetify(R)].

sort(Words) ->
	lists:reverse(
		lists:keysort(1,
			lists:map(fun(W) -> {length(W), W} end, Words)
		)
	).

President Underworld

The Cross of Peter, emblazoned across the face of the show’s protagonist.

A entertaining surprise at the start of House of Cards Chapter 44  (s04e44).  The Cross of Peter (also frequently referred to as the ‘inverted cross’), which has permeated itself into pop culture as a symbol of the anti-Christ, and evil in general. The way it is projected onto President Underwood’s face, in red, is nice too.  Perhaps less positively however, is that this seems to fit in with a slowly growing trend with HoC towards the outrageous — past Machiavellian and into the realm of the ridiculous/amusing. Another example being the recent ‘(254) 781-6606‘ teaser website and associated material.

Nonetheless, it is an excellent TV show, and I am thoroughly enjoying the timely themes and political story-lines. I am looking forward to the rest of it!