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

<channel>
	<title>Code Optimization | Taylor Design</title>
	<atom:link href="https://www.taylordesign.net/category/code-optimization/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.taylordesign.net</link>
	<description>Software Development</description>
	<lastBuildDate>Mon, 20 Sep 2021 09:12:46 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.4.2</generator>
	<item>
		<title>Plagiarizing Save Humanity</title>
		<link>https://www.taylordesign.net/code-optimization/plagiarizing-save-humanity/</link>
					<comments>https://www.taylordesign.net/code-optimization/plagiarizing-save-humanity/#respond</comments>
		
		<dc:creator><![CDATA[Daniel L. Taylor]]></dc:creator>
		<pubDate>Fri, 18 Dec 2020 13:16:48 +0000</pubDate>
				<category><![CDATA[Code Optimization]]></category>
		<guid isPermaLink="false">https://www.taylordesign.net/?p=7089</guid>

					<description><![CDATA[I shouldn&#8217;t care about something so small. I really shouldn&#8217;t. The world is in the midst of a horrific pandemic which has triggered a severe economic recession. There are riots, clashes between citizens and their governments, and chaotic events occurring everywhere. And what I&#8217;m about to discuss is so small in light of everything going [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I shouldn&#8217;t care about something so small. I really shouldn&#8217;t. The world is in the midst of a horrific pandemic which has triggered a severe economic recession. There are riots, clashes between citizens and their governments, and chaotic events occurring everywhere. And what I&#8217;m about to discuss is so small in light of everything going on in the world that I really shouldn&#8217;t care.</p>
<p>And yet&#8230;I do.</p>
<p>I haven&#8217;t been doing any challenges on <a href="https://www.hackerrank.com/" target="_blank" rel="noopener noreferrer">HackerRank</a> in a while due to lack of free time. But I still login from time to time when I get an email alert about new comments in the challenge discussions. When I logged in tonight I discovered that one Shehan Jayalath had taken my <a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b8.c" target="_blank" rel="noopener noreferrer">B8 solution</a> from <a href="https://www.taylordesign.net/code-optimization/saving-humanity/" target="_blank" rel="noopener noreferrer">Saving Humanity (By Vectorizing The ALU)</a>, stripped the header, and posted it in the challenge discussion as if it was his own. Sure enough, when I looked him up on the Leaderboard he had also submitted my solution verbatim to get a free 100 points.</p>
<p>And companies wonder why they <a href="https://letterstoanewdeveloper.com/2019/08/23/the-surprising-number-of-programmers-who-cant-program/" target="_blank" rel="noopener noreferrer">struggle to find programmers who can actually program.</a></p>
<p>Shehan Jayalath&#8217;s post to the discussion forum can be found <a href="https://www.hackerrank.com/challenges/save-humanity/forum/comments/809600" target="_blank" rel="noopener noreferrer">here.</a> My reply can be found <a href="https://www.hackerrank.com/challenges/save-humanity/forum/comments/899071" target="_blank" rel="noopener noreferrer">here.</a> And if you&#8217;re logged into HackerRank you can see that Jayalath used my solution for free points <a href="https://www.hackerrank.com/rest/contests/master/challenges/save-humanity/hackers/shehanjayalath/download_solution" target="_blank" rel="noopener noreferrer">here.</a></p>
<p>Now, I&#8217;m not naive. I am aware that plenty of people copy/paste their way to points and awards on HackerRank. (If you&#8217;re a prospective employer looking at anything from HackerRank on a candidate&#8217;s resume, you should be aware of this too.) And I knew when I made my blog post that the solutions would be copy/pasted into HackerRank for free points. Some people go there to learn, some people go there to build fake points and awards. It is what it is.</p>
<p>But if you&#8217;re going to post another person&#8217;s solution in the Discussion tab, <em>have the decency to attribute it to them.</em></p>
<p>And if you&#8217;re reading <em>anything I have to say about HackerRank challenges</em> I hope you have the self respect to use my posts and code in order to learn and not to cheat. If you like my approach, try re-writing it yourself without having mine open as a reference. See what you can improve. Earn the points. Don&#8217;t just copy/paste.</p>
<p>And do not ever publicly claim anyone else&#8217;s work as your own, on HackerRank or any where else.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.taylordesign.net/code-optimization/plagiarizing-save-humanity/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Saving Humanity (By Vectorizing The ALU)</title>
		<link>https://www.taylordesign.net/code-optimization/saving-humanity/</link>
					<comments>https://www.taylordesign.net/code-optimization/saving-humanity/#respond</comments>
		
		<dc:creator><![CDATA[Daniel L. Taylor]]></dc:creator>
		<pubDate>Mon, 21 Jan 2019 01:13:51 +0000</pubDate>
				<category><![CDATA[Code Optimization]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[code challenges]]></category>
		<category><![CDATA[HackerRank]]></category>
		<category><![CDATA[SSE2]]></category>
		<category><![CDATA[string search]]></category>
		<category><![CDATA[vector processing]]></category>
		<guid isPermaLink="false">http://www.taylordesign.net/?p=4469</guid>

					<description><![CDATA[The Challenge Oh!! Mankind is in trouble again. This time, it&#8217;s a deadly disease spreading at a rate never seen before. The need of the hour is to set up efficient virus detectors. You are the lead at Central Hospital and you need to find a fast and reliable way to detect the footprints of [&#8230;]]]></description>
										<content:encoded><![CDATA[<h3>The Challenge</h3>
<blockquote><p><em>Oh!! Mankind is in trouble again. This time, it&#8217;s a deadly disease spreading at a rate never seen before. The need of the hour is to set up efficient virus detectors. You are the lead at Central Hospital and you need to find a fast and reliable way to detect the footprints of the virus DNA in that of the patient.</em></p></blockquote>
<p>The HackerRank challenge <a href="https://www.hackerrank.com/challenges/save-humanity" target="_blank" rel="noopener noreferrer">Save Humanity</a> can be summarized as follows:</p>
<ul>
<li>You are given two strings of lowercase letters a-z. We&#8217;ll call them dnaP and dnaV.</li>
<li>You have to return the starting index (0-based) of every occurrence of dnaV in dnaP.</li>
<li>dnaV matches a substring in dnaP if all characters match, or if all characters but one match.</li>
</ul>
<p>This challenge is ranked as expert with a 100 point award. As of the day this post was published only 12.94% of submissions have succeeded, and the Discussion tab is filled with the laments of those who timeout on the most difficult test files.</p>
<p>I coded a solution in less than 15 minutes. (Cue the anger and wrath of anyone who is stuck on this challenge.)</p>
<p>To be fair, I did not initially code an <em>optimal</em> solution. I guessed when I read the challenge that an optimal solution would involve something like a <a href="http://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/" target="_blank" rel="noopener noreferrer">z-algorithm</a>, a <a href="http://www.geeksforgeeks.org/suffix-array-set-1-introduction/" target="_blank" rel="noopener noreferrer">suffix array</a>, or <a href="https://www.google.com/search?q=tree&amp;num=30&amp;source=lnms&amp;tbm=isch" target="_blank" rel="noopener noreferrer">some form of tree</a>. But I had a hunch there was an easier way to get 100 points.</p>
<h3>First Draft</h3>
<p>With this class of challenge it&#8217;s a sure bet that a <a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b1.c" target="_blank" rel="noopener">brute force solution</a> will timeout. Since the brute force approach is trivial to code I went ahead and tried it to verify that I wasn&#8217;t missing anything about the problem, and so that I could use my hackos to purchase test files.</p>
<p>It timed out on 5 of the test files but succeeded on the others. I bought the files, ran some tests on my MBP, and confirmed my hunch.</p>
<h3>Go Big or Go Home, Brutus</h3>
<p>The obvious brute force solution is to compare each character in dnaV to each character in dnaP and stop if there&#8217;s more than one mismatch. This of course has to be done repeatedly starting at each character index in dnaP. It&#8217;s the repeat comparisons that drive the processing time up, and an optimal solution would find a way to eliminate as many repeat comparisons as possible.</p>
<p>But there&#8217;s another problem with the brute force solution: it&#8217;s comparing one character at a time on a 64-bit processor which can compare 8 characters at a time using the ALU. Situations like this are why <em><a href="https://www.taylordesign.net/wp-content/uploads/2017/04/love_c.jpg" target="_blank" rel="noopener noreferrer">I freaking love C.</a></em> I took my solution and <a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b8.c" target="_blank" rel="noopener">modified it as follows:</a></p>
<ul>
<li>Cast the char pointers dnaP and dnaV to long long pointers.</li>
<li>Compare the character arrays as arrays of long long, essentially vectorizing the ALU.</li>
<li>If there&#8217;s a mismatch, drop down into a loop which examines the 8 characters at that position to count the mismatches.</li>
</ul>
<p>In C these were trivial modifications to make and they brought the worst time down to 1.17s for test file 7, passing the challenge with time to spare. We&#8217;ll call this the B8 solution (brute force 8-byte compares) and the original solution B1 (brute force 1-byte compares).</p>
<p>Having solved the challenge I wanted to explore the solution further to see if I could make it faster than the editorial solution on the longer test files (3-9).</p>
<h3>Saving Humanity with the Vector Processor</h3>
<p>The obvious next step in improving the brute force approach is to compare more than 8 bytes per iteration. SSE2 has instructions which can compare 16 bytes at a time. Initially I tried to both compare the values and get a count of mismatches all using SSE2 instructions. However, this proved to be slower than simply performing the compare and counting the mismatches normally if the SSE2 result indicated any mismatches at all. <a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b16.c" target="_blank" rel="noopener">The B16 solution</a> is therefore the same as the B8 solution, it just compares 16-bytes at a time.</p>
<p>Test file 7 is again the worst case and the B16 solution is able to process it in 0.68 seconds. That&#8217;s roughly 1.7x faster than using the ALU.</p>
<p>Later extensions to x86-64 vector processing added support for 256-bit operations (AVX2) and 512-bit operations (AVX-512). Unfortunately my MBP processor does not support AVX-512. It does support AVX2, but using 256-bit loads and compares slowed down all test files except 8 and 9, which saw a very slight performance gain. I suspect this has something to do with the algorithm&#8217;s inherent lack of alignment on 32-byte boundaries.</p>
<h3>Beating the Editorial Solution</h3>
<p>I won&#8217;t go into detail on the editorial solution here since HackerRank hides the editorial until you either get your points or forfeit those points in order to see the solution. Suffice it to say that the editorial solution involves the use of a suffix array.</p>
<p>The editorial solution is 3-4x faster than the B16 solution on files 3-7. But on test files 8 and 9 B16 is nearly 21x faster. Even brute force using single byte compares is faster than the editorial here by a factor of 3x. What&#8217;s going on?</p>
<p>Test files 3-7 involve very long repetitions of the letter &#8216;a&#8217; with a few other characters interspersed in the text to form a pattern. Test files 8 and 9 involve long repetitions of the <em>alphabet</em> with a few other characters interspersed. The brute force solutions have to repeatedly compare a large percentage of the bytes in test files 3-7. But on test files 8 and 9, 25 out of every 26 comparisons end on the 2nd byte being compared. Here the brute force solutions aren&#8217;t comparing nearly as many bytes as the editorial solution which has to sort the suffix array for it to be useful.</p>
<p>To deal with the high character repetition in some of the test files I <a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b16r.c" target="_blank" rel="noopener">made the following modifications</a> to the B16 solution. We&#8217;ll call this version B16R.</p>
<ul>
<li>Allocate an array of integers for both dnaP and dnaV.</li>
<li>Scan the strings from end to beginning counting repeat characters and storing the counts in the arrays.</li>
<li>Now at any given character position we can look at the corresponding integer arrays and see how many times the character will repeat in both dnaP and dnaV.</li>
<li>The string matching loop can use this information to jump ahead any time it finds a suitable repetition.</li>
</ul>
<h3>Mission Accomplished</h3>

<table id="tablepress-2" class="tablepress tablepress-id-2">
<thead>
<tr class="row-1 odd">
	<th class="column-1"></th><th class="column-2">B1</th><th class="column-3">B8</th><th class="column-4">B16</th><th class="column-5">B16R</th><th class="column-6">Editorial</th><th class="column-7">B16R vs Ed</th>
</tr>
</thead>
<tbody class="row-hover">
<tr class="row-2 even">
	<td class="column-1">03</td><td class="column-2">4.576205</td><td class="column-3">0.900688</td><td class="column-4">0.515656</td><td class="column-5">0.032629</td><td class="column-6">0.164616</td><td class="column-7">5.05</td>
</tr>
<tr class="row-3 odd">
	<td class="column-1">04</td><td class="column-2">4.704736</td><td class="column-3">0.946557</td><td class="column-4">0.575980</td><td class="column-5">0.041863</td><td class="column-6">0.170677</td><td class="column-7">4.08</td>
</tr>
<tr class="row-4 even">
	<td class="column-1">05</td><td class="column-2">3.347541</td><td class="column-3">0.668534</td><td class="column-4">0.396330</td><td class="column-5">0.040929</td><td class="column-6">0.165247</td><td class="column-7">4.04</td>
</tr>
<tr class="row-5 odd">
	<td class="column-1">06</td><td class="column-2">4.699864</td><td class="column-3">0.956699</td><td class="column-4">0.588319</td><td class="column-5">0.050467</td><td class="column-6">0.162984</td><td class="column-7">3.23</td>
</tr>
<tr class="row-6 even">
	<td class="column-1">07</td><td class="column-2">5.791916</td><td class="column-3">1.167417</td><td class="column-4">0.698043</td><td class="column-5">0.063837</td><td class="column-6">0.178140</td><td class="column-7">2.79</td>
</tr>
<tr class="row-7 odd">
	<td class="column-1">08</td><td class="column-2">0.159862</td><td class="column-3">0.036540</td><td class="column-4">0.026027</td><td class="column-5">0.050608</td><td class="column-6">0.541531</td><td class="column-7">10.70</td>
</tr>
<tr class="row-8 even">
	<td class="column-1">09</td><td class="column-2">0.169632</td><td class="column-3">0.036569</td><td class="column-4">0.026848</td><td class="column-5">0.057554</td><td class="column-6">0.542238</td><td class="column-7">9.42</td>
</tr>
</tbody>
</table>
<!-- #tablepress-2 from cache -->
<p style="text-align: center;"><em>All tests: MacBook Pro Retina 15-inch Mid 2015 • 2.8 GHz i7 • Xcode 10B61 • Max Optimization • Loop Unrolling</em></p>
<p>B16R is roughly 3-5x faster than the editorial solution on files 3-7, and each of the test files completes in under 1/10th of a second. None of the long test files complete in under 1/10 of a second with the editorial solution, and two of them take a half second.</p>
<p>These changes did double the run times on test files 8 and 9. If this were a real world scenario with larger data sets it would be worth keeping track of repetition frequency while building the array for dnaV. At that point the code could decide whether or not to bother looking for repetitions in the search.</p>
<h3>Is There An Even Better Way?</h3>
<p>String matching is a well researched area of computer science. <a href="http://www-igm.univ-mlv.fr/~lecroq/string/index.html" target="_blank" rel="noopener">This web site</a> lists the major algorithms along with their strengths, weaknesses, and sample implementations in C. Most programmers will never need to implement one of these algorithms and will simply rely on library calls whenever they need to search a haystack for a needle of text. It&#8217;s still educational to look over the various approaches to a common problem and to understand how each one tried to improve performance.</p>
<p>Time permitting I hope to explore a few of these algorithms, and how well they handle this particular challenge, in a later blog post.</p>
<h3>Source Files</h3>
<ul>
<li><a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b1.c" target="_blank" rel="noopener">Solution B1</a></li>
<li><a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b8.c" target="_blank" rel="noopener">Solution B8</a></li>
<li><a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b16.c" target="_blank" rel="noopener">Solution B16</a></li>
<li><a href="https://www.taylordesign.net/downloads/code-optimization-examples/save-humanity/save_humanity_b16r.c" target="_blank" rel="noopener">Solution B16R</a></li>
</ul>
]]></content:encoded>
					
					<wfw:commentRss>https://www.taylordesign.net/code-optimization/saving-humanity/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Of Bits &#038; Strings</title>
		<link>https://www.taylordesign.net/code-optimization/of-bits-and-strings/</link>
					<comments>https://www.taylordesign.net/code-optimization/of-bits-and-strings/#comments</comments>
		
		<dc:creator><![CDATA[Daniel L. Taylor]]></dc:creator>
		<pubDate>Mon, 06 Mar 2017 06:32:55 +0000</pubDate>
				<category><![CDATA[Code Optimization]]></category>
		<category><![CDATA[bit count]]></category>
		<category><![CDATA[bitwise]]></category>
		<category><![CDATA[C]]></category>
		<category><![CDATA[code challenges]]></category>
		<category><![CDATA[HackerRank]]></category>
		<category><![CDATA[of bits and strings]]></category>
		<guid isPermaLink="false">http://www.taylordesign.net/?p=4066</guid>

					<description><![CDATA[Lately I&#8217;ve been addicted to solving challenges at HackerRank.com. I decided early on that I wanted to solve the majority of Algorithm challenges in C. I spend so much time in higher level languages that I&#8217;ll generally jump at the chance to work closer to the machine. Sometimes this can be frustrating because you have [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Lately I&#8217;ve been addicted to solving challenges at <a href="https://www.hackerrank.com/" target="_blank">HackerRank.com.</a> I decided early on that I wanted to solve the majority of <a href="https://www.hackerrank.com/domains/algorithms/warmup" target="_blank">Algorithm</a> challenges in C. I spend so much time in higher level languages that I&#8217;ll generally jump at the chance to work closer to the machine. Sometimes this can be frustrating because you have to do heavy lifting where a higher level language hands you the perfect class or set of functions.</p>
<p>But sometimes&#8230;sometimes it can be very rewarding.</p>
<h3>The Challenge</h3>
<p><a href="https://www.hackerrank.com/challenges/acm-icpc-team" target="_blank">The ACM ICPC Team</a> challenge starts off with two numbers. N is the number of people at a conference, and M is the number of topics that the people can know about. The input then consists of N strings with M characters in each string. Each character is a 0 or a 1. The idea is that there&#8217;s a line for each person and a character position for each topic. 1 means the person is well versed in the topic, and 0 means they are not. The goal is to find the maximum number of topics any two person team is well versed in, and the count of teams that hit the max.</p>
<p>When I read the challenge my mind ran straight to a specific solution, and I never even considered another approach. After I submitted my solution and got the points I read both the editorial and the discussion. And I was rather surprised at what I found.</p>
<h3>You Can Do Better Than O(n^3)</h3>
<p>The editorial states that this is a brute force problem with O(n^3) complexity. The C++ code example uses three nested loops to compare every character of every pair of strings, each string stored in a vector.</p>
<p>The PHP example takes advantage of the fact that you can bitwise OR two strings to eliminate a loop. But internally there&#8217;s still a character by character operation to produce a new string, followed by another character comparison of the result to count the 1&#8217;s. So this solution merely hides the O(n^3) complexity behind language functions.</p>
<p>And finally the Python example converts the strings to integers and does a bitwise OR, but then converts the result back to a string to count the 1&#8217;s. The Python code actually touches on an important point, but the potential speed gain gets lost in Python itself.</p>
<p>Surprised by the inefficiency of these solutions I clicked over to the discussions tab.</p>
<h3>Nobody Saw It?</h3>
<p>I skimmed the comments going back two years. Aside from the normal <em>&#8220;why doesn&#8217;t my code work?&#8221;</em> posts, there were numerous complaints about timeouts. And numerous code postings that squeaked in under the finish line, but took similar approaches to the editorial: O(n^3) value comparisons or counting 1&#8217;s in a string which was the result of a bitwise OR.</p>
<p>There were a handful of more creative approaches involving Java&#8217;s BitSet (slow) or a 2D array of integers (not bad, but still).</p>
<p>Right before giving up on loading more comments I came across another C solution which was comparable to mine in its approach and speed. But for all the interest expressed in the discussion about faster ways to solve the puzzle, nobody paid much attention to the post or the reason why it was insanely fast.</p>
<p>I was shocked by this point because when I wrote my solution I didn&#8217;t think of it as being unique or special. I assumed the editorial samples would include a similar approach, along with many of the user submissions.</p>
<h3>Let The CPU Do Its Job</h3>
<p>The challenge input is simply a collection of bits represented as human readable characters in the 8-bit ASCII set. Yet almost no one reduced the data to a form that naturally fits the CPU.</p>
<p>The help section mentioned bitwise OR as did people in the discussion trying to help those with code that was timing out. <em>But the majority were using bitwise OR on the individual ASCII characters from the string.</em> In some cases literally, one character pair at a time. Others applied bitwise OR to multiple characters in a single operation, but they were still using 8-bits in memory to represent a single bit of the problem.</p>
<p>By analogy, if you compare two topic characters from the string at a time you are only using 1 lane of a 64 lane highway. If you bitwise OR 8 of the topic characters at a time you&#8217;re doing better, but still only using 8 lanes of a 64 lane highway.</p>
<p><a href="https://www.taylordesign.net/downloads/code-optimization-examples/fast_acm_icpc_team_solution.txt" target="_blank">The solution I wrote?</a></p>
<ul>
<li>calloc a properly sized block of memory based on the inputs.</li>
<li>Use strtoul to convert the base 2 strings, in chunks determined by sizeof, to unsigned long ints placed into the memory block. Each 0 and 1 character becomes a single bit in memory. On 64-bit CPUs unsigned longs are 8 bytes and can store 64 topic flags.</li>
<li>Loop through the two person teams in O(n^2).</li>
</ul>
<p>The key differences?</p>
<ul>
<li>The CPU is performing bitwise OR operations at its natural word size on a data structure with no waste. For a 64-bit system that means the topics of a two person team are merged with a single instruction for every 64 topics. It also means the code which replaces the innermost loop in the brute force approach performs with a fraction of the loop overhead.</li>
<li>The data describing each person&#8217;s topics is compressed by a factor of 8 meaning the CPU has less data to move and less chance of a cache miss.</li>
<li>With a <a href="https://graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable" target="_blank">fairly simple algorithm</a> you can reduce the act of counting the bits to a handful of instructions for the CPU. And in Xcode at least, __builtin_popcountl implements an even faster algorithm for you.</li>
</ul>
<p>The end result? On test case 7 with 500 people and 500 topics the editorial Python solution took 0.881728 seconds, as tested on my MacBook Pro. The editorial C++ solution took 0.401785 with the same Xcode compiler settings as my solution.</p>
<p>My solution? 0.002911 seconds. 138x faster than the C++ sample. And 303x faster than the Python sample.</p>
<p>Sometimes it pays to be close to the machine.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.taylordesign.net/code-optimization/of-bits-and-strings/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
