CINXE.COM
Programming | Linux Journal
<!DOCTYPE html> <html lang="en" dir="ltr" prefix="content: http://purl.org/rss/1.0/modules/content/ dc: http://purl.org/dc/terms/ foaf: http://xmlns.com/foaf/0.1/ og: http://ogp.me/ns# rdfs: http://www.w3.org/2000/01/rdf-schema# schema: http://schema.org/ sioc: http://rdfs.org/sioc/ns# sioct: http://rdfs.org/sioc/types# skos: http://www.w3.org/2004/02/skos/core# xsd: http://www.w3.org/2001/XMLSchema# " class="no-js wf-loading"> <head> <meta charset="utf-8" /> <meta name="Generator" content="Drupal 9 (https://www.drupal.org)" /> <meta name="MobileOptimized" content="width" /> <meta name="HandheldFriendly" content="true" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="icon" href="/themes/linuxjournal/favicon.ico" type="image/vnd.microsoft.icon" /> <link rel="alternate" type="application/rss+xml" title="Programming" href="https://www.linuxjournal.com/taxonomy/term/302/feed" /> <title>Programming | Linux Journal</title> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/align.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/fieldgroup.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/container-inline.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/clearfix.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/details.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/hidden.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/item-list.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/js.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/nowrap.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/position-container.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/progress.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/reset-appearance.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/resize.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/sticky-header.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-counter.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-report-counters.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/system-status-report-general-info.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/tablesort.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/system/css/components/tree-child.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/modules/contrib/poll/css/poll.base.css?smwnh4" /> <link rel="stylesheet" media="all" href="/modules/contrib/poll/css/poll.theme.css?smwnh4" /> <link rel="stylesheet" media="all" href="/core/modules/views/css/views.module.css?smwnh4" /> <link rel="stylesheet" media="all" href="/modules/contrib/webform/modules/webform_bootstrap/css/webform_bootstrap.css?smwnh4" /> <link rel="stylesheet" media="all" href="/libraries/shariff/shariff.complete.css?smwnh4" /> <link rel="stylesheet" media="all" href="/themes/linuxjournal/css/style.css?smwnh4" /> <link rel="stylesheet" media="all" href="/themes/linuxjournal/css/fonts.css?smwnh4" /> <!-- <script defer src="https://use.fontawesome.com/releases/v5.0.9/js/all.js" integrity="sha384-8iPTk2s/jMVj81dnzb/iFR2sdA7u06vHJyyLlAd4snFpCl/SnyUjRrbdJsw1pGIl" crossorigin="anonymous"></script>--> <script> // Non-blocking webfonts. (function iife() { 'use strict'; // JS is able to start executing. document.documentElement.classList.remove('no-js'); // Optimization for Repeat Views // Stop early for repeat views that have already cached fonts. if (sessionStorage.fontsLoadedLateef && sessionStorage.fontsLoadedOpensans /* && sessionStorage.fontsLoadedNEWFONT */) { document.documentElement.classList.remove('wf-loading'); document.documentElement.classList.add('wf-opensans'); document.documentElement.classList.add('wf-lateef'); // document.documentElement.classList.add('wf-NEWFONT'); return; } // Inlined Font Face Observer script + Promise polyfill. /*! Font Face Observer v2.0.13 - © Bram Stein. License: BSD-3-Clause */ (function(){'use strict';var f,g=[];function l(a){g.push(a);1==g.length&&f()}function m(){for(;g.length;)g[0](),g.shift()}f=function(){setTimeout(m)};function n(a){this.a=p;this.b=void 0;this.f=[];var b=this;try{a(function(a){q(b,a)},function(a){r(b,a)})}catch(c){r(b,c)}}var p=2;function t(a){return new n(function(b,c){c(a)})}function u(a){return new n(function(b){b(a)})}function q(a,b){if(a.a==p){if(b==a)throw new TypeError;var c=!1;try{var d=b&&b.then;if(null!=b&&"object"==typeof b&&"function"==typeof d){d.call(b,function(b){c||q(a,b);c=!0},function(b){c||r(a,b);c=!0});return}}catch(e){c||r(a,e);return}a.a=0;a.b=b;v(a)}} function r(a,b){if(a.a==p){if(b==a)throw new TypeError;a.a=1;a.b=b;v(a)}}function v(a){l(function(){if(a.a!=p)for(;a.f.length;){var b=a.f.shift(),c=b[0],d=b[1],e=b[2],b=b[3];try{0==a.a?"function"==typeof c?e(c.call(void 0,a.b)):e(a.b):1==a.a&&("function"==typeof d?e(d.call(void 0,a.b)):b(a.b))}catch(h){b(h)}}})}n.prototype.g=function(a){return this.c(void 0,a)};n.prototype.c=function(a,b){var c=this;return new n(function(d,e){c.f.push([a,b,d,e]);v(c)})}; function w(a){return new n(function(b,c){function d(c){return function(d){h[c]=d;e+=1;e==a.length&&b(h)}}var e=0,h=[];0==a.length&&b(h);for(var k=0;k<a.length;k+=1)u(a[k]).c(d(k),c)})}function x(a){return new n(function(b,c){for(var d=0;d<a.length;d+=1)u(a[d]).c(b,c)})};window.Promise||(window.Promise=n,window.Promise.resolve=u,window.Promise.reject=t,window.Promise.race=x,window.Promise.all=w,window.Promise.prototype.then=n.prototype.c,window.Promise.prototype["catch"]=n.prototype.g);}()); (function(){function l(a,b){document.addEventListener?a.addEventListener("scroll",b,!1):a.attachEvent("scroll",b)}function m(a){document.body?a():document.addEventListener?document.addEventListener("DOMContentLoaded",function c(){document.removeEventListener("DOMContentLoaded",c);a()}):document.attachEvent("onreadystatechange",function k(){if("interactive"==document.readyState||"complete"==document.readyState)document.detachEvent("onreadystatechange",k),a()})};function r(a){this.a=document.createElement("div");this.a.setAttribute("aria-hidden","true");this.a.appendChild(document.createTextNode(a));this.b=document.createElement("span");this.c=document.createElement("span");this.h=document.createElement("span");this.f=document.createElement("span");this.g=-1;this.b.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;";this.c.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;"; this.f.style.cssText="max-width:none;display:inline-block;position:absolute;height:100%;width:100%;overflow:scroll;font-size:16px;";this.h.style.cssText="display:inline-block;width:200%;height:200%;font-size:16px;max-width:none;";this.b.appendChild(this.h);this.c.appendChild(this.f);this.a.appendChild(this.b);this.a.appendChild(this.c)} function t(a,b){a.a.style.cssText="max-width:none;min-width:20px;min-height:20px;display:inline-block;overflow:hidden;position:absolute;width:auto;margin:0;padding:0;top:-999px;white-space:nowrap;font-synthesis:none;font:"+b+";"}function y(a){var b=a.a.offsetWidth,c=b+100;a.f.style.width=c+"px";a.c.scrollLeft=c;a.b.scrollLeft=a.b.scrollWidth+100;return a.g!==b?(a.g=b,!0):!1}function z(a,b){function c(){var a=k;y(a)&&a.a.parentNode&&b(a.g)}var k=a;l(a.b,c);l(a.c,c);y(a)};function A(a,b){var c=b||{};this.family=a;this.style=c.style||"normal";this.weight=c.weight||"normal";this.stretch=c.stretch||"normal"}var B=null,C=null,E=null,F=null;function G(){if(null===C)if(J()&&/Apple/.test(window.navigator.vendor)){var a=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))(?:\.([0-9]+))/.exec(window.navigator.userAgent);C=!!a&&603>parseInt(a[1],10)}else C=!1;return C}function J(){null===F&&(F=!!document.fonts);return F} function K(){if(null===E){var a=document.createElement("div");try{a.style.font="condensed 100px sans-serif"}catch(b){}E=""!==a.style.font}return E}function L(a,b){return[a.style,a.weight,K()?a.stretch:"","100px",b].join(" ")} A.prototype.load=function(a,b){var c=this,k=a||"BESbswy",q=0,D=b||3E3,H=(new Date).getTime();return new Promise(function(a,b){if(J()&&!G()){var M=new Promise(function(a,b){function e(){(new Date).getTime()-H>=D?b():document.fonts.load(L(c,'"'+c.family+'"'),k).then(function(c){1<=c.length?a():setTimeout(e,25)},function(){b()})}e()}),N=new Promise(function(a,c){q=setTimeout(c,D)});Promise.race([N,M]).then(function(){clearTimeout(q);a(c)},function(){b(c)})}else m(function(){function u(){var b;if(b=-1!= f&&-1!=g||-1!=f&&-1!=h||-1!=g&&-1!=h)(b=f!=g&&f!=h&&g!=h)||(null===B&&(b=/AppleWebKit\/([0-9]+)(?:\.([0-9]+))/.exec(window.navigator.userAgent),B=!!b&&(536>parseInt(b[1],10)||536===parseInt(b[1],10)&&11>=parseInt(b[2],10))),b=B&&(f==v&&g==v&&h==v||f==w&&g==w&&h==w||f==x&&g==x&&h==x)),b=!b;b&&(d.parentNode&&d.parentNode.removeChild(d),clearTimeout(q),a(c))}function I(){if((new Date).getTime()-H>=D)d.parentNode&&d.parentNode.removeChild(d),b(c);else{var a=document.hidden;if(!0===a||void 0===a)f=e.a.offsetWidth, g=n.a.offsetWidth,h=p.a.offsetWidth,u();q=setTimeout(I,50)}}var e=new r(k),n=new r(k),p=new r(k),f=-1,g=-1,h=-1,v=-1,w=-1,x=-1,d=document.createElement("div");d.dir="ltr";t(e,L(c,"sans-serif"));t(n,L(c,"serif"));t(p,L(c,"monospace"));d.appendChild(e.a);d.appendChild(n.a);d.appendChild(p.a);document.body.appendChild(d);v=e.a.offsetWidth;w=n.a.offsetWidth;x=p.a.offsetWidth;I();z(e,function(a){f=a;u()});t(e,L(c,'"'+c.family+'",sans-serif'));z(n,function(a){g=a;u()});t(n,L(c,'"'+c.family+'",serif')); z(p,function(a){h=a;u()});t(p,L(c,'"'+c.family+'",monospace'))})})};"object"===typeof module?module.exports=A:(window.FontFaceObserver=A,window.FontFaceObserver.prototype.load=A.prototype.load);}()); // Load and observe Lateef var Lateef = new FontFaceObserver('Lateef', {weight: 400}); Promise.all([Lateef.load()]).then(function() { document.documentElement.classList.remove('wf-loading'); document.documentElement.classList.add('wf-lateef'); // Optimization for Repeat Views // Set a flag in localstorage so repeat views can skip processing FFO. sessionStorage.fontsLoadedLateef = true; }); // Load and observe Open Sans var os300 = new FontFaceObserver('Open Sans', {weight: 300}); var os400 = new FontFaceObserver('Open Sans', {weight: 400}); Promise.all([os300.load(), os400.load()]).then(function() { document.documentElement.classList.remove('wf-loading'); document.documentElement.classList.add('wf-opensans'); // Optimization for Repeat Views // Set a flag in localstorage so repeat views can skip processing FFO. sessionStorage.fontsLoadedOpensans = true; }); // Load and observe NEWFONT /* var NEWFONT = new FontFaceObserver('NEWFONT', {weight: 400}); Promise.all([NEWFONT.load()]).then(function() { document.documentElement.classList.remove('wf-loading'); document.documentElement.classList.add('wf-NEWFONT'); // Optimization for Repeat Views // Set a flag in localstorage so repeat views can skip processing FFO. sessionStorage.fontsLoadedNEWFONT = true; }); */ })(); </script> <script src="https://www.google.com/recaptcha/api.js" async defer></script> <script src=https://slashdot.org/country.js></script> <script src="/themes/linuxjournal/js/ada.js"></script> <script src="/themes/linuxjournal/js/accessibility.js"></script> <script>window.addEventListener('load', function() { new Accessibility(); });</script> <script src="//a.fsdn.com/con/js/sftheme/cmp2.js"></script> <link rel="stylesheet" href="//a.fsdn.com/con/css/sftheme/sandiego/cmp.css" type="text/css"> <link rel="stylesheet" href="/themes/linuxjournal/css/ccpa.css" type="text/css"> <script>window.bizx.cmp.init({ geo: window });</script> <script> function bm_trace() { (function (w,d,t) { _ml = w._ml || {}; _ml.eid = '771'; var s, cd, tag; s = d.getElementsByTagName(t)[0]; cd = new Date(); tag = d.createElement(t); tag.async = 1; tag.src = 'https://ml314.com/tag.aspx?' + cd.getDate() + cd.getMonth(); s.parentNode.insertBefore(tag, s); })(window,document,'script'); } bizx.cmp.ifConsent('', ['all', 'bombora'],bm_trace); </script> </head> <body class="path-taxonomy has-glyphicons"> <a href="#main-content" class="visually-hidden focusable skip-link"> Skip to main content </a> <div class="dialog-off-canvas-main-canvas" data-off-canvas-main-canvas> <div id="wrap"> <div class="leader-wrapper" id="leader-wrapper"> </div> <div class="brand-wrapper" id="brand-wrapper"> <div class="brand container"> <div class="region region-brand"> <a class="logo navbar-btn" href="/" title="Home" rel="home"> <h1><img src="/themes/linuxjournal/images/ljlogo.png" alt="Linux Journal" /></h1> </a> <section id="block-topbannernearlogo" class="block block-block-content block-block-contenta8e75a3d-967c-416d-8944-4015d1f90a84 clearfix"> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><a href="https://www.windriver.com/products/elxr-pro?utm_source=ba&utm_medium=pa&utm_campaign=ba-dg-amer-awa-vsmf-eLxrProLau_lin_dis_09172024"><img alt="Windriver eLxrPro" data-entity-type="file" data-entity-uuid="8ba04368-7803-4329-a196-dc1ea780ec2a" src="/sites/default/files/inline-images/WindRiver-eLxrPro_0.png" width="728" height="90" loading="lazy" /></a></div> </section> </div> </div> <div class="header-wrapper"> <header class="navbar navbar-default container" id="navbar" role="banner"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <div id="navbar-collapse" class="navbar-collapse collapse"> <div class="region region-navigation-collapsible"> <section id="block-linuxjournal-main-menu" class="block block-system block-system-menu-blockmain clearfix navbar__menu col-xs-12 col-sm-8"> <ul class="menu menu--main nav navbar-nav"> <li class="expanded dropdown first"> <a href="/" class="dropdown-toggle" data-toggle="dropdown" data-drupal-link-system-path="<front>">Topics+ <span class="caret"></span></a> <ul class="dropdown-menu"> <li class="first"> <a href="/tag/cloud">Cloud</a> </li> <li> <a href="/tag/containers" data-drupal-link-system-path="taxonomy/term/978">Containers</a> </li> <li> <a href="/tag/desktop">Desktop</a> </li> <li> <a href="/tag/kernel" data-drupal-link-system-path="taxonomy/term/662">Kernel</a> </li> <li> <a href="/tag/mobile">Mobile</a> </li> <li> <a href="/tag/networking">Networking</a> </li> <li> <a href="/tag/privacy">Privacy</a> </li> <li> <a href="/tag/programming">Programming</a> </li> <li> <a href="/tag/security" data-drupal-link-system-path="taxonomy/term/31">Security</a> </li> <li> <a href="/tag/servers">Servers</a> </li> <li class="last"> <a href="/tag/sysadmin" data-drupal-link-system-path="taxonomy/term/21">SysAdmin</a> </li> </ul> </li> <li> <a href="/news" data-drupal-link-system-path="news">News</a> </li> <li class="last"> <a href="/books" data-drupal-link-system-path="books">eBooks</a> </li> </ul> </section> <section class="search-block-form block block-search block-search-form-block clearfix navbar__search col-xs-12 col-sm-4 col-md-4 col-md-offset-0" data-drupal-selector="search-block-form" id="block-linuxjournal-search" role="search"> <h2 class="block-title sr-only">Search</h2> <form action="/search/node" method="get" id="search-block-form" accept-charset="UTF-8"> <div class="form-item js-form-item form-type-search js-form-type-search form-item-keys js-form-item-keys form-no-label form-group"> <label for="edit-keys" class="control-label sr-only">Search</label> <div class="input-group"><input title="Enter the terms you wish to search for." data-drupal-selector="edit-keys" class="form-search form-control" placeholder="Search" type="search" id="edit-keys" name="keys" value="" size="15" maxlength="128" /><span class="input-group-btn"><button type="submit" value="Search" class="button js-form-submit form-submit btn-primary btn icon-only" name=""><span class="sr-only">Search</span><span class="icon glyphicon glyphicon-search" aria-hidden="true"></span></button></span></div> <div id="edit-keys--description" class="description help-block"> Enter the terms you wish to search for. </div> </div> <div class="form-actions form-group js-form-wrapper form-wrapper" data-drupal-selector="edit-actions" id="edit-actions"></div> </form> </section> </div> </div> <div class="navbar-header"> <div class="region region-navigation"> <section id="block-mobilenavigation" class="block block-system block-system-menu-blockmenu-mobile-navbar clearfix col-xs-12 col-md-8 col-md-offset-2 col-lg-8 col-lg-offset-0 navbar__menu navbar__mobilenavigation"> <ul class="menu menu--menu-mobile-navbar nav"> <li class="first"> <a href="/news" data-drupal-link-system-path="news">News</a> </li> <li> <a href="/popular" data-drupal-link-system-path="popular">Popular</a> </li> <li class="last"> <a href="/recent" data-drupal-link-system-path="recent">Recent</a> </li> </ul> </section> </div> </div> </header> </div> </div> <div role="main" class="main-container container js-quickedit-main-content" id="main"> <div class="row"> <section class="col-sm-12"> <div class="highlighted"> <div class="region region-highlighted"> <div data-drupal-messages-fallback class="hidden"></div> </div> </div> <a id="main-content"></a> <div class="region region-content"> <h1 class="page-header">Programming</h1> <div class="views-element-container form-group"><div class="view view-taxonomy-term view-id-taxonomy_term view-display-id-page_1 js-view-dom-id-211ad5ebb631cd3972ba92b7b044e9da1a11523da208edccbf2057cd61877e67"> <div class="view-header"> <div about="/tag/programming" typeof="schema:Thing"> <span property="schema:name" content="Programming" class="hidden"></span> </div> </div> <div class="view-content"> <div class="views-row"><article data-history-node-id="1340725" role="article" about="/content/understanding-pythons-asyncio" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/understanding-pythons-asyncio" rel="bookmark"> <span>Understanding Python's asyncio</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - August 7, 2019 </div> </footer> <div class="content-body"> How to get started using Python's asyncio. Earlier this year, I attended PyCon, the international Python conference. One topic, presented at numerous talks and discussed informally in the hallway, was the state of threading in Python—which is, in a nutshell, neither ideal nor as terrible as some critics would argue. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340661" role="article" about="/content/pythons-mypy-callables-and-generators" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/pythons-mypy-callables-and-generators" rel="bookmark"> <span>Python's Mypy: Callables and Generators</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - July 29, 2019 </div> </footer> <div class="content-body"> Learn how Mypy's type checking works with functions and generators. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340605" role="article" about="/content/finishing-bash-mail-merge-script" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/finishing-bash-mail-merge-script" rel="bookmark"> <span>Finishing Up the Bash Mail Merge Script</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/dave-taylor" lang="" about="/users/dave-taylor" typeof="schema:Person" property="schema:name" datatype="">Dave Taylor</a></span> - July 4, 2019 </div> </footer> <div class="content-body"> Finally, I'm going to finish the mail merge script, just in time for Replicant Day. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340606" role="article" about="/content/pythons-mypy-advanced-usage" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/pythons-mypy-advanced-usage" rel="bookmark"> <span>Python's Mypy--Advanced Usage</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - June 24, 2019 </div> </footer> <div class="content-body"> Mypy can check more than simple Python types. In my last article, I introduced Mypy, a package that enforces type checking in Python programs. Python itself is, and always will remain, a dynamically typed language. However, Python 3 supports "annotations", a feature that allows you to attach an object to variables, function parameters and function return values. These annotations are ignored by Python itself, but they can be used by external tools. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340545" role="article" about="/content/build-your-own-internet-radio-receiver" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/build-your-own-internet-radio-receiver" rel="bookmark"> <span>Build Your Own Internet Radio Receiver</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/nick-tufillaro" lang="" about="/users/nick-tufillaro" typeof="schema:Person" property="schema:name" datatype="">Nick Tufillaro</a></span> - May 27, 2019 </div> </footer> <div class="content-body"> Tune in to communities around the world with the push of a button. When I get home at night, I like to tune into the world with the push of a button. I've lived in lots of different places—from Dunedin, New Zealand, to Santa Fe, New Mexico—and in each town, I've come to love a radio station (usually a community radio station) that embodies the spirit of the place. With the push of a button, I can get a bit back in sync with each of these places and also visit new communities, thanks to internet radio. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340583" role="article" about="/content/introducing-mypy-experimental-optional-static-type-checker-python" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/introducing-mypy-experimental-optional-static-type-checker-python" rel="bookmark"> <span>Introducing Mypy, an Experimental Optional Static Type Checker for Python</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - May 13, 2019 </div> </footer> <div class="content-body"> Tighten up your code and identify errors before they occur with mypy. I've been using dynamic languages—Perl, Ruby and Python—for many years. I love the flexibility and expressiveness that such languages provide. For example, I can define a function that sums numbers: </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340624" role="article" about="/content/what-heck-hash-bang-thingy-my-bash-script" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/what-heck-hash-bang-thingy-my-bash-script" rel="bookmark"> <span>What The @#$%&! (Heck) is this #! (Hash-Bang) Thingy In My Bash Script</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/mitch-frazier" lang="" about="/users/mitch-frazier" typeof="schema:Person" property="schema:name" datatype="">Mitch Frazier</a></span> - May 10, 2019 </div> </footer> <div class="content-body"> You've seen it a million times—the hash-bang (#!) line at the top of a script—whether it be Bash, Python, Perl or some other scripting language. And, I'm sure you know what its purpose is: it specifies the script interpreter that's used to execute the script. But, do you know how it actually works? Your initial thought might be that your shell (bash) reads that line and then executes the specified interpreter, but that's not at all how it works. How it actually works is the main focus of this post, but I also want to introduce how you can create your own version of "hash-bang" if you're so inclined. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340508" role="article" about="/content/linuxdo-it-children" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/linuxdo-it-children" rel="bookmark"> <span>Linux...Do It for the Children</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/marcel-gagn%C3%A9" lang="" about="/users/marcel-gagn%C3%A9" typeof="schema:Person" property="schema:name" datatype="">Marcel Gagné</a></span> - April 11, 2019 </div> </footer> <div class="content-body"> A rundown of some fun and educational Linux software for kids. I'm probably going to regret that title. I've been making fun of those words, "do it for the children" for years. It's one of those "reasons" people turn to when all else has failed in terms of getting you to sign on to whatever lifestyle, agenda, law, changes to food—you name it. Hearing those words draws the Spock eyebrow lift out of me faster than you can say, "fascinating". Okay, pretend that I didn't start this article with that comment. Let's try this instead. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340501" role="article" about="/content/kids-take-over-0" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/kids-take-over-0" rel="bookmark"> <span>The Kids Take Over</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/doc-searls" lang="" about="/users/doc-searls" typeof="schema:Person" property="schema:name" datatype="">Doc Searls</a></span> - April 8, 2019 </div> </footer> <div class="content-body"> As with Linux, these kids are all about making things—and then making them better. They're also up against incumbent top-down systems they will reform or defeat. Those are the only choices. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340460" role="article" about="/content/fun-mail-merge-and-cool-bash-arrays" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/fun-mail-merge-and-cool-bash-arrays" rel="bookmark"> <span>Fun with Mail Merge and Cool Bash Arrays</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/dave-taylor" lang="" about="/users/dave-taylor" typeof="schema:Person" property="schema:name" datatype="">Dave Taylor</a></span> - March 25, 2019 </div> </footer> <div class="content-body"> Creating a sed-based file substitution tool. A few weeks ago, I was digging through my spam folder and found an email message that started out like this: </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340474" role="article" about="/content/text-processing-rust" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/text-processing-rust" rel="bookmark"> <span>Text Processing in Rust</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/mihalis-tsoukalos" lang="" about="/users/mihalis-tsoukalos" typeof="schema:Person" property="schema:name" datatype="">Mihalis Tsoukalos</a></span> - March 18, 2019 </div> </footer> <div class="content-body"> Create handy command-line utilities in Rust. This article is about text processing in Rust, but it also contains a quick introduction to pattern matching, which can be very handy when working with text. Strings are a huge subject in Rust, which can be easily realized by the fact that Rust has two data types for representing strings as well as support for macros for formatting strings. However, all of this also proves how powerful Rust is in string and text processing. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340448" role="article" about="/content/considering-fresh-c-extensions" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/considering-fresh-c-extensions" rel="bookmark"> <span>Considering Fresh C Extensions</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/zack-brown" lang="" about="/users/zack-brown" typeof="schema:Person" property="schema:name" datatype="">Zack Brown</a></span> - March 12, 2019 </div> </footer> <div class="content-body"> Matthew Wilcox recently realized there might be a value in depending on C extensions provided by the Plan 9 variant of the C programming language. All it would require is using the -fplan9-extensions command-line argument when compiling the kernel. As Matthew pointed out, Plan 9 extensions have been supported in GCC as of version 4.6, which is the minimum version supported by the kernel. So theoretically, there would be no conflict. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340367" role="article" about="/content/programming-text-windows-ncurses" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/programming-text-windows-ncurses" rel="bookmark"> <span>Programming Text Windows with ncurses</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/jim-hall" lang="" about="/users/jim-hall" typeof="schema:Person" property="schema:name" datatype="">Jim Hall</a></span> - March 5, 2019 </div> </footer> <div class="content-body"> How to use ncurses to manipulate your terminal screen. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340357" role="article" about="/content/converting-decimals-roman-numerals-bash" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/converting-decimals-roman-numerals-bash" rel="bookmark"> <span>Converting Decimals to Roman Numerals with Bash</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/dave-taylor" lang="" about="/users/dave-taylor" typeof="schema:Person" property="schema:name" datatype="">Dave Taylor</a></span> - February 18, 2019 </div> </footer> <div class="content-body"> Decimals to Roman numerals—here we hit all the limitations of Bash shell scripting. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340128" role="article" about="/content/introductory-go-programming-tutorial" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/introductory-go-programming-tutorial" rel="bookmark"> <span>Introductory Go Programming Tutorial</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/jay-ts" lang="" about="/users/jay-ts" typeof="schema:Person" property="schema:name" datatype="">Jay Ts</a></span> - January 24, 2019 </div> </footer> <div class="content-body"> How to get started with this useful new programming language. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340349" role="article" about="/content/python-testing-pytest-fixtures-and-coverage" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/python-testing-pytest-fixtures-and-coverage" rel="bookmark"> <span>Python Testing with pytest: Fixtures and Coverage</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - January 14, 2019 </div> </footer> <div class="content-body"> Improve your Python testing even more. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340258" role="article" about="/content/more-roman-numerals-and-bash" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/more-roman-numerals-and-bash" rel="bookmark"> <span>More Roman Numerals and Bash</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/dave-taylor" lang="" about="/users/dave-taylor" typeof="schema:Person" property="schema:name" datatype="">Dave Taylor</a></span> - December 27, 2018 </div> </footer> <div class="content-body"> When in Rome: finishing the Roman numeral converter script. In my last article, I started digging in to a classic computer science puzzle: converting Roman numerals to Arabic numerals. First off, it more accurately should be called Hindu-Arabic, and it's worth mentioning that it's believed to have been invented somewhere between the first and fourth century—a counting system based on 0..9 values. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340201" role="article" about="/content/about-ncurses-colors-0" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/about-ncurses-colors-0" rel="bookmark"> <span>About ncurses Colors</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/jim-hall" lang="" about="/users/jim-hall" typeof="schema:Person" property="schema:name" datatype="">Jim Hall</a></span> - December 13, 2018 </div> </footer> <div class="content-body"> Why does ncurses support only eight colors? If you've looked into the color palette available in curses, you may wonder why curses supports only eight colors. The curses.h include file defines these color macros: COLOR_BLACK COLOR_RED COLOR_GREEN COLOR_YELLOW COLOR_BLUE COLOR_MAGENTA COLOR_CYAN COLOR_WHITE But why only eight colors, and why these particular colors? At least with the Linux console, if you're running on a PC, the color range's origins are with the PC hardware. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340256" role="article" about="/content/testing-your-code-pythons-pytest-part-ii" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/testing-your-code-pythons-pytest-part-ii" rel="bookmark"> <span>Testing Your Code with Python's pytest, Part II</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - December 11, 2018 </div> </footer> <div class="content-body"> Testing functions isn't hard, but how do you test user input and output? In my last article, I started looking at "pytest", a framework for testing Python programs that's really changed the way I look at testing. For the first time, I really feel like testing is something I can and should do on a regular basis; pytest makes things so easy and straightforward. </div> </div> </article> </div> <div class="views-row"><article data-history-node-id="1340202" role="article" about="/content/testing-your-code-pythons-pytest" class="story is-promoted teaser clearfix"> <div class="teaser-image"> </div> <div class="teaser-text"> <h2> <a href="/content/testing-your-code-pythons-pytest" rel="bookmark"> <span>Testing Your Code with Python's pytest</span> </a> </h2> <footer> <div class="author"> <span><a title="View user profile." href="/users/reuven-m-lerner" lang="" about="/users/reuven-m-lerner" typeof="schema:Person" property="schema:name" datatype="">Reuven M. Lerner</a></span> - November 27, 2018 </div> </footer> <div class="content-body"> Don't test your code? pytest removes any excuses. Software developers don't just write software; they also use software. So, they're the first to recognize, and understand, that software is complex and inevitably contains bugs. </div> </div> </article> </div> </div> <nav class="pager-nav text-center" role="navigation" aria-labelledby="pagination-heading"> <h4 id="pagination-heading" class="visually-hidden">Pagination</h4> <ul class="pagination js-pager__items"> <li class="pager__item is-active active"> <a href="?page=0" title="Current page"> <span class="visually-hidden"> Current page </span>1</a> </li> <li class="pager__item"> <a href="?page=1" title="Go to page 2"> <span class="visually-hidden"> Page </span>2</a> </li> <li class="pager__item"> <a href="?page=2" title="Go to page 3"> <span class="visually-hidden"> Page </span>3</a> </li> <li class="pager__item"> <a href="?page=3" title="Go to page 4"> <span class="visually-hidden"> Page </span>4</a> </li> <li class="pager__item"> <a href="?page=4" title="Go to page 5"> <span class="visually-hidden"> Page </span>5</a> </li> <li class="pager__item"> <a href="?page=5" title="Go to page 6"> <span class="visually-hidden"> Page </span>6</a> </li> <li class="pager__item"> <a href="?page=6" title="Go to page 7"> <span class="visually-hidden"> Page </span>7</a> </li> <li class="pager__item"> <a href="?page=7" title="Go to page 8"> <span class="visually-hidden"> Page </span>8</a> </li> <li class="pager__item pager__item--next"> <a href="?page=1" title="Go to next page" rel="next"> <span class="visually-hidden">Next page</span> <span aria-hidden="true">››</span> </a> </li> <li class="pager__item pager__item--last"> <a href="?page=7" title="Go to last page" rel="last"> <span class="visually-hidden">Last page</span> <span aria-hidden="true">Last »</span> </a> </li> </ul> </nav> <div class="feed-icons"> <a href="https://www.linuxjournal.com/taxonomy/term/302/feed" class="feed-icon"> Subscribe to Programming </a> </div> </div> </div> </div> </section> </div> </div> <footer class="footer container" role="contentinfo"> <div class="region region-footer"> <section class="views-element-container block block-views block-views-blocknewsletter-promo-block-block-1 clearfix" id="block-views-block-newsletter-promo-block-block-1"> <div class="form-group"><div class="view view-newsletter-promo-block view-id-newsletter_promo_block view-display-id-block_1 js-view-dom-id-7884e9b367bcb57960d494cddc25168390ceff631a2ff0313abd84529b2019d2"> <div class="view-content"> <div class="views-row"> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><div class="newsletter-bottom"> <div class="col-md-9 col-sm-12 signup-form"> <!--<h3>Linux Journal Week in Review</h3> <p>Sign up to get all the good stuff delivered to your inbox every week.</p> <form id="subForm" class="js-cm-form" action="https://www.createsend.com/t/subscribeerror?description=" method="post" data-id="A61C50BEC994754B1D79C5819EC1255CDBC34DDF3E170B13E2BAC2D68C42BF424F853383C84F5BAE38EAB4CFA5C73907CAC074FF8192503AF80F3699F7FE5CE1"> <div class="flexform">--> <!--<label for="fieldEmail">Email</label> <br />--> <!--<input id="fieldEmail" name="cm-gjjtdh-gjjtdh" type="email" class="js-cm-email-input" placeholder="Enter your email. Get the newsletter." required /> <button class="js-cm-submit-button" type="submit">Sign Up</button> </div> <div> <input id="cm-privacy-consent" name="cm-privacy-consent" required type="checkbox" /> <label for="cm-privacy-consent">I give my consent to be emailed</label> <input id="cm-privacy-consent-hidden" name="cm-privacy-consent-hidden" type="hidden" value="true" /> </div> </form> <script type="text/javascript" src="https://js.createsend1.com/javascript/copypastesubscribeformlogic.js"></script> </div>--> <!--<div class="col-md-3 col-sm-12 subs-callout"> <img src="/sites/default/files/styles/large/public/2019-01/LJ294-Jan2019-Cover_0.jpg" width="100px" /> <h3>The Value of Open Source Journalism</h3> <p> Subscribe and support our coverage for technology's biggest thinkers – with up to 52% savings. </p> <strong><a href="https://www.linuxjournal.com/subscribe">Subscribe <i class="fa fa-angle-double-right" aria-hidden="true"></i></a> </strong> </div>--> </div> </div> </div> </div> </div> </div> </section> </div> <div class="footer-blocks col-sm-12"> <div class="col-md-6 col-sm-12 footer-left"> <div class="region region-footer-left"> <section id="block-connectwithusfooter" class="block block-block-content block-block-content5e722bd4-5e08-454b-8507-956089bfa661 clearfix"> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><div class="footer-heading">Connect With Us <span class="social-media sm-a-no-underline"><a href="https://youtube.com/linuxjournalonline" alt="Linux Journal on YouTube" aria-label="YouTube"><i class="fa fa-youtube fa-2x"></i></a><a href="https://www.facebook.com/linuxjournal/" alt="Linux Journal on Facebook" aria-label="Facebook"><i class="fa fa-facebook-f fa-2x"></i><a href="https://twitter.com/linuxjournal" alt="Linux Journal on Twitter" aria-label="Twitter"><i class="fa fa-twitter fa-2x"></i></a></span></div> <p>Linux Journal, representing 25+ years of publication, is the original magazine of the global Open Source community.</p></div> </section> <section id="block-linuxjournal-block-9" class="block block-block-content block-block-content8669793b-e217-4426-a79e-eb3c21ede127 clearfix"> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><div id="copyright">© 2024 Slashdot Media, LLC. All rights reserved.</div> </div> </section> <section id="block-privacyterms" class="block block-block-content block-block-contenta203b8bd-80ef-4982-bf6e-784dd7b44120 clearfix"> <div class="field field--name-body field--type-text-with-summary field--label-hidden field--item"><ul class="menu menu--footer-submenu nav" id="terms-nav"> <li><a href="https://slashdotmedia.com/privacy-statement/" rel="nofollow" target="_blank">PRIVACY POLICY</a></li> <li><a href="https://slashdotmedia.com/terms-of-use/" rel="nofollow" target="_blank">TERMS OF SERVICE</a></li> <li><a href="/sponsors">ADVERTISE</a></li> </ul></div> </section> </div> </div> <div class="col-md-4 col-sm-8 footer-middle"> <div class="region region-footer-middle"> <nav role="navigation" aria-labelledby="block-footermenucolumn2-menu" id="block-footermenucolumn2"> <h2 class="visually-hidden" id="block-footermenucolumn2-menu">Footer Menu Column 2</h2> <ul class="menu menu--footer-menu-column-2 nav"> <li class="first"> <a href="/content/masthead" data-drupal-link-system-path="node/1007727">Masthead</a> </li> <li> <a href="/author" data-drupal-link-system-path="node/1009249">Authors</a> </li> <li class="last"> <a href="/form/contact" data-drupal-link-system-path="webform/contact">Contact Us</a> </li> </ul> </nav> <nav role="navigation" aria-labelledby="block-footermenucolumn3-menu" id="block-footermenucolumn3"> <h2 class="visually-hidden" id="block-footermenucolumn3-menu">Footer Menu Column 3</h2> <ul class="menu menu--footer-menu-column-3 nav"> <li class="first"> <a href="/rss_feeds" data-drupal-link-system-path="node/1000457">RSS Feeds</a> </li> <li class="last"> <a href="/aboutus" data-drupal-link-system-path="node/1000267">About Us</a> </li> </ul> </nav> </div> </div> </div> </footer> </div> </div> <script type="application/json" data-drupal-selector="drupal-settings-json">{"path":{"baseUrl":"\/","scriptPath":null,"pathPrefix":"","currentPath":"taxonomy\/term\/302","currentPathIsAdmin":false,"isFront":false,"currentLanguage":"en"},"pluralDelimiter":"\u0003","suppressDeprecationErrors":true,"bootstrap":{"forms_has_error_value_toggle":1,"popover_enabled":1,"popover_animation":1,"popover_auto_close":1,"popover_container":"body","popover_content":"","popover_delay":"0","popover_html":0,"popover_placement":"right","popover_selector":"","popover_title":"","popover_trigger":"click"},"linuxjournal":{"disqus":{"origin":"https:\/\/www.linuxjournal.com","prettyUrl":"\/tag\/programming","fullUrl":"https:\/\/www.linuxjournal.com\/tag\/programming","embedUrl":"https:\/\/linuxjournal.disqus.com\/embed.js","shortname":"linuxjournal"}},"ajaxTrustedUrl":{"\/search\/node":true},"user":{"uid":0,"permissionsHash":"a7b3a803411eb9cbd5d7d374ffb326721ee8274ab5a665df8f38311e3aad858c"}}</script> <script src="/core/assets/vendor/jquery/jquery.min.js?v=3.6.3"></script> <script src="/core/assets/vendor/underscore/underscore-min.js?v=1.13.6"></script> <script src="/core/misc/polyfills/element.matches.js?v=9.5.9"></script> <script src="/core/misc/polyfills/object.assign.js?v=9.5.9"></script> <script src="/core/assets/vendor/once/once.min.js?v=1.0.1"></script> <script src="/core/assets/vendor/jquery-once/jquery.once.min.js?v=9.5.9"></script> <script src="/core/misc/drupalSettingsLoader.js?v=9.5.9"></script> <script src="/core/misc/drupal.js?v=9.5.9"></script> <script src="/core/misc/drupal.init.js?v=9.5.9"></script> <script src="/themes/contrib/bootstrap/js/drupal.bootstrap.js?smwnh4"></script> <script src="/themes/contrib/bootstrap/js/attributes.js?smwnh4"></script> <script src="/themes/contrib/bootstrap/js/theme.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/affix.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/alert.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/button.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/carousel.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/collapse.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/dropdown.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/modal.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/tooltip.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/popover.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/scrollspy.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/tab.js?smwnh4"></script> <script src="/themes/linuxjournal/bootstrap/assets/javascripts/bootstrap/transition.js?smwnh4"></script> <script src="/themes/linuxjournal/js/lj-consentmanager.js?smwnh4"></script> <script src="/modules/contrib/webform/js/webform.behaviors.js?v=9.5.9"></script> <script src="/core/misc/jquery.once.bc.js?v=9.5.9"></script> <script src="/core/misc/states.js?v=9.5.9"></script> <script src="/themes/contrib/bootstrap/js/misc/states.js?smwnh4"></script> <script src="/modules/contrib/webform/js/webform.states.js?v=9.5.9"></script> <script src="/modules/contrib/webform/modules/webform_bootstrap/js/webform_bootstrap.states.js?v=9.5.9"></script> <script src="/themes/contrib/bootstrap/js/popover.js?smwnh4"></script> <!-- START EMBED --> <noscript><img src="https://api.b2c.com/api/noscript-448i7exgpyqpr9c144q.gif"></noscript> <!-- END EMBED --> <!-- Matomo --> <script type="text/javascript"> var _paq = _paq || []; function initPiwik() { _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="https://analytics.linuxjournal.com/"; _paq.push(['setTrackerUrl', u+'piwik.php']); _paq.push(['setSiteId', '50']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); } </script> <noscript><p><img src="https://analytics.linuxjournal.com/piwik.php?idsite=50&rec=1" style="border:0;" alt="" /></p></noscript> <!-- End Matomo Code --> <div class="modal-custom overlay-custom" id="ccpa-modal" style="margin-left: 0; display: none; max-width: 100%; width: 100%"> <div id="modal-content" class="modal-content"> <div class="modal-header" id="ccpa-modal-content-destination"></div> <span class="close" id="modal-close">×</span> </div> </div> </body> </html>