PageSourceSearch

https://andrewtwest.com/page/2/

html andrewtwest.com collected 2026-10-07 00:41:05 UTC 141,816 bytes, 1,501 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="UTF-8">
5<meta name="viewport" content="width=device-width, initial-scale=1">
6<link rel="profile" href="http://gmpg.org/xfn/11">
7
8<title>The Public Void &#8211; Page 2 &#8211; Andy West&#039;s Blog: Software Development and More</title>
9<meta name='robots' content='max-image-preview:large' />
10<meta name="google-site-verification" content="dOt2zmeoyzy55jhej-q2J0j3r852Wu26UcuTHeKv1oM" />
11
12<!-- Async WordPress.com Remote Login -->
13<script id="wpcom_remote_login_js">
14var wpcom_remote_login_extra_auth = '';
15function wpcom_remote_login_remove_dom_node_id( element_id ) {
16	var dom_node = document.getElementById( element_id );
17	if ( dom_node ) { dom_node.parentNode.removeChild( dom_node ); }
18}
19function wpcom_remote_login_remove_dom_node_classes( class_name ) {
20	var dom_nodes = document.querySelectorAll( '.' + class_name );
21	for ( var i = 0; i < dom_nodes.length; i++ ) {
22		dom_nodes[ i ].parentNode.removeChild( dom_nodes[ i ] );
23	}
24}
25function wpcom_remote_login_final_cleanup() {
26	wpcom_remote_login_remove_dom_node_classes( "wpcom_remote_login_msg" );
27	wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_key" );
28	wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_validate" );
29	wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_js" );
30	wpcom_remote_login_remove_dom_node_id( "wpcom_request_access_iframe" );
31	wpcom_remote_login_remove_dom_node_id( "wpcom_request_access_styles" );
32}
33
34// Watch for messages back from the remote login
35window.addEventListener( "message", function( e ) {
36	if ( e.origin === "https://r-login.wordpress.com" ) {
37		var data = {};
38		try {
39			data = JSON.parse( e.data );
40		} catch( e ) {
41			wpcom_remote_login_final_cleanup();
42			return;
43		}
44
45		if ( data.msg === 'LOGIN' ) {
46			// Clean up the login check iframe
47			wpcom_remote_login_remove_dom_node_id( "wpcom_remote_login_key" );
48
49			var id_regex = new RegExp( /^[0-9]+$/ );
50			var token_regex = new RegExp( /^.*|.*|.*$/ );
51			if (
52				token_regex.test( data.token )
53				&& id_regex.test( data.wpcomid )
54			) {
55				// We have everything we need to ask for a login
56				var script = document.createElement( "script" );
57				script.setAttribute( "id", "wpcom_remote_login_validate" );
58				script.src = '/remote-login.php?wpcom_remote_login=validate'
59					+ '&wpcomid=' + data.wpcomid
60					+ '&token=' + encodeURIComponent( data.token )
61					+ '&host=' + window.location.protocol
62					+ '//' + window.location.hostname
63					+ '&postid=376'
64					+ '&is_singular=';
65				document.body.appendChild( script );
66			}
67
68			return;
69		}
70
71		// Safari ITP, not logged in, so redirect
72		if ( data.msg === 'LOGIN-REDIRECT' ) {
73			window.location = 'https://wordpress.com/log-in?redirect_to=' + window.location.href;
74			return;
75		}
76
77		// Safari ITP, storage access failed, remove the request
78		if ( data.msg === 'LOGIN-REMOVE' ) {
79			var css_zap = 'html { -webkit-transition: margin-top 1s; transition: margin-top 1s; } /* 9001 */ html { margin-top: 0 !important; } * html body { margin-top: 0 !important; } @media screen and ( max-width: 782px ) { html { margin-top: 0 !important; } * html body { margin-top: 0 !important; } }';
80			var style_zap = document.createElement( 'style' );
81			style_zap.type = 'text/css';
82			style_zap.appendChild( document.createTextNode( css_zap ) );
83			document.body.appendChild( style_zap );
84
85			var e = document.getElementById( 'wpcom_request_access_iframe' );
86			e.parentNode.removeChild( e );
87
88			document.cookie = 'wordpress_com_login_access=denied; path=/; max-age=31536000';
89
90			return;
91		}
92
93		// Safari ITP
94		if ( data.msg === 'REQUEST_ACCESS' ) {
95			console.log( 'request access: safari' );
96
97			// Check ITP iframe enable/disable knob
98			if ( wpcom_remote_login_extra_auth !== 'safari_itp_iframe' ) {
99				return;
100			}
101
102			// If we are in a "private window" there is no ITP.
103			var private_window = false;
104			try {
105				var opendb = window.openDatabase( null, null, null, null );
106			} catch( e ) {
107				private_window = true;
108			}
109
110			if ( private_window ) {
111				console.log( 'private window' );
112				return;
113			}
114
115			var iframe = document.createElement( 'iframe' );
116			iframe.id = 'wpcom_request_access_iframe';
117			iframe.setAttribute( 'scrolling', 'no' );
118			iframe.setAttribute( 'sandbox', 'allow-storage-access-by-user-activation allow-scripts allow-same-origin allow-top-navigation-by-user-activation' );
119			iframe.src = 'https://r-login.wordpress.com/remote-login.php?wpcom_remote_login=request_access&origin=' + encodeURIComponent( data.origin ) + '&wpcomid=' + encodeURIComponent( data.wpcomid );
120
121			var css = 'html { -webkit-transition: margin-top 1s; transition: margin-top 1s; } /* 9001 */ html { margin-top: 46px !important; } * html body { margin-top: 46px !important; } @media screen and ( max-width: 660px ) { html { margin-top: 71px !important; } * html body { margin-top: 71px !important; } #wpcom_request_access_iframe { display: block; height: 71px !important; } } #wpcom_request_access_iframe { border: 0px; height: 46px; position: fixed; top: 0; left: 0; width: 100%; min-width: 100%; z-index: 99999; background: #23282d; } ';
122
123			var style = document.createElement( 'style' );
124			style.type = 'text/css';
125			style.id = 'wpcom_request_access_styles';
126			style.appendChild( document.createTextNode( css ) );
127			document.body.appendChild( style );
128
129			document.body.appendChild( iframe );
130		}
131
132		if ( data.msg === 'DONE' ) {
133			wpcom_remote_login_final_cleanup();
134		}
135	}
136}, false );
137
138// Inject the remote login iframe after the page has had a chance to load
139// more critical resources
140window.addEventListener( "DOMContentLoaded", function( e ) {
141	var iframe = document.createElement( "iframe" );
142	iframe.style.display = "none";
143	iframe.setAttribute( "scrolling", "no" );
144	iframe.setAttribute( "id", "wpcom_remote_login_key" );
145	iframe.src = "https://r-login.wordpress.com/remote-login.php"
146		+ "?wpcom_remote_login=key"
147		+ "&origin=aHR0cHM6Ly9hbmRyZXd0d2VzdC5jb20%3D"
148		+ "&wpcomid=12038026"
149		+ "&time=" + Math.floor( Date.now() / 1000 );
150	document.body.appendChild( iframe );
151}, false );
152</script>
152
153<link rel='dns-prefetch' href='//s1.wp.com' />
154<link rel='dns-prefetch' href='//s2.wp.com' />
155<link rel='dns-prefetch' href='//s0.wp.com' />
156<link rel='dns-prefetch' href='//af.pubmine.com' />
157<link rel="alternate" type="application/rss+xml" title="The Public Void &raquo; Feed" href="https://andrewtwest.com/feed/" />
158<link rel="alternate" type="application/rss+xml" title="The Public Void &raquo; Comments Feed" href="https://andrewtwest.com/comments/feed/" />
159	
159<script type="text/javascript">
160		/* <![CDATA[ */
161		function addLoadEvent(func) {
162			var oldonload = window.onload;
163			if (typeof window.onload != 'function') {
164				window.onload = func;
165			} else {
166				window.onload = function () {
167					oldonload();
168					func();
169				}
170			}
171		}
172		/* ]]> */
173	</script>
173
174	<style id="wp-img-auto-sizes-contain-inline-css">
175img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px}
176/*# sourceURL=wp-img-auto-sizes-contain-inline-css */
177</style>
178<link crossorigin='anonymous' rel='stylesheet' id='all-css-2-1' href='/_static/??-eJxtjNEKwjAMRX/IGqeDPonfUro4sqVJMSllf78N9M2XC4fLOdBryCqO4lBaqNxmEoNO04xugO14dSUMnDo4lsrJ0cB8Y7xmswv8DyzoNeX1y1BUz5kaHzLJm4Qcg+WPMv94O3uv8hxijONwe9zHZQe30zrK&cssminify=yes' type='text/css' media='all' />
179<style id="wp-emoji-styles-inline-css">
180
181	img.wp-smiley, img.emoji {
182		display: inline !important;
183		border: none !important;
184		box-shadow: none !important;
185		height: 1em !important;
186		width: 1em !important;
187		margin: 0 0.07em !important;
188		vertical-align: -0.1em !important;
189		background: none !important;
190		padding: 0 !important;
191	}
192/*# sourceURL=wp-emoji-styles-inline-css */
193</style>
194<style id="wp-block-library-inline-css">
195:root{--wp-block-synced-color:#7a00df;--wp-block-synced-color--rgb:122,0,223;--wp-bound-block-color:var(--wp-block-synced-color);--wp-editor-canvas-background:#ddd;--wp-admin-theme-color:#007cba;--wp-admin-theme-color--rgb:0,124,186;--wp-admin-theme-color-darker-10:#006ba1;--wp-admin-theme-color-darker-10--rgb:0,107,160.5;--wp-admin-theme-color-darker-20:#005a87;--wp-admin-theme-color-darker-20--rgb:0,90,135;--wp-admin-border-width-focus:2px}@media (min-resolution:192dpi){:root{--wp-admin-border-width-focus:1.5px}}.wp-element-button{cursor:pointer}:root .has-very-light-gray-background-color{background-color:#eee}:root .has-very-dark-gray-background-color{background-color:#313131}:root .has-very-light-gray-color{color:#eee}:root .has-very-dark-gray-color{color:#313131}:root .has-vivid-green-cyan-to-vivid-cyan-blue-gradient-background{background:linear-gradient(135deg,#00d084,#0693e3)}:root .has-purple-crush-gradient-background{background:linear-gradient(135deg,#34e2e4,#4721fb 50%,#ab1dfe)}:root .has-hazy-dawn-gradient-background{background:linear-gradient(135deg,#faaca8,#dad0ec)}:root .has-subdued-olive-gradient-background{background:linear-gradient(135deg,#fafae1,#67a671)}:root .has-atomic-cream-gradient-background{background:linear-gradient(135deg,#fdd79a,#004a59)}:root .has-nightshade-gradient-background{background:linear-gradient(135deg,#330968,#31cdcf)}:root .has-midnight-gradient-background{background:linear-gradient(135deg,#020381,#2874fc)}:root{--wp--preset--font-size--normal:16px;
195--wp--preset--font-size--huge:42px}.has-regular-font-size{font-size:1em}.has-larger-font-size{font-size:2.625em}.has-normal-font-size{font-size:var(--wp--preset--font-size--normal)}.has-huge-font-size{font-size:var(--wp--preset--font-size--huge)}:root .has-text-align-center{text-align:center}:root .has-text-align-left{text-align:left}:root .has-text-align-right{text-align:right}.has-fit-text{white-space:nowrap!important}#end-resizable-editor-section{display:none}.aligncenter{clear:both}.items-justified-left{justify-content:flex-start}.items-justified-center{justify-content:center}.items-justified-right{justify-content:flex-end}.items-justified-space-between{justify-content:space-between}.screen-reader-text{border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;overflow-wrap:normal!important;padding:0;position:absolute;width:1px;word-break:normal!important}.screen-reader-text:focus{background-color:#ddd;clip-path:none;color:#444;display:block;font-size:1em;height:auto;left:5px;line-height:normal;padding:15px 23px 14px;text-decoration:none;top:5px;width:auto;z-index:100000}html :where(.has-border-color){border-style:solid}html :where([style^=border-color],[style*=";border-color"],[style*="; border-color"]){border-style:solid}html :where([style^=border-top-color],[style*=";border-top-color"],[style*="; border-top-color"]){border-top-style:solid}html :where([style^=border-right-color],[style*=";border-right-color"],[style*="; border-right-color"]){border-right-style:solid}html :where([style^=border-bottom-color],[style*=";border-bottom-color"],[style*="; border-bottom-color"]){border-bottom-style:solid}html :where([style^=border-left-color],[style*=";border-left-color"],[style*="; border-left-color"]){border-left-style:solid}html :where([style^=border-width],[style*=";border-width"],[style*="; border-width"]){border-style:solid}html :where([style^=border-top-width],[style*=";border-top-width"],[style*="; border-top-width"]){border-top-style:solid}html :where([style^=border-right-width],[style*=";border-right-width"],[style*="; border-right-width"]){border-right-style:solid}html :where([style^=border-bottom-width],[style*=";border-bottom-width"],[style*="; border-bottom-width"]){border-bottom-style:solid}html :where([style^=border-left-width],[style*=";border-left-width"],[style*="; border-left-width"]){border-left-style:solid}html :where(img[class*=wp-image-]){height:auto;max-width:100%}:where(figure){margin:0 0 1em}html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:var(--wp-admin--admin-bar--height,0px)}@media screen and (max-width:600px){html :where(.is-position-sticky){--wp-admin--admin-bar--position-offset:0px}}
196
197/*# sourceURL=/wp-content/plugins/gutenberg-core/v24.1.0/build/styles/block-library/common.min.css */
198</style>
199<style id="wp-block-library-inline-css-extra">
200.has-text-align-justify {
201	text-align:justify;
202}
203.has-text-align-justify{text-align:justify;}
204/*# sourceURL=wp-block-library-inline-css */
205</style>
206
207<style id="classic-theme-styles-inline-css">
208.wp-block-button__link{background-color:#32373c;border-radius:9999px;box-shadow:none;color:#fff;font-size:1.125em;padding:calc(.667em + 2px) calc(1.333em + 2px);text-decoration:none}.wp-block-file__button{background:#32373c;color:#fff}.wp-block-accordion-heading{margin:0}.wp-block-accordion-heading__toggle{background-color:inherit!important;color:inherit!important}.wp-block-accordion-heading__toggle:not(:focus-visible){outline:none}.wp-block-accordion-heading__toggle:focus,.wp-block-accordion-heading__toggle:hover{background-color:inherit!important;border:none;box-shadow:none;color:inherit;padding:var(--wp--preset--spacing--20,1em) 0;text-decoration:none}.wp-block-accordion-heading__toggle:focus-visible{outline:auto;outline-offset:0}.wp-block-tab:not(.has-text-color){color:inherit!important}.wp-block-tab:not(.has-background){background-color:inherit!important}.wp-block-tab:focus,.wp-block-tab:hover{text-decoration:none}.wp-block-tab:focus-visible{outline:auto;outline-offset:0}
209/*# sourceURL=/wp-content/plugins/gutenberg-core/v24.1.0/build/styles/block-library/classic.min.css */
210</style>
211
212<style id="coblocks-inline-format-inline-css">
213.uppercase{text-transform:uppercase}
214/*# sourceURL=coblocks-inline-format-inline-css */
215</style>
216<link crossorigin='anonymous' rel='stylesheet' id='all-css-12-1' href='/_static/??-eJx9jEEOAiEQBD/kQECjeDC+ZWEnijIwYWA3/l72op689KFTVXplCCU3zE1z6reYRYfiUwlP0VYZpwxIJE4IFRd10HOU9iFA2iuhCiI7/ROiDt9WxfETT20jCOc4YUIa2D9t5eGA91xRBMZS7ATtPkTZvCtdzNEZt7f2fHq8Afl7R7w=&cssminify=yes' type='text/css' media='all' />
217<style id="global-styles-inline-css">
218:root{--wp--preset--aspect-ratio--square: 1;--wp--preset--aspect-ratio--4-3: 4/3;--wp--preset--aspect-ratio--3-4: 3/4;--wp--preset--aspect-ratio--3-2: 3/2;--wp--preset--aspect-ratio--2-3: 2/3;--wp--preset--aspect-ratio--16-9: 16/9;--wp--preset--aspect-ratio--9-16: 9/16;--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #fff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--color--medium-blue: #0087be;--wp--preset--color--bright-blue: #00aadc;--wp--preset--color--dark-gray: #4d4d4b;--wp--preset--color--light-gray: #b3b3b1;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgb(6,147,227) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgb(252,185,
2180) 0%,rgb(255,105,0) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgb(255,105,0) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--font-family--albert-sans: 'Albert Sans', sans-serif;--wp--preset--font-family--alegreya: Alegreya, serif;--wp--preset--font-family--arvo: Arvo, serif;--wp--preset--font-family--bodoni-moda: 'Bodoni Moda', serif;--wp--preset--font-family--bricolage-grotesque: 'Bricolage Grotesque', sans-serif;--wp--preset--font-family--cabin: Cabin, sans-serif;--wp--preset--font-family--chivo: Chivo, sans-serif;--wp--preset--font-family--commissioner: Commissioner, sans-serif;--wp--preset--font-family--cormorant: Cormorant, serif;--wp--preset--font-family--courier-prime: 'Courier Prime', monospace;--wp--preset--font-family--crimson-pro: 'Crimson Pro', serif;--wp--preset--font-family--dm-mono: 'DM Mono', monospace;--wp--preset--font-family--dm-sans: 'DM Sans', sans-serif;--wp--preset--font-family--dm-serif-display: 'DM Serif Display', serif;--wp--preset--font-family--domine: Domine, serif;--wp--preset--font-family--eb-garamond: 'EB Garamond', serif;--wp--preset--font-family--epilogue: Epilogue, sans-serif;--wp--preset--font-family--fahkwang: Fahkwang, sans-serif;--wp--preset--font-family--figtree: Figtree, sans-serif;--wp--preset--font-family--fira-sans: 'Fira Sans', sans-serif;--wp--preset--font-family--fjalla-one: 'Fjalla One', sans-serif;--wp--preset--font-family--fraunces: Fraunces, serif;--wp--preset--font-family--gabarito: Gabarito, system-ui;--wp--preset--font-family--ibm-plex-mono: 'IBM Plex Mono', monospace;--wp--preset--font-family--ibm-plex-sans: 'IBM Plex Sans', sans-serif;--wp--preset--font-family--ibarra-real-nova: 'Ibarra Real Nova', serif;--wp--preset--font-family--instrument-serif: 'Instrument Serif', serif;--wp--preset--font-family--inter: Inter, sans-serif;--wp--preset--font-family--josefin-sans: 'Josefin Sans', sans-serif;--wp--preset--font-family--jost: Jost, sans-serif;--wp--preset--font-family--libre-baskerville: 'Libre Baskerville', serif;--wp--preset--font-family--libre-franklin: 'Libre Franklin', sans-serif;--wp--preset--font-family--literata: Literata, serif;--wp--preset--font-family--lora: Lora, serif;--wp--preset--font-family--merriweather: Merriweather, serif;--wp--preset--font-family--montserrat: Montserrat, sans-serif;--wp--preset--font-family--newsreader: Newsreader, serif;--wp--preset--font-family--noto-sans-mono: 'Noto Sans Mono', sans-serif;--wp--preset--font-family--nunito: Nunito, sans-serif;--wp--preset--font-family--open-sans: 'Open Sans', sans-serif;--wp--preset--font-family--overpass: Overpass, sans-serif;--wp--preset--font-family--pt-serif: 'PT Serif', serif;--wp--preset--font-family--petrona: Petrona, serif;--wp--preset--font-family--piazzolla: Piazzolla, serif;--wp--preset--font-family--playfair-display: 'Playfair Display', serif;--wp--preset--font-family--plus-jakarta-sans: 'Plus Jakarta Sans', sans-serif;--wp--preset--font-family--poppins: Poppins, sans-serif;--wp--preset--font-family--raleway: Raleway, sans-serif;--wp--preset--font-family--roboto: Roboto, sans-serif;--wp--preset--font-family--roboto-slab: 'Roboto Slab', serif;--wp--preset--font-family--rubik: Rubik, sans-serif;--wp--preset--font-family--rufina: Rufina, serif;--wp--preset--font-family--sora: Sora, sans-serif;--wp--preset--font-family--source-sans-3: 'Source Sans 3', sans-serif;--wp--preset--font-family--source-serif-4: 'Source Serif 4', serif;--wp--preset--font-family--space-mono: 'Space Mono', monospace;--wp--preset--font-family--syne: Syne, sans-serif;--wp--preset--font-family--texturina: Texturina, serif;--wp--preset--font-family--urbanist: Urbanist, sans-serif;--wp--preset--font-family--work-sans: 'Work Sans', sans-serif;--wp--preset--text-shadow--light: 0.05em 0.05em 0.1em rgba(0, 0, 0, 0.3);--wp--preset--text-shadow--strong: 0.1em 0.1em 0.25em rgba(0, 0, 0, 0.5);--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgb(255, 255, 255), 6px 6px rgb(0, 0, 0);--wp--preset--shadow--crisp: 6px 6px 0px rgb(0, 0, 0);}.wp-block-button{--wp--preset--dimension--25: 25%;--wp--preset--dimension--50: 50%;--wp--preset--dimension--75: 75%;--wp--preset--dimension--100: 100%;}:where(body) { margin: 0; }:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flex{display: flex;}.is-layout-flex{flex-wrap: wrap;align-items: center;}.is-layout-flex > :is(*, div){margin: 0;}body .is-layout-grid{display: grid;}.is-layout-grid > :is(*, div){margin: 0;}body{padding-top: 0px;padding-right: 0px;padding-bottom: 0px;padding-left: 0px;}:root :where(.wp-element-button, .wp-block-button__link){background-color: #32373c;border-width: 0;color: #fff;font-family: inherit;font-size: inherit;font-style: inherit;font-weight: inherit;letter-spacing: inherit;line-height: inherit;padding-top: calc(0.667em + 2px);padding-right: calc(1.333em + 2px);padding-bottom: calc(0.667em + 2px);padding-left: calc(1.333em + 2px);text-decoration: none;text-transform: inherit;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-medium-blue-color{color: var(--wp--preset--color--medium-blue) !important;}.has-bright-blue-color{color: var(--wp--preset--color--bright-blue) !important;}.has-dark-gray-color{color: var(--wp--preset--color--dark-gray) !important;}.has-light-gray-color{color: var(--wp--preset--color--light-gray) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-medium-blue-background-color{background-color: var(--wp--preset--color--medium-blue) !important;}.has-bright-blue-background-color{background-color: var(--wp--preset--color--bright-blue) !important;}.has-dark-gray-background-color{background-color: var(--wp--preset--color--dark-gray) !important;}.has-light-gray-background-color{background-color: var(--wp--preset--color--light-gray) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-medium-blue-border-color{border-color: var(--wp--preset--color--medium-blue) !important;}.has-bright-blue-border-color{border-color: var(--wp--preset--color--bright-blue) !important;}.has-dark-gray-border-color{border-color: var(--wp--preset--color--dark-gray) !important;}.has-light-gray-border-color{border-color: var(--wp--preset--color--light-gray) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}
218.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}.has-albert-sans-font-family{font-family: var(--wp--preset--font-family--albert-sans) !important;}.has-alegreya-font-family{font-family: var(--wp--preset--font-family--alegreya) !important;}.has-arvo-font-family{font-family: var(--wp--preset--font-family--arvo) !important;}.has-bodoni-moda-font-family{font-family: var(--wp--preset--font-family--bodoni-moda) !important;}.has-bricolage-grotesque-font-family{font-family: var(--wp--preset--font-family--bricolage-grotesque) !important;}.has-cabin-font-family{font-family: var(--wp--preset--font-family--cabin) !important;}.has-chivo-font-family{font-family: var(--wp--preset--font-family--chivo) !important;}.has-commissioner-font-family{font-family: var(--wp--preset--font-family--commissioner) !important;}.has-cormorant-font-family{font-family: var(--wp--preset--font-family--cormorant) !important;}.has-courier-prime-font-family{font-family: var(--wp--preset--font-family--courier-prime) !important;}.has-crimson-pro-font-family{font-family: var(--wp--preset--font-family--crimson-pro) !important;}.has-dm-mono-font-family{font-family: var(--wp--preset--font-family--dm-mono) !important;}.has-dm-sans-font-family{font-family: var(--wp--preset--font-family--dm-sans) !important;}.has-dm-serif-display-font-family{font-family: var(--wp--preset--font-family--dm-serif-display) !important;}.has-domine-font-family{font-family: var(--wp--preset--font-family--domine) !important;}.has-eb-garamond-font-family{font-family: var(--wp--preset--font-family--eb-garamond) !important;}.has-epilogue-font-family{font-family: var(--wp--preset--font-family--epilogue) !important;}.has-fahkwang-font-family{font-family: var(--wp--preset--font-family--fahkwang) !important;}.has-figtree-font-family{font-family: var(--wp--preset--font-family--figtree) !important;}.has-fira-sans-font-family{font-family: var(--wp--preset--font-family--fira-sans) !important;}.has-fjalla-one-font-family{font-family: var(--wp--preset--font-family--fjalla-one) !important;}.has-fraunces-font-family{font-family: var(--wp--preset--font-family--fraunces) !important;}.has-gabarito-font-family{font-family: var(--wp--preset--font-family--gabarito) !important;}.has-ibm-plex-mono-font-family{font-family: var(--wp--preset--font-family--ibm-plex-mono) !important;}.has-ibm-plex-sans-font-family{font-family: var(--wp--preset--font-family--ibm-plex-sans) !important;}.has-ibarra-real-nova-font-family{font-family: var(--wp--preset--font-family--ibarra-real-nova) !important;}.has-instrument-serif-font-family{font-family: var(--wp--preset--font-family--instrument-serif) !important;}.has-inter-font-family{font-family: var(--wp--preset--font-family--inter) !important;}.has-josefin-sans-font-family{font-family: var(--wp--preset--font-family--josefin-sans) !important;}.has-jost-font-family{font-family: var(--wp--preset--font-family--jost) !important;}.has-libre-baskerville-font-family{font-family: var(--wp--preset--font-family--libre-baskerville) !important;}.has-libre-franklin-font-family{font-family: var(--wp--preset--font-family--libre-franklin) !important;}.has-literata-font-family{font-family: var(--wp--preset--font-family--literata) !important;}.has-lora-font-family{font-family: var(--wp--preset--font-family--lora) !important;}.has-merriweather-font-family{font-family: var(--wp--preset--font-family--merriweather) !important;}.has-montserrat-font-family{font-family: var(--wp--preset--font-family--montserrat) !important;}.has-newsreader-font-family{font-family: var(--wp--preset--font-family--newsreader) !important;}.has-noto-sans-mono-font-family{font-family: var(--wp--preset--font-family--noto-sans-mono) !important;}.has-nunito-font-family{font-family: var(--wp--preset--font-family--nunito) !important;}.has-open-sans-font-family{font-family: var(--wp--preset--font-family--open-sans) !important;}.has-overpass-font-family{font-family: var(--wp--preset--font-family--overpass) !important;}.has-pt-serif-font-family{font-family: var(--wp--preset--font-family--pt-serif) !important;}.has-petrona-font-family{font-family: var(--wp--preset--font-family--petrona) !important;}.has-piazzolla-font-family{font-family: var(--wp--preset--font-family--piazzolla) !important;}.has-playfair-display-font-family{font-family: var(--wp--preset--font-family--playfair-display) !important;}.has-plus-jakarta-sans-font-family{font-family: var(--wp--preset--font-family--plus-jakarta-sans) !important;}.has-poppins-font-family{font-family: var(--wp--preset--font-family--poppins) !important;}.has-raleway-font-family{font-family: var(--wp--preset--font-family--raleway) !important;}.has-roboto-font-family{font-family: var(--wp--preset--font-family--roboto) !important;}.has-roboto-slab-font-family{font-family: var(--wp--preset--font-family--roboto-slab) !important;}.has-rubik-font-family{font-family: var(--wp--preset--font-family--rubik) !important;}.has-rufina-font-family{font-family: var(--wp--preset--font-family--rufina) !important;}.has-sora-font-family{font-family: var(--wp--preset--font-family--sora) !important;}.has-source-sans-3-font-family{font-family: var(--wp--preset--font-family--source-sans-3) !important;}.has-source-serif-4-font-family{font-family: var(--wp--preset--font-family--source-serif-4) !important;}.has-space-mono-font-family{font-family: var(--wp--preset--font-family--space-mono) !important;}.has-syne-font-family{font-family: var(--wp--preset--font-family--syne) !important;}.has-texturina-font-family{font-family: var(--wp--preset--font-family--texturina) !important;}.has-urbanist-font-family{font-family: var(--wp--preset--font-family--urbanist) !important;}.has-work-sans-font-family{font-family: var(--wp--preset--font-family--work-sans) !important;}.has-light-text-shadow{text-shadow: var(--wp--preset--text-shadow--light) !important;}.has-strong-text-shadow{text-shadow: var(--wp--preset--text-shadow--strong) !important;}
219/*# sourceURL=global-styles-inline-css */
220</style>
221
222<link crossorigin='anonymous' rel='stylesheet' id='all-css-14-1' href='/_static/??-eJydkNEKwjAMRX/IGh0D7YP4KbLV2GVr09J2DP/ebAgOFB/2Eu59OPcmgSkqE7ggF/Cjim60xBl6LLExw9uDD4HhRmzAImMiIfJvuTc572AVWjr0mCGOLRDfMaIMLkq8o9xhUhXk8nS4BRQEWhfMsKl2PmepVlM0wX9FrN6RUGqsSLt0fuw/yGJQslxTSJ63NurhGkozevWX4+lcaX3Qte5fvXGUcQ==&cssminify=yes' type='text/css' media='all' />
223<link crossorigin='anonymous' rel='stylesheet' id='print-css-15-1' href='/wp-content/mu-plugins/global-print/global-print.css?m=1465851035i&cssminify=yes' type='text/css' media='print' />
224<style id="jetpack-global-styles-frontend-style-inline-css">
225:root { --font-headings: unset; --font-base: unset; --font-headings-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; --font-base-default: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;}
226/*# sourceURL=jetpack-global-styles-frontend-style-inline-css */
227</style>
228<link crossorigin='anonymous' rel='stylesheet' id='all-css-18-1' href='/wp-content/themes/h4/global.css?m=1420737423i&cssminify=yes' type='text/css' media='all' />
229<script id="wpcom-actionbar-placeholder-js-extra">
230var actionbardata = {"siteID":"12038026","postID":"0","siteURL":"https://andrewtwest.com","xhrURL":"https://andrewtwest.com/wp-admin/admin-ajax.php","nonce":"f242555163","isLoggedIn":"","statusMessage":"","statusSubscribed":"","subsEmailDefault":"instantly","proxyScriptUrl":"https://s0.wp.com/wp-content/js/wpcom-proxy-request.js?m=1513050504i&amp;ver=20211021","i18n":{"followedText":"New posts from this site will now appear in your \u003Ca href=\"https://wordpress.com/reader\"\u003EReader\u003C/a\u003E","foldBar":"Collapse this bar","unfoldBar":"Expand this bar","shortLinkCopied":"Copied to clipboard."}};
231//# sourceURL=wpcom-actionbar-placeholder-js-extra
232</script>
vendor: 1 bytes, line 232
232
233<script id="jetpack-mu-wpcom-settings-js-before">
234var JETPACK_MU_WPCOM_SETTINGS = {"assetsUrl":"https://s1.wp.com/wp-content/mu-plugins/jetpack-mu-wpcom-plugin/moon/jetpack_vendor/automattic/jetpack-mu-wpcom/src/build/"};
235//# sourceURL=jetpack-mu-wpcom-settings-js-before
236</script>
vendor: 1 bytes, line 236
236
237<script crossorigin='anonymous' type='text/javascript'  src='/_static/??/wp-content/js/rlt-proxy.js,/wp-content/blog-plugins/wordads-classes/js/cmp/v2/cmp-non-gdpr.js?m=1780567333j'></script>
vendor: 1 bytes, line 237
237
238<script id="rlt-proxy-js-after">
239	rltInitialize( {"token":null,"iframeOrigins":["https:\/\/widgets.wp.com"]} );
240//# sourceURL=rlt-proxy-js-after
241</script>
241
242<link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://andrewtwest.wordpress.com/xmlrpc.php?rsd" />
243<meta name="generator" content="WordPress.com" />
244<link rel='shortlink' href='https://wp.me/OvDI' />
245
246<!-- Jetpack Open Graph Tags -->
247<meta property="og:type" content="website" />
248<meta property="og:title" content="The Public Void" />
249<meta property="og:description" content="Andy West&#039;s Blog: Software Development and More" />
250<meta property="og:url" content="https://andrewtwest.com/" />
251<meta property="og:site_name" content="The Public Void" />
252<meta property="og:image" content="https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=200&#038;ts=1791051773" />
253<meta property="og:image:width" content="200" />
254<meta property="og:image:height" content="200" />
255<meta property="og:image:alt" content="" />
256<meta property="og:locale" content="en_US" />
257
258<!-- End Jetpack Open Graph Tags -->
259<link rel="shortcut icon" type="image/x-icon" href="https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=32" sizes="16x16" />
260<link rel="icon" type="image/x-icon" href="https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=32" sizes="16x16" />
261<link rel="apple-touch-icon" href="https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=114" />
262<link rel='openid.server' href='https://andrewtwest.com/?openidserver=1' />
263<link rel='openid.delegate' href='https://andrewtwest.com/' />
264<link rel="search" type="application/opensearchdescription+xml" href="https://andrewtwest.com/osd.xml" title="The Public Void" />
265<link rel="search" type="application/opensearchdescription+xml" href="https://s1.wp.com/opensearch.xml" title="WordPress.com" />
266<meta name="description" content="Andy West&#039;s Blog: Software Development and More" />
267<script>
268var wa_client = {}; wa_client.cmd = []; wa_client.config = { 'blog_id': 12038026, 'blog_language': 'en', 'is_wordads': false, 'hosting_type': 0, 'afp_account_id': null, 'afp_host_id': 5038568878849053, 'theme': 'pub/independent-publisher-2', '_': { 'title': 'Advertisement', 'privacy_settings': 'Privacy Settings' }, 'formats': [ 'belowpost', 'bottom_sticky', 'sidebar_sticky_right', 'sidebar', 'gutenberg_rectangle', 'gutenberg_leaderboard', 'gutenberg_mobile_leaderboard', 'gutenberg_skyscraper' ] };
269</script>
269
270		
270<script type="text/javascript">
271
272			window.doNotSellCallback = function() {
273
274				var linkElements = [
275					'a[href="https://wordpress.com/?ref=footer_blog"]',
276					'a[href="https://wordpress.com/?ref=footer_website"]',
277					'a[href="https://wordpress.com/?ref=vertical_footer"]',
278					'a[href^="https://wordpress.com/?ref=footer_segment_"]',
279				].join(',');
280
281				var dnsLink = document.createElement( 'a' );
282				dnsLink.href = 'https://wordpress.com/advertising-program-optout/';
283				dnsLink.classList.add( 'do-not-sell-link' );
284				dnsLink.rel = 'nofollow';
285				dnsLink.style.marginLeft = '0.5em';
286				dnsLink.textContent = 'Do Not Sell or Share My Personal Information';
287
288				var creditLinks = document.querySelectorAll( linkElements );
289
290				if ( 0 === creditLinks.length ) {
291					return false;
292				}
293
294				Array.prototype.forEach.call( creditLinks, function( el ) {
295					el.insertAdjacentElement( 'afterend', dnsLink );
296				});
297
298				return true;
299			};
300
301		</script>
301
302		
302<script type="text/javascript">
303	window.google_analytics_uacct = "UA-52447-2";
304</script>
304
305
306<script type="text/javascript">
307	var _gaq = _gaq || [];
308	_gaq.push(['_setAccount', 'UA-52447-2']);
309	_gaq.push(['_gat._anonymizeIp']);
310	_gaq.push(['_setDomainName', 'none']);
311	_gaq.push(['_setAllowLinker', true]);
312	_gaq.push(['_initData']);
313	_gaq.push(['_trackPageview']);
314
315	(function() {
316		var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
317		ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
318		(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
319	})();
320</script>
320
321<link crossorigin='anonymous' rel='stylesheet' id='all-css-0-4' href='/_static/??-eJydjdEKwjAMRX/ImolC3cPYp0iXhdEtTUrTMvx7EdRHER/P4XIu7NmhSiWpkJrL3JYoBivVHHB7MSRVgVsUhIkVNwPbY6ZyRLMD/F5IOjcmAwxFmxF/Rm/xb7BGptktgZnK/Rs9D8Y0nHzfXS/e+/P6AHl7YJA=&cssminify=yes' type='text/css' media='all' />
322
323</head>
324
325<body class="home blog paged wp-embed-responsive paged-2 wp-theme-pubindependent-publisher-2 customizer-styles-applied has-sidebar jetpack-reblog-enabled">
326
327<div id="page" class="hfeed site">
328	<a class="skip-link screen-reader-text" href="#content">Skip to content</a>
329
330	<div id="hero-header" class="site-hero-section">
331				<header id="masthead" class="site-header" role="banner">
332			<div class="inner">
333				<div class="site-branding">
334					
335											<a class="site-logo-link" href="https://andrewtwest.com/">
336							<img referrerpolicy="no-referrer" alt='Unknown&#039;s avatar' src='https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=80&#038;d=identicon&#038;r=G' srcset='https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=80&#038;d=identicon&#038;r=G 1x, https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=120&#038;d=identicon&#038;r=G 1.5x, https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=160&#038;d=identicon&#038;r=G 2x, https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=240&#038;d=identicon&#038;r=G 3x, https://1.gravatar.com/avatar/48c9a549f35738b795067e5b733ada1deefd788cdaeb51662e1c39fd7fbab581?s=320&#038;d=identicon&#038;r=G 4x' class='avatar avatar-80 site-logo-image' height='80' width='80' loading='eager' decoding='async' />						</a><!-- .site-logo-link -->
337													<h1 class="site-title"><a href="https://andrewtwest.com/" rel="home">The Public Void</a></h1>
338													<p class="site-description">Andy West&#039;s Blog: Software Development and More</p>
339									</div><!-- .site-branding -->
340
341				
342				
343			</div><!-- .inner -->
344		</header><!-- #masthead -->
345	</div>
346
347		
348	
349	
350	<div id="content-wrapper" class="content-wrapper">
351		<div id="content" class="site-content">
352
353	<div id="primary" class="content-area">
354		<main id="main" class="site-main" role="main">
355
356		
357			
358						
359				
360<article id="post-376" class="post-376 post type-post status-publish format-standard hentry category-uncategorized tag-compatibility-view tag-ie8 tag-intranet tag-web-standards">
361			<header class="entry-header">
362			<h1 class="entry-title"><a href="https://andrewtwest.com/2011/02/23/same-markup-same-browser-different-results/" rel="bookmark">Same Markup, Same Browser, Different&nbsp;Results</a></h1>		</header><!-- .entry-header -->	
363	<div class="entry-content">
364		<p>Here is a simple HTML5 page I created:</p>
365<pre class="brush: xml; title: ; notranslate" title="">
366&lt;!DOCTYPE html&gt;
367&lt;html lang=&quot;en&quot;&gt;
368&lt;head&gt;
369 &lt;meta charset=&quot;utf-8&quot; /&gt;
370 &lt;title&gt;Inconsistent Rendering&lt;/title&gt;
371&lt;/head&gt;
372&lt;body&gt;
373 &lt;span style=&quot;height: 1px; overflow: visible; background-color: Green;&quot;&gt;
374 &lt;h1&gt;This is a test.&lt;/h1&gt;
375 &lt;/span&gt;
376&lt;/body&gt;
377&lt;/html&gt;
378</pre>
379<p>And  here is that page rendered in Internet Explorer 8.  In one case it’s  being served on my laptop, and the other on the local intranet.</p>
380<p><a href="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png"><img data-attachment-id="379" data-permalink="https://andrewtwest.com/2011/02/23/same-markup-same-browser-different-results/localhost/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png" data-orig-size="376,276" data-comments-opened="1" data-image-title="Test file on localhost" data-image-description="&lt;p&gt;Test file on localhost&lt;/p&gt;
381" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png?w=376" class="aligncenter size-full wp-image-379" title="Test file on localhost" src="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png?w=1100" alt="Test file on localhost"   srcset="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png 376w, https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png?w=150&amp;h=110 150w, https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png?w=300&amp;
381h=220 300w" sizes="(max-width: 376px) 100vw, 376px" /></a></p>
382<p><a href="https://andrewtwest.com/wp-content/uploads/2011/02/localhost.png"></a><a href="https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png"><img data-attachment-id="383" data-permalink="https://andrewtwest.com/2011/02/23/same-markup-same-browser-different-results/intranet/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png" data-orig-size="376,276" data-comments-opened="1" data-image-title="Test file on intranet" data-image-description="&lt;p&gt;Test file on intranet&lt;/p&gt;
383" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png?w=376" class="aligncenter size-full wp-image-383" title="Test file on intranet" src="https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png?w=1100" alt="Test file on intranet"   srcset="https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png 376w, https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png?w=150&amp;h=110 150w, https://andrewtwest.com/wp-content/uploads/2011/02/intranet1.png?w=300&amp;h=220 300w" sizes="(max-width: 376px) 100vw, 376px" /></a></p>
384<p>The  markup, the Web servers, and the browser are all set up 100% the same.   These should be identical, shouldn’t they?  What’s the problem?  The  answer is Compatibility View.</p>
385<p>Compatibility  View is a “feature” of Internet Explorer that causes it to ignore  modern Web standards.  That would be fine, except Compatibility View  settings vary by zone, and different zones have different defaults.   Also, the Compatibility View button in the address bar isn’t always  available, which means there’s no visual indicator as to what mode  you’re in, and you can’t change modes for the current page easily.</p>
386<p>Compatibility  View settings can be accessed in the Tools &#8211;&gt; Compatibility View  Settings menu, but if you’ve developed a standards compliant intranet  site, you need a better fix than simply asking each individual user to  reconfigure their browser.  Group Policy is one option, but there is a  much simpler solution.  Just add the following meta tag to your pages,  and it will force IE 8 to use the !DOCTYPE declaration in the page to  determine the rendering mode.</p>
387<pre class="brush: xml; title: ; notranslate" title="">
388&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=EmulateIE8&quot; /&gt;
389</pre>
390<p>If you&#8217;re experiencing rendering inconsistencies with the same markup being served from different environments, have a look into Compatibility View.  It just might be the culprit.</p>
391	</div><!-- .entry-content -->
392
393	<footer class="entry-footer">
394		
395				<div class="entry-meta">
396			<span class="byline">
397				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
398							<span class="cat-links">
399					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
400			
401			<span class="comments-link"><a href="https://andrewtwest.com/2011/02/23/same-markup-same-browser-different-results/#comments">2 Comments</a></span><!-- .comments-link -->
402			<span class="published-on">
403									<a href="https://andrewtwest.com/2011/02/23/same-markup-same-browser-different-results/" rel="bookmark"><time class="entry-date published" datetime="2011-02-23T21:34:17-08:00">February 23, 2011</time><time class="updated" datetime="2011-02-23T22:00:31-08:00">February 23, 2011</time></a>
404							</span>
405
406					</div><!-- .entry-meta -->
407		</footer><!-- .entry-footer -->
408</article><!-- #post-## -->
409
410			
411				
412<article id="post-362" class="post-362 post type-post status-publish format-standard hentry category-uncategorized tag-00changelog tag-access-is-denied tag-hg tag-http-error-500 tag-mercurial tag-permissions tag-push">
413			<header class="entry-header">
414			<h1 class="entry-title"><a href="https://andrewtwest.com/2011/01/13/mercurial-http-error-500-access-is-denied-on-00changelog-i/" rel="bookmark">Mercurial HTTP Error 500: Access is denied on&nbsp;00changelog.i</a></h1>		</header><!-- .entry-header -->	
415	<div class="entry-content">
416		<p>Today  I created a new Mercurial repository on a Windows server.  I cloned it,  made some changes, tried to push, and was greeted with this:</p>
417<p><code>C:\myapplication&gt;hg push<br />
418pushing to http://servername/myapplication<br />
419searching for changes<br />
420abort: HTTP Error 500: .hg\store0changelog.i: Access is denied</code></p>
421<p>My  user account had write permission to the <strong>myapplication </strong>folder on the  server, and the odd thing is that I’ve created repositories there before  and never had a problem pushing changes.  I compared <strong>00changelog.i</strong> to  the same file in another repository that was working.  Turns out I was using anonymous authentication and <strong>IUSR </strong>was missing write permission.  I gave full control to <strong>IUSR </strong>on <strong>hg\store</strong> folder and&#8230;</p>
422<p><code>C:\myapplication&gt;hg push<br />
423pushing to http://servername/myapplication<br />
424searching for changes<br />
425remote: adding changesets<br />
426remote: adding manifests<br />
427remote: adding file changes<br />
428remote: added 1 changesets with 114 changes to 114 files</code></p>
429<p>Success!</p>
430<p>If  you’re having problems pushing to a central server with Mercurial, make  sure <del>the IIS anonymous authentication account (<strong>IUSR </strong>or  <strong>IUSR_<em>MachineName</em></strong>)</del> you have write permission to the <strong>hg\store</strong> folder and  subfolders in your repository.</p>
431<div id="atatags-370373-6ac147fd7e200">
432		
432<script type="text/javascript">
433			__ATA = window.__ATA || {};
434			__ATA.cmd = window.__ATA.cmd || [];
435			__ATA.cmd.push(function() {
436				__ATA.initVideoSlot('atatags-370373-6ac147fd7e200', {
437					sectionId: '370373',
438					format: 'inread'
439				});
440			});
441		</script>
441
442	</div>	</div><!-- .entry-content -->
443
444	<footer class="entry-footer">
445		
446				<div class="entry-meta">
447			<span class="byline">
448				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
449							<span class="cat-links">
450					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
451			
452			<span class="comments-link"><a href="https://andrewtwest.com/2011/01/13/mercurial-http-error-500-access-is-denied-on-00changelog-i/#comments">4 Comments</a></span><!-- .comments-link -->
453			<span class="published-on">
454									<a href="https://andrewtwest.com/2011/01/13/mercurial-http-error-500-access-is-denied-on-00changelog-i/" rel="bookmark"><time class="entry-date published" datetime="2011-01-13T21:19:47-08:00">January 13, 2011</time><time class="updated" datetime="2011-01-14T23:32:18-08:00">January 14, 2011</time></a>
455							</span>
456
457					</div><!-- .entry-meta -->
458		</footer><!-- .entry-footer -->
459</article><!-- #post-## -->
460
461			
462				
463<article id="post-340" class="post-340 post type-post status-publish format-standard hentry category-uncategorized tag-asp-net-mvc tag-data-annotations tag-model-state tag-validation">
464			<header class="entry-header">
465			<h1 class="entry-title"><a href="https://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/" rel="bookmark">Conditional Validation with Data Annotations in ASP.NET&nbsp;MVC</a></h1>		</header><!-- .entry-header -->	
466	<div class="entry-content">
467		<p>In  the <a href="https://bitbucket.org/andrewtwest/dotblog" target="_blank">simple blog engine</a> I’m building, I encountered a scenario where I  wanted to display different UI elements depending on whether the user  was logged in:</p>
468<figure data-shortcode="caption" id="attachment_346" aria-describedby="caption-attachment-346" style="width: 293px" class="wp-caption aligncenter"><a href="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png"><img data-attachment-id="346" data-permalink="https://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/leave_reply/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png" data-orig-size="293,322" data-comments-opened="1" data-image-title="Comment Form" data-image-description="" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png?w=293" class="size-full wp-image-346" style="border:1px solid #999999;" title="Comment Form" src="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png?w=1100" alt="Comment Form"   srcset="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png 293w, https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply.png?w=136&amp;h=150 136w" sizes="(max-width: 293px) 100vw, 293px" /></a><figcaption id="caption-attachment-346" class="wp-caption-text">Not logged in</figcaption></figure>
469<p>&nbsp;</p>
470<figure data-shortcode="caption" id="attachment_347" aria-describedby="caption-attachment-347" style="width: 288px" class="wp-caption aligncenter"><a href="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png"><img data-attachment-id="347" data-permalink="https://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/leave_reply_logged_in/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png" data-orig-size="288,232" data-comments-opened="1" data-image-title="Comment Form Logged In" data-image-description="" data-image-caption="&lt;p&gt;Comment Form Logged In&lt;/p&gt;
471" data-large-file="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png?w=288" loading="lazy" class="size-full wp-image-347 " style="border:1px solid #999999;" title="Comment Form Logged In" src="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png?w=1100" alt="Comment Form Logged In"   srcset="https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png 288w, https://andrewtwest.com/wp-content/uploads/2011/01/leave_reply_logged_in.png?w=150&amp;h=121 150w" sizes="(max-width: 288px) 100vw, 288px" /></a><figcaption id="caption-attachment-347" class="wp-caption-text">Logged in</figcaption></figure>
472<p>&nbsp;</p>
473<p>When  the user is authenticated, their name and email is known, so it’s  unnecessary to display them on the comment input form.  While it would  be possible to hide just those fields, I decided to make separate  partial views and display them in the Post view with the following code:</p>
474<pre class="brush: csharp; title: ; notranslate" title="">
475&lt;%
476    if (Model.AllowComments)
477    {
478        var commentControlName = Request.IsAuthenticated ? AuthenticatedCommentFormControl&quot; : &quot;CommentFormControl&quot;;
479        Html.RenderPartial(commentControlName, new DotBlog.Models.ViewModels.CommentViewModel(Model.PostId));
480    }
481%&gt;
482</pre>
483<p>This is the view model I used for both partial views:</p>
484<pre class="brush: csharp; title: ; notranslate" title="">
485public class CommentViewModel
486{
487    ...
488
489    [Required]
490    [StringLength(50)]
491    [DisplayName(&quot;Name&quot;)]
492    public string CommenterName { get; set; }
493
494    public DateTime Date { get; set; }
495
496    [Required]
497    [StringLength(100)]
498    public string Email { get; set; }
499
500    [StringLength(100)]
501    [DisplayName(&quot;Web Site&quot;)]
502    public string WebSite { get; set; }
503
504    [Required]
505    [StringLength(1024)]
506    [DisplayName(&quot;Comment&quot;)]
507    public string CommentText { get; set; }
508
509    ...
510}
511</pre>
512<p>As  you can see, I’m using data annotations to enforce required fields and  string lengths.  The problem is, even though the name and email aren’t  always displayed, they are still required.  I needed a way to validate  certain fields conditionally.  Here are the options I came up with:</p>
513<ul>
514<li>Stop using data annotations and find a different solution for validation</li>
515<li>Use two different view models: one for each partial view</li>
516<li>Use actual conditional data annotations, like <a href="http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx" target="_blank">the library built by Simon Ince</a>.</li>
517<li>When the form is posted, remove the fields from the model state so they’re not validated.</li>
518</ul>
519<p>&nbsp;</p>
520<p>Let’s look at each of these individually:</p>
521<h2>Stop Using Data Annotations</h2>
522<p>Data  annotations are not the only way to specify validation rules, but  they’re easy to implement.  xVal was fine for ASP.MVC 1.0, but is now  deprecated.  Custom validation code with ModelState.AddModelError() is  flexible, but requires extra work.</p>
523<h2>Use Two Different View Models</h2>
524<p>
524Since  I’m using two partial views for the comment form (one for authenticated  users and one for guests), I could use a dedicated view model for each.   One would omit the data annotations on name and email and therefore  not cause any validation problems.  This was my original implementation,  but lead to unnecessary code duplication and other design problems.</p>
525<h2>Use Conditional Data Annotations</h2>
526<p>Simon Ince has built <a href="http://blogs.msdn.com/b/simonince/archive/2010/06/04/conditional-validation-in-mvc.aspx" target="_blank">a cool library</a> for conditional annotations that allows you to write code like this:</p>
527<pre class="brush: csharp; title: ; notranslate" title="">
528public class ValidationSample
529{
530    [RequiredIf(&quot;PropertyValidationDependsOn&quot;, true)]
531    public string PropertyToValidate { get; set; }
532
533    public bool PropertyValidationDependsOn { get; set; }
534}
535</pre>
536<h2>Conditionally Remove Fields from the Model State in the Controller</h2>
537<p>In the end, this is the solution I went with.  The controller executes this code when the form is posted:</p>
538<pre class="brush: csharp; title: ; notranslate" title="">
539if (Request.IsAuthenticated)
540{
541    ...
542
543    // We don't need to validate user fields if user is logged in.
544    ModelState.Remove(&quot;CommenterName&quot;);
545    ModelState.Remove(&quot;Email&quot;);
546}
547</pre>
548<p>By  removing the fields from the model state, it won’t be invalid when they  are missing.  This method is simple and avoids adding additional  dependencies.</p>
549	</div><!-- .entry-content -->
550
551	<footer class="entry-footer">
552		
553				<div class="entry-meta">
554			<span class="byline">
555				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
556							<span class="cat-links">
557					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
558			
559			<span class="comments-link"><a href="https://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/#comments">7 Comments</a></span><!-- .comments-link -->
560			<span class="published-on">
561									<a href="https://andrewtwest.com/2011/01/10/conditional-validation-with-data-annotations-in-asp-net-mvc/" rel="bookmark"><time class="entry-date published updated" datetime="2011-01-10T20:54:54-08:00">January 10, 2011</time></a>
562							</span>
563
564					</div><!-- .entry-meta -->
565		</footer><!-- .entry-footer -->
566</article><!-- #post-## -->
567
568			
569				
570<article id="post-324" class="post-324 post type-post status-publish format-standard hentry category-uncategorized tag-bug tag-entity-framework tag-nhibernate tag-storegeneratedpattern">
571			<header class="entry-header">
572			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/10/24/when-will-the-entity-framework-storegeneratedpattern-bug-go-away/" rel="bookmark">Entity Framework StoreGeneratedPattern Bug&nbsp;Persists</a></h1>		</header><!-- .entry-header -->	
573	<div class="entry-content">
574		<p>I’m  using System.Data.SQLite v1.0.66.0 with Entity Framework 4.0 and Visual  Studio 2010.  I designed some tables in SQLite and generated an Entity  Data Model from those tables.  One of them (we’ll call it <strong>Person </strong>for the sake of argument) has an autogenerated integer primary key.  I manually set the <strong>StoreGeneratedPattern </strong>property to <strong>Identity </strong>in the designer, but when I started creating new rows in the database I encountered a problem.</p>
575<p>I create new <strong>Person </strong>entities with a dummy <strong>PersonID </strong>of  -1.  The first row inserts fine, but instead of generating a new ID it  uses the dummy value.  That means when I insert the second row, it  fails:</p>
576<blockquote><p>Abort due to constraint violation<br />
577PRIMARY KEY must be unique</p></blockquote>
578<p>I did a little Googling and realized I’m not the only person experiencing this:</p>
579<ul>
580<li><a href="http://geeksharp.com/2010/05/27/ef4-bug-in-storegeneratedpattern-ssdl/" target="_blank">EF4: Bug in StoreGeneratedPattern SSDL | geek#</a></li>
581<li><a href="http://social.msdn.microsoft.com/Forums/en-US/adodotnetentityframework/thread/404d3017-01b7-4129-8e05-f4aa48f15f08" target="_blank">edmx designer properties does not set StoreGeneratedPattern=&#8221;Computed&#8221; in SSDL</a></li>
582<li><a href="http://stackoverflow.com/questions/2995086/storegeneratedpattern-in-entitiy-framework" target="_blank">StoreGeneratedPattern in Entitiy framework &#8211; Stack Overflow</a></li>
583</ul>
584<p>It seems there is a bug in which the <strong>StoragePattern </strong>property is not updated in the SSDL when you change it in the designer, even though the CSDL is.</p>
585<p>The impact of this is that you have to open the .edmx file in the XML editor and manually add the <strong>StorageGeneratedPattern </strong>property to the definition for your entity in the <strong>StorageModels </strong>section:</p>
586<pre class="brush: xml; title: ; notranslate" title="">
587&lt;EntityType Name=&quot;Person&quot;&gt;
588    &lt;Key&gt;
589        &lt;PropertyRef Name=&quot;PersonID&quot; /&gt;
590    &lt;/Key&gt;
591    &lt;Property Name=&quot;PersonID&quot; Type=&quot;integer&quot; Nullable=&quot;false&quot; StoreGeneratedPattern=&quot;Identity&quot; /&gt;
592    &lt;Property Name=&quot;Name&quot; Type=&quot;nvarchar&quot; Nullable=&quot;false&quot; MaxLength=&quot;50&quot; /&gt;
593    &lt;Property Name=&quot;Age&quot; Type=&quot;integer&quot; Nullable=&quot;false&quot; /&gt;
594&lt;/EntityType&gt;
595</pre>
596<p>Even  worse, you’ll have to do this for every identity column every time you  update the model from the database because the property gets clobbered.   The workaround does work, technically, but it’s a major nuisance during  development when things change often.</p>
597<p>Identity  columns are not uncommon, which means that this issue should have been  uncovered early during testing.  Why didn’t Microsoft fix it right away?   According to some claims, it’s been around since EF 1.0.  In a couple  of weeks I’m starting a new job where they use NHibernate.  It will be  interesting to compare it to EF 4.0 and see if I run into the same kind  of bugs.  Perhaps it will also help to wean me off graphical designers altogether.</p>
598	</div><!-- .entry-content -->
599
600	<footer class="entry-footer">
601		
602				<div class="entry-meta">
603			<span class="byline">
604				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
605							<span class="cat-links">
606					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
607			
608			<span class="comments-link"><a href="https://andrewtwest.com/2010/10/24/when-will-the-entity-framework-storegeneratedpattern-bug-go-away/#comments">4 Comments</a></span><!-- .comments-link -->
609			<span class="published-on">
610									<a href="https://andrewtwest.com/2010/10/24/when-will-the-entity-framework-storegeneratedpattern-bug-go-away/" rel="bookmark"><time class="entry-date published" datetime="2010-10-24T18:54:00-08:00">October 24, 2010</time><time class="updated" datetime="2010-10-24T22:01:05-08:00">October 24, 2010</time></a>
611							</span>
612
613					</div><!-- .entry-meta -->
614		</footer><!-- .entry-footer -->
615</article><!-- #post-## -->
616
617			
618				
619<article id="post-315" class="post-315 post type-post status-publish format-standard hentry category-uncategorized tag-sqlite tag-unique-constraint tag-unique-index">
620			<header class="entry-header">
621			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/10/17/multi-column-unique-constraints-in-sqlite-net/" rel="bookmark">Multi-Column Unique Constraints in&nbsp;SQLite.NET</a></h1>		</header><!-- .entry-header -->	
622	<div class="entry-content">
623		<p>While  working on my blog engine project to learn ASP.NET MVC and Entity  Framework, I encountered a common scenario.  I’m using SQLite on the  back-end, and I needed a unique constraint across two columns.  As  demonstrated in <a href="http://stackoverflow.com/questions/2701877/sqlite-table-constraint-unique-on-multiple-columns" target="_blank">this stackoverflow question</a>, you can specify a unique table constraint immediately after the  column definitions when using the CREATE TABLE command.  However, for  the purpose of rapid prototyping, I prefer using <a href="http://sqlite.phxsoftware.com/" target="_blank">SQLite.NET</a> and the graphical Server Explorer interface in Visual Studio rather than explicit DDL to define my tables.</p>
624<p>The  problem is that the GUI-based designer is still in development and  doesn’t support unique table constraints.  One solution is to create a  unique index instead.  Right-click one of the row headers in the table  designer and select Indexes/Keys&#8230;</p>
625<p><a href="https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png"><img data-attachment-id="316" data-permalink="https://andrewtwest.com/2010/10/17/multi-column-unique-constraints-in-sqlite-net/table_design_context_menu/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png" data-orig-size="281,279" data-comments-opened="1" data-image-title="Table design context menu" data-image-description="" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png?w=281" loading="lazy" class="aligncenter size-full wp-image-316" title="Table design context menu" src="https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png?w=1100" alt="Table design context menu"   srcset="https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png 281w, https://andrewtwest.com/wp-content/uploads/2010/10/table_design_context_menu.png?w=150&amp;h=150 150w" sizes="(max-width: 281px) 100vw, 281px" /></a></p>
626<p>In  the Index Editor, add a new index.  Under the Misc category, set the  Unique property to True, and under the Source category, list the columns  you want in the index, separated by commas.</p>
627<p><a href="https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png"><img data-attachment-id="317" data-permalink="https://andrewtwest.com/2010/10/17/multi-column-unique-constraints-in-sqlite-net/index_editor/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png" data-orig-size="633,465" data-comments-opened="1" data-image-title="Index editor" data-image-description="" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png?w=633" loading="lazy" class="aligncenter size-full wp-image-317" title="Index editor" src="https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png?w=1100" alt="Index editor"   srcset="https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png?w=497&amp;h=365 497w, https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png?w=150&amp;h=110 150w, https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png?w=300&amp;h=220 300w, https://andrewtwest.com/wp-content/uploads/2010/10/index_editor.png 633w" sizes="(max-width: 497px) 100v
627w, 497px" /></a></p>
628<p>This works because, <a href="http://www.sqlite.org/lang_createtable.html" target="_blank">as stated in the SQLite documentation</a>:</p>
629<blockquote><p><a href="http://www.sqlite.org/lang_createtable.html#rowid" target="_blank">INTEGER PRIMARY KEY</a> columns aside, both UNIQUE and PRIMARY KEY constraints are implemented  by creating an index in the database (in the same way as a<a href="http://www.sqlite.org/lang_createindex.html" target="_blank"> &#8220;CREATE UNIQUE INDEX&#8221;</a> statement would).</p></blockquote>
630<p>Using  the Index Editor to create an index with Unique = True generates a  “CREATE UNIQUE INDEX” statement behind the scenes, which can be verified  by using the Generate Change Script&#8230; feature.</p>
631<p>In  summary, if you’re thinking about using Server Explorer to create a  multi-column unique constraint in SQLite, just go with a unique index,  since that’s how it’s implemented anyway.</p>
632	</div><!-- .entry-content -->
633
634	<footer class="entry-footer">
635		
636				<div class="entry-meta">
637			<span class="byline">
638				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
639							<span class="cat-links">
640					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
641			
642			<span class="comments-link"><a href="https://andrewtwest.com/2010/10/17/multi-column-unique-constraints-in-sqlite-net/#respond">Leave a comment</a></span><!-- .comments-link -->
643			<span class="published-on">
644									<a href="https://andrewtwest.com/2010/10/17/multi-column-unique-constraints-in-sqlite-net/" rel="bookmark"><time class="entry-date published updated" datetime="2010-10-17T19:58:07-08:00">October 17, 2010</time></a>
645							</span>
646
647					</div><!-- .entry-meta -->
648		</footer><!-- .entry-footer -->
649</article><!-- #post-## -->
650
651			
652				
653<article id="post-308" class="post-308 post type-post status-publish format-standard hentry category-uncategorized tag-presentation tag-public-speaking tag-user-group">
654			<header class="entry-header">
655			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/09/12/how-to-survive-your-technical-presentation/" rel="bookmark">How to Survive Your Technical&nbsp;Presentation</a></h1>		</header><!-- .entry-header -->	
656	<div class="entry-content">
657		<p>A  few weeks ago I did a presentation on F# at a local user group meeting.   It was an opportunity to learn something new, network with other  developers, and improve my communication skills.  Here are some of the  things I learned from the experience.</p>
658<p style="text-align:center;"><a href="https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg"><img data-attachment-id="312" data-permalink="https://andrewtwest.com/2010/09/12/how-to-survive-your-technical-presentation/fsharp_talk/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg" data-orig-size="455,342" data-comments-opened="1" data-image-title="My F# presentation" data-image-description="" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg?w=455" loading="lazy" class="aligncenter size-full wp-image-312" style="border:1px solid black;" title="My F# presentation" src="https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg?w=1100" alt="My F# presentation"   srcset="https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg 455w, https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg?w=150&amp;h=113 150w, https://andrewtwest.com/wp-content/uploads/2010/09/fsharp_talk.jpg?w=300&amp;h=225 300w" sizes="(max-width: 455px) 100vw, 455px" /></a></p>
659<h2>Know your subject well in advance</h2>
660<p>Building  slides, writing code snippets and demos, and coming up with talking  points are all difficult enough, not to mention the time it takes to  practice your presentation thoroughly.  Don’t complicate matters by  trying to learn a new language or technology from scratch.</p>
661<h2>Make friends with the experts in the room</h2>
662<p>Get  knowledgeable attendees on your side right away.  During my F# talk, I  turned to them when confronted with questions I couldn’t answer, and  they bailed me out a couple of times.</p>
663<h2>Know your equipment inside and out</h2>
664<p>Try  to keep things as simple as possible.  The fewer tools you have to  manage, the less chance something will go wrong.  Arrive early so you  can test your laptop, projector, and all your software.  Make sure to  have fresh batteries for your presentation remote and microphone.  If at  all possible, do a dry run with the actual equipment you’ll be using  during your talk.</p>
665<h2>Don’t go over the allotted time</h2>
666<p>At  one point while I was talking, a meeting attendee rose from his seat  and left.  It wasn’t until then that I realized I had gone several  minutes too long.  The room was packed, but everyone was too polite to  mention that it was time to leave.</p>
667<p>
667Ironically,  I had worked very hard to fill that time with content.  But the  important thing to remember is that talking at a user group meeting  isn’t about filling dead air with noise; it’s about teaching and sharing  information.  Only say what is necessary and relevant, and then let  your audience go home.</p>
668<h2>Don’t be boring</h2>
669<p>This  is probably easier said than done, but if you want to hold your  audience’s attention, you can’t be dull and predictable.  Own your  presentation and make it unique.  Record a video of yourself speaking  and make sure you don’t look like a robot, with monotonous speech and  stiff movements.</p>
670<h2>Read <a href="http://www.amazon.com/Confessions-Public-Speaker-Scott-Berkun/dp/0596801998" target="_blank"><em>Confessions of a Public Speaker</em></a> by Scott Berkun</h2>
671<p>I  didn’t have to learn all these lessons on my own, and neither do you.   In his book, Scott captures years worth of public speaking wisdom in  two hundred brief and entertaining pages.  I only wish I had read it  earlier.</p>
672	</div><!-- .entry-content -->
673
674	<footer class="entry-footer">
675		
676				<div class="entry-meta">
677			<span class="byline">
678				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
679							<span class="cat-links">
680					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
681			
682			<span class="comments-link"><a href="https://andrewtwest.com/2010/09/12/how-to-survive-your-technical-presentation/#respond">Leave a comment</a></span><!-- .comments-link -->
683			<span class="published-on">
684									<a href="https://andrewtwest.com/2010/09/12/how-to-survive-your-technical-presentation/" rel="bookmark"><time class="entry-date published" datetime="2010-09-12T03:24:56-08:00">September 12, 2010</time><time class="updated" datetime="2010-09-12T03:33:00-08:00">September 12, 2010</time></a>
685							</span>
686
687					</div><!-- .entry-meta -->
688		</footer><!-- .entry-footer -->
689</article><!-- #post-## -->
690
691			
692				
693<article id="post-294" class="post-294 post type-post status-publish format-standard hentry category-uncategorized tag-asp-net tag-book-review tag-mvc">
694			<header class="entry-header">
695			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/08/02/book-review-professional-asp-net-mvc-2/" rel="bookmark">Book Review: Professional ASP.NET MVC&nbsp;2</a></h1>		</header><!-- .entry-header -->	
696	<div class="entry-content">
697		<p>ASP.NET  MVC is part of the broader ASP.NET framework, and serves as an  alternative development model to that of ASP.NET Web Forms.  It adheres  to the Model-View-Controller architectural pattern, and offers  developers greater control by bringing them closer to the underlying  HTTP protocol.  ASP.NET MVC leaves out many of the abstractions that Web  Forms uses to hide the stateless nature of HTTP, such as ViewState and  events.  This is bewildering to some developers who are comfortable with  the high-level, drag-and-drop nature of Web Forms, but it’s liberating  to others who feel the Web Form philosophy is too restrictive, or <a href="http://blog.wekeroad.com/blog/i-spose-ill-just-say-it-you-should-learn-mvc/" target="_blank">even deceptive</a>.</p>
698<p>Several months ago, ASP.NET MVC 2 was released, and about a month ago, <em><a href="http://www.wrox.com/WileyCDA/WroxTitle/Professional-ASP-NET-MVC-2.productCd-0470643188.html" target="_blank">Professional ASP.NET MVC 2</a></em> hit the shelves.  Some of the authors actually work on the ASP.NET  team, which gives this book an authoritative feel.  I decided to pick it  up when I chose ASP.NET MVC as the core technology for my new blog  engine.</p>
699<p>The  first chapter is by far the longest, and gives readers a detailed tour  of a fully-functioning, nontrivial sample application called  “NerdDinner”.  It introduces most of the important ASP.NET MVC concepts  without being too overwhelming.  Later chapters dive into these topics  in more detail.  <a href="http://nerddinner.codeplex.com/" target="_blank">Source code</a> for the application is hosted at CodePlex.  You can also <a href="http://tinyurl.com/aspnetmvc" target="_blank">download this chapter for free</a> from the publisher’s Web site, or <a href="http://www.nerddinner.com/" target="_blank">view the app running live</a>.</p>
700<p>In  Chapter 7, “AJAX”, I was surprised to find the considerable attention  paid to disabled-scripting scenarios.  At first I was concerned about  spending too much time supporting a very small percentage of users, but  as it turns out, ASP.NET MVC lightens the load a lot with <a href="http://msdn.microsoft.com/en-us
700/library/system.web.mvc.ajaxrequestextensions.isajaxrequest.aspx" target="_blank">IsAjaxRequest()</a>.</p>
701<p>Chapter  9, which covers security, has some interesting stories and  anecdotes, and I’m sure it will be a great reference when I’m making a  security checklist for my own apps.  After Chapter 1 (NerdDinner),  Chapter 9 is the most important chapter in the book &#8212; don’t skip it!</p>
702<p>I  was impressed with a side note in Chapter 10 that addressed a pet  peeve of mine.  There is a code snippet that uses string concatenation  with the + operator, rather than using a StringBuilder.  The snippet is  correct, but the authors went out of their way to explain to  inexperienced developers why StringBuilder should <em>not </em>have been used.  This is nothing new; Google developer Jon Skeet <a href="http://www.yoda.arachsys.com/csharp/stringbuilder.html" target="_blank">wrote an article about it</a> years ago, but I still die a little inside every time I see code like this:</p>
703<pre class="brush: csharp; title: ; notranslate" title="">
704StringBuilder sb = new StringBuilder();
705
706sb.Append(&quot;SELECT * &quot;);
707sb.Append(&quot;FROM customer &quot;);
708sb.Append(&quot;LEFT JOIN order &quot;);
709sb.Append(&quot;ON (customer.customer_id = order.customer_id &quot;);
710sb.Append(&quot;AND YEAR(order.order_date) = 2010) &quot;);
711sb.Append(&quot;WHERE order.order_id IS NULL&quot;);
712
713string s = sb.ToString();
714</pre>
715<p>Chapter  11, “Testable Design Patterns”, wants desperately to promote  testability, but is afraid to offend anyone by doing so.  The entire  first page is an apology to developers for recommending that they test  their code.  Everybody has an opinion &#8212; if you think people should be  writing testable apps, just come out and say it.</p>
716<p>Chapter  12 discusses using Web Forms and MVC together.  With the exception of  master pages, I didn’t find it particularly useful.  I’m sure there are  teams out there that want to migrate an existing app from Web Forms to  MVC one piece at a time, but not me.  The more I read about MVC, the  more Web Forms feels like Web development with training wheels.</p>
717<p>Throughout the text, the authors mentioned several tools they thought were useful, such as:</p>
718<ul>
719<li><a href="http://wpl.codeplex.com/" target="_blank">AntiXSS</a> provides a myriad of encoding functions for user input, including HTML, HTML attributes, XML, CSS and JavaScript.</li>
720<li><a href="http://watin.sourceforge.net/" target="_blank">WaitiN</a> is developed in C# and aims to bring you an easy way to automate your tests with Internet Explorer and FireFox using .Net.</li>
721<li><a href="http://code.google.com/p/moq/" target="_blank">moq</a> is designed to be a very practical, unobtrusive and straight-forward way to quickly setup dependencies for your tests.</li>
722</ul>
723<p>There  are some errata in the book.  Some are minor technical errors,  while others are typos or simple grammatical problems.  Several appear  to be cut-and-paste mistakes that occurred in sections that were updated  from MVC 1.0 to MVC 2.  In total, I found about 30 non-verified errata.   I’ve submitted a few to the Wrox Web site, and I’ll be uploading the  rest soon.</p>
724<p>Overall,  <em>Professional ASP.NET MVC 2</em> is a thorough and engaging book on an  alternative Web development framework that’s full of controversy.  It’s  not afraid to step outside the boundaries of library functions and  markup syntax, and explores many of the related tools and techniques  needed to get the most out of the MVC approach.  I recommend it.</p>
725	</div><!-- .entry-content -->
726
727	<footer class="entry-footer">
728		
729				<div class="entry-meta">
730			<span class="byline">
731				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
732							<span class="cat-links">
733					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
734			
735			<span class="comments-link"><a href="https://andrewtwest.com/2010/08/02/book-review-professional-asp-net-mvc-2/#respond">Leave a comment</a></span><!-- .comments-link -->
736			<span class="published-on">
737									<a href="https://andrewtwest.com/2010/08/02/book-review-professional-asp-net-mvc-2/" rel="bookmark"><time class="entry-date published" datetime="2010-08-02T00:02:13-08:00">August 2, 2010</time><time class="updated" datetime="2010-08-03T15:00:30-08:00">August 3, 2010</time></a>
738							</span>
739
740					</div><!-- .entry-meta -->
741		</footer><!-- .entry-footer -->
742</article><!-- #post-## -->
743
744			
745				
746<article id="post-272" class="post-272 post type-post status-publish format-standard hentry category-uncategorized tag-beta tag-prototype tag-quplo tag-redesign">
747			<header class="entry-header">
748			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/07/21/quplos-redesign-a-website-feature/" rel="bookmark">Quplo&#8217;s &#8220;Redesign a Website&#8221;&nbsp;Feature</a></h1>		</header><!-- .entry-header -->	
749	<div class="entry-content">
750		<p>Last month I evaluated a  preview of a new Web prototyping tool called Quplo and <a href="https://andrewtwest.com/2010/06/18/test-driving-the-quplo-preview/" target="_blank">
750wrote about it  here</a>.   Since that time, Quplo beta has gone live, and the development team  has added several new features and bug fixes.  Perhaps the most  significant of these is a feature they call “redesign a website”, which  imports external HTML from a URL, cleans it, and creates a new sheet.   This gives designers an alternative way to create prototypes, and comes  in handy when clients have an existing Website they want tweaked.</p>
751<p>To test Quplo’s  redesign capability, I chose the <a href="http://gcc.gnu.org/" target="_blank">GNU Compiler  Collection</a> Web site, because it’s simple and contains mostly text.  Importing the  main page was quick and painless.  Quplo created a sheet called  “Redesign” with the HTML.  The following message was inserted at the top:</p>
752<pre>&lt;!-- This page contains the HTML from http://gcc.gnu.org/
753 We've added a &lt;base href=...&gt; element to the &lt;head&gt; section.
754 CSS and images below it will load from the original site.
755 Put your custom CSS above it to mockup the site. --&gt;</pre>
756<p>What this means is  that resources like CSS files and images are not imported with the  site’s markup.  They are requested from the server of the original site  when you view your mockup.  Slightly further down the sheet is a comment  that denotes the cutoff point for your new CSS.  Anything above that  line will override the original site’s CSS.</p>
757<pre>&lt;page url="/"&gt;
758 &lt;html&gt;
759 &lt;head&gt;
760 &lt;meta content="text/html; charset=iso-8859-1" /&gt;
761 <strong><span style="color:#ff0000;">&lt;!-- Place custom CSS above this line. --&gt;</span></strong>
762 ...</pre>
763<p>After the import, it’s  time to start making changes.  First, I decided to alter the menu  headers on the right-hand side.  Instead of a thin, dark border, I  wanted a dark background color.  I added my custom CSS link above the  cutoff line.</p>
764<pre>&lt;page url="/"&gt;
765 &lt;html&gt;
766 &lt;head&gt;
767 &lt;meta content="text/html; charset=iso-8859-1" /&gt;
768 <strong><span style="color:#ff0000;">&lt;link rel="stylesheet" type="text/css" href="custom.css" /&gt;</span></strong>
769 &lt;!-- Place custom CSS above this line. --&gt;
770 ...</pre>
771<p>Then I added a new  sheet called CustomCSS with the overriding style.</p>
772<pre>&lt;page url="/custom.css"&gt;
773td.td_title {
774 border-style: none;
775 color: #3366cc;
776 background-color: #d2d2d9;
777 font-weight: bold;
778}
779&lt;/page&gt;</pre>
780<p>The next thing I did was add a splash of  color to the News and Status sections by adding the background-color  attribute to the existing inline styles.  I also changed the padding to  create an even border of color around the text.</p>
781<pre>&lt;td style="width: 50%; <span style="color:#ff0000;"><strong>padding: 8px; background-color: #20b0f0;</strong></span>" valign="top"&gt;</pre>
782<pre>&lt;td style="width: 50%; <span style="color:#ff0000;"><strong>padding: 12px;</strong></span> border-left: #3366cc thin solid; <span style="color:#ff0000;"><strong>background-color: #f0b020;</strong></span>" valign="top"&gt;</pre>
783<p>Finally, I moved the  GCC logo from the right-hand side to the left by removing the deprecated  align attribute and adding an inline style.</p>
784<pre>&lt;img src="img/gccegg-65.png" alt="" <strong><span style="color:#ff0000;">style="float: left;</span>"</strong> /&gt;</pre>
785<p>Here are the final  results:</p>
786<figure data-shortcode="caption" id="attachment_273" aria-describedby="caption-attachment-273" style="width: 455px" class="wp-caption aligncenter"><a href="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png"><img data-attachment-id="273" data-permalink="https://andrewtwest.com/2010/07/21/quplos-redesign-a-website-feature/gcc_before/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png" data-orig-size="455,370" data-comments-opened="1" data-image-title="GCC Prototype Before" data-image-description="" data-image-caption="&lt;p&gt;GCC Prototype Before&lt;/p&gt;
787" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png?w=455" loading="lazy" class="size-full wp-image-273 " title="GCC Site Before" src="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png?w=1100" alt="GCC Site Before"   srcset="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png 455w, https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png?w=150&amp;
787h=122 150w, https://andrewtwest.com/wp-content/uploads/2010/07/gcc_before.png?w=300&amp;h=244 300w" sizes="(max-width: 455px) 100vw, 455px" /></a><figcaption id="caption-attachment-273" class="wp-caption-text">GCC Site Before</figcaption></figure>
788<figure data-shortcode="caption" id="attachment_274" aria-describedby="caption-attachment-274" style="width: 455px" class="wp-caption aligncenter"><a href="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png"><img data-attachment-id="274" data-permalink="https://andrewtwest.com/2010/07/21/quplos-redesign-a-website-feature/gcc_after/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png" data-orig-size="455,370" data-comments-opened="1" data-image-title="GCC Prototype After" data-image-description="" data-image-caption="&lt;p&gt;GCC Prototype After&lt;/p&gt;
789" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png?w=455" loading="lazy" class="size-full wp-image-274" title="GCC Prototype After" src="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png?w=1100" alt="GCC Prototype After"   srcset="https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png 455w, https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png?w=150&amp;h=122 150w, https://andrewtwest.com/wp-content/uploads/2010/07/gcc_after.png?w=300&amp;h=244 300w" sizes="(max-width: 455px) 100vw, 455px" /></a><figcaption id="caption-attachment-274" class="wp-caption-text">GCC Prototype After</figcaption></figure>
790<p>And there you have it.   My apologies to the GCC team and anyone with any design sense  whatsoever.</p>
791<p>While not  groundbreaking, Quplo’s new Web site redesign feature is a time saver  that fits within their model of designing prototypes quickly.  Give it a  try if you have access to the preview, or <a href="http://quplo.com/" target="_blank">sign up today</a>.</p>
792<p><em>GCC Website content Copyright (C) Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.</em></p>
793	</div><!-- .entry-content -->
794
795	<footer class="entry-footer">
796		
797				<div class="entry-meta">
798			<span class="byline">
799				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
800							<span class="cat-links">
801					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
802			
803			<span class="comments-link"><a href="https://andrewtwest.com/2010/07/21/quplos-redesign-a-website-feature/#respond">Leave a comment</a></span><!-- .comments-link -->
804			<span class="published-on">
805									<a href="https://andrewtwest.com/2010/07/21/quplos-redesign-a-website-feature/" rel="bookmark"><time class="entry-date published" datetime="2010-07-21T03:06:16-08:00">July 21, 2010</time><time class="updated" datetime="2010-08-02T00:06:30-08:00">August 2, 2010</time></a>
806							</span>
807
808					</div><!-- .entry-meta -->
809		</footer><!-- .entry-footer -->
810</article><!-- #post-## -->
811
812			
813				
814<article id="post-249" class="post-249 post type-post status-publish format-standard hentry category-uncategorized tag-blog-engine tag-dogfooding tag-resume tag-rob-conery">
815			<header class="entry-header">
816			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/06/30/taking-the-rob-conery-challenge/" rel="bookmark">Taking the Rob Conery&nbsp;Challenge</a></h1>		</header><!-- .entry-header -->	
817	<div class="entry-content">
818		<p>Last August, Tekpub  co-founder and ex-Microsoft employee Rob Conery presented a challenge to  all developers: <a href="http://blog.wekeroad.com/2009/08/10/be-a-good-jedi-build-your-own-blog" target="_blank">build your own  blog</a>.   He suggested that a self-built blog engine would serve perfectly as a résumé, and that makes a lot of sense to me.</p>
819<p>Most of the code I’ve  written over the years is either:</p>
820<p style="padding-left:30px;"><strong>a)</strong> proprietary, and owned by the company I  was working for when I wrote it</p>
821<p style="text-align:center;"><em>&#8211; or &#8211;</em></p>
822<p style="padding-left:30px;"><strong>b)</strong> embarrassing  throw-away code that helped me learn some concept, but isn’t good enough  for anyone else to see.</p>
823<p>Writing a blog engine is a great idea because  once it matures I can start <a href="http://en.wikipedia.org/wiki/Eating_your_own_dog_food" target="_blank">dogfooding</a>, migrate my existing  blog to it, and build in the features I want the most.  It’s also an  opportunity to practice and learn new skills.  Here are some things I  haven’t tried yet, or would like to use more but haven’t had the chance:</p>
824<ul>
825<li>Mercurial</li>
826<li>TDD</li>
827<li>ASP.NET MVC 2.0</li>
828<li>Entity Framework 4.0</li>
829<li>jQuery</li>
830</ul>
831<p>Therefore, I’m  announcing here and now that I’m taking the challenge.  I plan on  hosting the project on <a href="http://bitbucket.org/" target="_blank">bitbucket.org</a> so anyone can see or  use it.  I’ll post updates here as I make progress.</p>
832	</div><!-- .entry-content -->
833
834	<footer class="entry-footer">
835		
836				<div class="entry-meta">
837			<span class="byline">
838				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
839							<span class="cat-links">
840					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
841			
842			<span class="comments-link"><a href="https://andrewtwest.com/2010/06/30/taking-the-rob-conery-challenge/#comments">2 Comments</a></span><!-- .comments-link -->
843			<span class="published-on">
844									<a href="https://andrewtwest.com/2010/06/30/taking-the-rob-conery-challenge/" rel="bookmark"><time class="entry-date published" datetime="2010-06-30T16:28:24-08:00">June 30, 2010</time><time class="updated" datetime="2010-06-30T16:32:23-08:00">June 30, 2010</time></a>
845							</span>
846
847					</div><!-- .entry-meta -->
848		</footer><!-- .entry-footer -->
849</article><!-- #post-## -->
850
851			
852				
853<article id="post-237" class="post-237 post type-post status-publish format-standard hentry category-uncategorized tag-dslr tag-iss tag-space-station">
854			<header class="entry-header">
855			<h1 class="entry-title"><a href="https://andrewtwest.com/2010/06/28/spotting-the-international-space-station/" rel="bookmark">Spotting the International Space&nbsp;Station</a></h1>		</header><!-- .entry-header -->	
856	<div class="entry-content">
857		<p>Under the right  conditions, you can see the International Space Station passing  overhead, even without a telescope or binoculars.  In fact, the ISS  travels so fast at 17,000 mph that magnification can make it difficult  to track.</p>
858<p>Last night we stepped outside at about  10:30pm to see if we could catch a glimpse of it, and I managed to capture a photo.  I took this, hand-held, with a Nikon D60 and the  Nikkor AF-S 70-300mm lens with Vibration Reduction turned on:</p>
859<p><a href="https://andrewtwest.com/wp-content/uploads/2010/06/iss.png"><img data-attachment-id="238" data-permalink="https://andrewtwest.com/2010/06/28/spotting-the-international-space-station/iss/" data-orig-file="https://andrewtwest.com/wp-content/uploads/2010/06/iss.png" data-orig-size="400,300" data-comments-opened="1" data-image-title="International Space Station" data-image-description="" data-image-caption="" data-large-file="https://andrewtwest.com/wp-content/uploads/2010/06/iss.png?w=400" loading="lazy" class="aligncenter size-full wp-image-238" title="International Space Station" src="https://andrewtwest.com/wp-content/uploads/2010/06/iss.png?w=1100" alt="International Space Station"   srcset="https://andrewtwest.com/wp-content/uploads/2010/06/iss.png 400w, https://andrewtwest.com/wp-content/uploads/2010/06/iss.png?w=150&amp;h=113 150w, https://andrewtwest.com/wp-content/uploads/2010/06/iss.png?w=300&amp;h=225 300w" sizes="(max-width: 400px) 100vw, 400px" /></a></p>
860<p>I expected to get a featureless, round blob, but you can just start to make out the  form in this image.  Maybe next time we’ll try getting some pictures  with the telescope.</p>
861<p>If you want to see the  ISS, you need to look up the predicted times for visible passes in your area.  I  use <a href="http://www.n2yo.com/" target="_blank">www.n2yo.com</a>, but some people  prefer <a href="http://www.heavens-above.com/" target="_blank">Heavens-Above</a>.  The station travels  roughly west to east, and looks like a steady, fast-moving star.</p>
862<p>It’s pretty cool to  look up at an object in the sky without using any special equipment and  realize that there are probably astronauts on board.</p>
863	</div><!-- .entry-content -->
864
865	<footer class="entry-footer">
866		
867				<div class="entry-meta">
868			<span class="byline">
869				<a href="https://andrewtwest.com/author/divinerecursion/" rel="author">Andy West</a>			</span>
870							<span class="cat-links">
871					<a href="https://andrewtwest.com/category/uncategorized/" rel="category tag">Uncategorized</a>				</span><!-- .cat-links -->
872			
873			<span class="comments-link"><a href="https://andrewtwest.com/2010/06/28/spotting-the-international-space-station/#respond">Leave a comment</a></span><!-- .comments-link -->
874			<span class="published-on">
875									<a href="https://andrewtwest.com/2010/06/28/spotting-the-international-space-station/" rel="bookmark"><time class="entry-date published" datetime="2010-06-28T03:26:28-08:00">June 28, 2010</time><time class="updated" datetime="2010-06-30T16:35:17-08:00">June 30, 2010</time></a>
876							</span>
877
878					</div><!-- .entry-meta -->
879		</footer><!-- .entry-footer -->
880</article><!-- #post-## -->
881
882			
883			
884	<nav class="navigation posts-navigation" aria-label="Posts">
885		<h2 class="screen-reader-text">Posts navigation</h2>
886		<div class="nav-links"><div class="nav-previous"><a href="https://andrewtwest.com/page/3/" >Older posts</a></div><div class="nav-next"><a href="https://andrewtwest.com/" >Newer posts</a></div></div>
887	</nav>
888		
889		</main><!-- #main -->
890	</div><!-- #primary -->
891
892<div id="secondary" class="widget-area" role="complementary">
893	
894		<aside id="recent-posts-2" class="widget widget_recent_entries">
895		<h1 class="widget-title">Recent Posts</h1>
896		<ul>
897											<li>
898					<a href="https://andrewtwest.com/2019/05/31/getting-started-with-machine-learning/">Getting Started with Machine&nbsp;Learning</a>
899									</li>
900											<li>
901					<a href="https://andrewtwest.com/2019/04/29/experimenting-with-videogrammetry/">Experimenting with Videogrammetry</a>
902									</li>
903											<li>
904					<a href="https://andrewtwest.com/2019/04/03/using-dependency-injection-with-csla/">Using Dependency Injection with&nbsp;CSLA</a>
905									</li>
906											<li>
907					<a href="https://andrewtwest.com/2012/08/21/micro-orms-for-net-compared-part-3/">Micro-ORMs for .NET Compared – Part&nbsp;3</a>
908									</li>
909											<li>
910					<a href="https://andrewtwest.com/2012/08/20/micro-orms-for-net-compared-part-2/">Micro-ORMs for .NET Compared – Part&nbsp;2</a>
911									</li>
912					</ul>
913
914		</aside><aside id="archives-4" class="widget widget_archive"><h1 class="widget-title">Archives</h1>
915			<ul>
916					<li><a href='https://andrewtwest.com/2019/05/'>May 2019</a></li>
917	<li><a href='https://andrewtwest.com/2019/04/'>April 2019</a></li>
918	<li><a href='https://andrewtwest.com/2012/08/'>August 2012</a></li>
919	<li><a href='https://andrewtwest.com/2011/07/'>July 2011</a></li>
920	<li><a href='https://andrewtwest.com/2011/04/'>April 2011</a></li>
921	<li><a href='https://andrewtwest.com/2011/03/'>March 2011</a></li>
922	<li><a href='https://andrewtwest.com/2011/02/'>February 2011</a></li>
923	<li><a href='https://andrewtwest.com/2011/01/'>January 2011</a></li>
924	<li><a href='https://andrewtwest.com/2010/10/'>October 2010</a></li>
925	<li><a href='https://andrewtwest.com/2010/09/'>September 2010</a></li>
926	<li><a href='https://andrewtwest.com/2010/08/'>August 2010</a></li>
927	<li><a href='https://andrewtwest.com/2010/07/'>July 2010</a></li>
928	<li><a href='https://andrewtwest.com/2010/06/'>June 2010</a></li>
929	<li><a href='https://andrewtwest.com/2010/05/'>May 2010</a></li>
930	<li><a href='https://andrewtwest.com/2010/04/'>April 2010</a></li>
931	<li><a href='https://andrewtwest.com/2010/02/'>February 2010</a></li>
932			</ul>
933
934			</aside></div><!-- #secondary -->
935
936		</div><!-- #content -->
937
938		<footer id="colophon" class="site-footer" role="contentinfo">
939						<div class="site-info">
940				<a href="https://wordpress.com/?ref=footer_custom_powered" rel="nofollow">Website Powered by WordPress.com</a>.
941				
942							</div><!-- .site-info -->
943		</footer><!-- #colophon -->
944	</div><!-- #content-wrapper -->
945</div><!-- #page -->
946
947		
947<script type="text/javascript">
948		var infiniteScroll = {"settings":{"id":"main","ajaxurl":"https://andrewtwest.com/?infinity=scrolling","type":"scroll","wrapper":true,"wrapper_class":"infinite-wrap","footer":"page","click_handle":"1","text":"Older posts","totop":"Scroll back to top","currentday":"28.06.10","order":"DESC","scripts":[],"styles":[],"google_analytics":false,"offset":2,"history":{"host":"andrewtwest.com","path":"/page/%d/","use_trailing_slashes":true,"parameters":""},"query_args":{"paged":2,"error":"","m":"","p":0,"post_parent":"","subpost":"","subpost_id":"","attachment":"","attachment_id":0,"name":"","pagename":"","page_id":0,"second":"","minute":"","hour":"","day":0,"monthnum":0,"year":0,"w":0,"category_name":"","tag":"","cat":"","tag_id":"","author":"","author_name":"","feed":"","tb":"","meta_key":"","meta_value":"","preview":"","s":"","sentence":"","title":"","fields":"all","menu_order":"","embed":"","category__in":[],"category__not_in":[],"category__and":[],"post__in":[],"post__not_in":[],"post_name__in":[],"tag__in":[],"tag__not_in":[],"tag__and":[],"tag_slug__in":[],"tag_slug__and":[],"post_parent__in":[],"post_parent__not_in":[],"author__in":[],"author__not_in":[],"search_columns":[],"lazy_load_term_meta":false,"posts_per_page":10,"ignore_sticky_posts":false,"suppress_filters":false,"cache_results":true,"update_post_term_cache":true,"update_menu_item_cache":false,"update_post_meta_cache":true,"post_type":"","nopaging":false,"comments_per_page":"50","no_found_rows":false,"order":"DESC"},"query_before":"2026-10-03 10:22:53","last_post_date":"2010-06-28 03:26:28","body_class":"infinite-scroll neverending","loading_text":"Loading new page","stats":"blog=12038026\u0026v=wpcom\u0026tz=-8\u0026user_id=0\u0026arch_home=1\u0026subd=andrewtwest\u0026x_pagetype=infinite"}};
949		</script>
949
950		<!--  -->
951<script type="speculationrules">
952{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/files/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/pub/independent-publisher-2/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}
953</script>
953
954	<div style="display:none">
955	<div class="grofile-hash-map-2a9bdd97ace3d09eebc9ad502d6ae374">
956	</div>
957	</div>
958		<div id="infinite-footer">
959			<div class="container">
960				<div class="blog-info">
961					<a id="infinity-blog-title" href="https://andrewtwest.com/" rel="home">
962						The Public Void					</a>
963				</div>
964				<div class="blog-credits">
965					<a href="https://wordpress.com/?ref=footer_custom_powered" rel="nofollow">Website Powered by WordPress.com</a>. 				</div>
966			</div>
967		</div><!-- #infinite-footer -->
968				<!-- CCPA [start] -->
969		
969<script type="text/javascript">
970			( function () {
971
972				var setupPrivacy = function() {
973
974					// Minimal Mozilla Cookie library
975					// https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie/Simple_document.cookie_framework
976					var cookieLib = window.cookieLib = {getItem:function(e){return e&&decodeURIComponent(document.cookie.replace(new RegExp("(?:(?:^|.*;)\\s*"+encodeURIComponent(e).replace(/[\-\.\+\*]/g,"\\$&")+"\\s*\\=\\s*([^;]*).*$)|^.*$"),"$1"))||null},setItem:function(e,o,n,t,r,i){if(!e||/^(?:expires|max\-age|path|domain|secure)$/i.test(e))return!1;var c="";if(n)switch(n.constructor){case Number:c=n===1/0?"; expires=Fri, 31 Dec 9999 23:59:59 GMT":"; max-age="+n;break;case String:c="; expires="+n;break;case Date:c="; expires="+n.toUTCString()}return"rootDomain"!==r&&".rootDomain"!==r||(r=(".rootDomain"===r?".":"")+document.location.hostname.split(".").slice(-2).join(".")),document.cookie=encodeURIComponent(e)+"="+encodeURIComponent(o)+c+(r?"; domain="+r:"")+(t?"; path="+t:"")+(i?"; secure":""),!0}};
977
978					// Implement IAB USP API.
979					window.__uspapi = function( command, version, callback ) {
980
981						// Validate callback.
982						if ( typeof callback !== 'function' ) {
983							return;
984						}
985
986						// Validate the given command.
987						if ( command !== 'getUSPData' || version !== 1 ) {
988							callback( null, false );
989							return;
990						}
991
992						// Check for GPC. If set, override any stored cookie.
993						if ( navigator.globalPrivacyControl ) {
994							callback( { version: 1, uspString: '1YYN' }, true );
995							return;
996						}
997
998						// Check for cookie.
999						var consent = cookieLib.getItem( 'usprivacy' );
1000
1001						// Invalid cookie.
1002						if ( null === consent ) {
1003							callback( null, false );
1004							return;
1005						}
1006
1007						// Everything checks out. Fire the provided callback with the consent data.
1008						callback( { version: 1, uspString: consent }, true );
1009					};
1010
1011					// Initialization.
1012					document.addEventListener( 'DOMContentLoaded', function() {
1013
1014						// Internal functions.
1015						var setDefaultOptInCookie = function() {
1016							var value = '1YNN';
1017							var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
1018							cookieLib.setItem( 'usprivacy', value, 365 * 24 * 60 * 60, '/', domain );
1019						};
1020
1021						var setDefaultOptOutCookie = function() {
1022							var value = '1YYN';
1023							var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
1024							cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
1025						};
1026
1027						var setDefaultNotApplicableCookie = function() {
1028							var value = '1---';
1029							var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
1030							cookieLib.setItem( 'usprivacy', value, 24 * 60 * 60, '/', domain );
1031						};
1032
1033						var setCcpaAppliesCookie = function( applies ) {
1034							var domain = '.wordpress.com' === location.hostname.slice( -14 ) ? '.rootDomain' : location.hostname;
1035							cookieLib.setItem( 'ccpa_applies', applies, 24 * 60 * 60, '/', domain );
1036						}
1037
1038						var maybeCallDoNotSellCallback = function() {
1039							if ( 'function' === typeof window.doNotSellCallback ) {
1040								return window.doNotSellCallback();
1041							}
1042
1043							return false;
1044						}
1045
1046						// Look for usprivacy cookie first.
1047						var usprivacyCookie = cookieLib.getItem( 'usprivacy' );
1048
1049						// Found a usprivacy cookie.
1050						if ( null !== usprivacyCookie ) {
1051
1052							// If the cookie indicates that CCPA does not apply, then bail.
1053							if ( '1---' === usprivacyCookie ) {
1054								return;
1055							}
1056
1057							// CCPA applies, so call our callback to add Do Not Sell link to the page.
1058							maybeCallDoNotSellCallback();
1059
1060							// We're all done, no more processing needed.
1061							return;
1062						}
1063
1064						// We don't have a usprivacy cookie, so check to see if we have a CCPA applies cookie.
1065						var ccpaCookie = cookieLib.getItem( 'ccpa_applies' );
1066
1067						// No CCPA applies cookie found, so we'll need to geolocate if this visitor is from California.
1068						// This needs to happen client side because we do not have region geo data in our $SERVER headers,
1069						// only country data -- therefore we can't vary cache on the region.
1070						if ( null === ccpaCookie ) {
1071
1072							var request = new XMLHttpRequest();
1073							request.open( 'GET', 'https://public-api.wordpress.com/geo/', true );
1074
1075							request.onreadystatechange = function () {
1076								if ( 4 === this.readyState ) {
1077									if ( 200 === this.status ) {
1078
1079										// Got a geo response. Parse out the region data.
1080										var data = JSON.parse( this.response );
1081										var region      = data.region ? data.region.toLowerCase() : '';
1082										var ccpa_applies = ['california', 'colorado', 'connecticut', 'delaware', 'indiana', 'iowa', 'montana', 'new jersey', 'oregon', 'tennessee', 'texas', 'utah', 'virginia'].indexOf( region ) > -1;
1083										// Set CCPA applies cookie. This keeps us from having to make a geo request too frequently.
1084										setCcpaAppliesCookie( ccpa_applies );
1085
1086										// Check if CCPA applies to set the proper usprivacy cookie.
1087										if ( ccpa_applies ) {
1088											if ( maybeCallDoNotSellCallback() ) {
1089												// Do Not Sell link added, so set default opt-in.
1090												setDefaultOptInCookie();
1091											} else {
1092												// Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe.
1093												setDefaultOptOutCookie();
1094											}
1095										} else {
1096											// CCPA does not apply.
1097											setDefaultNotApplicableCookie();
1098										}
1099									} else {
1100										// Could not geo, so let's assume for now that CCPA applies to be safe.
1101										setCcpaAppliesCookie( true );
1102										if ( maybeCallDoNotSellCallback() ) {
1103											// Do Not Sell link added, so set default opt-in.
1104											setDefaultOptInCookie();
1105										} else {
1106											// Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe.
1107											setDefaultOptOutCookie();
1108										}
1109									}
1110								}
1111							};
1112
1113							// Send the geo request.
1114							request.send();
1115						} else {
1116							// We found a CCPA applies cookie.
1117							if ( ccpaCookie === 'true' ) {
1118								if ( maybeCallDoNotSellCallback() ) {
1119									// Do Not Sell link added, so set default opt-in.
1120									setDefaultOptInCookie();
1121								} else {
1122									// Failed showing Do Not Sell link as required, so default to opt-OUT just to be safe.
1123									setDefaultOptOutCookie();
1124								}
1125							} else {
1126								// CCPA does not apply.
1127								setDefaultNotApplicableCookie();
1128							}
1129						}
1130					} );
1131				};
1132
1133				// Kickoff initialization.
1134				if ( window.defQueue && defQueue.isLOHP && defQueue.isLOHP === 2020 ) {
1135					defQueue.items.push( setupPrivacy );
1136				} else {
1137					setupPrivacy();
1138				}
1139
1140			} )();
1141		</script>
1141
1142
1143		<!-- CCPA [end] -->
1144		<div class="widget widget_eu_cookie_law_widget">
1145<div
1146	class="hide-on-button ads-active"
1147	data-hide-timeout="30"
1148	data-consent-expiration="180"
1149	id="eu-cookie-law"
1150	style="display: none"
1151>
1152	<form method="post">
1153		<input type="submit" value="Close and accept" class="accept" />
1154
1155		Privacy &amp; Cookies: This site uses cookies. By continuing to use this website, you agree to their use. <br />
1156To find out more, including how to control cookies, see here:
1157				<a href="https://automattic.com/cookies/" rel="nofollow">
1158			Cookie Policy		</a>
1159 </form>
1160</div>
1161</div>			<div id="actionbar" dir="ltr" style="display: none;"
1162				class="actnbr-pub-independent-publisher-2" role="region" aria-label="Site actions">
1163			<span class="actnbr-live" aria-live="polite"></span>
1164			<ul>
1165										<li class="actnbr-btn actnbr-hidden">
1166										<a class="actnbr-action actnbr-actn-follow " href="" role="button" aria-haspopup="dialog" aria-expanded="false">
1167				<svg class="actnbr-icon actnbr-icon-bell" width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" fill="currentColor"><path fill-rule="evenodd" clip-rule="evenodd" d="M17 11.5c0 1.353.17 2.368.976 3 .266.209.602.376 1.024.5v1H5v-1c.422-.124.757-.291 1.024-.5.806-.632.976-1.647.976-3V9c0-2.8 2.2-5 5-5s5 2.2 5 5v2.5ZM15.5 9v2.5c0 .93.066 1.98.515 2.897l.053.103H7.932a4.018 4.018 0 0 0 .053-.103c.449-.917.515-1.967.515-2.897V9c0-1.972 1.528-3.5 3.5-3.5s3.5 1.528 3.5 3.5Zm-5.492 9.008c0-.176.023-.346.065-.508h3.854A1.996 1.996 0 0 1 12 20c-1.1 0-1.992-.892-1.992-1.992Z"/></svg>				<span>Subscribe</span>
1168			</a>
1169			<a class="actnbr-action actnbr-actn-following  no-display" href="" role="button">
1170				<svg class="actnbr-icon actnbr-icon-check" width="20" height="20" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" style="fill: none" stroke="currentColor" stroke-width="1.5"><path d="M7 12L10 15L17 8" vector-effect="non-scaling-stroke"/></svg>				<span>Subscribed</span>
1171			</a>
1172									<div class="actnbr-popover actnbr-panel actnbr-notice" id="follow-bubble" role="dialog" aria-label="Subscribe to The Public Void">
1173								<div class="actnbr-follow-bubble">
1174								<div class="actnbr-panel__group"><a class="actnbr-menu__item actnbr-sitename" href="https://andrewtwest.com"><img loading='lazy' alt='' src='https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=50&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png' srcset='https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=50&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 1x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=75&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 1.5x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=100&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 2x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=150&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 3x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=200&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 4x' class='avatar avatar-50' height='50' width='50' /><span class="actnbr-menu__label">The Public Void</span></a></div>																	<div class="actnbr-panel__group">
1175										<div class="actnbr-message no-display" aria-live="polite"></div>
1176										<form method="post" action="https://subscribe.wordpress.com" accept-charset="utf-8" class="no-display">
1177																						<input type="email" name="email" placeholder="Want updates? Enter your email" class="actnbr-email-field" aria-label="Email address" />
1178											<input type="hidden" name="action" value="subscribe" />
1179											<input type="hidden" name="blog_id" value="12038026" />
1180											<input type="hidden" name="source" value="https://andrewtwest.com/page/2/" />
1181											<input type="hidden" name="sub-type" value="actionbar-follow" />
1182											<input type="hidden" id="_wpnonce" name="_wpnonce" value="6494cc5864" />											<button type="submit" class="actnbr-button">Sign me up</button>
1183										</form>
1184										<p class="actnbr-login-nudge">
1185											Have a WordPress.com account? <a href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fr-login.wordpress.com%2Fremote-login.php%3Faction%3Dlink%26back%3Dhttps%253A%252F%252Fandrewtwest.com%252F2011%252F02%252F23%252Fsame-markup-same-browser-different-results%252F">Log in now.</a>										</p>
1186									</div>
1187																	</div>
1188							</div>
1189						</li>
1190									<li class="actnbr-ellipsis actnbr-hidden">
1191					<button type="button" class="actnbr-more-toggle" aria-haspopup="true" aria-expanded="false" aria-label="More options">
1192						<svg class="actnbr-icon actnbr-icon-more-horizontal" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" fill="currentColor"><path d="M11 13h2v-2h-2v2zm-6 0h2v-2H5v2zm12-2v2h2v-2h-2z"/></svg>					</button>
1193					<div class="actnbr-popover actnbr-menu" role="menu" aria-label="Site options">
1194						<div class="actnbr-menu__group" role="group"><a role="menuitem" class="actnbr-menu__item actnbr-sitename" href="https://andrewtwest.com"><img loading='lazy' alt='' src='https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=50&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png' srcset='https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=50&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 1x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=75&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 1.5x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=100&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 2x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=150&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 3x, https://secure.gravatar.com/blavatar/f27dd4810b0d60e02039a2026bbe04cf2e6e4a73b015d64ca5c899a9f3a5fed0?s=200&#038;d=https%3A%2F%2Fs-ssl.wordpress.com%2Fi%2Flogo%2Fwpcom-gray-white.png 4x' class='avatar avatar-50' height='50' width='50' /><span class="actnbr-menu__label">The Public Void</span></a></div><div class="actnbr-menu__group" role="group"><a role="menuitem" class="actnbr-menu__item actnbr-reader" href="https://wordpress.com/reader/feeds/323164"><span class="actnbr-menu__label">View site in Reader</span></a></div><div class="actnbr-menu__group" role="group"><a role="menuitem" class="actnbr-menu__item actnbr-subs" href="https://subscribe.wordpress.com/"><span class="actnbr-menu__label">Manage subscriptions</span></a><a role="menuitem" class="actnbr-menu__item actnbr-signup" href="https://wordpress.com/start/"><span class="actnbr-menu__label">Sign up</span></a><a role="menuitem" class="actnbr-menu__item actnbr-login" href="https://wordpress.com/log-in?redirect_to=https%3A%2F%2Fr-login.wordpress.com%2Fremote-login.php%3Faction%3Dlink%26back%3Dhttps%253A%252F%252Fandrewtwest.com%252F2011%252F02%252F23%252Fsame-markup-same-browser-different-results%252F"><span class="actnbr-menu__label">Log in</span></a></div><div class="actnbr-menu__group" role="group"><a role="menuitem" class="actnbr-menu__item flb-report" href="https://wordpress.com/abuse/?report_url=https://andrewtwest.com" target="_blank" rel="noopener noreferrer"><span class="actnbr-menu__label">Report this content</span><span class="actnbr-menu__icon"><svg class="actnbr-icon actnbr-icon-external" width="18" height="18" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" fill="currentColor"><path d="M19.5 4.5h-7V6h4.44l-5.97 5.97 1.06 1.06L18 7.06v4.44h1.5v-7Zm-13 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-3H17v3a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h3V5.5h-3Z"/></svg></span></a></div><div class="actnbr-menu__group" role="group"><a role="menuitem" class="actnbr-menu__item actnbr-fold" href=""><span class="actnbr-menu__label">Collapse this bar</span></a></div>					</div>
1195				</li>
1196			</ul>
1197		</div>
1198		
1198<script>
1199window.addEventListener( "DOMContentLoaded", function () {
1200				var link = document.createElement( "link" );
1201				link.href = "\/wp-content\/mu-plugins\/jetpack-plugin\/moon\/jetpack_vendor\/automattic\/jetpack-newsletter\/src\/..\/build\/action-bar.css?ver=35dd33285eb46dc308dd";
1202				link.rel = "stylesheet";
1203				document.head.appendChild( link );
1204
1205				var script = document.createElement( "script" );
1206				script.src = "\/wp-content\/mu-plugins\/jetpack-plugin\/moon\/jetpack_vendor\/automattic\/jetpack-newsletter\/src\/..\/build\/action-bar.js?ver=35dd33285eb46dc308dd";
1207				document.body.appendChild( script );
1208			} );
1209</script>
1209
1210<link rel="prefetch" href="/wp-content/mu-plugins/jetpack-plugin/moon/_inc/blocks/swiper.js" as="script" />
1211		<div id="jp-carousel-loading-overlay" style="display: none;">
1212			<div id="jp-carousel-loading-wrapper">
1213				<span id="jp-carousel-library-loading"><svg class="jetpack-spinner" width="40" height="40" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><circle cx="50" cy="50" r="46" fill="none" stroke="#ddd" stroke-width="8"/><path d="M 50 4 A 46 46 0 0 1 96 50" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round"><animateTransform attributeName="transform" type="rotate" dur="1.4s" from="0 50 50" to="360 50 50" repeatCount="indefinite"/></path></svg></span>
1214			</div>
1215		</div>
1216		<div class="jp-carousel-overlay" style="display: none;">
1217
1218		<div class="jp-carousel-container">
1219			<!-- The Carousel Swiper -->
1220			<div
1221				class="jp-carousel-wrap swiper jp-carousel-swiper-container jp-carousel-transitions"
1222				itemscope
1223				itemtype="https://schema.org/ImageGallery">
1224				<div class="jp-carousel swiper-wrapper"></div>
1225				<div class="jp-swiper-button-prev swiper-button-prev">
1226					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1227						<mask id="maskPrev" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="9" height="12">
1228							<path d="M16.2072 16.59L11.6496 12L16.2072 7.41L14.8041 6L8.8335 12L14.8041 18L16.2072 16.59Z" fill="white"/>
1229						</mask>
1230						<g mask="url(#maskPrev)">
1231							<rect x="0.579102" width="23.8823" height="24" fill="#FFFFFF"/>
1232						</g>
1233					</svg>
1234				</div>
1235				<div class="jp-swiper-button-next swiper-button-next">
1236					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1237						<mask id="maskNext" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="8" height="12">
1238							<path d="M8.59814 16.59L13.1557 12L8.59814 7.41L10.0012 6L15.9718 12L10.0012 18L8.59814 16.59Z" fill="white"/>
1239						</mask>
1240						<g mask="url(#maskNext)">
1241							<rect x="0.34375" width="23.8822" height="24" fill="#FFFFFF"/>
1242						</g>
1243					</svg>
1244				</div>
1245			</div>
1246			<!-- The main close buton -->
1247			<div class="jp-carousel-close-hint">
1248				<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1249					<mask id="maskClose" mask-type="alpha" maskUnits="userSpaceOnUse" x="5" y="5" width="15" height="14">
1250						<path d="M19.3166 6.41L17.9135 5L12.3509 10.59L6.78834 5L5.38525 6.41L10.9478 12L5.38525 17.59L6.78834 19L12.3509 13.41L17.9135 19L19.3166 17.59L13.754 12L19.3166 6.41Z" fill="white"/>
1251					</mask>
1252					<g mask="url(#maskClose)">
1253						<rect x="0.409668" width="23.8823" height="24" fill="#FFFFFF"/>
1254					</g>
1255				</svg>
1256			</div>
1257			<!-- Image info, comments and meta -->
1258			<div class="jp-carousel-info">
1259				<div class="jp-carousel-info-footer">
1260					<div class="jp-carousel-pagination-container">
1261						<div class="jp-swiper-pagination swiper-pagination"></div>
1262						<div class="jp-carousel-pagination"></div>
1263					</div>
1264					<div class="jp-carousel-photo-title-container">
1265						<div class="jp-carousel-photo-caption"></div>
1266					</div>
1267					<div class="jp-carousel-photo-icons-container">
1268						<a href="#" class="jp-carousel-icon-btn jp-carousel-icon-info" aria-label="Toggle photo metadata visibility">
1269							<span class="jp-carousel-icon">
1270								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1271									<mask id="maskInfo" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20">
1272										<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7537 2C7.26076 2 2.80273 6.48 2.80273 12C2.80273 17.52 7.26076 22 12.7537 22C18.2466 22 22.7046 17.52 22.7046 12C22.7046 6.48 18.2466 2 12.7537 2ZM11.7586 7V9H13.7488V7H11.7586ZM11.7586 11V17H13.7488V11H11.7586ZM4.79292 12C4.79292 16.41 8.36531 20 12.7537 20C17.142 20 20.7144 16.41 20.7144 12C20.7144 7.59 17.142 4 12.7537 4C8.36531 4 4.79292 7.59 4.79292 12Z" fill="white"/>
1273									</mask>
1274									<g mask="url(#maskInfo)">
1275										<rect x="0.8125" width="23.8823" height="24" fill="#FFFFFF"/>
1276									</g>
1277								</svg>
1278							</span>
1279						</a>
1280												<a href="#" class="jp-carousel-icon-btn jp-carousel-icon-comments" aria-label="Toggle photo comments visibility">
1281							<span class="jp-carousel-icon">
1282								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1283									<mask id="maskComments" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20">
1284										<path fill-rule="evenodd" clip-rule="evenodd" d="M4.3271 2H20.2486C21.3432 2 22.2388 2.9 22.2388 4V16C22.2388 17.1 21.3432 18 20.2486 18H6.31729L2.33691 22V4C2.33691 2.9 3.2325 2 4.3271 2ZM6.31729 16H20.2486V4H4.3271V18L6.31729 16Z" fill="white"/>
1285									</mask>
1286									<g mask="url(#maskComments)">
1287										<rect x="0.34668" width="23.8823" height="24" fill="#FFFFFF"/>
1288									</g>
1289								</svg>
1290
1291								<span class="jp-carousel-has-comments-indicator" aria-label="This image has comments."></span>
1292							</span>
1293						</a>
1294											</div>
1295				</div>
1296				<div class="jp-carousel-info-extra">
1297					<div class="jp-carousel-info-content-wrapper">
1298						<div class="jp-carousel-photo-title-container">
1299							<div class="jp-carousel-photo-title"></div>
1300						</div>
1301						<div class="jp-carousel-comments-wrapper">
1302															<div id="jp-carousel-comments-loading">
1303									<span>Loading Comments...</span>
1304								</div>
1305								<div class="jp-carousel-comments"></div>
1306								<div id="jp-carousel-comment-form-container">
1307									<span id="jp-carousel-comment-form-spinner"><svg class="jetpack-spinner" width="20" height="20" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false"><circle cx="50" cy="50" r="46" fill="none" stroke="#ddd" stroke-width="8"/><path d="M 50 4 A 46 46 0 0 1 96 50" fill="none" stroke="currentColor" stroke-width="8" stroke-linecap="round"><animateTransform attributeName="transform" type="rotate" dur="1.4s" from="0 50 50" to="360 50 50" repeatCount="indefinite"/></path></svg></span>
1308									<div id="jp-carousel-comment-post-results"></div>
1309																														<form id="jp-carousel-comment-form">
1310												<label for="jp-carousel-comment-form-comment-field" class="screen-reader-text">Write a Comment...</label>
1311												<textarea
1312													name="comment"
1313													class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea"
1314													id="jp-carousel-comment-form-comment-field"
1315													placeholder="Write a Comment..."
1316												></textarea>
1317												<div id="jp-carousel-comment-form-submit-and-info-wrapper">
1318													<div id="jp-carousel-comment-form-commenting-as">
1319																													<fieldset>
1320																<label for="jp-carousel-comment-form-email-field">Email</label>
1321																<input type="text" name="email" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-email-field" />
1322															</fieldset>
1323															<fieldset>
1324																<label for="jp-carousel-comment-form-author-field">Name</label>
1325																<input type="text" name="author" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-author-field" />
1326															</fieldset>
1327															<fieldset>
1328																<label for="jp-carousel-comment-form-url-field">Website</label>
1329																<input type="text" name="url" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-url-field" />
1330															</fieldset>
1331																											</div>
1332													<input
1333														type="submit"
1334														name="submit"
1335														class="jp-carousel-comment-form-button"
1336														id="jp-carousel-comment-form-button-submit"
1337														value="Post Comment" />
1338												</div>
1339											</form>
1340																											</div>
1341													</div>
1342						<div class="jp-carousel-image-meta">
1343							<div class="jp-carousel-title-and-caption">
1344								<div class="jp-carousel-photo-info">
1345									<div class="jp-carousel-caption" itemprop="caption description"></div>
1346								</div>
1347
1348								<div class="jp-carousel-photo-description"></div>
1349							</div>
1350							<a class="jp-carousel-image-download" href="#" aria-label="Download image" target="_blank" style="display: none;">
1351								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1352									<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="3" y="3" width="19" height="18">
1353										<path fill-rule="evenodd" clip-rule="evenodd" d="M5.84615 5V19H19.7775V12H21.7677V19C21.7677 20.1 20.8721 21 19.7775 21H5.84615C4.74159 21 3.85596 20.1 3.85596 19V5C3.85596 3.9 4.74159 3 5.84615 3H12.8118V5H5.84615ZM14.802 5V3H21.7677V10H19.7775V6.41L9.99569 16.24L8.59261 14.83L18.3744 5H14.802Z" fill="white"/>
1354									</mask>
1355									<g mask="url(#mask0)">
1356										<rect x="0.870605" width="23.8823" height="24" fill="#FFFFFF"/>
1357									</g>
1358								</svg>
1359								<span class="jp-carousel-download-text"></span>
1360							</a>
1361							<div class="jp-carousel-image-map" style="display: none;"></div>
1362						</div>
1363					</div>
1364				</div>
1365			</div>
1366		</div>
1367
1368		</div>
1369		
1369<script crossorigin='anonymous' type='text/javascript'  src='/_static/??-eJzTLy/QTc7PK0nNK9EvyClNz8wr1i+uzCtJrMjITM/IAeKS1CJMEWP94uSizIISoOIM5/yiVL2sYh19yo1yKiotzojIzaGmcc7BGYlFBUAT7XNtDc1MzUyNTC1MLbIA3HVf6g=='></script>
vendor: 1 bytes, line 1369
1369
1370<script type='text/javascript'>
1371	(function(){
1372		var corecss = document.createElement('link');
1373		var themecss = document.createElement('link');
1374		var corecssurl = "/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shCore.css?ver=3.0.9b";
1375		if ( corecss.setAttribute ) {
1376				corecss.setAttribute( "rel", "stylesheet" );
1377				corecss.setAttribute( "type", "text/css" );
1378				corecss.setAttribute( "href", corecssurl );
1379		} else {
1380				corecss.rel = "stylesheet";
1381				corecss.href = corecssurl;
1382		}
1383		document.head.appendChild( corecss );
1384		var themecssurl = "/wp-content/plugins/syntaxhighlighter/syntaxhighlighter3/styles/shThemeDefault.css?m=1363304414i&amp;ver=3.0.9b";
1385		if ( themecss.setAttribute ) {
1386				themecss.setAttribute( "rel", "stylesheet" );
1387				themecss.setAttribute( "type", "text/css" );
1388				themecss.setAttribute( "href", themecssurl );
1389		} else {
1390				themecss.rel = "stylesheet";
1391				themecss.href = themecssurl;
1392		}
1393		document.head.appendChild( themecss );
1394	})();
1395	SyntaxHighlighter.config.strings.expandSource = '+ expand source';
1396	SyntaxHighlighter.config.strings.help = '?';
1397	SyntaxHighlighter.config.strings.alert = 'SyntaxHighlighter\n\n';
1398	SyntaxHighlighter.config.strings.noBrush = 'Can\'t find brush for: ';
1399	SyntaxHighlighter.config.strings.brushNotHtmlScript = 'Brush wasn\'t configured for html-script option: ';
1400	SyntaxHighlighter.defaults['pad-line-numbers'] = false;
1401	SyntaxHighlighter.defaults['toolbar'] = false;
1402	SyntaxHighlighter.all();
1403
1404	// Infinite scroll support
1405	document.addEventListener( 'is.post-load', function () {
1406		SyntaxHighlighter.highlight();
1407	} );
1408</script>
1408
1409
1410	
1410<script type="text/javascript">
1411		(function () {
1412			var wpcom_reblog = {
1413				source: 'toolbar',
1414
1415				toggle_reblog_box_flair: function (obj_id, post_id) {
1416
1417					// Go to site selector. This will redirect to their blog if they only have one.
1418					const postEndpoint = `https://wordpress.com/post`;
1419
1420					// Ideally we would use the permalink here, but fortunately this will be replaced with the 
1421					// post permalink in the editor.
1422					const originalURL = `${ document.location.href }?page_id=${ post_id }`; 
1423					
1424					const url =
1425						postEndpoint +
1426						'?url=' +
1427						encodeURIComponent( originalURL ) +
1428						'&is_post_share=true' +
1429						'&v=5';
1430
1431					const redirect = function () {
1432						if (
1433							! window.open( url, '_blank' )
1434						) {
1435							location.href = url;
1436						}
1437					};
1438
1439					if ( /Firefox/.test( navigator.userAgent ) ) {
1440						setTimeout( redirect, 0 );
1441					} else {
1442						redirect();
1443					}
1444				},
1445			};
1446
1447			window.wpcom_reblog = wpcom_reblog;
1448		})();
1449	</script>
vendor: 1 bytes, line 1449
1449
1450<script id="jetpack-carousel-js-extra">
1451var jetpackSwiperLibraryPath = {"url":"/wp-content/mu-plugins/jetpack-plugin/moon/_inc/blocks/swiper.js"};
1452var jetpackCarouselStrings = {"widths":[370,700,1000,1200,1400,2000],"is_logged_in":"","lang":"en","ajaxurl":"https://andrewtwest.com/wp-admin/admin-ajax.php","nonce":"e5e139dc5e","display_exif":"1","display_comments":"1","single_image_gallery":"1","single_image_gallery_media_file":"","background_color":"black","comment":"Comment","post_comment":"Post Comment","write_comment":"Write a Comment...","loading_comments":"Loading Comments...","image_label":"Open image in full-screen.","download_original":"View full size \u003Cspan class=\"photo-size\"\u003E{0}\u003Cspan class=\"photo-size-times\"\u003E\u00d7\u003C/span\u003E{1}\u003C/span\u003E","no_comment_text":"Please be sure to submit some text with your comment.","no_comment_email":"Please provide an email address to comment.","no_comment_author":"Please provide your name to comment.","comment_post_error":"Sorry, but there was an error posting your comment. Please try again later.","comment_approved":"Your comment was approved.","comment_unapproved":"Your comment is in moderation.","camera":"Camera","aperture":"Aperture","shutter_speed":"Shutter Speed","focal_length":"Focal Length","copyright":"Copyright","comment_registration":"0","require_name_email":"0","login_url":"https://andrewtwest.wordpress.com/wp-login.php?redirect_to=https%3A%2F%2Fandrewtwest.com%2F2011%2F02%2F23%2Fsame-markup-same-browser-different-results%2F","blog_id":"12038026","meta_data":["camera","aperture","shutter_speed","focal_length","copyright"],"stats_query_args":"blog=12038026&v=wpcom&tz=-8&user_id=0&arch_home=1&subd=andrewtwest","is_public":"1"};
1453//# sourceURL=jetpack-carousel-js-extra
1454</script>
vendor: 1 bytes, line 1454
1454
1455<script crossorigin='anonymous' type='text/javascript'  src='/_static/??-eJydUEFOw0AM/BDuloIoHBBPqTYbJ3XitVext4Hfs5VaQD1w6MXSjD1jzYS1QFJxFA8d6wiF60hiYdWlj71B4miGFqZGRWc47TaTPYQ/slx/RdSP6Bawtq3OhMBxDY65cHS84f/xmdBLTPMFh6wq4UCSQleJ+0AykJAjWFqU+Yq/Npnk1tWPmNvnUrt21mPBNsShYSY74gK7czSJJxqjk96pt5kKMMkMg6ZqMNDnHUbnhC0SFYe1JM33N5TiotWQf+6uxKWij/z+uH/bbvfPL0+v0zckmME0'></script>
vendor: 1 bytes, line 1455
1455
1456<script data-wp-strategy="defer" defer id="tiled-gallery-js" src="/wp-content/mu-plugins/jetpack-plugin/moon/_inc/build/tiled-gallery/tiled-gallery/tiled-gallery.min.js?m=1755006225i&#038;ver=16.3-a.8"></script>
vendor: 1 bytes, line 1456
1456
1457<script crossorigin='anonymous' type='text/javascript'  src='/wp-content/mu-plugins/carousel-wpcom/carousel-wpcom.js?m=1761899756i'></script>
vendor: 1 bytes, line 1457
1457
1458<script id="wp-emoji-settings" type="application/json">
1459{"baseUrl":"https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/","ext":".png","svgUrl":"https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/","svgExt":".svg","source":{"concatemoji":"/wp-includes/js/wp-emoji-release.min.js?m=1783090810i&ver=7.2-alpha-63885"}}
1460</script>
vendor: 1 bytes, line 1460
1460
1461<script type="module">
1462/*! This file is auto-generated */
1463var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\udec8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))});
1464//# sourceURL=/wp-includes/js/wp-emoji-loader.min.js
1465</script>
1465
1466		
1466<script type="text/javascript">
1467			(function() {
1468				var extend = function(out) {
1469					out = out || {};
1470
1471					for (var i = 1; i < arguments.length; i++) {
1472						if (!arguments[i])
1473						continue;
1474
1475						for (var key in arguments[i]) {
1476						if (arguments[i].hasOwnProperty(key))
1477							out[key] = arguments[i][key];
1478						}
1479					}
1480
1481					return out;
1482				};
1483				extend( window.infiniteScroll.settings.scripts, ["jetpack-mu-wpcom-settings","rlt-proxy","cmp-script-stub","wpcom-actionbar-placeholder","syntaxhighlighter-core","syntaxhighlighter-brush-xml","syntaxhighlighter-brush-csharp","wordads-client","eu-cookie-law-script","the-neverending-homepage","independent-publisher-2-navigation","independent-publisher-2-skip-link-focus-fix","independent-publisher-2-wpcom-functions","jetpack-carousel","tiled-gallery","carousel-wpcom"] );
1484				extend( window.infiniteScroll.settings.styles, ["eu-cookie-law-style","the-neverending-homepage","coblocks-frontend","wpcom-core-compat-playlist-styles","wpcom-bbpress2-staff-css","genericons","independent-publisher-2-style","
1484independent-publisher-2-block-style","independent-publisher-2-wpcom-style","reblogging","geo-location-flair","a8c-global-print","h4-global","wp-img-auto-sizes-contain","wp-emoji-styles","wp-block-library","classic-theme-styles","wp-block-styles-placeholder","coblocks-inline-format","wp-global-styles-placeholder","jetpack-global-styles-frontend-style","global-styles","jetpack-swiper-library","jetpack-carousel","tiled-gallery","core-block-supports-duotone"] );
1485			})();
1486		</script>
1486
1487				<span id="infinite-aria" aria-live="polite"></span>
1488		
1488<script src="//stats.wp.com/w.js?69" defer></script>
1488 
1488<script type="text/javascript">
1489_tkq = window._tkq || [];
1490_stq = window._stq || [];
1491_tkq.push(['storeContext', {'blog_id':'12038026','blog_tz':'-8','user_lang':'en','blog_lang':'en','user_id':'0'}]);
1492		// Prevent sending pageview tracking from WP-Admin pages.
1493		_stq.push(['view', {'blog':'12038026','v':'wpcom','tz':'-8','user_id':'0','arch_home':'1','subd':'andrewtwest'}]);
1494		_stq.push(['extra', {'crypt':'UE5XaGUuOTlwaD85flAmcm1mcmZsaDhkV11YdWtpP0NsWnVkPS9sL0ViLndld3BuVT01Uj14Ti1yYTBnX3xuYUQ3Qz1oblZbVHV3MTZ6aj0wcy01aFV6Y1RhRDhuPzkwMncsNm1ad0EldTZtNXh1JSxyYW44MzAxMFBndmg2Wy16eVsyMS1CX1JPdmxiekFZW2tNTjA4diU2aUEtZmRmbWhKVEprM3xOVCs4andhb21IOE1xdGpDVjREcy4sRzZNTFQsbm5ZYys2XWlkdStUeW9peWJ6Xy1vZHw0RGwlQXZTNVYzbDhIXXBjYzg4QVpGaENUZnBIUV9sNzlaMWxFZ19FLXwxNCU2UzQ9P0NmQUZxdEZiY2VVSVEzcF9dR2IleTlCXWwmW05ZOU5Cbm9SaGN4ZFpuUmxDQkQvP0tpcnVxUXVCfnBxY2hfbltiL1p2MU1Hd35PYm9ZRzFzV24='}]);
1495_stq.push([ 'clickTrackerInit', '12038026', '0' ]);
1496</script>
1496
1497<noscript><img src="https://pixel.wp.com/b.gif?v=noscript" style="height:1px;width:1px;overflow:hidden;position:absolute;bottom:1px;" alt="" /></noscript>
1498<meta id="bilmur" property="bilmur:data" content="" data-provider="wordpress.com" data-service="simple" data-site-tz="Etc/GMT+8" data-custom-props="{&quot;logged_in&quot;:&quot;0&quot;,&quot;wptheme&quot;:&quot;pub\/independent-publisher-2&quot;,&quot;wptheme_is_block&quot;:&quot;0&quot;}"   >
1499		
1499<script defer src="/wp-content/js/bilmur.min.js?i=19&amp;m=202640"></script>
1499 	
1500</body>
1501</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.