1<!DOCTYPE html> 2 3<html lang="en-GB"> 4 5 <head> 6 7 <meta charset="UTF-8"> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" > 9 10 <title>AndyPi – Python & Programming</title> 11<meta name='robots' content='max-image-preview:large' /> 12<link rel="alternate" type="application/rss+xml" title="AndyPi » Feed" href="https://andypi.co.uk/feed/" /> 13<link rel="alternate" type="application/rss+xml" title="AndyPi » Comments Feed" href="https://andypi.co.uk/comments/feed/" /> 14<style id="wp-img-auto-sizes-contain-inline-css"> 15img:is([sizes=auto i],[sizes^="auto," i]){contain-intrinsic-size:3000px 1500px} 16/*# sourceURL=wp-img-auto-sizes-contain-inline-css */ 17</style> 18<style id="wp-emoji-styles-inline-css"> 19 20 img.wp-smiley, img.emoji { 21 display: inline !important; 22 border: none !important; 23 box-shadow: none !important; 24 height: 1em !important; 25 width: 1em !important; 26 margin: 0 0.07em !important; 27 vertical-align: -0.1em !important; 28 background: none !important; 29 padding: 0 !important; 30 } 31/*# sourceURL=wp-emoji-styles-inline-css */ 32</style> 33<style id="wp-block-library-inline-css"> 34: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;
34--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{word-wrap:normal!important;border:0;clip-path:inset(50%);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.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]){border-style:solid}html :where([style*=border-top-color]){border-top-style:solid}html :where([style*=border-right-color]){border-right-style:solid}html :where([style*=border-bottom-color]){border-bottom-style:solid}html :where([style*=border-left-color]){border-left-style:solid}html :where([style*=border-width]){border-style:solid}html :where([style*=border-top-width]){border-top-style:solid}html :where([style*=border-right-width]){border-right-style:solid}html :where([style*=border-bottom-width]){border-bottom-style:solid}html :where([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}} 35 36/*# sourceURL=/wp-includes/css/dist/block-library/common.min.css */ 37</style> 38<style id="classic-theme-styles-inline-css"> 39/*! This file is auto-generated */ 40.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none} 41/*# sourceURL=/wp-includes/css/classic-themes.min.css */ 42</style> 43 44<style id="global-styles-inline-css"> 45: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: #222;--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--accent: #13C4A5;--wp--preset--color--dark-gray: #444;--wp--preset--color--medium-gray: #666;--wp--preset--color--light-gray: #888;--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,0) 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%);
45--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: 16px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 24px;--wp--preset--font-size--x-large: 42px;--wp--preset--font-size--regular: 18px;--wp--preset--font-size--larger: 32px;--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);}: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-accent-color{color: var(--wp--preset--color--accent) !important;}.has-dark-gray-color{color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-color{color: var(--wp--preset--color--medium-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-accent-background-color{background-color: var(--wp--preset--color--accent) !important;}.has-dark-gray-background-color{background-color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-background-color{background-color: var(--wp--preset--color--medium-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-accent-border-color{border-color: var(--wp--preset--color--accent) !important;}.has-dark-gray-border-color{border-color: var(--wp--preset--color--dark-gray) !important;}.has-medium-gray-border-color{border-color: var(--wp--preset--color--medium-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;}
45.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-regular-font-size{font-size: var(--wp--preset--font-size--regular) !important;}.has-larger-font-size{font-size: var(--wp--preset--font-size--larger) !important;} 46/*# sourceURL=global-styles-inline-css */ 47</style> 48 49<link rel='stylesheet' id='tablepress-default-css' href='https://andypi.co.uk/wp-content/plugins/tablepress/css/build/default.css?ver=3.3.3' media='all' /> 50<link rel='stylesheet' id='baskerville_googleFonts-css' href='//fonts.googleapis.com/css?family=Roboto+Slab:400,700|Roboto:400,400italic,700,700italic,300|Pacifico:400&ver=1' media='all' /> 51<link rel='stylesheet' id='baskerville_style-css' href='https://andypi.co.uk/wp-content/themes/baskerville/style.css?ver=1.0' media='all' />
52<script data-wp-strategy="defer" defer id="stop-user-enumeration-js" src="https://andypi.co.uk/wp-content/plugins/stop-user-enumeration/frontend/js/frontend.js?ver=1.7.7"></script>
vendor: 1 bytes, line 52
52
53<script id="jquery-core-js" src="https://andypi.co.uk/wp-includes/js/jquery/jquery.min.js?ver=3.7.1"></script>
vendor: 1 bytes, line 53
53
54<script id="jquery-migrate-js" src="https://andypi.co.uk/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1"></script>
vendor: 1 bytes, line 54
54
55<script id="baskerville_imagesloaded-js" src="https://andypi.co.uk/wp-content/themes/baskerville/js/imagesloaded.pkgd.js?ver=1"></script>
vendor: 1 bytes, line 55
55
56<script id="baskerville_flexslider-js" src="https://andypi.co.uk/wp-content/themes/baskerville/js/flexslider.min.js?ver=1"></script>
56 57<link rel="https://api.w.org/" href="https://andypi.co.uk/wp-json/" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://andypi.co.uk/xmlrpc.php?rsd" /> 58<meta name="generator" content="WordPress 7.0.6" /> 59<style id="custom-background-css"> 60body.custom-background { background-color: #f1f1f1; } 61</style> 62<link rel="icon" href="https://andypi.co.uk/wp-content/uploads/2023/12/cropped-small-sq-32x32.png" sizes="32x32" /> 63<link rel="icon" href="https://andypi.co.uk/wp-content/uploads/2023/12/cropped-small-sq-192x192.png" sizes="192x192" /> 64<link rel="apple-touch-icon" href="https://andypi.co.uk/wp-content/uploads/2023/12/cropped-small-sq-180x180.png" /> 65<meta name="msapplication-TileImage" content="https://andypi.co.uk/wp-content/uploads/2023/12/cropped-small-sq-270x270.png" />
66<script src="https://cdn.counter.dev/script.js" data-id="4f79969f-7643-492c-80c7-a85e5877c194" data-utcoffset="0"></script>
66 67 68 </head> 69 70 71 <body class="home blog custom-background wp-theme-baskerville no-featured-image"> 72 73 74 75 <div class="header section small-padding bg-dark bg-image" style="background-image: url( https://andypi.co.uk/wp-content/uploads/2018/03/andypi_logo_web_bannerjpg.jpg );"> 76 77 <div class="cover"></div> 78 79 <div class="header-search-block bg-graphite hidden"> 80 81 <form method="get" class="searchform" action="https://andypi.co.uk/"> 82 <input type="search" value="" placeholder="Search Form" name="s" class="s" /> 83 <input type="submit" class="searchsubmit" value="Search"> 84</form> 85 </div><!-- .header-search-block --> 86 87 <div class="header-inner section-inner"> 88 89 90 <div class="blog-logo"> 91 92 <a class="logo" href='https://andypi.co.uk/' title='AndyPi — Python & Programming' rel='home'> 93 <img src='https://andypi.co.uk/wp-content/uploads/2018/03/transparent.png' alt='AndyPi'> 94 </a> 95 96 </div> 97 98 99 </div><!-- .header-inner --> 100 101 </div><!-- .header --> 102 103 <div class="navigation section no-padding bg-dark"> 104 105 <div class="navigation-inner section-inner"> 106 107 <div class="nav-toggle fleft hidden"> 108 109 <div class="bar"></div> 110 <div class="bar"></div> 111 <div class="bar"></div> 112 113 <div class="clear"></div> 114 115 </div> 116 117 <ul class="main-menu"> 118 119 <li id="menu-item-18614" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-18614"><a href="https://andypi.co.uk" aria-current="page">Home</a></li> 120<li id="menu-item-17570" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-17570"><a href="https://andypi.co.uk/subscribe/">Subscribe</a></li> 121<li id="menu-item-18210" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children has-children menu-item-18210"><a href="https://andypi.co.uk/category/portfolio/">Pro Portfolio</a> 122<ul class="sub-menu"> 123 <li id="menu-item-18834" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18834"><a href="https://verticalvideoconverter.com/">Vertical Video Converter</a></li> 124 <li id="menu-item-18227" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18227"><a href="https://github.com/andy-pi">Github Page</a></li> 125 <li id="menu-item-18333" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18333"><a href="https://andypi.co.uk/2013/12/05/magpi-article/">MagPi Article!</a></li> 126 <li id="menu-item-18420" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18420"><a href="https://andypi.co.uk/2021/04/10/countly-wordpress-plugin/">Countly WordPress plugin</a></li> 127 <li id="menu-item-18335" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18335"><a href="https://andypi.co.uk/2020/01/15/cloudflare-stream-video-analytics-wordpress-plugin/">Cloudflare Stream Power Tools WordPress Plugin</a></li> 128 <li id="menu-item-18208" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18208"><a href="https://andypi.co.uk/2017/05/02/countly-two-factor-authentication-plugin/">Countly Two Factor Authentication Plugin</a></li> 129 <li id="menu-item-18207" class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18207"><a href="https://andypi.co.uk/2017/11/01/automating-global-https-deployment-using-flys-api-and-ansible/">Automating Global HTTPS Deployment using Flyâs API and Ansible</a></li> 130</ul> 131</li> 132<li id="menu-item-17476" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-has-children has-children menu-item-17476"><a href="https://andypi.co.uk" aria-current="page">Categories</a> 133<ul class="sub-menu"> 134 <li id="menu-item-17477" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17477"><a href="https://andypi.co.uk/category/raspberrypi/">Raspberry Pi</a></li> 135 <li id="menu-item-17554" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17554"><a href="https://andypi.co.uk/category/arduino/">Arduino</a></li> 136 <li id="menu-item-17555" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17555"><a href="https://andypi.co.uk/category/cloud/">Cloud</a></li> 137 <li id="menu-item-17478" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17478"><a href="https://andypi.co.uk/category/displays/">Displays & Lights</a></li> 138 <li id="menu-item-17553" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17553"><a href="https://andypi.co.uk/category/web-apps/">Web Apps</a></li> 139 <li id="menu-item-18755" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18755"><a href="https://andypi.co.uk/category/devops/">DevOps</a></li> 140 <li id="menu-item-17552" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17552"><a href="https://andypi.co.uk/category/python/">Python</a></li> 141 <li id="menu-item-17960" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17960"><a href="https://andypi.co.uk/category/python-beginner-to-pro-in-5steps/">Python: beginner to pro in 5 steps</a></li> 142 <li id="menu-item-17556" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17556"><a href="https://andypi.co.uk/category/php/">PHP</a></li> 143 <li id="menu-item-18756" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18756"><a href="https://andypi.co.uk/category/wordpress/">WordPress</a></li> 144 <li id="menu-item-17585" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17585"><a href="https://andypi.co.uk/category/javascript/">JavaScript</a></li> 145 <li id="menu-item-17962" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17962"><a href="https://andypi.co.uk/category/random/">Random</a></li> 146</ul> 147</li> 148<li id="menu-item-17566" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-17566"><a href="https://andypi.co.uk/about/">About</a></li> 149<li id="menu-item-17474" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-17474"><a href="http://zhongwen.andypi.co.uk">䏿</a></li> 150 151 </ul><!-- .main-menu --> 152 153 <a class="search-toggle fright" href="#"></a> 154 155 <div class="clear"></div> 156 157 </div><!-- .navigation-inner --> 158 159 </div><!-- .navigation --> 160 161 <div class="mobile-navigation section bg-graphite no-padding hidden"> 162 163 <ul class="mobile-menu"> 164 165 <li class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-18614"><a href="https://andypi.co.uk" aria-current="page">Home</a></li> 166<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-17570"><a href="https://andypi.co.uk/subscribe/">Subscribe</a></li> 167<li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-has-children has-children menu-item-18210"><a href="https://andypi.co.uk/category/portfolio/">Pro Portfolio</a> 168<ul class="sub-menu"> 169 <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18834"><a href="https://verticalvideoconverter.com/">Vertical Video Converter</a></li> 170 <li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-18227"><a href="https://github.com/andy-pi">Github Page</a></li> 171 <li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18333"><a href="https://andypi.co.uk/2013/12/05/magpi-article/">
171MagPi Article!</a></li> 172 <li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18420"><a href="https://andypi.co.uk/2021/04/10/countly-wordpress-plugin/">Countly WordPress plugin</a></li> 173 <li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18335"><a href="https://andypi.co.uk/2020/01/15/cloudflare-stream-video-analytics-wordpress-plugin/">Cloudflare Stream Power Tools WordPress Plugin</a></li> 174 <li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18208"><a href="https://andypi.co.uk/2017/05/02/countly-two-factor-authentication-plugin/">Countly Two Factor Authentication Plugin</a></li> 175 <li class="menu-item menu-item-type-post_type menu-item-object-post menu-item-18207"><a href="https://andypi.co.uk/2017/11/01/automating-global-https-deployment-using-flys-api-and-ansible/">Automating Global HTTPS Deployment using Flyâs API and Ansible</a></li> 176</ul> 177</li> 178<li class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home menu-item-has-children has-children menu-item-17476"><a href="https://andypi.co.uk" aria-current="page">Categories</a> 179<ul class="sub-menu"> 180 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17477"><a href="https://andypi.co.uk/category/raspberrypi/">Raspberry Pi</a></li> 181 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17554"><a href="https://andypi.co.uk/category/arduino/">Arduino</a></li> 182 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17555"><a href="https://andypi.co.uk/category/cloud/">Cloud</a></li> 183 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17478"><a href="https://andypi.co.uk/category/displays/">Displays & Lights</a></li> 184 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17553"><a href="https://andypi.co.uk/category/web-apps/">Web Apps</a></li> 185 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18755"><a href="https://andypi.co.uk/category/devops/">DevOps</a></li> 186 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17552"><a href="https://andypi.co.uk/category/python/">Python</a></li> 187 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17960"><a href="https://andypi.co.uk/category/python-beginner-to-pro-in-5steps/">Python: beginner to pro in 5 steps</a></li> 188 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17556"><a href="https://andypi.co.uk/category/php/">PHP</a></li> 189 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-18756"><a href="https://andypi.co.uk/category/wordpress/">WordPress</a></li> 190 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17585"><a href="https://andypi.co.uk/category/javascript/">JavaScript</a></li> 191 <li class="menu-item menu-item-type-taxonomy menu-item-object-category menu-item-17962"><a href="https://andypi.co.uk/category/random/">Random</a></li> 192</ul> 193</li> 194<li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-17566"><a href="https://andypi.co.uk/about/">About</a></li> 195<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-17474"><a href="http://zhongwen.andypi.co.uk">䏿</a></li> 196 197 </ul><!-- .main-menu --> 198 199 </div><!-- .mobile-navigation --> 200 201<div class="wrapper section medium-padding"> 202 203 204 <div class="content section-inner"> 205 206 207 <div class="posts"> 208 209 210 <div class="post-container"> 211 212 <div id="post-19181" class="post-19181 post type-post status-publish format-standard hentry category-python"> 213 214 <div class="post-header"> 215 216 217 <h2 class="post-title"><a href="https://andypi.co.uk/2026/08/17/how-to-switch-simple-saleforce-python-package-to-use-oauth-soap-api-login-retiring-june-2027/" rel="bookmark" title="How to switch simple-saleforce python package to use OAuth (SOAP API login retiring June 2027)">How to switch simple-saleforce python package to use OAuth (SOAP API login retiring June 2027)</a></h2> 218 219 220 221</div><!-- .post-header --> 222 223 224<div class="post-excerpt"> 225 226 <p>Salesforce OAuth Setup for `simple-salesforce` Salesforce is retiring the SOAP API login o
226peration on June 1, 2027, ending username-password authentication for all SOAP, REST, and Bulk API integrations. This post explains how to switch from using SOAP username / password… <a class="more-link" href="https://andypi.co.uk/2026/08/17/how-to-switch-simple-saleforce-python-package-to-use-oauth-soap-api-login-retiring-june-2027/">Continue Reading →</a></p> 227 228</div><!-- .post-excerpt --> 229 230 231 <div class="post-meta"> 232 233 <a class="post-date" href="https://andypi.co.uk/2026/08/17/how-to-switch-simple-saleforce-python-package-to-use-oauth-soap-api-login-retiring-june-2027/" title="How to switch simple-saleforce python package to use OAuth (SOAP API login retiring June 2027)">2026/08/17</a> 234 235 236 <div class="clear"></div> 237 238 </div><!-- .post-meta --> 239 240 241<div class="clear"></div> 242 </div><!-- .post --> 243 244 </div> 245 246 247 <div class="post-container"> 248 249 <div id="post-18814" class="post-18814 post type-post status-publish format-standard has-post-thumbnail hentry category-devops category-django-deployment category-python"> 250 251 <div class="post-header"> 252 253 254 <h2 class="post-title"><a href="https://andypi.co.uk/2026/05/02/deployment-of-a-django-app-on-caddy-server-using-ansible-docker/" rel="bookmark" title="Deployment of a Django app on Caddy server using Ansible & Docker">Deployment of a Django app on Caddy server using Ansible & Docker</a></h2> 255 256 257 258</div><!-- .post-header --> 259 260 261 <div class="featured-media"> 262 263 <a href="https://andypi.co.uk/2026/05/02/deployment-of-a-django-app-on-caddy-server-using-ansible-docker/" rel="bookmark" title="Deployment of a Django app on Caddy server using Ansible & Docker"> 264 265 <img width="600" height="342" src="https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-600x342.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" fetchpriority="high" srcset="https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-600x342.jpg 600w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-300x171.jpg 300w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-1024x583.jpg 1024w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-768x437.jpg 768w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-1536x874.jpg 1536w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663-945x538.jpg 945w, https://andypi.co.uk/wp-content/uploads/2024/08/c9ba8d8c-0d23-46f8-8be8-c578c987b663.jpg 1662w" sizes="(max-width: 600px) 100vw, 600px" /> 266 </a> 267 268 </div><!-- .featured-media --> 269 270 271<div class="post-excerpt"> 272 273 <p>A tutorial showing how to reliably and repeatably deploy a Django app in production using Docker and Ansible. Caddy server instead of Nginx and Gunicorn instead of uWSGI which require less configuration – see the conclusion for why I made these changes.</p> 274 275</div><!-- .post-excerpt --> 276 277 278 <div class="post-meta"> 279 280 <a class="post-date" href="https://andypi.co.uk/2026/05/02/deployment-of-a-django-app-on-caddy-server-using-ansible-docker/" title="Deployment of a Django app on Caddy server using Ansible & Docker">2026/05/02</a> 281 282 <a href="https://andypi.co.uk/2026/05/02/deployment-of-a-django-app-on-caddy-server-using-ansible-docker/#respond" class="post-comments" >0</a> 283 <div class="clear"></div> 284 285 </div><!-- .post-meta --> 286 287 288<div class="clear"></div> 289 </div><!-- .post --> 290 291 </div> 292 293 294 <div class="post-container"> 295 296 <div id="post-19118" class="post-19118 post type-post status-publish format-standard has-post-thumbnail hentry category-ai category-random"> 297 298 <div class="post-header"> 299 300 301 <h2 class="post-title"><a href="https://andypi.co.uk/2026/03/13/amiga-500-rgb2hdmi-mod-plus-debugging-dead-motherboard-with-chatgpt/" rel="bookmark" title="Amiga 500 RGB2HDMI mod plus debugging dead motherboard with ChatGPT">Amiga 500 RGB2HDMI mod plus debugging dead motherboard with ChatGPT<
301/a></h2> 302 303 304 305</div><!-- .post-header --> 306 307 308 <div class="featured-media"> 309 310 <a href="https://andypi.co.uk/2026/03/13/amiga-500-rgb2hdmi-mod-plus-debugging-dead-motherboard-with-chatgpt/" rel="bookmark" title="Amiga 500 RGB2HDMI mod plus debugging dead motherboard with ChatGPT"> 311 312 <img width="600" height="338" src="https://andypi.co.uk/wp-content/uploads/2026/03/breakout-600x338.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="breakout" decoding="async" srcset="https://andypi.co.uk/wp-content/uploads/2026/03/breakout-600x338.jpg 600w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-300x169.jpg 300w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-1024x576.jpg 1024w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-768x432.jpg 768w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-1536x864.jpg 1536w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-2048x1152.jpg 2048w, https://andypi.co.uk/wp-content/uploads/2026/03/breakout-945x532.jpg 945w" sizes="(max-width: 600px) 100vw, 600px" /> 313 </a> 314 315 </div><!-- .featured-media --> 316 317 318<div class="post-excerpt"> 319 320 <p>My Mrs has an Amiga 500 that she is desperate to play and reclaim her childhood, but the CRT monitor broke. We don’t have room for a CRT so I decided to mod it to output the AV to HDMI… <a class="more-link" href="https://andypi.co.uk/2026/03/13/amiga-500-rgb2hdmi-mod-plus-debugging-dead-motherboard-with-chatgpt/">Continue Reading →</a></p> 321 322</div><!-- .post-excerpt --> 323 324 325 <div class="post-meta"> 326 327 <a class="post-date" href="https://andypi.co.uk/2026/03/13/amiga-500-rgb2hdmi-mod-plus-debugging-dead-motherboard-with-chatgpt/" title="Amiga 500 RGB2HDMI mod plus debugging dead motherboard with ChatGPT">2026/03/13</a> 328 329 <a href="https://andypi.co.uk/2026/03/13/amiga-500-rgb2hdmi-mod-plus-debugging-dead-motherboard-with-chatgpt/#respond" class="post-comments" >0</a> 330 <div class="clear"></div> 331 332 </div><!-- .post-meta --> 333 334 335<div class="clear"></div> 336 </div><!-- .post --> 337 338 </div> 339 340 341 <div class="post-container"> 342 343 <div id="post-19101" class="post-19101 post type-post status-publish format-standard has-post-thumbnail hentry category-ruby"> 344 345 <div class="post-header"> 346 347 348 <h2 class="post-title"><a href="https://andypi.co.uk/2026/01/12/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-3-basic-rails-app/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (3 â Basic Rails App)">How I started learning Ruby on Rails from scratch as a Python dev (3 â Basic Rails App)</a></h2> 349 350 351 352</div><!-- .post-header --> 353 354 355 <div class="featured-media"> 356 357 <a href="https://andypi.co.uk/2026/01/12/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-3-basic-rails-app/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (3 â Basic Rails App)"> 358 359 <img width="600" height="325" src="https://andypi.co.uk/wp-content/uploads/2026/01/rails-600x325.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" srcset="https://andypi.co.uk/wp-content/uploads/2026/01/rails-600x325.png 600w, https://andypi.co.uk/wp-content/uploads/2026/01/rails-300x162.png 300w, https://andypi.co.uk/wp-content/uploads/2026/01/rails-768x415.png 768w, https://andypi.co.uk/wp-content/uploads/2026/01/rails.png 808w" sizes="(max-width: 600px) 100vw, 600px" /> 360 </a> 361 362 </div><!-- .featured-media --> 363 364 365<div class="post-excerpt"> 366 367 <p>There’s a couple of very helpful guides to creating a basic Ruby on Rails app: There’s a text based tutorial: https://guides.rubyonrails.org/getting_started.html#introduction I followed this video tutorial (quite fast so needed to pause at some points as I was coding alongside… <a class="more-link" href="https://andypi.co.uk/2026/01/12/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-3-basic-rails-app/">Continue Reading →</a></p> 368 369</div><!-- .post-excerpt --> 370 371 372 <div class="post-meta"> 373 374 <a class="post-date" href="https://andypi.co.uk/2026/01/12/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-3-basic-rails-app/" title="How I started learning Ruby on Rails from scratch as a Python dev (3 â Basic Rails App)">2026/01/12</a> 375 376 <a href="https://andypi.co.uk/2026/01/12/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-3-basic-rails-app/#respond" class="post-comments" >0</a> 377 <div class="clear"></div> 378 379 </div><!-- .post-meta --> 380 381 382<div class="clear"></div> 383 </div><!-- .post --> 384 385 </div> 386 387 388 <div class="post-container"> 389 390 <div id="post-19091" class="post-19091 post type-post status-publish format-standard has-post-thumbnail hentry category-ruby"> 391 392 <div class="post-header"> 393 394 395 <h2 class="post-title"><a href="https://andypi.co.uk/2025/12/24/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-2-syntax/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (2 – Syntax)">How I started learning Ruby on Rails from scratch as a Python dev (2 – Syntax)</a></h2> 396 397 398 399</div><!-- .post-header --> 400 401 402 <div class="featured-media"> 403 404 <a href="https://andypi.co.uk/2025/12/24/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-2-syntax/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (2 – Syntax)"> 405 406 <img width="600" height="300" src="https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-600x300.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-600x300.png 600w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-300x150.png 300w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-768x384.png 768w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-945x473.png 945w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1.png 1024w" sizes="auto, (max-width: 600px) 100v
406w, 600px" /> 407 </a> 408 409 </div><!-- .featured-media --> 410 411 412<div class="post-excerpt"> 413 414 <p>In order to get a familiar with Ruby syntax before diving into a real project, I did a couple of things to practice. The first was to use the Try Ruby online playground – this took me a bit more… <a class="more-link" href="https://andypi.co.uk/2025/12/24/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-2-syntax/">Continue Reading →</a></p> 415 416</div><!-- .post-excerpt --> 417 418 419 <div class="post-meta"> 420 421 <a class="post-date" href="https://andypi.co.uk/2025/12/24/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-2-syntax/" title="How I started learning Ruby on Rails from scratch as a Python dev (2 – Syntax)">2025/12/24</a> 422 423 <a href="https://andypi.co.uk/2025/12/24/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-2-syntax/#respond" class="post-comments" >0</a> 424 <div class="clear"></div> 425 426 </div><!-- .post-meta --> 427 428 429<div class="clear"></div> 430 </div><!-- .post --> 431 432 </div> 433 434 435 <div class="post-container"> 436 437 <div id="post-19083" class="post-19083 post type-post status-publish format-standard has-post-thumbnail hentry category-ruby"> 438 439 <div class="post-header"> 440 441 442 <h2 class="post-title"><a href="https://andypi.co.uk/2025/12/13/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-1-project-setup/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (1 – Project Setup)">How I started learning Ruby on Rails from scratch as a Python dev (1 – Project Setup)</a></h2> 443 444 445 446</div><!-- .post-header --> 447 448 449 <div class="featured-media"> 450 451 <a href="https://andypi.co.uk/2025/12/13/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-1-project-setup/" rel="bookmark" title="How I started learning Ruby on Rails from scratch as a Python dev (1 – Project Setup)"> 452 453 <img width="600" height="300" src="https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-600x300.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-600x300.png 600w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-300x150.png 300w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-768x384.png 768w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1-945x473.png 945w, https://andypi.co.uk/wp-content/uploads/2025/12/ruby-lang-ar21-1024x512-1.png 1024w" sizes="auto, (max-width: 600px) 100vw, 600px" /> 454 </a> 455 456 </div><!-- .featured-media --> 457 458 459<div class="post-excerpt"> 460 461 <p>I’ve got the opportunity to do some work on a Ruby on Rails web app coming up soon. I’m documenting my journey here of getting up to speed with Ruby coming from Python on MacOS. This post is going to… <a class="more-link" href="https://andypi.co.uk/2025/12/13/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-1-project-setup/">Continue Reading →</a></p> 462 463</div><!-- .post-excerpt --> 464 465 466 <div class="post-meta"> 467 468 <a class="post-date" href="https://andypi.co.uk/2025/12/13/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-1-project-setup/" title="How I started learning Ruby on Rails from scratch as a Python dev (1 – Project Setup)">2025/12/13</a> 469 470 <a href="https://andypi.co.uk/2025/12/13/how-i-started-learning-ruby-on-rails-from-scratch-as-a-python-dev-1-project-setup/#respond" class="post-comments" >0</a> 471 <div class="clear"></div> 472 473 </div><!-- .post-meta --> 474 475 476<div class="clear"></div> 477 </div><!-- .post --> 478 479 </div> 480 481 482 <div class="post-container"> 483 484 <div id="post-19067" class="post-19067 post type-post status-publish format-standard has-post-thumbnail hentry category-python"> 485 486 <div class="post-header"> 487 488 489 <h2 class="post-title"><a href="https://andypi.co.uk/2025/08/17/how-to-create-a-private-python-package-on-github/" rel="bookmark" title="How to create a private python package on Github">
489How to create a private python package on Github</a></h2> 490 491 492 493</div><!-- .post-header --> 494 495 496 <div class="featured-media"> 497 498 <a href="https://andypi.co.uk/2025/08/17/how-to-create-a-private-python-package-on-github/" rel="bookmark" title="How to create a private python package on Github"> 499 500 <img width="500" height="500" src="https://andypi.co.uk/wp-content/uploads/2025/08/packages.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/08/packages.jpg 500w, https://andypi.co.uk/wp-content/uploads/2025/08/packages-300x300.jpg 300w, https://andypi.co.uk/wp-content/uploads/2025/08/packages-150x150.jpg 150w" sizes="auto, (max-width: 500px) 100vw, 500px" /> 501 </a> 502 503 </div><!-- .featured-media --> 504 505 506<div class="post-excerpt"> 507 508 <p>Sometimes the need arises to share code across different python projects. This can be achieved by extracting that code into a separate project and making it into a python package. This can be uploaded to the PyPi python package repository,… <a class="more-link" href="https://andypi.co.uk/2025/08/17/how-to-create-a-private-python-package-on-github/">Continue Reading →</a></p> 509 510</div><!-- .post-excerpt --> 511 512 513 <div class="post-meta"> 514 515 <a class="post-date" href="https://andypi.co.uk/2025/08/17/how-to-create-a-private-python-package-on-github/" title="How to create a private python package on Github">2025/08/17</a> 516 517 <a href="https://andypi.co.uk/2025/08/17/how-to-create-a-private-python-package-on-github/#respond" class="post-comments" >0</a> 518 <div class="clear"></div> 519 520 </div><!-- .post-meta --> 521 522 523<div class="clear"></div> 524 </div><!-- .post --> 525 526 </div> 527 528 529 <div class="post-container"> 530 531 <div id="post-18947" class="post-18947 post type-post status-publish format-image has-post-thumbnail hentry category-cryptocurreny post_format-post-format-image"> 532 533 534 535 <div class="featured-media"> 536 537 538 <a href="https://andypi.co.uk/2025/07/07/full-guide-to-creating-your-own-cryptocurrency-token-on-the-solana-blockchain/" rel="bookmark" title="Full guide to creating your own cryptocurrency token on the Solana blockchain"> 539 540 <img width="600" height="199" src="https://andypi.co.uk/wp-content/uploads/2025/07/11-duplicate-600x199.png" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/07/11-duplicate-600x199.png 600w, https://andypi.co.uk/wp-content/uploads/2025/07/11-duplicate-300x100.png 300w, https://andypi.co.uk/wp-content/uploads/2025/07/11-duplicate.png 666w" sizes="auto, (max-width: 600px) 100vw, 600px" /> 541 </a> 542 543 </div><!-- .featured-media --> 544 545 546<div class="post-excerpt"> 547 548 <p>The AndyPi (Meme) Coin! Full guide to creating your own cryptocurrency token on the Solana blockchain This guide is based on the excellent video by Network Chuck (https://youtu.be/L4ASwqLZVV0?t=397). I’ve documented actually minting a real token with real money, and clarified… <a class="more-link" href="https://andypi.co.uk/2025/07/07/full-guide-to-creating-your-own-cryptocurrency-token-on-the-solana-blockchain/">Continue Reading →</a></p> 549 550</div><!-- .post-excerpt --> 551 552 553 <div class="post-meta"> 554 555 <a class="post-date" href="https://andypi.co.uk/2025/07/07/full-guide-to-creating-your-own-cryptocurrency-token-on-the-solana-blockchain/" title="Full guide to creating your own cryptocurrency token on the Solana blockchain">2025/07/07</a> 556 557 558 <div class="clear"></div> 559 560 </div><!-- .post-meta --> 561 562 563<div class="clear"></div> 564 </div><!-- .post --> 565 566 </div> 567 568 569 <div class="post-container"> 570 571 <div id="post-18930" class="post-18930 post type-post status-publish format-standard has-post-thumbnail hentry category-devops category-python category-web-apps"> 572 573 <div class="post-header"> 574 575 576 <h2 class="post-title"><a href="https://andypi.co.uk/2025/06/27/why-i-switched-to-using-caddy-uvicorn-for-python-web-projects-instead-of-nginx-uwsgi/" rel="bookmark" title="Why I switched to using Caddy + Uvicorn for python web projects instead of Nginx + uWSGI">Why I switched to using Caddy + Uvicorn for python web projects instead of Nginx + uWSGI</a></h2> 577 578 579 580</div><!-- .post-header --> 581 582 583 <div class="featured-media"> 584 585 <a href="https://andypi.co.uk/2025/06/27/why-i-switched-to-using-caddy-uvicorn-for-python-web-projects-instead-of-nginx-uwsgi/" rel="bookmark" title="Why I switched to using Caddy + Uvicorn for python web projects instead of Nginx + uWSGI"> 586 587 <img width="600" height="193" src="https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-600x193.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-600x193.jpg 600w, https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-300x97.jpg 300w, https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-1024x329.jpg 1024w, https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-768x247.jpg 768w, https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354-945x304.jpg 945w, https://andypi.co.uk/wp-content/uploads/2025/06/caddy-e1751053507354.jpg 1200w" sizes="auto, (max-width: 600px) 100v
587w, 600px" /> 588 </a> 589 590 </div><!-- .featured-media --> 591 592 593<div class="post-excerpt"> 594 595 <p>For each python app I build, the server deployment always seems to be the most difficult part! As well as Python we need some kind of python server (uWSGI) and a web server AND getting the SSL certs…. I guess… <a class="more-link" href="https://andypi.co.uk/2025/06/27/why-i-switched-to-using-caddy-uvicorn-for-python-web-projects-instead-of-nginx-uwsgi/">Continue Reading →</a></p> 596 597</div><!-- .post-excerpt --> 598 599 600 <div class="post-meta"> 601 602 <a class="post-date" href="https://andypi.co.uk/2025/06/27/why-i-switched-to-using-caddy-uvicorn-for-python-web-projects-instead-of-nginx-uwsgi/" title="Why I switched to using Caddy + Uvicorn for python web projects instead of Nginx + uWSGI">2025/06/27</a> 603 604 <a href="https://andypi.co.uk/2025/06/27/why-i-switched-to-using-caddy-uvicorn-for-python-web-projects-instead-of-nginx-uwsgi/#respond" class="post-comments" >0</a> 605 <div class="clear"></div> 606 607 </div><!-- .post-meta --> 608 609 610<div class="clear"></div> 611 </div><!-- .post --> 612 613 </div> 614 615 616 <div class="post-container"> 617 618 <div id="post-18903" class="post-18903 post type-post status-publish format-standard has-post-thumbnail hentry category-random"> 619 620 <div class="post-header"> 621 622 623 <h2 class="post-title"><a href="https://andypi.co.uk/2025/03/21/automating-a-daily-email-using-google-sheets-and-apps-script/" rel="bookmark" title="Automating a daily email using Google Sheets and Apps Script">Automating a daily email using Google Sheets and Apps Script</a></h2> 624 625 626 627</div><!-- .post-header --> 628 629 630 <div class="featured-media"> 631 632 <a href="https://andypi.co.uk/2025/03/21/automating-a-daily-email-using-google-sheets-and-apps-script/" rel="bookmark" title="Automating a daily email using Google Sheets and Apps Script"> 633 634 <img width="600" height="338" src="https://andypi.co.uk/wp-content/uploads/2025/03/google_apps_script-600x338.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://andypi.co.uk/wp-content/uploads/2025/03/google_apps_script-600x338.jpg 600w, https://andypi.co.uk/wp-content/uploads/2025/03/google_apps_script-300x169.jpg 300w, https://andypi.co.uk/wp-content/uploads/2025/03/google_apps_script.jpg 760w" sizes="auto, (max-width: 600px) 100vw, 600px" /> 635 </a> 636 637 </div><!-- .featured-media --> 638 639 640<div class="post-excerpt"> 641 642 <p>1. Automate the boring stuff… A client needed to send short email every day with pre-prepared content to a list of people in google contacts who have a specific label. At the moment, they are doing this by creating and… <a class="more-link" href="https://andypi.co.uk/2025/03/21/automating-a-daily-email-using-google-sheets-and-apps-script/">Continue Reading →</a></p> 643 644</div><!-- .post-excerpt --> 645 646 647 <div class="post-meta"> 648 649 <a class="post-date" href="https://andypi.co.uk/2025/03/21/automating-a-daily-email-using-google-sheets-and-apps-script/" title="Automating a daily email using Google Sheets and Apps Script">2025/03/21</a> 650 651 <a href="https://andypi.co.uk/2025/03/21/automating-a-daily-email-using-google-sheets-and-apps-script/#respond" class="post-comments" >0</a> 652 <div class="clear"></div> 653 654 </div><!-- .post-meta --> 655 656 657<div class="clear"></div> 658 </div><!-- .post --> 659 660 </div> 661 662 663 664 </div><!-- .posts --> 665 666 </div><!-- .content --> 667 668 669 <div class="archive-nav section-inner"> 670 671 <a href="https://andypi.co.uk/page/2/" class="post-nav-older fleft">« Older posts</a> 672 673 <div class="clear"></div> 674 675 </div><!-- .post-nav archive-nav --> 676 677 678 <div class="clear"></div> 679 680</div><!-- .wrapper --> 681 682<div class="footer section medium-padding bg-graphite"> 683 684 685 <div class="section-inner row"> 686 687 688 <div class="column column-1 one-third"> 689 690 <div class="widgets"> 691 692 <div class="widget widget_categories"><div class="widget-content"><h3 class="widget-title">Categories</h3> 693 <ul> 694 <li class="cat-item cat-item-28"><a href="https://andypi.co.uk/category/3d-printing/">3D Printing</a> 695</li> 696 <li class="cat-item cat-item-44"><a href="https://andypi.co.uk/category/ai/">AI</a> 697</li> 698 <li class="cat-item cat-item-41"><a href="https://andypi.co.uk/category/analytics/">Analytics</a> 699</li> 700 <li class="cat-item cat-item-2"><a href="https://andypi.co.uk/category/arduino/">Arduino</a> 701</li> 702 <li class="cat-item cat-item-3"><a href="https://andypi.co.uk/category/cloud/">Cloud</a> 703</li> 704 <li class="cat-item cat-item-29"><a href="https://andypi.co.uk/category/cryptocurreny/">Cryptocurrency</a> 705</li> 706 <li class="cat-item cat-item-45"><a href="https://andypi.co.uk/category/devops/">DevOps</a> 707</li> 708 <li class="cat-item cat-item-4"><a href="https://andypi.co.uk/category/displays/">Displays & Lights</a> 709</li> 710 <li class="cat-item cat-item-47"><a href="https://andypi.co.uk/category/django-deployment/">Django Deployment</a> 711</li> 712 <li class="cat-item cat-item-49"><a href="https://andypi.co.uk/category/golang/">Golang</a> 713</li> 714 <li class="cat-item cat-item-5"><a href="https://andypi.co.uk/category/javascript/">JavaScript</a> 715</li> 716 <li class="cat-item cat-item-48"><a href="https://andypi.co.uk/category/networking/">Networking</a> 717</li> 718 <li class="cat-item cat-item-6"><a href="https://andypi.co.uk/category/php/">PHP</a> 719</li> 720 <li class="cat-item cat-item-32"><a href="https://andypi.co.uk/category/portfolio/">Portfolio</a> 721</li> 722 <li class="cat-item cat-item-8"><a href="https://andypi.co.uk/category/python/">Python</a> 723</li> 724 <li class="cat-item cat-item-31"><a href="https://andypi.co.uk/category/python-for-mechanical-engineers/">Python for Mechanical Engineers</a> 725</li> 726 <li class="cat-item cat-item-30"><a href="https://andypi.co.uk/category/python-beginner-to-pro-in-5steps/">Python: beginner to pro in 5 steps</a> 727</li> 728 <li class="cat-item cat-item-27"><a href="https://andypi.co.uk/category/random/">Random</a> 729</li> 730 <li class="cat-item cat-item-9"><a href="https://andypi.co.uk/category/raspberrypi/">Raspberry Pi</a> 731</li> 732 <li class="cat-item cat-item-52"><a href="https://andypi.co.uk/category/ruby/">Ruby</a> 733</li> 734 <li class="cat-item cat-item-42"><a href="https://andypi.co.uk/category/sysadmin/">SysAdmin</a> 735</li> 736 <li class="cat-item cat-item-1"><a href="https://andypi.co.uk/category/uncategorised/">Uncategorised</a> 737</li> 738 <li class="cat-item cat-item-43"><a href="https://andypi.co.uk/category/web/">Web</a> 739</li> 740 <li class="cat-item cat-item-10"><a href="https://andypi.co.uk/category/web-apps/">Web Apps</a> 741</li> 742 <li class="cat-item cat-item-46"><a href="https://andypi.co.uk/category/wordpress/">WordPress</a> 743</li> 744 </ul> 745 746 </div><div class="clear"></div></div> 747 </div> 748 749 </div><!-- .column-1 --> 750 751 752 753 <div class="column column-2 one-third"> 754 755 <div class="widgets"> 756 757 <div class="widget widget_text"><div class="widget-content"><h3 class="widget-title">Follow AndyPi</h3> <div class="textwidget"><iframe src="https://ghbtns.com/github-btn.html?user=andy-pi&type=follow&count=true&size=large" frameborder="0" scrolling="0" width="220px" height="30px"></iframe> 758<br><br> 759 760<a href="https://twitter.com/Andypitech"><img src="https://andypi.co.uk/wp-content/uploads/2017/04/followandypitechbuttonblack.png" height="20" width="120"></a></div> 761 </div><div class="clear"></div></div> 762 </div><!-- .widgets --> 763 764 </div><!-- .column-2 --> 765 766 767 768 <div class="column column-3 one-third"> 769 770 <div class="widgets"> 771 772 <div class="widget widget_text"><div class="widget-content"><h3 class="widget-title">Privacy Policy</h3> <div class="textwidget"><p>
772This site uses cookies and by using the site you are consenting to this. Find out why we use cookies and how to opt out by reading our <a href="https://andypi.co.uk/privacy-policy/">Privacy Policy</a>.</p> 773</div> 774 </div><div class="clear"></div></div> 775 </div><!-- .widgets --> 776 777 </div> 778 779 <!-- .footer-c --> 780 781 <div class="clear"></div> 782 783 </div><!-- .section-inner --> 784 785 786</div><!-- .footer --> 787 788<div class="credits section bg-dark small-padding"> 789 790 <div class="credits-inner section-inner"> 791 792 <p class="credits-left fleft"> 793 794 © 2026 <a href="https://andypi.co.uk" title="AndyPi">AndyPi</a><span> — Powered by <a href="http://www.wordpress.org">WordPress</a></span> 795 796 </p> 797 798 <p class="credits-right fright"> 799 800 <span>Theme by <a href="https://www.andersnoren.se">Anders Noren</a> — </span><a class="tothetop" title="To the top" href="#">Up ↑</a> 801 802 </p> 803 804 <div class="clear"></div> 805 806 </div><!-- .credits-inner --> 807 808</div><!-- .credits --> 809
810<script type="speculationrules"> 811{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/baskerville/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} 812</script>
vendor: 1 bytes, line 812
812
813<script id="imagesloaded-js" src="https://andypi.co.uk/wp-includes/js/imagesloaded.min.js?ver=5.0.0"></script>
vendor: 1 bytes, line 813
813
814<script id="masonry-js" src="https://andypi.co.uk/wp-includes/js/masonry.min.js?ver=4.2.2"></script>
vendor: 1 bytes, line 814
814
815<script id="baskerville_global-js" src="https://andypi.co.uk/wp-content/themes/baskerville/js/global.js?ver=7.0.6"></script>
vendor: 1 bytes, line 815
815
816<script id="wp-emoji-settings" type="application/json"> 817{"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://andypi.co.uk/wp-includes/js/wp-emoji-release.min.js?ver=7.0.6"}} 818</script>
vendor: 1 bytes, line 818
818
819<script type="module"> 820/*! This file is auto-generated */ 821var 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\u1fac8")}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)))}); 822//# sourceURL=https://andypi.co.uk/wp-includes/js/wp-emoji-loader.min.js 823</script>
823 824
825<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a403c3875acfe080',t:'MTc5MDI3MzYxMw=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
825<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"1c051d73aabb4e0c8fcbd130a989cbfc","r":1,"spa":2}' crossorigin="anonymous"></script>
825 826</body> 827</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.