Linux Fu: Fusing Hackaday [Hackaday]

View Article on Hackaday

Unix and, by extension, Linux, has a mantra to make everything possible look like a file. Files, of course, look like files. But also devices, network sockets, and even system information show up as things that appear to be files. There are plenty of advantages to doing that since you can use all the nice tools like grep and find to work with files. However, making your own programs expose a filesystem can be hard. Filesystem code traditionally works at the kernel module level, where mistakes can wipe out lots of things and debugging is difficult. However, there is FUSE — the file system in user space library — that allows you to write more or less ordinary code and expose anything you want as a file system. You’ve probably seen FUSE used to mount, say, remote drives via ssh or Dropbox. We’ve even looked at FUSE before, even for Windows.

What’s missing, naturally, is the Hackaday RSS feed, mountable as a normal file. And that’s what we’re building today.

Writing a FUSE filesystem isn’t that hard, but there are a lot of tedious jobs. You essentially have to provide callbacks that FUSE uses to do things when the operating system asks for them. Open a file, read a file, list a directory, etc. The problem is that for some simple projects, you don’t care about half of these things, but you still have to provide them.

Luckily, there are libraries that can make it a lot easier. I’m going to show you a simple C++ program that can mount your favorite RSS feed (assuming your favorite one is Hackaday, of course) as a file system. Granted, that’s not amazing, but it is kind of neat to be able to grep through the front page stories from the command line or view the last few articles using Dolphin.

Pick a Library

There are plenty of libraries and wrappers around FUSE. I picked one by [jachappell] over on GitHub. It was pretty simple and hides just enough of FUSE to be handy, but not so much as to be a problem. All the code is hidden around in Fuse.h.

One thing to note is that the library assumes you are using libfuse 3.0. If you don’t already have it, you’ll have to install the libfuse 3.0 development package from your package manager. There are other choices of libraries, of course, and you could just write to the underlying libfuse implementation, but a good library can make it much simpler to get started.

Just to keep things simple, I forked the original project on GitHub and added a fusehad directory.

Constraints

To keep things simple, I decided not to worry about performance too much. Since the data is traveling over the network, I do attempt to cache it, and I don’t refresh data later. Of course, you can’t write to the filesystem at all. This is purely for reading Hackaday.

These constraints make things easier. Of course, if you were writing your own filesystem, you might relax some of these, but it still helps to get something as simple as possible working first.

Making it Work First

Speaking of which, the first order of business is to be able to read the Hackaday RSS feed and pull out the parts we need. Again, not worrying about performance, I decided to do that with a pipe and calling out to curl. Yes, that’s cheating, but it works just fine, and that’s why we have tools in the first place.

The HaDFS.cpp file has a few functions related to FUSE and some helper functions, too. However, I wanted to focus on getting the RSS feed working so I put the related code into a function I made up called userinit. I found out the hard way that naming it init would conflict with the library.

The normal FUSE system processes your command line arguments — a good thing, as you’ll see soon. So the main in HaD.cpp is really simple:

#include 
#include "HaDFS.h"
int main(int argc, char *argv[])
{
  HaDFS fs;
  if (fs.userinit())
  {
    fprintf(stderr,"Can't fetch feedn");
    return 99;
  };
  int status;
  status= fs.run(argc, argv);
  return status;
}

However, for now, I simply commented out the line that calls fs.run. That left me with a simple program that just calls userinit.

Reading the feed isn’t that hard since I’m conscripting curl. Each topic is in a structure and there is an array of these structures. If you try to load too many stories, the code just quietly discards the excess (see MAXTOPIC). The topics global variable tells how many stories we’ve actually loaded.


// The curl line to read our feed
static char cmd[]="curl https://hackaday.com/feed/ 2>/dev/null | egrep '(;)|(<link>)'";
// User initialization--read the feed (note that init is reserved by the FUSE library)
int HaDFS::userinit(void)
{
   FILE *fp;
   char buf[1024]; // working buffer for reading strings
   if (!( fp = popen(cmd,"r") )) return 1; // open pipe
   while ( fgets(buf,sizeof(buf),fp) )
     {
     string line = buf;
     line = trimrss(line); // trim off extra stuff
     if ( line.substr(0,7) == "<title>" ) // identify line type and process
        {
        topic[topics].title = line.substr(7);
        topic[topics].title += ".html";
        }
    else if (line.substr(0,6)=="<link>")
        {
        topic[topics].url = line.substr(6);
        topics++;
        if ( topics == MAXTOPIC ) break; // quietly truncate a long feed
        }
    }
   pclose(fp);
   return 0;
} 
</pre>
<p>The <code>popen</code> function runs a command line and gives us the <code>stdout</code> stream as a bunch of lines. Processing the lines is just brute force looking for <title> and <link> to identify the data we need. I filtered <code>curl</code> through <code>grep</code> to make sure I didn’t get a lot of extra lines, by the way, and I assumed lowercase, but a <code>-i</code> option could easily fix that. The redirect is to prevent <code>curl</code> from polluting <code>stderr</code>, although normally FUSE will disconnect the output streams so it doesn’t really matter. Note that I add an HTML extension to each fake file name so opening one is more likely to get to the browser.</p>
<p>By putting a <code>printf</code> in the code I was able to make sure the feed fetching was working the way I expected. Note that I don’t fetch the actual pages until later in the process. For now, I just want the titles and the URL links.</p>
<h2>The Four Functions</h2>
<p>There are four functions we need to create in a subclass to get a minimal read-only filesystem going: <code>getattr</code>, <code>readdir</code>, <code>open</code>, and <code>read</code>. These functions pretty much do what you expect.  The <code>getattr</code> call will return 755 for our root (and only) directory and 444 for any other file that exists. The <code>readdir</code> outputs entries for . and .. along with our “files.” <code>Open</code> and <code>read</code> do just what you think they do.</p>
<p>There are some other functions, but those are ones I added to help myself:</p>
<ul>
<li><code>userinit</code> – Called to kick off the file system data</li>
<li><code>trimrss</code> – Trim an RSS line to make it easier to parse</li>
<li><code>pathfind</code> – Turn a file name into a descriptor (an index into the array of topics)</li>
<li><code>readurl</code> – Return a string with the contents of a URL (uses curl)</li>
</ul>
<p>There’s not much to it. You’ll see in the code that there are a few things to look out for like catching someone trying to write to a file since that isn’t allowed.</p>
<h2>Debugging and Command Line Options</h2>
<p>Of course, it doesn’t matter how simple it is, it isn’t going to work the first time is it? Of course, first, you have to remember to put the call to <code>fs.run</code> back in the main function. But, of course, things won’t work like you expect for any of a number of reasons. There are a few things to remember as you go about running and debugging.</p>
<p>When you build your executable, you simply run it and provide a command line argument to specify the mount point which, of course, should exist. I have a habit of using <code>/tmp/mnt</code> while debugging, but it can be anywhere you have permissions.</p>
<p>Under normal operation, FUSE detaches your program so you can’t just kill it. You’ll need to use unmount command (<code>fusermount -u</code>) with the mount point as an argument. Even if your program dies with a segment fault, you’ll need to use the unmount command or you will probably get the dreaded “disconnected endpoint” error message.</p>
<p>Being detached leads to a problem. If you put <code>printf</code> statements in your code, they will never show up after detachment. For this reason, FUSE understands the <code>-f</code> flag which tells the system to keep your filesystem running in the foreground. Then you can see messages and a clean exit, like a Control+C, will cleanly unmount the filesystem. You can also use <code>-d</code> which enables some built-in debugging and implies <code>-f</code>. The <code>-s</code> flag turns off threading which can make debugging easier, or harder if you are dealing with a thread-related problem.</p>
<p>You can use <code>gdb</code>, and there are some <a href="https://blog.jeffli.me/blog/2014/08/30/use-gdb-to-understand-fuse-file-system/" target="_blank" rel="noopener">good articles</a> about that. But for such a simple piece of code, it isn’t really necessary.</p>
<h2>What’s Next?</h2>
<p>The documentation for the library is almost nothing. However, the library closely mirrors the <code>libfuse</code> API so the documentation for that (mostly in <a href="http://libfuse.github.io/doxygen/fuse-3_810_84_2include_2fuse_8h.html" target="_blank" rel="noopener">fuse.h</a>) will help you go further. If you want to graduate from FUSE to a “real” file system, you have a long road. The video below gives some background on Linux VFS, but that’s just the start down that path.</p>
<p>Maybe stick to FUSE for a while. If you prefer Python, <a href="https://hackaday.com/2013/11/06/writing-a-fuse-filesystem-in-python/">no problem</a>. FUSE is very popular for mapping <a href="https://hackaday.com/2020/11/10/linux-fu-send-in-the-cloud-clones/">cloud storage into your filesystem</a>, but with your own coding, you could just as easily expose your Arduino or anything else your computer can communicate with.</p>
<div id=amzRelated style="border: 1px solid black ;">
<script type="text/javascript">
amzn_assoc_placement = "adunit0";
amzn_assoc_search_bar = "false";
amzn_assoc_tracking_id = "upmytech-20";
amzn_assoc_ad_mode = "search";
amzn_assoc_ad_type = "smart";
amzn_assoc_marketplace = "amazon";
amzn_assoc_region = "US";
amzn_assoc_title = "";
amzn_assoc_default_search_phrase = "Linux Hacks";
amzn_assoc_default_category = "All";
amzn_assoc_linkid = "db985b71e56cddbda9907a2dfaad6108";
</script><br />
<script src="//z-na.amazon-adsystem.com/widgets/onejs?MarketPlace=US"></script></div>
<hr />
<div id="tags" style="display: none;">Hackaday Columns,Linux Hacks,c++,fuse,linux</div>
<div id="randomtag" style="display: none;">Linux Hacks</div>
<div class="sharedaddy sd-sharing-enabled"><div class="robots-nocontent sd-block sd-social sd-social-icon sd-sharing"><h3 class="sd-title">Spread the word!</h3><div class="sd-content"><ul><li class="share-twitter"><a rel="nofollow noopener noreferrer" data-shared="sharing-twitter-50270" class="share-twitter sd-button share-icon no-text" href="https://upmytech.com/linux-fu-fusing-hackaday-hackaday/?share=twitter" target="_blank" title="Click to share on Twitter" ><span></span><span class="sharing-screen-reader-text">Click to share on Twitter (Opens in new window)</span></a></li><li class="share-facebook"><a rel="nofollow noopener noreferrer" data-shared="sharing-facebook-50270" class="share-facebook sd-button share-icon no-text" href="https://upmytech.com/linux-fu-fusing-hackaday-hackaday/?share=facebook" target="_blank" title="Click to share on Facebook" ><span></span><span class="sharing-screen-reader-text">Click to share on Facebook (Opens in new window)</span></a></li><li class="share-linkedin"><a rel="nofollow noopener noreferrer" data-shared="sharing-linkedin-50270" class="share-linkedin sd-button share-icon no-text" href="https://upmytech.com/linux-fu-fusing-hackaday-hackaday/?share=linkedin" target="_blank" title="Click to share on LinkedIn" ><span></span><span class="sharing-screen-reader-text">Click to share on LinkedIn (Opens in new window)</span></a></li><li class="share-end"></li></ul></div></div></div>
<div id='jp-relatedposts' class='jp-relatedposts' >
	
</div>   	</div>

   </div>

	</article>

			
		</div><!-- #content -->

      
		<ul class="default-wp-page clearfix">
			<li class="previous"><a href="https://upmytech.com/no-mans-skys-next-expansion-sentinel-entirely-overhauls-combat-techspot/" rel="prev"><span class="meta-nav">←</span> No Man’s Sky’s next expansion ‘Sentinel’ entirely overhauls combat [TechSpot]</a></li>
			<li class="next"><a href="https://upmytech.com/tiny-ethernet-cable-arms-race-spawns-from-reddit-discussion-hackaday/" rel="next">Tiny Ethernet Cable Arms Race Spawns From Reddit Discussion [Hackaday] <span class="meta-nav">→</span></a></li>
		</ul>
	
      
      


      
	</div><!-- #primary -->

	
<div id="secondary">
			
		<aside id="wpcom_social_media_icons_widget-2" class="widget widget_wpcom_social_media_icons_widget clearfix"><h3 class="widget-title"><span>Follow</span></h3><ul><li><a href="https://www.facebook.com/upmytech/" class="genericon genericon-facebook" target="_blank"><span class="screen-reader-text">View upmytech’s profile on Facebook</span></a></li><li><a href="https://twitter.com/upmytech/" class="genericon genericon-twitter" target="_blank"><span class="screen-reader-text">View upmytech’s profile on Twitter</span></a></li><li><a href="https://www.instagram.com/upmytech/" class="genericon genericon-instagram" target="_blank"><span class="screen-reader-text">View upmytech’s profile on Instagram</span></a></li><li><a href="https://www.youtube.com/channel/UCy6H6VOzIa0_L_xHAgQvDOA/" class="genericon genericon-youtube" target="_blank"><span class="screen-reader-text">View UCy6H6VOzIa0_L_xHAgQvDOA’s profile on YouTube</span></a></li></ul></aside><aside id="custom_html-4" class="widget_text widget widget_custom_html clearfix"><h3 class="widget-title"><span>Read</span></h3><div class="textwidget custom-html-widget"></div></aside><aside id="recent-posts-widget-with-thumbnails-2" class="widget recent-posts-widget-with-thumbnails clearfix">
<div id="rpwwt-recent-posts-widget-with-thumbnails-2" class="rpwwt-widget">
	<ul>
		<li><a href="https://upmytech.com/get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet/"><img width="130" height="90" src="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?resize=130%2C90&ssl=1" class="attachment-colormag-featured-post-small size-colormag-featured-post-small wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?resize=130%2C90&ssl=1 130w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?zoom=2&resize=130%2C90&ssl=1 260w" sizes="(max-width: 130px) 100vw, 130px" data-attachment-id="193415" data-permalink="https://upmytech.com/get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet/get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet-2/" data-orig-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?fit=300%2C169&ssl=1" data-orig-size="300,169" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="get-a-sitewide-20%-discount-at-urban-armor-gear-for-july-4th-[cnet]" data-image-description="<p>Get a Sitewide 20% Discount at Urban Armor Gear for July 4th [CNET]</p>
" data-image-caption="<p>Get a Sitewide 20% Discount at Urban Armor Gear for July 4th [CNET]</p>
" data-medium-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?fit=300%2C169&ssl=1" data-large-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193414-get-a-sitewide-20-discount-at-urban-armor-gear-for-july-4th-cnet.jpg?fit=300%2C169&ssl=1" tabindex="0" role="button" /><span class="rpwwt-post-title">Get a Sitewide 20% Discount at Urban Armor Gear for July 4th [CNET]</span></a></li>
		<li><a href="https://upmytech.com/epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet/"><img width="130" height="90" src="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?resize=130%2C90&ssl=1" class="attachment-colormag-featured-post-small size-colormag-featured-post-small wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?resize=130%2C90&ssl=1 130w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?zoom=2&resize=130%2C90&ssl=1 260w" sizes="(max-width: 130px) 100vw, 130px" data-attachment-id="193417" data-permalink="https://upmytech.com/epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet/epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet-2/" data-orig-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?fit=300%2C169&ssl=1" data-orig-size="300,169" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="epic-july-4th-laptop-sales:-deep-discounts-on-top-brands-like-apple,-lenovo,-hp-and-dell-[cnet]" data-image-description="<p>Epic July 4th Laptop Sales: Deep Discounts on Top-brands like Apple, Lenovo, HP and Dell [CNET]</p>
" data-image-caption="<p>Epic July 4th Laptop Sales: Deep Discounts on Top-brands like Apple, Lenovo, HP and Dell [CNET]</p>
" data-medium-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?fit=300%2C169&ssl=1" data-large-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193416-epic-july-4th-laptop-sales-deep-discounts-on-top-brands-like-apple-lenovo-hp-and-dell-cnet.jpg?fit=300%2C169&ssl=1" tabindex="0" role="button" /><span class="rpwwt-post-title">Epic July 4th Laptop Sales: Deep Discounts on Top-brands like Apple, Lenovo, HP and Dell [CNET]</span></a></li>
		<li><a href="https://upmytech.com/57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet/"><img width="130" height="90" src="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?resize=130%2C90&ssl=1" class="attachment-colormag-featured-post-small size-colormag-featured-post-small wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?resize=130%2C90&ssl=1 130w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?zoom=2&resize=130%2C90&ssl=1 260w" sizes="(max-width: 130px) 100vw, 130px" data-attachment-id="193419" data-permalink="https://upmytech.com/57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet/57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet-2/" data-orig-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?fit=300%2C169&ssl=1" data-orig-size="300,169" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="57-great-july-4th-sales-at-walmart:-home-goods,-tech,-video-games-and-more-[cnet]" data-image-description="<p>57 Great July 4th Sales at Walmart: Home Goods, Tech, Video Games and More [CNET]</p>
" data-image-caption="<p>57 Great July 4th Sales at Walmart: Home Goods, Tech, Video Games and More [CNET]</p>
" data-medium-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?fit=300%2C169&ssl=1" data-large-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193418-57-great-july-4th-sales-at-walmart-home-goods-tech-video-games-and-more-cnet.png?fit=300%2C169&ssl=1" tabindex="0" role="button" /><span class="rpwwt-post-title">57 Great July 4th Sales at Walmart: Home Goods, Tech, Video Games and More [CNET]</span></a></li>
		<li><a href="https://upmytech.com/from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat/"><img width="130" height="90" src="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?resize=130%2C90&ssl=1" class="attachment-colormag-featured-post-small size-colormag-featured-post-small wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?resize=392%2C272&ssl=1 392w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?resize=130%2C90&ssl=1 130w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?zoom=2&resize=130%2C90&ssl=1 260w" sizes="(max-width: 130px) 100vw, 130px" data-attachment-id="193413" data-permalink="https://upmytech.com/from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat/from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat-2/" data-orig-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?fit=1412%2C941&ssl=1" data-orig-size="1412,941" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="from-code-to-impact:-devs-unleash-ai-in-energy-at-crusoe’s-hackathon-[venturebeat]" data-image-description="<p>From code to impact: Devs unleash AI in energy at Crusoe’s hackathon [VentureBeat]</p>
" data-image-caption="<p>From code to impact: Devs unleash AI in energy at Crusoe’s hackathon [VentureBeat]</p>
" data-medium-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?fit=300%2C200&ssl=1" data-large-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193412-from-code-to-impact-devs-unleash-ai-in-energy-at-crusoes-hackathon-venturebeat.jpeg?fit=800%2C533&ssl=1" tabindex="0" role="button" /><span class="rpwwt-post-title">From code to impact: Devs unleash AI in energy at Crusoe’s hackathon [VentureBeat]</span></a></li>
		<li><a href="https://upmytech.com/shapeways-files-for-bankruptcy-hackaday/"><img width="130" height="90" src="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?resize=130%2C90&ssl=1" class="attachment-colormag-featured-post-small size-colormag-featured-post-small wp-post-image" alt="" decoding="async" loading="lazy" srcset="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?resize=392%2C272&ssl=1 392w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?resize=130%2C90&ssl=1 130w, https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?zoom=2&resize=130%2C90&ssl=1 260w" sizes="(max-width: 130px) 100vw, 130px" data-attachment-id="193407" data-permalink="https://upmytech.com/shapeways-files-for-bankruptcy-hackaday/shapeways-files-for-bankruptcy-hackaday-2/" data-orig-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?fit=1884%2C724&ssl=1" data-orig-size="1884,724" data-comments-opened="1" data-image-meta="{"aperture":"0","credit":"","camera":"","caption":"","created_timestamp":"0","copyright":"","focal_length":"0","iso":"0","shutter_speed":"0","title":"","orientation":"0"}" data-image-title="shapeways-files-for-bankruptcy-[hackaday]" data-image-description="<p>Shapeways Files for Bankruptcy [Hackaday]</p>
" data-image-caption="<p>Shapeways Files for Bankruptcy [Hackaday]</p>
" data-medium-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?fit=300%2C115&ssl=1" data-large-file="https://i0.wp.com/upmytech.com/wp-content/uploads/2024/07/193406-shapeways-files-for-bankruptcy-hackaday.png?fit=800%2C308&ssl=1" tabindex="0" role="button" /><span class="rpwwt-post-title">Shapeways Files for Bankruptcy [Hackaday]</span></a></li>
	</ul>
</div><!-- .rpwwt-widget -->
</aside><aside id="custom_html-2" class="widget_text widget widget_custom_html clearfix"><div class="textwidget custom-html-widget"><hr />
<p style="font-size:80%">Advertisements
</p>
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=1&p=12&l=ur1&category=electronics&banner=1RJ5QAT5B55ECPXSXB82&f=ifr&linkID=a74bec50546615affd9111077ebf3b00&t=upmytech-20&tracking_id=upmytech-20" width="300" height="250" scrolling="no" border="0" marginwidth="0" style="border:none;" frameborder="0"></iframe>
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=1&p=12&l=ur1&category=primegift&banner=10BSGCHPCJG0HZN45H82&f=ifr&lc=pf4&linkID=24735b4c4411b0336703554c3ac4385e&t=upmytech-20&tracking_id=upmytech-20" width="300" height="250" scrolling="no" border="0" marginwidth="0" style="border:none;" frameborder="0"></iframe>
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=1&p=12&l=ur1&category=amzn_music_bounty&banner=01ZTJ18Y6PDZG4QH4NG2&f=ifr&linkID=261ef33001b0b1d4d2f404c0785d8f0b&t=upmytech-20&tracking_id=upmytech-20" width="300" height="250" scrolling="no" border="0" marginwidth="0" style="border:none;" frameborder="0"></iframe>
<iframe src="//rcm-na.amazon-adsystem.com/e/cm?o=1&p=12&l=ur1&category=kuft&banner=07V9YHKS4HY556H67002&f=ifr&lc=pf4&linkID=7b42f56caeead9edad3b2019786434bc&t=upmytech-20&tracking_id=upmytech-20" width="300" height="250" scrolling="no" border="0" marginwidth="0" style="border:none;" frameborder="0"></iframe>

</div></aside><aside id="custom_html-3" class="widget_text widget widget_custom_html clearfix"><div class="textwidget custom-html-widget"></div></aside>
	</div>
	

</div><!-- .inner-wrap -->
</div><!-- #main -->




<footer id="colophon" class="clearfix colormag-footer--classic">
	
	<div class="footer-socket-wrapper clearfix">
		<div class="inner-wrap">
			<div class="footer-socket-area">
				<div class="footer-socket-right-section">
									</div>

				<div class="footer-socket-left-section">
					<div class="copyright">Copyright © 2024 <a href="https://upmytech.com/" title="Up My Tech" ><span>Up My Tech</span></a>. All rights reserved.<br>Theme: ColorMag by <a href="https://themegrill.com/themes/colormag" target="_blank" title="ThemeGrill" rel="author"><span>ThemeGrill</span></a>. Powered by <a href="https://wordpress.org" target="_blank" title="WordPress"><span>WordPress</span></a>.</div>				</div>
			</div>
		</div>
	</div>
</footer>

<a href="#masthead" id="scroll-up"><i class="fa fa-chevron-up"></i></a>

</div><!-- #page -->
		<div id="jp-carousel-loading-overlay">
			<div id="jp-carousel-loading-wrapper">
				<span id="jp-carousel-library-loading"> </span>
			</div>
		</div>
		<div class="jp-carousel-overlay" style="display: none;">

		<div class="jp-carousel-container">
			<!-- The Carousel Swiper -->
			<div
				class="jp-carousel-wrap swiper-container jp-carousel-swiper-container jp-carousel-transitions"
				itemscope
				itemtype="https://schema.org/ImageGallery">
				<div class="jp-carousel swiper-wrapper"></div>
				<div class="jp-swiper-button-prev swiper-button-prev">
					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
						<mask id="maskPrev" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="9" height="12">
							<path d="M16.2072 16.59L11.6496 12L16.2072 7.41L14.8041 6L8.8335 12L14.8041 18L16.2072 16.59Z" fill="white"/>
						</mask>
						<g mask="url(#maskPrev)">
							<rect x="0.579102" width="23.8823" height="24" fill="#FFFFFF"/>
						</g>
					</svg>
				</div>
				<div class="jp-swiper-button-next swiper-button-next">
					<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
						<mask id="maskNext" mask-type="alpha" maskUnits="userSpaceOnUse" x="8" y="6" width="8" height="12">
							<path d="M8.59814 16.59L13.1557 12L8.59814 7.41L10.0012 6L15.9718 12L10.0012 18L8.59814 16.59Z" fill="white"/>
						</mask>
						<g mask="url(#maskNext)">
							<rect x="0.34375" width="23.8822" height="24" fill="#FFFFFF"/>
						</g>
					</svg>
				</div>
			</div>
			<!-- The main close buton -->
			<div class="jp-carousel-close-hint">
				<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
					<mask id="maskClose" mask-type="alpha" maskUnits="userSpaceOnUse" x="5" y="5" width="15" height="14">
						<path d="M19.3166 6.41L17.9135 5L12.3509 10.59L6.78834 5L5.38525 6.41L10.9478 12L5.38525 17.59L6.78834 19L12.3509 13.41L17.9135 19L19.3166 17.59L13.754 12L19.3166 6.41Z" fill="white"/>
					</mask>
					<g mask="url(#maskClose)">
						<rect x="0.409668" width="23.8823" height="24" fill="#FFFFFF"/>
					</g>
				</svg>
			</div>
			<!-- Image info, comments and meta -->
			<div class="jp-carousel-info">
				<div class="jp-carousel-info-footer">
					<div class="jp-carousel-pagination-container">
						<div class="jp-swiper-pagination swiper-pagination"></div>
						<div class="jp-carousel-pagination"></div>
					</div>
					<div class="jp-carousel-photo-title-container">
						<h2 class="jp-carousel-photo-caption"></h2>
					</div>
					<div class="jp-carousel-photo-icons-container">
						<a href="#" class="jp-carousel-icon-btn jp-carousel-icon-info" aria-label="Toggle photo metadata visibility">
							<span class="jp-carousel-icon">
								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
									<mask id="maskInfo" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20">
										<path fill-rule="evenodd" clip-rule="evenodd" d="M12.7537 2C7.26076 2 2.80273 6.48 2.80273 12C2.80273 17.52 7.26076 22 12.7537 22C18.2466 22 22.7046 17.52 22.7046 12C22.7046 6.48 18.2466 2 12.7537 2ZM11.7586 7V9H13.7488V7H11.7586ZM11.7586 11V17H13.7488V11H11.7586ZM4.79292 12C4.79292 16.41 8.36531 20 12.7537 20C17.142 20 20.7144 16.41 20.7144 12C20.7144 7.59 17.142 4 12.7537 4C8.36531 4 4.79292 7.59 4.79292 12Z" fill="white"/>
									</mask>
									<g mask="url(#maskInfo)">
										<rect x="0.8125" width="23.8823" height="24" fill="#FFFFFF"/>
									</g>
								</svg>
							</span>
						</a>
												<a href="#" class="jp-carousel-icon-btn jp-carousel-icon-comments" aria-label="Toggle photo comments visibility">
							<span class="jp-carousel-icon">
								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
									<mask id="maskComments" mask-type="alpha" maskUnits="userSpaceOnUse" x="2" y="2" width="21" height="20">
										<path fill-rule="evenodd" clip-rule="evenodd" d="M4.3271 2H20.2486C21.3432 2 22.2388 2.9 22.2388 4V16C22.2388 17.1 21.3432 18 20.2486 18H6.31729L2.33691 22V4C2.33691 2.9 3.2325 2 4.3271 2ZM6.31729 16H20.2486V4H4.3271V18L6.31729 16Z" fill="white"/>
									</mask>
									<g mask="url(#maskComments)">
										<rect x="0.34668" width="23.8823" height="24" fill="#FFFFFF"/>
									</g>
								</svg>

								<span class="jp-carousel-has-comments-indicator" aria-label="This image has comments."></span>
							</span>
						</a>
											</div>
				</div>
				<div class="jp-carousel-info-extra">
					<div class="jp-carousel-info-content-wrapper">
						<div class="jp-carousel-photo-title-container">
							<h2 class="jp-carousel-photo-title"></h2>
						</div>
						<div class="jp-carousel-comments-wrapper">
															<div id="jp-carousel-comments-loading">
									<span>Loading Comments...</span>
								</div>
								<div class="jp-carousel-comments"></div>
								<div id="jp-carousel-comment-form-container">
									<span id="jp-carousel-comment-form-spinner"> </span>
									<div id="jp-carousel-comment-post-results"></div>
																														<form id="jp-carousel-comment-form">
												<label for="jp-carousel-comment-form-comment-field" class="screen-reader-text">Write a Comment...</label>
												<textarea
													name="comment"
													class="jp-carousel-comment-form-field jp-carousel-comment-form-textarea"
													id="jp-carousel-comment-form-comment-field"
													placeholder="Write a Comment..."
												></textarea>
												<div id="jp-carousel-comment-form-submit-and-info-wrapper">
													<div id="jp-carousel-comment-form-commenting-as">
																													<fieldset>
																<label for="jp-carousel-comment-form-email-field">Email (Required)</label>
																<input type="text" name="email" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-email-field" />
															</fieldset>
															<fieldset>
																<label for="jp-carousel-comment-form-author-field">Name (Required)</label>
																<input type="text" name="author" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-author-field" />
															</fieldset>
															<fieldset>
																<label for="jp-carousel-comment-form-url-field">Website</label>
																<input type="text" name="url" class="jp-carousel-comment-form-field jp-carousel-comment-form-text-field" id="jp-carousel-comment-form-url-field" />
															</fieldset>
																											</div>
													<input
														type="submit"
														name="submit"
														class="jp-carousel-comment-form-button"
														id="jp-carousel-comment-form-button-submit"
														value="Post Comment" />
												</div>
											</form>
																											</div>
													</div>
						<div class="jp-carousel-image-meta">
							<div class="jp-carousel-title-and-caption">
								<div class="jp-carousel-photo-info">
									<h3 class="jp-carousel-caption" itemprop="caption description"></h3>
								</div>

								<div class="jp-carousel-photo-description"></div>
							</div>
							<ul class="jp-carousel-image-exif" style="display: none;"></ul>
							<a class="jp-carousel-image-download" href="#" target="_blank" style="display: none;">
								<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
									<mask id="mask0" mask-type="alpha" maskUnits="userSpaceOnUse" x="3" y="3" width="19" height="18">
										<path fill-rule="evenodd" clip-rule="evenodd" d="M5.84615 5V19H19.7775V12H21.7677V19C21.7677 20.1 20.8721 21 19.7775 21H5.84615C4.74159 21 3.85596 20.1 3.85596 19V5C3.85596 3.9 4.74159 3 5.84615 3H12.8118V5H5.84615ZM14.802 5V3H21.7677V10H19.7775V6.41L9.99569 16.24L8.59261 14.83L18.3744 5H14.802Z" fill="white"/>
									</mask>
									<g mask="url(#mask0)">
										<rect x="0.870605" width="23.8823" height="24" fill="#FFFFFF"/>
									</g>
								</svg>
								<span class="jp-carousel-download-text"></span>
							</a>
							<div class="jp-carousel-image-map" style="display: none;"></div>
						</div>
					</div>
				</div>
			</div>
		</div>

		</div>
		
	<script type="text/javascript">
		window.WPCOM_sharing_counts = {"https:\/\/upmytech.com\/linux-fu-fusing-hackaday-hackaday\/":50270};
	</script>
				<link rel='stylesheet' id='genericons-css' href='https://c0.wp.com/p/jetpack/13.6/_inc/genericons/genericons/genericons.css' type='text/css' media='all' />
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/jquery.bxslider.min.js?ver=4.2.10" id="colormag-bxslider-js"></script>
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/navigation.js?ver=6.5.5" id="colormag-navigation-js"></script>
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/sticky/jquery.sticky.js?ver=20150309" id="colormag-sticky-menu-js"></script>
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/fitvids/jquery.fitvids.js?ver=20150311" id="colormag-fitvids-js"></script>
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/skip-link-focus-fix.js?ver=6.5.5" id="colormag-skip-link-focus-fix-js"></script>
<script type="text/javascript" src="https://upmytech.com/wp-content/themes/colormag/js/colormag-custom.js?ver=6.5.5" id="colormag-custom-js"></script>
<script type="text/javascript" src="https://stats.wp.com/e-202427.js" id="jetpack-stats-js" data-wp-strategy="defer"></script>
<script type="text/javascript" id="jetpack-stats-js-after">
/* <![CDATA[ */
_stq = window._stq || [];
_stq.push([ "view", JSON.parse("{\"v\":\"ext\",\"blog\":\"133080443\",\"post\":\"50270\",\"tz\":\"0\",\"srv\":\"upmytech.com\",\"j\":\"1:13.6\"}") ]);
_stq.push([ "clickTrackerInit", "133080443", "50270" ]);
/* ]]> */
</script>
<script type="text/javascript" id="jetpack-carousel-js-extra">
/* <![CDATA[ */
var jetpackSwiperLibraryPath = {"url":"https:\/\/upmytech.com\/wp-content\/plugins\/jetpack\/_inc\/build\/carousel\/swiper-bundle.min.js"};
var jetpackCarouselStrings = {"widths":[370,700,1000,1200,1400,2000],"is_logged_in":"","lang":"en","ajaxurl":"https:\/\/upmytech.com\/wp-admin\/admin-ajax.php","nonce":"7a4ea063e1","display_exif":"1","display_comments":"1","single_image_gallery":"1","single_image_gallery_media_file":"","background_color":"black","comment":"Comment","post_comment":"Post Comment","write_comment":"Write a Comment...","loading_comments":"Loading Comments...","download_original":"View full size <span class=\"photo-size\">{0}<span class=\"photo-size-times\">\u00d7<\/span>{1}<\/span>","no_comment_text":"Please be sure to submit some text with your comment.","no_comment_email":"Please provide an email address to comment.","no_comment_author":"Please provide your name to comment.","comment_post_error":"Sorry, but there was an error posting your comment. Please try again later.","comment_approved":"Your comment was approved.","comment_unapproved":"Your comment is in moderation.","camera":"Camera","aperture":"Aperture","shutter_speed":"Shutter Speed","focal_length":"Focal Length","copyright":"Copyright","comment_registration":"0","require_name_email":"1","login_url":"https:\/\/upmytech.com\/wp-login.php?redirect_to=https%3A%2F%2Fupmytech.com%2Flinux-fu-fusing-hackaday-hackaday%2F","blog_id":"1","meta_data":["camera","aperture","shutter_speed","focal_length","copyright"]};
/* ]]> */
</script>
<script type="text/javascript" src="https://c0.wp.com/p/jetpack/13.6/_inc/build/carousel/jetpack-carousel.min.js" id="jetpack-carousel-js"></script>
<script type="text/javascript" id="sharing-js-js-extra">
/* <![CDATA[ */
var sharing_js_options = {"lang":"en","counts":"1","is_stats_active":"1"};
/* ]]> */
</script>
<script type="text/javascript" src="https://c0.wp.com/p/jetpack/13.6/_inc/build/sharedaddy/sharing.min.js" id="sharing-js-js"></script>
<script type="text/javascript" id="sharing-js-js-after">
/* <![CDATA[ */
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches && el.matches( sel ) ||
						el.msMatchesSelector && el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-twitter' ) ) {
						el = event.target;
					} else if ( event.target.parentNode && matches( event.target.parentNode, 'a.share-twitter' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomtwitter', 'menubar=1,resizable=1,width=600,height=350' );
						return false;
					}
				} );
			} )();
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches && el.matches( sel ) ||
						el.msMatchesSelector && el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-facebook' ) ) {
						el = event.target;
					} else if ( event.target.parentNode && matches( event.target.parentNode, 'a.share-facebook' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomfacebook', 'menubar=1,resizable=1,width=600,height=400' );
						return false;
					}
				} );
			} )();
var windowOpen;
			( function () {
				function matches( el, sel ) {
					return !! (
						el.matches && el.matches( sel ) ||
						el.msMatchesSelector && el.msMatchesSelector( sel )
					);
				}

				document.body.addEventListener( 'click', function ( event ) {
					if ( ! event.target ) {
						return;
					}

					var el;
					if ( matches( event.target, 'a.share-linkedin' ) ) {
						el = event.target;
					} else if ( event.target.parentNode && matches( event.target.parentNode, 'a.share-linkedin' ) ) {
						el = event.target.parentNode;
					}

					if ( el ) {
						event.preventDefault();

						// If there's another sharing window open, close it.
						if ( typeof windowOpen !== 'undefined' ) {
							windowOpen.close();
						}
						windowOpen = window.open( el.getAttribute( 'href' ), 'wpcomlinkedin', 'menubar=1,resizable=1,width=580,height=450' );
						return false;
					}
				} );
			} )();
/* ]]> */
</script>
</body>
</html>