<?xml version="1.0" encoding="UTF-8" standalone="no"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" version="2.0">

<channel>
	<title>Bob on Medical Device Software</title>
	<atom:link href="https://bobonmedicaldevicesoftware.com/blog/feed/" rel="self" type="application/rss+xml"/>
	<link>https://bobonmedicaldevicesoftware.com/blog</link>
	<description>Software Development and Biomedical Engineering</description>
	<lastBuildDate>Mon, 27 Oct 2025 15:03:03 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0</generator>
<cloud domain="bobonmedicaldevicesoftware.com" path="/blog/?rsscloud=notify" port="80" protocol="http-post" registerProcedure=""/>
	<xhtml:meta content="noindex" name="robots" xmlns:xhtml="http://www.w3.org/1999/xhtml"/><item>
		<title>Elfeed Curate Update: Two new features</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 27 Oct 2025 15:03:02 +0000</pubDate>
				<category><![CDATA[Emacs]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1189</guid>

					<description><![CDATA[<p>Die-hard Emacs users (myself included) happily spend an inordinate amount of time tweaking their configurations in order to personalize their look-and-feel, or more importantly, streamline their workflows. The elimination of even a few keystrokes can significantly reduce the time spent &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/">Elfeed Curate Update: Two new features</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<div class="wp-block-image">
<figure class="alignright is-resized"><img fetchpriority="high" decoding="async" width="1024" height="683" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-1024x683.png" alt="" class="wp-image-1208" style="width:166px;height:auto" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-1024x683.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-300x200.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-768x512.png 768w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-1536x1024.png 1536w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/Emacs-Logo.wine_-2048x1365.png 2048w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>
</div>


<p class="wp-block-paragraph">Die-hard <a href="https://www.gnu.org/software/emacs/" target="_blank" rel="noopener" title="">Emacs </a>users (myself included) happily spend an inordinate amount of time tweaking their configurations in order to personalize their look-and-feel, or more importantly, streamline their workflows. The elimination of even a few keystrokes can significantly reduce the time spent completing a task. Whether it's a keyboard macro, a newly discovered package, or custom elisp code, the time savings - and the sense of accomplishment - make the tinkering worthwhile.</p>



<p class="wp-block-paragraph">I started using <a href="https://github.com/rnadler/elfeed-curate" target="_blank" rel="noopener" title="">elfeed-curate</a> (see <a href="https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/" target="_blank" rel="noopener" title="">Introducing elfeed-curate</a>) regularly a couple of years ago. In the recent v0.3.0 release, I added two time-saving features: annotation link creation - for those who publish curated link content - and ask gptel, which may appeal to most <a href="https://github.com/skeeto/elfeed" target="_blank" rel="noopener" title="">elfeed</a> RSS users.</p>



<p class="has-medium-font-size wp-block-paragraph"><strong>Annotation Link Creation</strong></p>



<p class="wp-block-paragraph">One curation feature that I often use is the ability to override the feed link with a custom link. This link most often originates from the original feed post. This is done by adding an org-mode link and other text between two brackets, <code>&lt;Org-Link ...&gt;</code>, into the annotation buffer. It has always been time consuming and error prone to do this manually.</p>



<p class="wp-block-paragraph">The new function <code>elfeed-curate-get-link</code> (<code>j</code> key) solves the most annoying part of the workflow. Normally, I have to open a link in a Browser and create an org-mode link (I use the Chrome <a href="https://chromewebstore.google.com/detail/create-link/gcmghdmnkfdbncmnmlkkglmnnhagajbm?hl=en&amp;pli=1" target="_blank" rel="noopener" title="">Create Link plugin</a> for this) and then paste it back into the annotation buffer.</p>



<p class="wp-block-paragraph">The <code>elfeed-curate-get-link</code> function takes the link under point in the entry buffer, creates the org-mode link from it, and inserts it as part of an annotation template: <code>&lt;Org-Link (author) =comment=&gt;</code>. The org-mode link is also added to the kill ring in case you want to add it to an org-mode file.</p>



<h3 class="wp-block-heading">Usage and Configuration</h3>



<p class="wp-block-paragraph"><code>M-x elfeed-curate-get-link RET</code><br><br><code>(define-key elfeed-show-mode-map "j" #'elfeed-curate-get-link)</code></p>



<p class="wp-block-paragraph">This may seem like a small thing, but it greatly improves the speed and enjoyment of my curation workflow.</p>



<p class="has-medium-font-size wp-block-paragraph"><strong>Ask gptel (experimental)</strong></p>



<p class="wp-block-paragraph">As everyone knows, LLMs are eating the world! I've been using the amazing <a href="https://github.com/karthink/gptel" target="_blank" rel="noopener" title="">gptel</a> package for a while and have been spoiled by its seamless integration into Emacs. </p>



<p class="wp-block-paragraph">I wanted to ask an LLM about the content of links in my RSS feed. Because many feeds truncate articles while others are too long to read, I built custom integration between elfeed and gptel to handle both cases.</p>



<p class="wp-block-paragraph">Also, if you ask an LLM to get the contents from a URL, it responds:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p class="wp-block-paragraph">I can't fetch URLs from here. Please paste the page content, or run one of these and share the output, and I'll summarize it:</p>
</blockquote>



<p class="wp-block-paragraph">This necessitated implementing a function to fetch the content from the link URL and convert it to text for inclusion in the prompt request. </p>



<p class="wp-block-paragraph"><code>elfeed-curate-ask-gptel</code> (<code>i</code> key) will first ask you to enter a prompt (see <code>elfeed-curate-gptel-prompt--default = </code>"Briefly summarize:") and then send a request to an LLM (see the <a href="https://github.com/karthink/gptel/wiki/Defining-custom-gptel-commands" target="_blank" rel="noopener" title="">gptel-request API</a>) with the prompt text along with the link content. The response will be displayed in the <code>*ask-gptel*</code> buffer and added to the kill ring. The gptel backends and models are configured separately and can be changed as desired.</p>



<h3 class="wp-block-heading">Usage and Configuration</h3>



<p class="wp-block-paragraph"><code>M-x elfeed-curate-ask-gptel RET</code><br><br><code>(define-key elfeed-search-mode-map "i" #'elfeed-curate-ask-gptel)</code><br><code>(define-key elfeed-show-mode-map "i" #'elfeed-curate-ask-gptel)</code></p>



<h3 class="wp-block-heading">*ask-gptel* Buffer example</h3>


<div class="wp-block-image">
<figure class="aligncenter size-large"><a href="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel.png" target="_blank" rel=" noreferrer noopener"><img decoding="async" width="1024" height="178" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel-1024x178.png" alt="" class="wp-image-1205" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel-1024x178.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel-300x52.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel-768x134.png 768w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2025/10/ask-gptel.png 1121w" sizes="(max-width: 1024px) 100vw, 1024px" /></a></figure>
</div>


<p class="wp-block-paragraph">The reasons I consider <code>ask-gptel</code> experimental are:</p>



<ol class="wp-block-list">
<li>Testing&nbsp;<code>ask-gptel</code>&nbsp;was mostly done with only one LLM:&nbsp;<code>ChatGPT:gpt-5</code>. Other backends and models may not function properly and changes may be needed for broader support.</li>



<li>Extraction of the URL content is a work in progress. I've already seen that some URLs do not work at all, but I haven't had time to investigate the root causes. Also, I think the extracted content sent to the LLM can be improved to be more concise which will reduce the token count (and cost) and increase upload speed.</li>



<li>Besides <a href="https://en.wikipedia.org/wiki/CliffsNotes" target="_blank" rel="noopener" title="">CliffNotes</a>-like functionality, I'm not really sure what other RSS reader use cases there might be for LLM integration. This is currently a "hammer looking for a nail", so it may not end up going anywhere.</li>
</ol>



<p class="has-medium-font-size wp-block-paragraph"><strong>Feedback Welcome</strong></p>



<p class="wp-block-paragraph">Please do not hesitate to report bugs and suggestions. Thanks and enjoy!</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/">Elfeed Curate Update: Two new features</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2025/10/27/elfeed-curate-update-two-new-features/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Communicating Ideas</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Sat, 18 Jan 2025 22:46:25 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1075</guid>

					<description><![CDATA[<p>For me, the primary takeaway from Paul Graham's Putting Ideas into Words is this: Ideas can feel complete. It's only when you try to put them into words that you discover they're not. PG's other message, also echoed by many &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/">Communicating Ideas</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p><img decoding="async" class="alignright wp-image-421" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2011/02/penpaper.jpg" alt="" width="80" height="80" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2011/02/penpaper.jpg 225w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2011/02/penpaper-150x150.jpg 150w" sizes="(max-width: 80px) 100vw, 80px" />For me, the primary takeaway from Paul Graham's <a href="http://paulgraham.com/words.html" target="_blank" rel="noopener">Putting Ideas into Words</a> is this:</p>
<blockquote>
<p>Ideas can feel complete. It's only when you try to put them into words that you discover they're not.</p>
</blockquote>
<p>PG's other message, also echoed by many others, is that "<strong>Writing is hard. ... You have to work at it.</strong>" (<a href="https://blog.codinghorror.com/fear-of-writing/" target="_blank" rel="noopener">Fear of Writing</a>).  Another thing you read a lot about is how writing improves your overall professional abilities. If you're a journalist or novel writer, you hone these skills as part of your chosen craft. Suppose you're a business or technical professional. In that case, communicating ideas is probably a big part of your job, but improving your writing skills is likely something that requires extra effort beyond your day job.</p>
<p>Of course, the prerequisite for writing is coming up with an <em>idea</em> in the first place. In the software industry, these ideas typically boil down to explaining the details of a technology or the mechanics of some complex code, library/API, or algorithm. Most software solutions involve understanding the pros and cons of multiple open-source and/or commercial offerings.  Good technology writers not only communicate the nuts and bolts, but they also effectively express <strong>opinions </strong>about these alternatives.</p>
<p>Many (actually, most) technology decisions involve trade-offs that have to be evaluated. Architectural decision-making processes are a good example of this. E.g. <a href="https://martinfowler.com/articles/scaling-architecture-conversationally.html" target="_blank" rel="noopener">Scaling the Practice of Architecture, Conversationally</a> proposes that software architecture can be done "<i>as a series of conversations</i>".  A critical aspect of the “Advice Process” is documenting the decisions. This must be done effectively so anyone (a new employee or even the author 6 months later) can understand it.</p>
<p>My primary motivation for writing (see <a href="https://bobonmedicaldevicesoftware.com/blog/2007/10/26/blogging-is-hard/" target="_blank" rel="noopener">Blogging is hard</a>) is <strong>envy</strong>:</p>
<blockquote>
<p>Whenever I read a great article or book I’m always envious of the writer’s talent. It’s like watching an athlete: you know how great they are by how easy they make extraordinary feats look.</p>
</blockquote>
<p>This post is a great example of one of my (many) writing challenges: procrastination! PG's original article was published in Feb. 2022 which was when I created the first draft. Over the last 3 years (!) I've made sporadic edits but for some reason didn't pull the trigger. Typical delay tactics include not being satisfied with the flow, content, or even minor sentence structure. A lot of times, just finding the right title can be a real challenge.</p>
<p>Anyway, one of my New Year's resolutions (all unspoken, until now!) was to blog more often. Just like exercising and eating better, this is easier said than done. I had an idea for a technical post (Emacs-related, of course), but that led me to old drafts like this one. If posting this is like the first visit after joining a gym, I guess we'll have to wait and see if I keep coming back!</p>
<p>Happy 2025! </p>


<p class="wp-block-paragraph"></p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/">Communicating Ideas</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2025/01/18/communicating-ideas/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Creating an Emacs package: ‘password-menu’</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/#comments</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 08 Apr 2024 15:04:01 +0000</pubDate>
				<category><![CDATA[Emacs]]></category>
		<category><![CDATA[Tools]]></category>
		<category><![CDATA[elisp]]></category>
		<category><![CDATA[emacs]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1141</guid>

					<description><![CDATA[<p>TL;DR This post documents the development journey and some implementation details of a relatively simple Emacs package and is arguably overkill for such a small piece of functionality. On the other hand, some of these details may be useful for &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/">Creating an Emacs package: ‘password-menu’</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">TL;DR</h2>



<p class="wp-block-paragraph">This post documents the development journey and some implementation details of a relatively simple <a href="https://www.gnu.org/software/emacs/" target="_blank" rel="noopener" title="">Emacs</a> package and is arguably overkill for such a small piece of functionality. On the other hand, some of these details may be useful for others who want to develop similar functionality.</p>



<p class="wp-block-paragraph">If you're <em>not </em>interested, skip to the <a href="#package-desc" title="last section">last section</a> for a brief package description, or see the full package here: <a href="https://github.com/rnadler/password-menu" target="_blank" rel="noopener" title="">password-menu</a>.</p>



<h2 class="wp-block-heading">Making life easier</h2>



<p class="wp-block-paragraph">The need to automate something usually becomes apparent when an often-used workflow is awkward or inefficient. The effort to create the automation will hopefully pay off over time. I.e. ideally, the ROI will be high. This is why Emacs users spend so much time tweaking their configurations, even though I suspect the ROI may not be as high as they'd like!</p>



<p class="wp-block-paragraph">In my case, the pain point was about the repeated need to provide passwords and tokens in a variety of situations. This is a common scenario — websites, CLI logins, curl/Postman, etc. all need credentials.</p>



<p class="wp-block-paragraph">In addition to using <a href="https://www.gnu.org/software/emacs/manual/html_mono/auth.html" target="_blank" rel="noopener" title="auth-source">auth-source</a> (<code>authinfo.gpg</code>) I had gotten into the <em>bad </em>habit of scattering credentials around various org-mode files (unencrypted! ?). When I needed a password, it required a search, buffer open, select, copy, and then paste to the target to complete. This is (and felt) very clumsy and inefficient. The addition of <a href="https://sachachua.com/blog/2024/01/org-mode-custom-link-copy-to-clipboard/"></a><a href="https://sachachua.com/blog/2024/01/org-mode-custom-link-copy-to-clipboard/" target="_blank" rel="noopener" title="">Org Mode custom link: copy to clipboard</a> made the select/copy a little easier, but the overall experience still sucked.</p>



<p class="wp-block-paragraph">The search for an existing solution came up empty. This was surprising given that the Emacs package ecosystem (<a href="https://melpa.org/#/" target="_blank" rel="noopener" title="Melpa">Melpa</a>) is extensive and has been around for a long time.</p>



<p class="wp-block-paragraph">One of the distinguishing features of Emacs is the ability to customize and extend its functionality with <a href="https://www.gnu.org/software/emacs/manual/html_node/eintr/" target="_blank" rel="noopener" title="Elisp">Elisp</a>. So, here we go.</p>



<h2 class="wp-block-heading">Feature #1: Transient prefix menu</h2>



<p class="wp-block-paragraph">My approach was to use the <a href="https://www.gnu.org/software/emacs/manual/html_mono/auth.html#index-auth_002dsource_002dsearch" target="_blank" rel="noopener" title="auth-source-search">auth-source-search</a> API along with the <a href="https://github.com/magit/transient" target="_blank" rel="noopener" title="">transient</a> package to provide the menu UI. This type of "porcelain" has become popular for Emacs projects that have complex user interfaces (<a href="https://magit.vc/" target="_blank" rel="noopener" title="Magit">Magit!</a> being the best example). My use case is far simpler, but the UI style was still desirable.</p>



<p class="wp-block-paragraph">The only real Elisp challenge (for me anyway) was creating a <em>dynamic transient prefix list</em>. I couldn't find any examples of this. Transient prefixes are implemented as vectors. Also, note that the <code>transient</code> interface is very complex (Prefixes, Suffixes, Infixes) but this use case only needed prefixes.</p>



<p class="wp-block-paragraph">A typical transient prefix group looks like this (excerpted from <a href="https://github.com/positron-solutions/transient-showcase" target="_blank" rel="noopener" title="transient-showcase">transient-showcase</a>). </p>



<pre class="crayon-plain-tag">(transient-define-prefix messenger ()
  &quot;Prefix with descriptions&quot;
   [&quot;Send Message&quot;
     (&quot;s&quot; &quot;snow people&quot; (lambda () (interactive) (message &quot;snow people!&quot;)))
     (&quot;k&quot; &quot;kitty cats&quot;  (lambda () (interactive) (message &quot;kitty cats!&quot;)))])</pre>



<p class="wp-block-paragraph">Dynamically creating a vector like this can be implemented with this <strong>pseudocode</strong>:</p>



<pre class="crayon-plain-tag">(defun get-prefix-list ()
  &quot;Create dynamic transient prefix list.&quot;
  (vconcat '[&quot;Get password for: &quot;]
    (apply #'vector
      (mapcar
       (lambda (source))
         ;; Extract user and host from source
         (list
          (get-next-picker-string) 
          (concat user &quot;@&quot; host)
          `(lambda () (interactive) (get-password ,user ,host)))
      (get-sources)))))</pre>



<p class="wp-block-paragraph">You won't find this code in <code>password-menu.el</code> because it was refactored with macros as described below. </p>



<p class="wp-block-paragraph">An Elisp expert could have knocked out this implementation without breaking a sweat, but it was a learning experience for me.</p>



<p class="wp-block-paragraph">The development of the picker string functionality (<code>1..0, a1..a0, b1..b0,...</code>) was also a lot of fun.</p>



<h2 class="wp-block-heading">Feature #2: Completing-read menu</h2>



<p class="wp-block-paragraph">All done, right? In the middle of the transient work, I ran across a post that included a good description of using <a href="https://arialdomartini.github.io/emacs-surround-2" target="_blank" rel="noopener" title="Completing-read with a list">completing-read with a list</a>. The <code>completing-read</code> list interface could leverage the same core transient prefix list elements. Specifically, the <code>user@host</code> string menu item and the lambda that gets the password. The prefix picker string is not needed.</p>



<p class="wp-block-paragraph">The implementation was refactored with a couple of macros so both UI interfaces could share the list generation. I won't dig into the details here, but the <code>password-menu.el</code> code should be self-explanatory. Getting the completing-read list boiled down to <a href="https://github.com/rnadler/password-menu/blob/main/password-menu.el#L189" target="_blank" rel="noopener" title="this">this</a>:</p>



<pre class="crayon-plain-tag">(defun password-menu-get-completing-list ()
  &quot;Get the completing list from the password sources.&quot;
  (password-menu--get-source-list
   (password-menu--selection-item)))</pre>



<p class="wp-block-paragraph">The <code>transient</code> version uses these same two macros, but is a little more complex. This shows the usefulness of <strong>macros </strong>and was another Elisp learning experience.</p>



<h2 class="wp-block-heading">Feature #3: Kill ring and clipboard expiration</h2>



<p class="wp-block-paragraph">Finally, while investigating other password management packages I ran across this <a href="https://github.com/zx2c4/password-store/blob/master/contrib/emacs/password-store.el#L291" target="_blank" rel="noopener" title="Kill ring expiration">kill ring expiration</a> implementation. It makes sense to remove the secret from the kill ring and system clipboard automatically so I incorporated their code pretty much unmodified.</p>



<p class="wp-block-paragraph">This additional functionality is like icing on the cake.</p>



<h2 class="wp-block-heading">Epilogue</h2>



<p class="wp-block-paragraph">I've been dogfooding <code>password-menu</code> for a while. I use it often and can safely say it has improved the "get credential" experience. Before, it was "Oh crap, here we go...". Now it's simply <code>C-x j 3</code> from anywhere, then paste. Easy peasy!</p>



<p class="wp-block-paragraph">The other benefit is that I've now removed all those unencrypted secrets from my org files and have everything tucked away in one secure place: <code>authinfo.gpg</code>. That's a big win too.</p>



<h2 class="wp-block-heading" id="package-desc">The <em>password-menu</em> package</h2>



<p class="wp-block-paragraph"><a href="https://github.com/rnadler/password-menu" target="_blank" rel="noopener" title="">Password-menu</a> is a UI wrapper ("porcelain") for the built-in Emacs <code>auth-source</code> secrets library. This package allows you to display auth-source entries in the minibuffer with either <a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Completion.html" target="_blank" rel="noopener" title="completing-read">completing-read</a> or <a href="https://github.com/magit/transient" target="_blank" rel="noopener" title=""><code>transient</code></a>. The password for the selected entry is copied to the kill ring and system clipboard and automatically removed later.</p>



<div class="wp-block-columns is-layout-flex wp-container-core-columns-is-layout-8f761849 wp-block-columns-is-layout-flex">
<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><strong>Transient</strong></p>



<figure class="wp-block-image size-full"><a href="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-transient.png"><img loading="lazy" decoding="async" width="304" height="222" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-transient.png" alt="" class="wp-image-1143" style="object-fit:cover" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-transient.png 304w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-transient-300x219.png 300w" sizes="auto, (max-width: 304px) 100vw, 304px" /></a></figure>
</div>



<div class="wp-block-column is-layout-flow wp-block-column-is-layout-flow">
<p class="has-text-align-center wp-block-paragraph"><strong>Completing-read</strong></p>


<div class="wp-block-image">
<figure class="aligncenter size-full"><a href="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-completing-read.png"><img loading="lazy" decoding="async" width="297" height="227" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2024/04/password-menu-completing-read.png" alt="" class="wp-image-1144" style="object-fit:cover"/></a></figure>
</div></div>
</div>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/">Creating an Emacs package: ‘password-menu’</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2024/04/08/creating-an-emacs-package-password-menu/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Introducing elfeed-curate</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 02 Oct 2023 15:08:19 +0000</pubDate>
				<category><![CDATA[Emacs]]></category>
		<category><![CDATA[elfeed]]></category>
		<category><![CDATA[emacs]]></category>
		<category><![CDATA[rss]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1123</guid>

					<description><![CDATA[<p>The Need I read a lot of RSS feeds on a select set of topics (see About &#124; Bob's Content of Interest). I sometimes tweet/toot about individual posts but have the desire to expand that capability. I'd like to be &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/">Introducing <em>elfeed-curate</em></a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<h2 class="wp-block-heading">The Need</h2>



<p class="wp-block-paragraph">I read a lot of RSS feeds on a select set of topics (see <a href="https://bobonmedicaldevicesoftware.com/coi/about/" target="_blank" rel="noopener" title="">About | Bob's Content of Interest</a>). I sometimes tweet/toot about individual posts but have the desire to expand that capability. I'd like to be able to regularly (and efficiently) publish a curated collection of articles. There are three primary functional requirements needed to accomplish this:</p>



<p class="wp-block-paragraph"><strong>Collection</strong>: Deciding which articles you want to export (publish). Filtering can be done based on their title, subject matter (tags), and time constraints. My preference is to specifically mark (or tag) selected entries independent of their subject matter (see below).</p>



<p class="wp-block-paragraph"><strong>Annotation</strong>: Some article titles speak for themselves, but others are best presented with associated comments that allow the reader to know what's special about the content. You need the ability to add annotations to individual articles that are included in the published result.</p>



<p class="wp-block-paragraph"><strong>Publication</strong>: Once a set of articles has been identified, exporting them in an easily consumable format is the next step. One important component of exporting this content is <strong>grouping </strong>the articles based on their subject matter.</p>



<h2 class="wp-block-heading">The Investigation</h2>



<p class="wp-block-paragraph">There are many RSS feed aggregators out there, but there was no solution that even came near to addressing the curation requirements listed above. Apparently, all of those link collection sites are just rolling their own. </p>



<p class="wp-block-paragraph">As a software developer, finding such a glaring functionality gap that needs to be filled is a real win-win! ? Not only is this something I want to use, but there are probably a few others who will also find a solution helpful. </p>



<p class="wp-block-paragraph">Now all I had to do was design and develop that solution. I've been using <a href="https://www.gnu.org/software/emacs/" target="_blank" rel="noopener" title="">Emacs</a> and <a href="https://github.com/skeeto/elfeed" target="_blank" rel="noopener">Elfeed</a> as my RSS reader for many years.  Extending Emacs functionality is a cult-like activity that attracts many. I'm not brain-washed, but even as a (non-evil) Doom user, I do spend a lot of time tweaking my Emacs configuration.</p>



<p class="wp-block-paragraph">Anyway, providing this RSS curation functionality as an <code>elfeed</code> extension was not only the ideal technical solution, but it was also the perfect opportunity to author my first Emacs package (another win, I hope).</p>



<h2 class="wp-block-heading">The Solution</h2>



<p class="wp-block-paragraph"><a href="https://github.com/rnadler/elfeed-curate" target="_blank" rel="noopener">Elfeed-curate</a> is an add-on to the&nbsp;<code>elfeed</code> Emacs-based RSS feed management system that provides the ability to easily curate RSS feed entries.</p>



<p class="wp-block-paragraph">Elfeed's tagging and search functionality takes care of the <em>collection </em>requirements and <code>elfeed-curate</code> adds <em>annotation </em>and <em>publication </em>(exporting) capabilities.</p>



<p class="wp-block-paragraph">I have an opinionated workflow that looks like this:</p>



<figure class="wp-block-image size-full"><a href="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-workflow.png"><img loading="lazy" decoding="async" width="532" height="488" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-workflow.png" alt="" class="wp-image-1135" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-workflow.png 532w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-workflow-300x275.png 300w" sizes="auto, (max-width: 532px) 100vw, 532px" /></a></figure>



<p class="wp-block-paragraph">See <a href="https://github.com/rnadler/elfeed-curate#curation-workflow" target="_blank" rel="noopener" title="">Curation Workflow</a> for details. </p>



<p class="wp-block-paragraph">A key factor (essentially, a non-functional requirement) for making this workflow practical is that each step (marking, annotation, export review, etc.) has to be <em>fast</em>. I think the combination of <code>elfeed</code> and <code>elfeed-curate</code> accomplishes this. I'm also sure there will be refinements and improvements in the future.</p>



<h2 class="wp-block-heading">Export example</h2>



<figure class="wp-block-image size-full"><a href="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-export.png"><img loading="lazy" decoding="async" width="929" height="885" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-export.png" alt="" class="wp-image-1133" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-export.png 929w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-export-300x286.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2023/10/elfeed-curate-export-768x732.png 768w" sizes="auto, (max-width: 929px) 100vw, 929px" /></a></figure>



<p class="wp-block-paragraph">The same content exported to Hugo is here: <a href="https://robertn78.sg-host.com/coi/posts/21-sep-2023-export/" target="_blank" rel="noopener" title="">21-Sep-2023 Content of Interest</a></p>



<p class="wp-block-paragraph">Feedback is always welcome. Thanks!</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/">Introducing <em>elfeed-curate</em></a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2023/10/02/introducing-elfeed-curate/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Dealing with ClojureScript Cross-build NPM Dependencies</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 03 Oct 2022 04:02:46 +0000</pubDate>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[re-frame re-frame-10x]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1090</guid>

					<description><![CDATA[<p>I recently posted this Clojurians Slack re-frame question: I have a deps.edn/figwheel-main re-frame project that I'm trying to add re-frame-10x to. The deps.edn (day8.re-frame/re-frame-10x {:mvn/version "1.5.0"}) and dev.cjls.edn (:preloads [day8.re-frame-10x.preload]) seem correct and the project builds without errors. When the &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/">Dealing with ClojureScript Cross-build NPM Dependencies</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p>I recently posted this Clojurians Slack re-frame <a href="https://clojurians.slack.com/archives/C073DKH9P/p1661733368716379" target="_blank" rel="noopener">question</a>:</p>
<p>I have a deps.edn/figwheel-main <a href="https://github.com/day8/re-frame" target="_blank" rel="noopener">re-frame</a> project that I'm trying to add <a href="https://github.com/day8/re-frame-10x" target="_blank" rel="noopener">re-frame-10x</a> to. The deps.edn (day8.re-frame/re-frame-10x {:mvn/version "1.5.0"}) and dev.cjls.edn (:preloads [day8.re-frame-10x.preload]) seem correct and the project builds without errors. When the web app is started though, I get this run-time error:</p>
<blockquote><p>Uncaught Error: Bad dependency path or symbol: highlight.js.lib.core</p></blockquote>
<p>I and <a href="https://github.com/thheller/shadow-cljs/discussions/912" target="_blank" rel="noopener">others</a> have also seen this type of build-time error:</p>
<blockquote><p>No such namespace: highlight.js/lib/core, could not locate highlight/js_SLASH_lib_SLASH_core.cljs, highlight/js_SLASH_lib_SLASH_core.cljc, or JavaScript source providing "highlight.js/lib/core" (Please check that namespaces with dashes use underscores in the ClojureScript file name) in file target/public/cljs-out/dev/re_highlight/core.cljs</p></blockquote>
<p>Both errors are originating from <a href="https://github.com/superstructor/re-highlight/blob/master/src/re_highlight/core.cljs" target="_blank" rel="noopener">re-highlight/core.cljs</a>:</p><pre class="crayon-plain-tag">(ns re-highlight.core
  (:require
    [goog.object                          :as gobj]
    [reagent.core                         :as r]
    [reagent.dom                          :as rdom]
    [&quot;highlight.js/lib/core&quot;              :as hljs]
    [&quot;highlight.js/lib/languages/clojure&quot; :as clojure]))
...</pre><p>re-highlight (a re-frame-10x dependency) is built with <a href="https://github.com/thheller/shadow-cljs" target="_blank" rel="noopener">shadow-cljs</a> while the re-frame project is built with <a href="https://leiningen.org/" target="_blank" rel="noopener">lein</a>/deps.edn/<a href="https://figwheel.org/" target="_blank" rel="noopener">figwheel-main</a>. The re-frame project does not have a dependency on either re-highlight or highlight.js.  The challenge here is providing the highlight.js (an NPM library) dependencies to re-highlight.</p>
<p>There are ways to include NPM libraries in ClojureScript projects, but each is specific to a particular build system:</p>
<ul>
<li><a href="https://clojurescript.org/news/2017-07-12-clojurescript-is-not-an-island-integrating-node-modules" target="_blank" rel="noopener">ClojureScript is not an Island: Integrating Node Modules</a></li>
<li><a href="https://clojurescript.org/guides/webpack" target="_blank" rel="noopener">ClojureScript with Webpack</a></li>
<li><a href="https://figwheel.org/docs/npm.html" target="_blank" rel="noopener">figwheel-main: Using NPM</a></li>
<li><a href="https://shadow-cljs.github.io/docs/UsersGuide.html#npm" target="_blank" rel="noopener">shadow-cljs: NPM</a></li>
</ul>
<p>This cross-build system situation seems unique though. Providing the <code>highlight.js</code> library to <code>re-highlight</code> turned out to be an eye-opening deep dive into ClojureScript build systems. See the <strong>Commentary</strong> section at the end of this post.</p>
<p>Long story short, I was able to find a solution for exposing NPM libraries to shadow-cljs projects included in a deps.edn build.</p>
<p>It involves creating a Javascript bundle containing the needed NPM dependency (highlight.js) using <a href="https://webpack.js.org/" target="_blank" rel="noopener">webpack</a> and then "manually" making it available to re-highlight.</p>
<p>Here is a step-by-step guide for adding re-frame-10x to a deps.edn re-reframe project.</p>
<p>First, create package.json with the needed dependencies.</p><pre class="crayon-plain-tag">npm install highlight.js --save
npm install webpack webpack-cli --save-dev
# Manually add this to package.json:
# &quot;scripts&quot;: {
#    &quot;build&quot;: &quot;webpack --mode=development&quot;
#  },</pre><p>Final<strong> package.json</strong>:</p><pre class="crayon-plain-tag">{
  &quot;scripts&quot;: {
    &quot;build&quot;: &quot;webpack --mode=development&quot;
  },
  &quot;dependencies&quot;: {
    &quot;highlight.js&quot;: &quot;^11.5.1&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;webpack&quot;: &quot;^5.74.0&quot;,
    &quot;webpack-cli&quot;: &quot;^4.10.0&quot;
  }
}</pre><p>Create <strong>src/js/main.js</strong> with these contents. The <code>require()</code> statements are needed so webpack will include the NPM libraries in the output bundle.</p><pre class="crayon-plain-tag">require('highlight.js')
require('highlight.js/lib/languages/clojure')</pre><p>Create <strong>webpack.config.js</strong> with these contents:</p><pre class="crayon-plain-tag">const webpack = require('webpack');
const path = require('path');

const BUILD_DIR = path.resolve(__dirname, 'resources', 'public', 'js', 'compiled');
const APP_DIR = path.resolve(__dirname, 'src', 'js');

const config = {
&nbsp; entry: `${APP_DIR}/main.js`,
&nbsp; output: {
&nbsp; &nbsp; path: BUILD_DIR,
&nbsp; &nbsp; filename: 'bundle.js'
&nbsp; }
};
module.exports = config;</pre><p>Add the following lines <strong>before</strong> the complied <code>app.js</code> in <strong>resources/public/index.html</strong>.</p><pre class="crayon-plain-tag">...
&lt;script src=&quot;js/compiled/out/goog/base.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
&lt;script&gt;
   goog.addDependency(&quot;../../bundle.js&quot;, ['highlight.js.lib.core', 'highlight.js.lib.languages.clojure'], []);
&lt;/script&gt;
&lt;script src=&quot;js/compiled/app.js&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
...</pre><p>This is where the magic is happening.</p>
<ul>
<li>The highlight.js dependencies are being manually added with <code>goog.addDependency()</code> before the rest of the application dependencies are loaded.</li>
<li>The Clojurescript compiler-generated app.js has the following code. We're just loading goog/base.js first so the <code>goog</code> functions are defined.</li>
</ul>
<p></p><pre class="crayon-plain-tag">...
if(typeof goog == &quot;undefined&quot;) document.write('&lt;script src=&quot;js/compiled/out/goog/base.js&quot;&gt;&lt;/script&gt;');
...</pre><p><strong>Note</strong>: The paths and JS build file names (e.g. <code>app.js</code>) above may not match your specific project structure. If so, they would need to be adjusted accordingly.</p>
<p>Add re-frame-10x dependencies to <strong>deps.edn</strong>:</p><pre class="crayon-plain-tag">...
 day8.re-frame/tracing {:mvn/version &quot;0.6.2&quot;}
 day8.re-frame/test {:mvn/version &quot;0.1.5&quot;}
 day8.re-frame/re-frame-10x {:mvn/version &quot;1.5.0&quot;}
...</pre><p>The <strong>dev.cljs.edn</strong> file needs the following so re-frame-10x is loaded properly:</p><pre class="crayon-plain-tag">...
:closure-defines {
  &quot;goog.DEBUG&quot; true
  &quot;re_frame.trace.trace_enabled_QMARK_&quot; true}
:preloads [day8.re-frame-10x.preload]
...</pre><p>Run the project:</p><pre class="crayon-plain-tag">npm run build  # Creates bundle.js
lein repl
# or
lein figwheel</pre><p>Voilà! The highlight.js dependency in re-highlight is satisfied and re-frame-10x runs as expected.</p>
<p>There must be a better way to do this. I just couldn't find it...</p>
<h3>Commentary</h3>
<p>This solution seems rather hacky and took way too long to discover. I can't tell you the number of rabbit holes I went down with the NPM inclusion methods listed above. Each of them just uncovered further dependency and configuration issues or would have resulted in undesirable refactoring. The code base I'm working with is rather large and I didn't want to completely change the build system just to add a development tool.</p>
<p>To be honest, the CLJ/CLJS build tools and their cross-pollinated dependency systems (lein, shadown-cljs, etc.) are very confusing. There is no idiomatic/standard way to build Clojure(Script) projects. Everyone is using a different combination or permutation of build systems.  Also, the <a href="https://clojure.org/reference/deps_and_cli" target="_blank" rel="noopener">clojure/clj CLI and tooling</a> just plain suck.  I think these things are a real barrier to Clojure(Script) adoption.</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/">Dealing with ClojureScript Cross-build NPM Dependencies</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2022/10/02/dealing-with-clojurescript-cross-build-npm-dependencies/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>On Selecting Clojure</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 08 Mar 2021 17:45:16 +0000</pubDate>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[FP]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[lisp]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=1022</guid>

					<description><![CDATA[<p>The Clojure and Scheme Compared comments about Peter Bex's Clojure from a Schemer's perspective article caught my attention. I know that discussion is about language features, but it got me thinking about the different criteria used for selecting a programming &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/">On Selecting Clojure</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p><img loading="lazy" decoding="async" class=" wp-image-881 alignright" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2019/01/clojure.png" alt="" width="130" height="131" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2019/01/clojure.png 195w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2019/01/clojure-150x150.png 150w" sizes="auto, (max-width: 130px) 100vw, 130px" />The <a href="https://irreal.org/blog/?p=9530" target="_blank" rel="noopener">Clojure and Scheme Compared</a> comments about Peter Bex's <a href="https://www.more-magic.net/posts/thoughts-on-clojure.html" target="_blank" rel="noopener">Clojure from a Schemer's perspective</a> article caught my attention. I know that discussion is about language features, but it got me thinking about the different criteria used for selecting a programming language like Clojure. E.g., it's interesting that Irreal considers the JVM a negative, while I consider it a positive. It just goes to show that every situation is unique, i.e. there is no right or wrong in these types of technology decisions.</p>
<p>I've only dabbled with Clojure over the last few years. See <a href="https://bobonmedicaldevicesoftware.com/blog/2019/01/27/exploring-clojure-and-fp-vs-oop/" target="_blank" rel="noopener">Exploring Clojure (and FP vs OOP)</a>. The real motivation was to explore the advantages of <strong>functional programming</strong>. Shifting your fundamental programming paradigm from <a href="https://en.wikipedia.org/wiki/Object-oriented_programming" target="_blank" rel="noopener">OOP</a> to FP has far-reaching impact. Language warts are not going to be a major factor in determining your success in doing this type of transformation.</p>
<p>The other major language/technology selection considerations involve <strong>organizational headwinds</strong>. For most large companies, there are three major challenges:</p>
<ol>
<li><strong>Inertia</strong>. Convincing management that an esoteric language and techniques (FP) are worth diverting and training existing personnel is a difficult hill to climb. I also think there's a certain amount of organizational entrenchment going on here. For example, the C#/CLR vs. Java/JVM divide is really more cultural than technical. Because niche technologies like Clojure/FP are also generally viewed in this cultural context ("esoteric"), they don't stand a chance.</li>
<li><strong>Talent</strong>. Unless you're in Finland, it's difficult to find qualified people. This is also an on-going issue because programs developed today need to be maintained for the long-term (years). With all-remote employment now being more mainstream, maybe this will become less of an issue.</li>
<li><strong>Trends</strong>. As you can see from the 5-year trends below, Clojure has been on a slow decline. Also, Lisp languages are minor players. They are orders of magnitude smaller than the mainstream (Java, JavaScript, Python) and do not show up on the <a href="https://www.tiobe.com/tiobe-index/" target="_blank" rel="noopener">TIOBE</a> top 20 lists (Lisp is #36).</li>
</ol>
<p><a href="https://trends.google.com/trends/explore?date=today%205-y&amp;geo=US&amp;q=%2Fm%2F03yb8hb,%2Fm%2F06zrb,%2Fm%2F0974fb,%2Fm%2F01tlw" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-1024" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/03/lisp-5-year-trends-300x135.png" alt="" width="481" height="216" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/03/lisp-5-year-trends-300x135.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/03/lisp-5-year-trends-1024x460.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/03/lisp-5-year-trends-768x345.png 768w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/03/lisp-5-year-trends.png 1168w" sizes="auto, (max-width: 481px) 100vw, 481px" /></a></p>
<p>Even if you're a small company or a startup, selecting Clojure is still a tough call. This would likely only happen if there were a critical mass of programmers (#2) that already had positive Clojure/FP development experiences.</p>
<p>There are many good reasons to choose Clojure as a front-end (JavaScript) and/or back-end (JVM) technology solution. I would love to see first-hand how well Clojure/FP performs on a large-scale project.  Unfortunately, there are also plenty of non-technical reasons that prevent organizations from choosing Clojure.</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/">On Selecting Clojure</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2021/03/08/on-selecting-clojure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Full Cycle Teams in a FDA regulated setting</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Mon, 04 Jan 2021 15:56:53 +0000</pubDate>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[FDA]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[IEC 62304]]></category>
		<category><![CDATA[mdds]]></category>
		<category><![CDATA[Netflix]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=921</guid>

					<description><![CDATA[<p>The 200X hot topic was Agile development in a FDA regulated setting. Over a decade later this should (hopefully) be a settled issue. I can’t imagine anyone still doing water-fall these days. The new challenge for medical device companies is &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/">Full Cycle Teams in a FDA regulated setting</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p><a href="https://netflixtechblog.com/full-cycle-developers-at-netflix-a08c31f83249" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="wp-image-1009 alignright" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/fcdevs-300x262.png" alt="Full Cycle Developers" width="210" height="184" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/fcdevs-300x262.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/fcdevs.png 559w" sizes="auto, (max-width: 210px) 100vw, 210px" /></a>The 200X hot topic was <a href="https://bobonmedicaldevicesoftware.com/blog/2007/07/22/agile-development-in-a-fda-regulated-setting/" target="_blank" rel="noopener">Agile development in a FDA regulated setting</a>. Over a decade later this should (hopefully) be a settled issue. I can’t imagine anyone still doing water-fall these days. The <strong>new challenge</strong> for medical device companies is implementing Full Cycle Teams (FCTs), which is well described in <a href="https://netflixtechblog.com/full-cycle-developers-at-netflix-a08c31f83249">Full Cycle Developers at Netflix — Operate What You Build</a>.</p>
<p>This organizational structure increases the speed of feature delivery and allows for experimentation to further improve the customer experience. Tooling and automation ("paved roads") are key. The model that Netflix came up with:</p>
<blockquote><p>"Full cycle developers" is a model where a development team, equipped with amazing developer productivity tools, is responsible for the full software life cycle: design, development, test, deploy, operate, and support.</p></blockquote>
<p>If you work for a large enough enterprise, you likely have <strong>teams</strong> of people that provide the following functions:</p>
<ul>
<li><strong>Product development</strong> (creates and designs applications software and includes architects, product owners, and scrum masters)</li>
<li><strong>Quality assurance</strong> (QA). They test the software. For a medical device company, we call this team <a href="https://bobonmedicaldevicesoftware.com/blog/2009/03/26/software-verification-vs-validation/" target="_blank" rel="noopener">Verification and Validation</a> (V&amp;V)</li>
<li><strong>Site Reliability Engineering</strong> (SRE). Ensures scalability and reliability of the infrastructure and applications. They do performance testing and may implement some <a href="https://en.wikipedia.org/wiki/Chaos_engineering" target="_blank" rel="noopener">Chaos engineering</a> techniques.</li>
<li><strong>Development operations</strong> (DevOps). Manage the code repositories, shared development tools, CI/CD pipelines, middleware, databases, etc.</li>
<li><strong>Infrastructure management</strong> (on-prem hardware and operating systems)</li>
<li><strong>Cloud management</strong> (same as above,  but in the cloud)</li>
<li><strong>Applications support</strong> (monitor and manage applications in production)</li>
</ul>
<p>Do not confuse FCTs with "Full Stack Teams" (see <a href="https://medium.com/better-programming/2020-001-full-stack-pronounced-dead-355d7f78e733" target="_blank" rel="noopener noreferrer">Full Stack Pronounced Dead</a>). This "stack" refers to technologies that are used to implement a typical web-based application (e.g. <a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)" target="_blank" rel="noopener">LAMP</a>).</p>
<p>FCTs are about supporting functionality end-to-end (product idea to production), but both have the challenge of <strong>developer specialization</strong> in common. A FCT has to broaden their skill-set even further to include application/infrastructure deployment, monitoring, and support. This is the future!</p>
<h4>Full Cycle Team Challenges for Medical Device Companies</h4>
<p>The transformation from a legacy organization (as described above) to FCTs is made even more challenging for a medical device company creating software that has to maintain <strong>FDA regulatory controls </strong>(see Quality System Regulation <em>Subpart C–Design Control</em> <a href="http://www.accessdata.fda.gov/scripts/cdrh/cfdocs/cfcfr/CFRSearch.cfm?fr=820.30">§ 820.30</a>).</p>
<p>Below is a list of regulatory and transition considerations that impact the <strong>release process</strong>. Most are associated with keeping the Design History File (<a href="https://www.greenlight.guru/glossary/design-history-file" target="_blank" rel="noopener">DHF</a>) documentation up-to-date. The organizational challenge in a FCT world is figuring out <strong>who is responsible</strong> for these tasks.</p>
<p>Spoiler alert: The suggested answers should be obvious, but many times the best I can do is just ask the question. Every organization, and even different teams within a single organization, will have different solutions. These can be tough problems to solve. Don't shoot the messenger!</p>
<h4>Medical Device Data System (MDDS)</h4>
<p>Not all of your software may be under FDA Class II/III regulatory controls. Some could fall under MDDS, see <a href="https://www.fda.gov/medical-devices/medical-device-data-systems/identifying-mdds" target="_blank" rel="noopener">Identifying an MDDS</a>. There is still some risk associated with MDDS but special controls and premarket approval -- the <a href="https://www.fda.gov/medical-devices/device-approvals-denials-and-clearances/510k-clearances" target="_blank" rel="noopener">510(k)</a> -- are not necessary (see <a href="https://www.fda.gov/medical-devices/medical-device-data-systems/mdds-rule" target="_blank" rel="noopener">MDDS Rule</a>).</p>
<p>MDDS software requires the same <a href="https://en.wikipedia.org/wiki/Quality_management_system" target="_blank" rel="noopener">QMS</a> documentation (see MDDS Section VI-E. <em>Current Good Manufacturing Practices (CGMP)/QS Regulation/MDR Compliance</em> of the rule) so most of the items listed here still apply.</p>
<p>Also, see Comment 25 from the rule which addresses "modular software". I.e mixing MDDS components with medical device components. The response says "The MDDS regulation does not necessarily prevent modular implementation.", but the FDA can't make a "generalized determination" on the various ways these combinations may be made. This may be a situation you run into and the FDA suggests it is best to contact them if you have questions.</p>
<h4>Validation and Verification</h4>
<p><a href="https://www.fda.gov/media/73141/download" target="_blank" rel="noopener">General Principles of Software Validation; Final Guidance for Industry and FDA Staff</a> (PDF)</p>
<blockquote><p>Based on the intended use and the safety risk associated with the software to be developed, the software developer should determine the specific approach, the combination of techniques to be used, and the level of effort to be applied. While this guidance does not recommend any specific life cycle model or any specific technique or method, it does recommend that software validation and verification activities be conducted throughout the entire software life cycle.</p></blockquote>
<p>FDA guidance documents, and FDA regulations in general (e.g. <em class="ix">IEC 62304</em>), tell you <strong>what</strong> to do, but leave the <strong>how</strong> up to the organization. <em class="ix"> </em></p>
<p><a href="http://www.v-model.info/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-1014" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/01/v-model-3-300x156.png" alt="" width="400" height="208" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/01/v-model-3-300x156.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/01/v-model-3-1024x533.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/01/v-model-3-768x399.png 768w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2021/01/v-model-3.png 1242w" sizes="auto, (max-width: 400px) 100vw, 400px" /></a>Let's highlight the SRS<strong>*</strong> to System test verification from the V-model. This is essentially end-to-end testing. In a microservice-based architecture, each FCT is likely responsible for different sets of services. These services may be dependent on the services provided by other teams.</p>
<p><em>Which team is responsible for ensuring that the entire system is functioning properly (i.e. end-to-end test protocols and results) after changes are made to one or more of these services?</em></p>
<p>In an ideal world, these end-to-end tests are completely automated, but even then someone still needs to maintain them.</p>
<p><strong>Validation testing</strong> (was the right product built?) presents even more challenges as a single FCT is may only be responsible for a small portion of the entire product.</p>
<h4>Risk analysis</h4>
<p>From <a href="https://www.wipro.com/medical-devices/basic-principles-of-risk-management-for-medical-device-design/">Medical Device Design Risk Management Basic Principles</a>:</p>
<p><a href="https://www.wipro.com/medical-devices/basic-principles-of-risk-management-for-medical-device-design/" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-1011" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/risk-analysis-flow.png" alt="" width="400" height="230" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/risk-analysis-flow.png 706w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/12/risk-analysis-flow-300x173.png 300w" sizes="auto, (max-width: 400px) 100vw, 400px" /></a></p>
<p>Risk analysis is typically done by a cross-functional team that may span multiple business units, but it is probably not unreasonable for the FCT Product Owner to drive this process and get the documentation updated as needed.</p>
<h4>Traceability</h4>
<p>From the FDA guidance:</p>
<blockquote><p>A source code traceability analysis is an important tool to verify that all code is linked to established specifications and established test procedures.</p></blockquote>
<p>Creating this documentation is well suited for automation. It still requires ensuring that all requirements and related test scenarios are properly tagged so they can be parsed to produce a release report.</p>
<h4>Software Design Evidence</h4>
<p>From the FDA guidance:</p>
<blockquote><p>The Quality System regulation requires that at least one formal design review be conducted during the device design process. However, it is recommended that multiple design reviews be conducted (e.g., at the end of each software life cycle activity, in preparation for proceeding to the next activity).</p></blockquote>
<p>This is a challenge for any Agile-based development process so is not specific to the FCT-based organization. Running formal design reviews as early in the development process as possible should be a team responsibility.</p>
<h4>Manual Approval Gates</h4>
<p>For many unregulated software products continuous integration (CI) and continuous delivery (CD) is a reality. I.e. Code can be pushed, run through the CI/CD pipelines, and delivered to customers without human intervention.</p>
<p>It is very unlikely (not impossible though I suppose, depending on the product) that this would occur for FDA-regulated software. Even with automated document generation, software deployment to production will still require human sign-off steps and audit trails.</p>
<h4>Off-The-Shelf (OTS) Software</h4>
<p>OTS/SOUP Software Validation documentation needs to be kept up-to-date. This is mostly a book-keeping exercise for OTS/SOUP that is part of the software product. For tools though, see <a href="https://bobonmedicaldevicesoftware.com/blog/2012/02/16/otssoup-software-validation-strategies/" target="_blank" rel="noopener">OTS/SOUP Software Validation Strategies</a>.</p>
<p>Another consideration to keep in mind for including 3rd party software into your product is the software license. The corporate (legal) policy should dictate license requirements, but teams would be aided by an automated tracking process.</p>
<h4>Infrastructure</h4>
<p>Installation, operational, and performance qualification -- <a href="https://www.thefdagroup.com/blog/a-basic-guide-to-iq-oq-pq-in-fda-regulated-industries" target="_blank" rel="noopener">IQ/OQ/PQ</a>. FDA regulated software must have these processes in place to ensure that after any changes are made, the infrastructure continues to meet quality requirements.  With the microservice architecture becoming a best practice, the team would now be responsible for documenting the IQ/OQ/PQ for their particular microservice or container flavor(s).</p>
<h4>Cloud Offerings</h4>
<p>Serverless architectures (Note: I'm most familiar with <a href="https://aws.amazon.com/" target="_blank" rel="noopener">AWS</a>, so will use their cloud products as examples. <a href="https://azure.microsoft.com" target="_blank" rel="noopener">Azure</a> and <a href="https://cloud.google.com/" target="_blank" rel="noopener">GCP</a> have similar offerings.) One of the key advantages of the <a href="https://aws.amazon.com/lambda/" target="_blank" rel="noopener">Lambda</a>, <a href="https://aws.amazon.com/fargate/" target="_blank" rel="noopener">Fargate</a>, <a href="https://aws.amazon.com/rds/" target="_blank" rel="noopener">RDS</a>, and similar managed/SaaS products is their <strong>undifferentiated heavy lifting</strong>.  AWS is responsible for the care and maintenance of the underlying infrastructure and servers. For on-prem servers, this is something the organization spends significant time and money on, but these expenditures do not directly benefit the customer.  Serverless allows companies to focus their efforts on things that make a difference to their customers.</p>
<p><em>How do you ensure IQ/OQ/PQ quality when you don't have control over the servers that are running your application(s)?</em></p>
<p>Another consideration: Teams will need to take regulatory impact into consideration when selecting new cloud technologies.</p>
<h4>Infrastructure as Code (<a href="https://en.wikipedia.org/wiki/Infrastructure_as_code" target="_blank" rel="noopener">IaC</a>)</h4>
<p>The use of IaC (e.g. <a href="https://aws.amazon.com/cloudformation/" target="_blank" rel="noopener">CloudFormation</a> or <a href="https://www.terraform.io/" target="_blank" rel="noopener">Terraform</a>) may require new release cycle processes. I.e since this code is not part of the application, you may want to have a separate release cycle for when the infrastructure is updated. The same is true for container (<a href="https://www.docker.com/" target="_blank" rel="noopener">Docker</a>) code updates.</p>
<p>The FCT should be responsible for the IaC associated with their product as it directly impacts both functionality and performance.</p>
<h4>Transformation</h4>
<p>When thinking about transforming to a FCT-based organization, the 2019 AWS re:invent keynote by Andy Jassy comes to mind. His "transformation" is referring to migrating from on-premise to cloud infrastructure (AWS, of course), but I think the non-technical transformation recommendations he outlines (start: <a href="https://youtu.be/7-31KgImGgU?list=PLhr1KZpdzukcAXSVwQ3L9cWD4QgKPCQ5S&amp;t=304" target="_blank" rel="noopener noreferrer">5:04</a> end <a href="https://youtu.be/7-31KgImGgU?list=PLhr1KZpdzukcAXSVwQ3L9cWD4QgKPCQ5S&amp;t=708" target="_blank" rel="noopener noreferrer">11:48</a>) are also applicable to the FCT organizational change:</p>
<p><a href="https://youtu.be/7-31KgImGgU?list=PLhr1KZpdzukcAXSVwQ3L9cWD4QgKPCQ5S&amp;t=304" target="_blank" rel="noopener"><img loading="lazy" decoding="async" class="aligncenter wp-image-923" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/01/re-invent.png" alt="" width="335" height="97" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/01/re-invent.png 1310w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/01/re-invent-300x87.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/01/re-invent-1024x296.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/01/re-invent-768x222.png 768w" sizes="auto, (max-width: 335px) 100vw, 335px" /></a></p>
<p>I think aggressive goals (item #2) is particularly important. Legacy organizations have a lot of inertia that needs to be overcome in order to move things forward. Breaking those initial barriers is even more difficult when you're having to deal with regulatory requirements.</p>
<h4>Bottom Line</h4>
<p>FDA regulatory requirements add tasks and documentation to the software release process. This has always been the case for medical device companies, but how this additional work is managed when trying to implement full-cycle teams can be a complicated problem to solve.</p>
<p>Just like unregulated development, providing the tooling to automate these tasks is the key to allow teams to deliver quality software to customers more quickly.</p>
<p>---------------</p>
<p><strong>*</strong>SRS, Software Requirements Specification. The old-school water-fall requirements document. I don't miss those days!</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/">Full Cycle Teams in a FDA regulated setting</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2021/01/04/full-cycle-teams-in-a-fda-regulated-setting/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>VirtualBox 6.1.x Windows 10 2004 Upgrade Problem Resolution</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Thu, 28 May 2020 21:40:32 +0000</pubDate>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Microsoft]]></category>
		<category><![CDATA[Virtualbox]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=952</guid>

					<description><![CDATA[<p>This is just a quick note that will hopefully save someone time. When I upgraded Windows 10 (64-bit) from 1909 to 2004 I found that Virtualbox 6.1.x no longer worked properly. All of my guest instances (Ubuntu, Mint, etc.) failed &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/">VirtualBox 6.1.x Windows 10 2004 Upgrade Problem Resolution</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">This is just a quick note that will hopefully save someone time.</p>
<p>When I upgraded Windows 10 (64-bit) from <strong>1909 to 2004</strong> I found that Virtualbox 6.1.x no longer worked properly. All of my guest instances (Ubuntu, Mint, etc.) failed to start. Specifically, they just <span style="color: #ff6600;">hung with a blinking cursor</span> and there were no errors in the logs.</p>
<p><del>There were no reports on this problem on the <a href="https://forums.virtualbox.org/viewforum.php?f=6" target="_blank" rel="noopener noreferrer">VirtualBox on Windows Hosts</a> forum</del>. [30-May-2020 Update] See <a href="https://forums.virtualbox.org/viewtopic.php?f=6&amp;t=98418" target="_blank" rel="noopener noreferrer">No VMs Work On Windows 10</a>.</p>
<p>It turns out that when Windows 10 2004 is installed it enables the <strong>Windows Hypervisor Platform</strong> feature. Note that the <strong>Hyper-V</strong> feature was disabled prior to the upgrade and remained so after.</p>
<p>To check this setting run <em><strong>OptionalFeatures.exe</strong></em> from a Windows command shell. You'll see this:</p>
<p><img loading="lazy" decoding="async" class="size-medium wp-image-954 aligncenter" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/05/win10-optional-features-300x266.png" alt="" width="300" height="266" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/05/win10-optional-features-300x266.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/05/win10-optional-features.png 411w" sizes="auto, (max-width: 300px) 100vw, 300px" /></p>
<p>The resolution to the hang problem is to <strong>disable this feature</strong>. Doing this is simple:</p>
<ol>
<li><strong>Uncheck</strong> the <em>Windows Hypervisor Platform</em> checkbox (above).</li>
<li><strong>Reboot</strong>. Even though it's not indicated when you do step #1, a reboot is required to disable the feature.</li>
</ol>
<p>That's it!</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/">VirtualBox 6.1.x Windows 10 2004 Upgrade Problem Resolution</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2020/05/28/virtualbox-6-1-x-windows-10-2004-upgrade-problem-resolution/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>314 Digits of Pi (Python to Clojure)</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Thu, 12 Mar 2020 15:03:39 +0000</pubDate>
				<category><![CDATA[Clojure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[PI Day]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=930</guid>

					<description><![CDATA[<p>Pi Day (3/14) is in a couple of days so I want to wish everyone a Happy Pi Day 2020! It's great to see that 55% of American's plan to celebrate and many will be eating pie or pi-themed food &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/">314 Digits of Pi (Python to Clojure)</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p><img loading="lazy" decoding="async" class="alignright wp-image-937" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/pi-symbol-2-150x150.jpg" alt="" width="100" height="100" /><span style="font-size: 1em;">Pi Day (3/14) is in a couple of days so I want to wish everyone a Happy </span><a style="font-size: 1em;" href="https://nationaltoday.com/national-pi-day/" target="_blank" rel="noopener noreferrer">Pi Day 2020</a><span style="font-size: 1em;">! It's great to see that 55% of American's plan to celebrate and many will be eating pie or pi-themed food (whatever that is).  </span></p>
<p>My work colleague and basketball buddy Stan sells a nerd t-shirt here: <a href="https://www.amazon.com/Stans-Geek-Tees-Digits-Pi-py/dp/B07BBGG9B5" target="_blank" rel="noopener noreferrer">314 Digits of Pi.py</a>. It has the Python code on the front and the results on the back. I "won" one of these at our annual White Elephant gift exchange in December. Even though the Amazon Best Sellers Rank is <strong>#12,306,667</strong> in Clothing, Shoes &amp; Jewelry, I really like it!</p>
<p>I've been staring at the code backward in the mirror for a number of months:</p>
<p><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-934" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/pi-tshirt.png" alt="" width="399" height="371" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/pi-tshirt.png 399w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/pi-tshirt-300x279.png 300w" sizes="auto, (max-width: 399px) 100vw, 399px" /></p>
<p>This got me wondering what this algorithm would look like in <a href="https://clojure.org/" target="_blank" rel="noopener noreferrer">Clojure</a>?</p>
<p>The first pass on the port was pretty straight forward, but I think it's worth noting some of the subtle differences. All of the code is here: <a href="https://github.com/rnadler/pi-digits" target="_blank" rel="noopener noreferrer">pi-digits</a>.</p>
<p>Here's the original Python code and result:</p><pre class="crayon-plain-tag">import math

def pi():
  r = 4*(4*arccot(5) - arccot(239))
  return str(r)[0] + '.' + str(r)[1:-5]

def arccot(x):
  total = power = 10**319 // x
  divisor = 1
  while abs(power) &gt;= divisor:
    power = -power // x**2
    divisor += 2
    total += power // divisor
  return total

print("314 digits of Pi " + pi())</pre><p></p><pre class="crayon-plain-tag">$ python3 pi.py
314 digits of Pi 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631</pre><p>For the interested, here's an explanation of the calculation of Pi using fixed point math for speed improvements: <a href="https://www.craig-wood.com/nick/articles/pi-machin/" target="_blank" rel="noopener noreferrer">Pi - Machin</a>: The Machin formula, developed by John Machin in 1706 (!), is:<br />
<img loading="lazy" decoding="async" class="aligncenter wp-image-932" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/machin-formula.png" alt="" width="195" height="45" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/machin-formula.png 414w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/machin-formula-300x69.png 300w" sizes="auto, (max-width: 195px) 100vw, 195px" /><br />
And here's a Clojure version that returns the identical result:</p><pre class="crayon-plain-tag">(ns pi-digits.core
  (:gen-class)
  (:require [clojure.math.numeric-tower :as math]))

(defn pow [b e] (math/expt b e))
(defn abs [n] (math/abs n))

(defn arccot
  [x]
  (let [power (atom (quot (pow 10 319) x))
        total (atom @power)
        divisor (atom 1)]
    (while (&gt;= (abs @power) @divisor)
      (do
        (swap! power #(quot (- %) (pow x 2)))
        (swap! divisor #(+ % 2))
        (swap! total #(+ % (quot @power @divisor)))))
    @total))

(defn pi
  "Calculate Pi to 314 digits"
  []
  (let [r (str (* 4 (- (* 4 (arccot 5)) (arccot 239))))]
    (str (subs r 0 1) "." (subs r 1 315))))

(defn -main
  [&amp; _]
  (println "314 digits of Pi" (pi)))</pre><p></p>
<ul>
<li>One thing I discovered is Python's use of an <a href="https://rushter.com/blog/python-integer-implementation/" target="_blank" rel="noopener noreferrer">arbitrary-precision integer implementation</a> that allows 10<sup>319 </sup>to actually have 319 digits of precision.  The use of <a href="https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#pow-double-double-" target="_blank" rel="noopener noreferrer">Java's double power implementation</a>, <pre class="crayon-plain-tag">(Math/pow b e)</pre> in Clojure, will not work because a <strong>double</strong> value can only represent about ± 10<sup>308</sup>.  Getting the required precision required the use of the <a href="https://github.com/clojure/math.numeric-tower" target="_blank" rel="noopener noreferrer">clojure/math.numeric-tower</a> library and the <pre class="crayon-plain-tag">(math/expt b e)</pre> function (<a href="https://github.com/clojure/math.numeric-tower/blob/master/src/main/clojure/clojure/math/numeric_tower.clj#L72" target="_blank" rel="noopener noreferrer">integer implementation</a> when e is a positive value).</li>
<li>The Clojure <a href="https://clojuredocs.org/clojure.core/quot" target="_blank" rel="noopener noreferrer">quot</a>[ient] does the same thing as Python's <a href="https://python-reference.readthedocs.io/en/latest/docs/operators/floor_division.html" target="_blank" rel="noopener noreferrer">floor division (//)</a> function.</li>
</ul>
<p>One problem with the <pre class="crayon-plain-tag">arccot</pre> (arc-cotangent) implementation is that it just duplicates the Python logic and is not idiomatic Clojure. Instead of coding this in a non-functional style, i.e. using mutable state (<a href="https://clojure.org/reference/atoms" target="_blank" rel="noopener noreferrer">atom</a>), let's create a functional version:</p><pre class="crayon-plain-tag">(defn arccot-recur
  [x]
  (loop [power (quot (pow 10 319) x)
         divisor  1
         tot 0]
    (let [total (+ tot (quot power divisor))]
      (if (&gt;= (abs power) divisor)
        (recur (quot (- power) (pow x 2)) (+ divisor 2) total)
        total))))</pre><p>We use <a href="http://clojurebridge.org/community-docs/docs/clojure/recur/" target="_blank" rel="noopener noreferrer">loop/recur</a> for a recursive implementation. This has the benefit of tail-call optimization (<a href="https://www.youtube.com/watch?v=RLqqGSthmC0" target="_blank" rel="noopener noreferrer">TCO</a>). Here are the execution times (average of 10 runs) for calculating Pi with the three implementations:<br />

<table id="tablepress-2" class="tablepress tablepress-id-2">
<thead>
<tr class="row-1">
	<th class="column-1">Method</th><th colspan="4" class="column-2">Digits<br />
Time in seconds</th>
</tr>
</thead>
<tbody class="row-hover">
<tr class="row-2">
	<td class="column-1"></td><td class="column-2">10,000</td><td class="column-3">50,000</td><td class="column-4">100,000</td><td class="column-5">200,000</td>
</tr>
<tr class="row-3">
	<td class="column-1">python</td><td class="column-2">0.158</td><td class="column-3">3.74</td><td class="column-4">14.9</td><td class="column-5">60.3</td>
</tr>
<tr class="row-4">
	<td class="column-1">clojure-while</td><td class="column-2">0.260</td><td class="column-3">5.14</td><td class="column-4">19.8</td><td class="column-5">78.6</td>
</tr>
<tr class="row-5">
	<td class="column-1">clojure-recur</td><td class="column-2">0.252</td><td class="column-3">5.10</td><td class="column-4">19.8</td><td class="column-5">78.5</td>
</tr>
</tbody>
</table>
<!-- #tablepress-2 from cache --></p>
<p><img loading="lazy" decoding="async" class=" wp-image-944 aligncenter" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/03/pi-calculation-times-300x165.png" alt="" width="487" height="268" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/03/pi-calculation-times-300x165.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/03/pi-calculation-times-1024x563.png 1024w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/03/pi-calculation-times-768x422.png 768w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/03/pi-calculation-times.png 1176w" sizes="auto, (max-width: 487px) 100vw, 487px" /></p>
<p>Python is certainly faster, but the purpose here was not to compare computation speed. It was to get a Clojure version of the t-shirt made! Who's the real nerd now? <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/">314 Digits of Pi (Python to Clojure)</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2020/03/12/314-digits-of-pi-python-to-clojure/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Bioimpedance Analysis to Detect Sleep Apnea</title>
		<link>https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/</link>
					<comments>https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/#respond</comments>
		
		<dc:creator><![CDATA[Bob]]></dc:creator>
		<pubDate>Tue, 11 Feb 2020 17:59:43 +0000</pubDate>
				<category><![CDATA[Medical Devices]]></category>
		<category><![CDATA[ICG]]></category>
		<guid isPermaLink="false">https://bobonmedicaldevicesoftware.com/blog/?p=938</guid>

					<description><![CDATA[<p>The company I worked for over 10 years ago, CardioDynamics*, manufactured an impedance cardiography (ICG) diagnostic device. The technology behind ICG and the Onera Bioimpedance Patch to Detect Sleep Apnea is called thoracic electrical bioimpedance (TEB). It's no surprise that &#8230; <a href="https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/">Continue reading <span class="meta-nav">&#8594;</span></a></p>
The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/">Bioimpedance Analysis to Detect Sleep Apnea</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></description>
										<content:encoded><![CDATA[<p>The company I worked for over 10 years ago, CardioDynamics*, manufactured an impedance cardiography (<a href="https://en.wikipedia.org/wiki/Impedance_cardiography" target="_blank" rel="noopener noreferrer">ICG</a>) diagnostic device. The technology behind ICG and the <a href="https://www.medgadget.com/2020/02/onera-bioimpedance-patch-to-detect-sleep-apnea.html" target="_blank" rel="noopener noreferrer">Onera Bioimpedance Patch to Detect Sleep Apnea</a> is called thoracic electrical bioimpedance (<a href="http://www.signavitae.com/2008/02/thoracic-electrical-bioimpedance-theory-and-clinical-possibilities-in-perioperative-medicine/" target="_blank" rel="noopener noreferrer">TEB</a>).</p>
<p><a href="https://www.onerahealth.com/" target="_blank" rel="noopener noreferrer"><img loading="lazy" decoding="async" class="aligncenter wp-image-940 size-medium" src="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/onera-patch-300x195.png" alt="" width="300" height="195" srcset="https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/onera-patch-300x195.png 300w, https://bobonmedicaldevicesoftware.com/blog/wp-content/uploads/2020/02/onera-patch.png 595w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a></p>
<p>It's no surprise that <a href="https://www.onerahealth.com/" target="_blank" rel="noopener noreferrer">Onera</a> has leveraged research on <span class="title-text">monitoring lung resistivity with this technology </span>(e.g. <a href="https://www.sciencedirect.com/science/article/abs/pii/S1746809418302301"><span class="title-text">here</span></a> and <a href="https://www.sciencedirect.com/science/article/abs/pii/S1350453306000427" target="_blank" rel="noopener noreferrer">here</a>) and is applying AI for automated respiratory event detection. Since electrode placement is important for reliable data acquisition, the patch is a good design choice, but it doesn't look like it would be that comfortable to wear to sleep.</p>
<p>Another review, <a href="https://spectrum.ieee.org/the-human-os/biomedical/devices/prototype-wearable-monitor-sleep-apnea-news" target="_blank" rel="noopener noreferrer">Wearable Patch Uses Machine Learning to Detect Sleep Apnea</a>, notes that assessing sleep apnea requires additional physiological signals to be monitored and that more work needs to be done to combine this technology with these other signals.</p>
<p>………………………………………………</p>
<p>*Purchased by <a href="https://www.sonosite.com/" target="_blank" rel="noopener noreferrer">SonoSite</a> in 2009. SonoSite has since <a href="https://www.sonosite.com/support/icg-resources" target="_blank" rel="noopener noreferrer">stopped</a> manufacturing the BioZ DX.</p>The post <a href="https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/">Bioimpedance Analysis to Detect Sleep Apnea</a> first appeared on <a href="https://bobonmedicaldevicesoftware.com/blog">Bob on Medical Device Software</a>.]]></content:encoded>
					
					<wfw:commentRss>https://bobonmedicaldevicesoftware.com/blog/2020/02/11/bioimpedance-analysis-to-detect-sleep-apnea/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>