<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>marcosilva_eu</title>
  <subtitle>marcosilva_eu blog feed</subtitle>
  <link href="https://marcosilva.eu/feed.xml" rel="self"/>
  <link href="https://marcosilva.eu"/>
  <updated>2021-05-17T00:00:00Z</updated>
  <id>https://marcosilva.eu</id>
  <author>
    <name>Marco Silva</name>
  </author>
  
  <entry>
    <title>How (not) to clone a linux installation</title>
    <link href="https://marcosilva.eu/blog/link-how-to-not-clone-a-linux-installation/"/>
    <updated>2021-05-17T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/link-how-to-not-clone-a-linux-installation/</id>
    <content type="html">&lt;p&gt;Recently I decided to move my second Linux Mint environment to another disk. One tiny detail left me stranded in GRUB console.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;I keep a second Mint installation in a portable hard drive (actually a very small thing I can plug into USB in any hardware) that I don&#39;t use for anything serious, some browsing, Netflix and the sort, leaving everything development-wise to my beefier main system.&lt;/p&gt;
&lt;p&gt;Not long ago, I got a small laptop that was perfect for this form factor, tempted me to let go of the USB thingie altogether and just use that laptop like a &lt;em&gt;normal person&lt;/em&gt;. But, not wanting to reconfigure Mint, I decided to simply &lt;code&gt;dd&lt;/code&gt; the entire thing to the new disk.&lt;/p&gt;
&lt;p&gt;This was uneventful. &lt;code&gt;dd&lt;/code&gt; did its job, I rebooted the system, booted it once from USB to check I didn&#39;t break anything, rebooted and let it boot from internal storage. This seemed ok so I unplugged the USB drive and carried on with the important task of watching some The Crown.&lt;/p&gt;
&lt;p&gt;A couple of days later, a routing Mint update in this system exploded GRUB and the system stopped booting. Having recently used the USB disk with the original installation in other hardware and updated without incident, I tried booting from external, was cheerfully welcomed by GRUB, selected the first entry and was greeted with&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;Loading Linux linux &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;error: &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt; `/boot/vmlinuz-5.4.0-72-generic&#39; not found.&lt;br /&gt;Loading initial ramdisk &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;.&lt;br /&gt;error: you need to load the kernel first.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;quot;Well, that can&#39;t be right&amp;quot; and sure enough, the external USB drive booted fine in another laptop. So the issue had to be in the system itself. Rebooting from external, I press &lt;code&gt;e&lt;/code&gt; to check what GRUB was dreaming of but everything seemed fine, I compared the root UUID with the external in another system and it was a match.
I&#39;m sort of kinda familiar with GRUB&#39;s console, so a &lt;code&gt;Ctrl+C&lt;/code&gt; later I was staring at a &lt;code&gt;grub&amp;gt;&lt;/code&gt; prompt. So, let&#39;s start with the basics:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;proc&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd1,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Expected until now, since I booted from external &lt;code&gt;hd0&lt;/code&gt; would be my external (working) system and &lt;code&gt;hd1&lt;/code&gt; would be the broken internal system&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/boot&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;a bunch of vmlinuz, initrd, etc, including the vmlinuz supposedly MIA&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd1,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/boot&lt;br /&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;another bunch of vmlinuz, initrd, but not the MIA vmlinuz&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Well, this also made sense, as the internal installation broke before the last update (and last kernel) I got in the external system, so the next step was to manually boot linux from GRUB:&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/boot/grub&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; linux /boot/vmlinuz-5.4.0-72-generic&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; initrd /boot/initrd.img-5.4.0-72-generic&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally I start seeing Mint booting but soon enough I get the dreaded&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Target filesystem doesn&#39;t have /sbin/init. No init found. Try passing init= bootarg.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and I get dropped into the emergency console. This one confused me a bit more. After &lt;code&gt;fsck -f&lt;/code&gt; the disks and retrying the reboot, I still got the same result. And that&#39;s more or less when it hit me: I did a very dumb thing when cloning this Mint installation.&lt;/p&gt;
&lt;p&gt;To confirm this, from the emergency console I ran&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; blkid&lt;br /&gt;/dev/sda1: &lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx&quot;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ext4&quot;&lt;/span&gt;&lt;br /&gt;/dev/sdb1: &lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx&quot;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ext4&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and &lt;strong&gt;obviously&lt;/strong&gt; the UUIDs matched, as I &lt;em&gt;totally forgot&lt;/em&gt; to change the UUID of the target disk after running &lt;code&gt;dd&lt;/code&gt;. So GRUB was dutifully booting from external, but when searching for the root to load the kernel, kept trying the &lt;em&gt;internal&lt;/em&gt; disk as it was the first block device with the root UUID.&lt;/p&gt;
&lt;p&gt;I mounted both disks from the emergency console, checked &lt;code&gt;fstab&lt;/code&gt; and yep, I totally forgot about changing the UUIDs. I didn&#39;t have &lt;code&gt;uuidgen&lt;/code&gt; in this console so I wasn&#39;t too keen on messing with GRUB and fstab from here. However, GRUB lets us easily bypass this sort of stupidity from its console. So, another reboot from external, and now my manual boot sequence was&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/boot/grub&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; linux /boot/vmlinuz-5.4.0-72-generic &lt;span class=&quot;token assign-left variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/sda1&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; initrd /boot/initrd.img-5.4.0-72-generic&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; boot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;after a while, I was greeted with Mint&#39;s login screen. Now to fix this screw-up: open a terminal&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; tune2fs /dev/sdb1 &lt;span class=&quot;token parameter variable&quot;&gt;-U&lt;/span&gt; &lt;span class=&quot;token variable&quot;&gt;&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;uuidgen&lt;span class=&quot;token variable&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Confirmation prompt and a while after (changing the UUID in a live disk takes a bit) I double checked&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; blkid&lt;br /&gt;/dev/sda1: &lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx&quot;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ext4&quot;&lt;/span&gt;&lt;br /&gt;/dev/sdb1: &lt;span class=&quot;token assign-left variable&quot;&gt;UUID&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;yyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyy&quot;&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;TYPE&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;ext4&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Mounted the internal system disk and replaced the new UUID in &lt;code&gt;/etc/fstab&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Another reboot from external, select first entry at GRUB screen, and the system booted fine.&lt;/p&gt;
&lt;p&gt;Next I tried recovering booting from the internal disk — and hit a roadblock. GRUB displayed but as I hadn&#39;t run &lt;code&gt;update-grub&lt;/code&gt; it would be looking for the &lt;em&gt;external&lt;/em&gt; block device which I had unplugged at this point. So trying the same routine I got to a different issue&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token builtin class-name&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;token assign-left variable&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;hd0,msdos1&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;/boot/grub&lt;br /&gt;&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; linux /boot/vmlinuz-5.4.0-66-generic &lt;span class=&quot;token assign-left variable&quot;&gt;root&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/dev/sdb1&lt;br /&gt;symbol grub_calloc not found&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GRUB was broken on internal. Booting back from external I tried a fresh GRUB install to that disk&lt;/p&gt;
&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mount&lt;/span&gt; /dev/sdb1 /mnt&lt;br /&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; grub-install --root-directory&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/mnt /dev/sdb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which after another reboot no longer complains about &lt;code&gt;grub_calloc&lt;/code&gt; but unfortunately also hang when loading the kernel without any more info.&lt;/p&gt;
&lt;p&gt;However, this one will be fixed next time. For now, my second system is working again and I can drown my sorrows in another episode of The Crown (I know, I&#39;m &lt;em&gt;ridiculously&lt;/em&gt; late!)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update:&lt;/strong&gt; I actually figured out the kernel hang: I&#39;m missing a kernel module needed to drive the internal disk. Fixing this one will be uneventful, so it doesn&#39;t merit a separate blog post. What a downer :)&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>On the importance of design and how it affects everyday life</title>
    <link href="https://marcosilva.eu/blog/2014-12-05-on-the-importance-of-design-and-how-it-affects-everyday-life/"/>
    <updated>2014-12-05T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2014-12-05-on-the-importance-of-design-and-how-it-affects-everyday-life/</id>
    <content type="html">&lt;p&gt;Welcome to the second entry of my commentaries on The Design of Everyday Things by Don Norman and how it applies to the everyday software design. In this entry we&#39;ll focus on the interaction of the user with complex software and what the natural approach would be to design this kind of system. For this it is important to start with the definition of knowledge in the mind (or brain) vs. knowledge in the world (or in the system).&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;Knowledge in the brain is essentially all the knowledge that we must know before hand when executing an action. There are no cues to guide us through the execution of said action, only our knowledge of how to perform it. This is still prevalent in business or industrial software.
Knowledge in the world, on the other hand, means that the information we require to execute an action resides in the physical world itself, or in our case, in the system itself. We can easily execute this action without familiarity with it or without memorizing a set of steps, because all needed information is available to us when performing the action, embedded in the object or system being used.&lt;/p&gt;
&lt;blockquote&gt;When people fail to follow these bizarre, secret rules, and the machine does the wrong thing, its operators are blamed for not understanding the machine, for not following its rigid specifications. With everyday objects, the result is frustration. With complex devices and commercial and industrial processes, the resulting difficulties can lead to accidents, injuries, and even deaths. It is time to reverse the situation: to cast the blame upon the machines and their design. It is the machine and its design that are at fault. It is the duty of machines and those who design them to understand people. It is not our duty to understand the arbitrary, meaningless dictates of machines.&lt;/blockquote&gt;
&lt;p&gt;Having developed business software for most of my career, it&#39;s worrying that this simple truth is still largely ignored. Such complex applications warrant the use of the best possible interaction paradigms, as well as innovative design which is familiar to users from everyday apps, giving the user less data to learn (again). I&#39;ve heard more than once the old excuse that &amp;quot;this application is very complex, so we&#39;ll just explain everything to the users during training, don&#39;t worry so much about the design&amp;quot; or &amp;quot;it&#39;s already complicated, they&#39;ll just learn this new way of doing things&amp;quot;. Knowledge in the mind is notoriously unreliable and without great design care and as much knowledge in the world (or system in this case) mistakes will inevitably happen, which is of paramount importance in systems in which undo is not easily done.&lt;/p&gt;
&lt;blockquote&gt;Unless it is your ambition to become a nightclub performer and amaze people with great skills of memory, here is a simpler way to dramatically enhance both memory and accuracy: write things down. Writing is a powerful technology: why not use it? Use a pad of paper, or the back of your hand. Write it or type it. Use a phone or a computer. Dictate it. This is what technology is for.
The unaided mind is surprisingly limited. It is things that make us smart. Take advantage of them.&lt;/blockquote&gt;
&lt;p&gt;In software, this kind of action can be included in the system design itself. Instead of an endless list of fields the user must fill, provide the relevant information in each screen. This will, in general, increase the number of screens in your system, but will allow for less errors and less effort from the user, due to the minor reliance on knowledge in the brain. If this is not possible or feasible, allowing for notes or comments from the user to be updated during the execution of a complex action may be sufficient. Let the user type in notes that give him the necessary context to perform the action without errors. This contemplates information not available in the system as well.
There is an exception to this rule, and that is the use of cultural knowledge. This knowledge is present in the subconscious of the user, as it is something ingrained into their everyday lives. However, it is easy to cause grave mishaps when relying on this type of knowledge: it differs from where the user is from. In this case and if you decide to rely on cultural knowledge, beware of your target audience and design accordingly, changing cultural references and parameters when such is needed.&lt;/p&gt;
&lt;p&gt;As architects and designers, it is our mission to provide reliable software that simplifies the user&#39;s everyday life. In the corporate world, we, almost exclusively, build tools to ease common tasks. If from the start we focus on the psychology of ours users instead of the data structures we are working with, we&#39;ll build better products that people love to use and make everyone&#39;s lives a little bit better.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Don Norman&#39;s Error credo</title>
    <link href="https://marcosilva.eu/blog/2014-10-06-don-normans-error-credo/"/>
    <updated>2014-10-06T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2014-10-06-don-normans-error-credo/</id>
    <content type="html">&lt;p&gt;I have been reading Don Norman&#39;s seminal The Design of Everyday things and thought to share some passages that resounded during my reading. I&#39;ll be posting a few of these in the near future with compilations of small chunks of text. For now, I leave you with the first of those quotes, one that is of great importance when designing tools for everyday use.&lt;/p&gt;
&lt;!--more--&gt;
&lt;blockquote&gt;True collaboration requires each party to make some effort to accommodate and understand the other. When we collaborate with machines, it is people who must do all the accommodation. Why shouldn’t the machine be more friendly? The machine should accept normal human behavior, but just as people often subconsciously assess the accuracy of things being said, machines should judge the quality of information given it, in this case to help its operators avoid grievous errors because of simple slips. Today, we insist that people perform abnormally, to adapt themselves to the peculiar demands of machines, which includes always giving precise, accurate information. Humans are particularly bad at this, yet when they fail to meet the arbitrary, inhuman requirements of machines, we call it human error. No, it is design error.
&lt;p&gt; &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Don Norman&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;

</content>
  </entry>
  
  <entry>
    <title>Easy REST API mock-up testing</title>
    <link href="https://marcosilva.eu/blog/2013-12-04-easy-rest-api-mock-up-testing/"/>
    <updated>2013-12-04T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2013-12-04-easy-rest-api-mock-up-testing/</id>
    <content type="html">&lt;p&gt;One of the things I&#39;ve recently been working on is a large HTML5 website for a client. This site communicates with a WCF-based REST backend, using a Knockout plugin for the calls that, in the end, basically uses the usual $.ajax call from jQuery.&lt;/p&gt;
&lt;p&gt;As I started the development of the proof of concept, I came to a point in which I wanted to display some dummy data in the UI without hard-coding into the source, as some fellow developers were to take over this codebase and write the actual production website. What I needed was a fast way to deploy some mock API calls and responses. If you deploy automated testing using a framework like Selenium WebDriver, which I also used for this project, this can be very useful for UI testing.&lt;/p&gt;
&lt;!--more--&gt;
&lt;p&gt;I was deploying this website using Internet Information Services. IIS has a very nice feature, on which you can pretty much configure all of the website using &lt;strong&gt;web.config&lt;/strong&gt; files. This has de advantage that if you include this in a Team Foundation Server build which automatically deploys the website, then shipping these web.config files means wherever you run it, it will always be correctly configured. Also, web.config is accepted not only at the root of the website but &lt;em&gt;anywhere.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, my API has a URI format of&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;http://example.local/&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;service_group&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;/&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;service&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;[query param...]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you make the root of the API configurable, which is always a good idea anyway so you can switch between e.g. productive and testing servers, you can easily point this to another server with a similar API structure. So, the solution to my problem was easy!&lt;/p&gt;
&lt;p&gt;I created an api/ folder in my proof of concept and placed a web.config file there specifying that all the files in that folder and respective children should have the &lt;strong&gt;application/json&lt;/strong&gt; MIME type. Then I simply create a &lt;strong&gt;service group&lt;/strong&gt; folder and a file named &lt;strong&gt;service&lt;/strong&gt; in it, and in this file I place the mock reply. If the URI takes parameters, e.g. a GET, I keep creating folders and the last part of the URL is the file. Easy.&lt;/p&gt;
&lt;p&gt;Now, if you try to do this from the IIS management console, it will ask you for an extension. Of course you can say that the extension is &#39;&lt;strong&gt;*&#39;&lt;/strong&gt; to match all files, but this will only match files &lt;em&gt;with extensions&lt;/em&gt;, which was not what I want. A workaround is to specify an extension of &#39;&lt;strong&gt;.&#39; &lt;/strong&gt;without the quotes. The important part is that dot. It tells IIS that the files with &lt;em&gt;no extension&lt;/em&gt; need to be served with &lt;strong&gt;application/json&lt;/strong&gt; MIME type.&lt;/p&gt;
&lt;p&gt;Take into account that if you are serving the API files from the same website, you won&#39;t be testing against cross origin requests, so if when changing to the real API server no call goes through, remember this.&lt;/p&gt;
&lt;p&gt;And you&#39;re done! Pointing your AJAX calls to the local URL will get you the mock replies. While you&#39;re at it, stick another web.config file into the root to disable caching. Saves you a ton of time debugging!&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Checking in changes in a different branch in TFS</title>
    <link href="https://marcosilva.eu/blog/2013-06-06-checking-in-changes-in-a-different-branch-in-tfs/"/>
    <updated>2013-06-06T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2013-06-06-checking-in-changes-in-a-different-branch-in-tfs/</id>
    <content type="html">&lt;p&gt;Recently I had the need to check in some changes in a different branch. In git this is very easy, but as far as I know in TFS not so much.&lt;/p&gt;
&lt;p&gt;Using the approach detailed by  &lt;a href=&quot;http://stackoverflow.com/a/9909917&quot; target=&quot;_blank&quot;&gt;Torbjörn Bergstedt at Stack Overflow&lt;/a&gt;, I created a shelveset on my source branch and subsequently migrated said shelveset onto the target branch&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;tfpt unshelve client /migrate /source:$/MY-PROJ/SourceCode/dev-branch /target:$/MY-PROJ/SourceCode/UI-branch&lt;/pre&gt;
&lt;/blockquote&gt;
to which tfpt helpfully replied
&lt;blockquote&gt;
&lt;pre&gt;Creating the backup shelveset which will serve as a snapshot of your workspace&#39;s current state...&lt;/pre&gt;
&lt;/blockquote&gt;
asking me then to deal with the merges. As it was a new branch, selecting auto-merge solved all of the conflicts. At this point, I got
&lt;blockquote&gt;
&lt;pre&gt;The backup snapshot was preserved as the shelveset myshelve_backup1.&lt;/pre&gt;
&lt;/blockquote&gt;
Analyzing this shelveset, however, turned out to be a bit weird. My source shelveset had about 8 changes. The target changeset (and as I asked for an unshelve, also my workspace) has about 360 changes. Why?
&lt;p&gt;I have a folder at the same level of the source and target branch. This is a regular folder, not a branch in itself. For some reason, even though I explicitly requested a migration for the source to target branch, this top level folder was included into the target shelveset as with every item &lt;strong&gt;added&lt;/strong&gt;, which is in itself weird: the files obviously already exist.&lt;/p&gt;
&lt;p&gt;That being said, I undid my pending changes in that folder and continued to work on the target branch. So, this works, but I wouldn&#39;t recommend its use on a regular basis.&lt;/p&gt;
&lt;p&gt;If you know any better way to do this, please, find me on Twitter and let me know.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Mocking an internal method with generic parameters using jMockit</title>
    <link href="https://marcosilva.eu/blog/2013-01-07-mocking-an-internal-method-with-generic-parameters-using-jmockit/"/>
    <updated>2013-01-07T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2013-01-07-mocking-an-internal-method-with-generic-parameters-using-jmockit/</id>
    <content type="html">&lt;p&gt;Last week, in order to write a test in a way that assumed less about the internal class, I got to the point where the best approach would be to mock an internal method, responsible for loading some metadata. I could test this from the behaviour of the class with my passed inputs, but for this I would have to know what logic resides inside it. This was, however, no good here as this was not the logic to be tested.&lt;/p&gt;
&lt;h2&gt;Our scenario&lt;/h2&gt;
We use jMockit as our mocking framework in the project and almost exclusively with the Expectations API. This API provides an &lt;em&gt;invoke &lt;/em&gt;method, which can, in turn be used to mock internal methods. Logically, I followed this route, but hit a (major) snag right after it.
&lt;p&gt;My method has a simple but, for this topic, tricky signature&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;private void loadMetadata(String id, Map&amp;lt;String, String&amp;gt; arguments)&lt;/pre&gt;
&lt;/blockquote&gt;
What &lt;em&gt;invoke&lt;/em&gt; does is that, through Reflection at runtime, it will determine the type of the parameters and, together with the method name, it will determine what is the best match method in the class. There is, however, one basic flaw to this approach, which some background on Java generics will point out
&lt;h2&gt;Java Generics: not like .NET&lt;/h2&gt;
In .NET, generics are first class citizens and an integral part of .NET 2.0+. They are compiled to bytecode and are understood by the CLI. Java, however, uses generics more as an afterthought, in that they are not understood by the JVM. When compiling a Java application, all generic classes will suffer what is called erasure. What this means is that they will be translated to their bounds, or at its limit, to Object. The compiler does a bunch of other stuff like casting to maintain consistency, but the point is that the bytecode contains nothing more than ordinary classes. A simple run with invoke will show just how naive this approach is
&lt;p&gt;Invoking our way through&lt;/p&gt;
&lt;p&gt;Using jMockit&#39;s Expectations API, on can declare in the Expectations block&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;invoke(obj, &quot;loadMetadata&quot;, &quot;id&quot;, args); times=1;&lt;/pre&gt;
&lt;/blockquote&gt;
which means that the &lt;em&gt;loadMetadata&lt;/em&gt; method on object &lt;em&gt;obj &lt;/em&gt;with &lt;em&gt;&quot;id&quot;&lt;/em&gt; and &lt;em&gt;args&lt;/em&gt; as arguments. As args is a generic Map, which is an interface, the object actually passed is an HashMap&amp;lt;String, String&amp;gt;. So what happens when you run the test?
&lt;blockquote&gt;
&lt;pre&gt;java.lang.IllegalArgumentException: No compatible method found: loadMetadata(java.lang.String, java.util.HashMap)&lt;/pre&gt;
&lt;/blockquote&gt;
So what happened here? Quite simply, the generics were erased, from HashMap&amp;lt;String,String&amp;gt; into HashMap at runtime. This will not matched our declared signature as stated above. So, we&#39;re out of luck. Or are we?
&lt;h2&gt;Why jMockit pays&lt;/h2&gt;
One thing I had to endure from my team colleagues for a while was why did I choose jMockit as a mocking framework when it is harder to use than most. And I always present the same reason: flexibility!
&lt;p&gt;jMockit packs not one but three APIs for testing, Expectations, Verifications and Annotations. Until now I had no reason to use Annotations (noted as to being the most powerful of the three), but some testing actually proved that this is easily done with it. Annotations is, however, more verbose and harder to read for someone not familiar with it.&lt;/p&gt;
&lt;p&gt;Annotations is, from the start, a partial mocking API. This means that when you are mocking any class, you specify only what methods you want to mock and the remaining will remain as they are in the original implementation. Also, taking advantage that in jMockit you mock not instances but entire classes, you can easily mock a specific method in all instances of a given class straight in the JVM (how cool is that?) This does not work in the same way as Expectations&#39; &lt;em&gt;invoke&lt;/em&gt;. It will replace the original method signature and content with your code. So, how do we do it?&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;//jMockit annotations API! woohoo!
 new MockUp&amp;lt;MyClass&amp;gt;() {
 public String magic; //for testing, no getter/setter here
 @Mock
 void loadMetadata(String id, Map&amp;lt;String, String&amp;gt; arguments) {
 assert id.equals(magic);
 }
 }.magic = magic;&lt;/pre&gt;
&lt;/blockquote&gt;
We start by declaring a new mock for the desired class and writing our methods. It&#39;s important to note that I dropped the &lt;em&gt;private&lt;/em&gt; from the method declaration. This is necessary. If you do not, jMockit will error out. This does not, however, change the method&#39;s visibility at runtime. Also important is to annotate the method as a Mock. As I need an external string from this object, I declare a public variable and fill it directly when declaring the anonymous class (it can be argued that this variable should be private and a public getter/setter should be used, but for test purposes this is enough.)
&lt;p&gt;And that&#39;s it! jMockit will replace the &lt;em&gt;loadMetadata&lt;/em&gt; method in every object of &lt;em&gt;MyClass&lt;/em&gt; right in the JVM. Running the test with a breakpoint on the assert will show our mock is being triggered as expected.&lt;/p&gt;
&lt;p&gt;So this is how you can easily mock an internal method with generic arguments. I&#39;m in no way a jMockit expert, so if you find a better approach to do this, please sound of in the comments.&lt;/p&gt;
&lt;p&gt;Bye!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Sharing Team Foundation Server workspaces</title>
    <link href="https://marcosilva.eu/blog/2012-11-08-sharing-team-foundation-server-workspaces/"/>
    <updated>2012-11-08T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2012-11-08-sharing-team-foundation-server-workspaces/</id>
    <content type="html">&lt;p&gt;Recently I needed to allow another user to use one of my TFS workspaces. This user needed to be able to check-out a file, change it and check it in again. This turned out to be quite harder than, in my opinion, it ever should. First, what Microsoft says&lt;/p&gt;
&lt;h3&gt;Public workspaces&lt;/h3&gt;
According to Microsoft, in TFS 2010 you can now share workspaces. When editing or creating a workspace, you should see a combo
&lt;img class=&quot;aligncenter&quot; alt=&quot;&quot; src=&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAlwAAAAuCAIAAAByC1AEAAAINUlEQVR4nO2dT0/kNhjG/ZE2SJNP0jZwmfVHyCVFZcSNJXMDLq2Khvuscq2qIhD3rVapWlUV2ooL4oBYVnXLn8PAoYfY8X9PZpkws+H5HZCdvH792BP5IU6kEAYAAAAAxhhjZNECAAAAgGUBpggAAABwYIqc3d3d9fX1FAAAQBdZX1/f3d2d6gUwRcYYy4fDvb29y8vLRwAAAF3k8vJyb28vHw7DdgBTZIyxLMuurq4mk8l/AAAAushkMrm6usqyLGwHMEXGGEvT9PHxcdE/GQAAgBZ5fHxM0zRsBzBFxhhL0/Th4eFfAAAA3eXh4QGm2IjKFBetAgAAQIvAFJtSmeI/AAAAusu8TLGgpCbOy3m4UJnHTVI1DHsyaZpOJpNPnLev5Xh7b95/Mnn/puc8vjDevl4uPQAAsIxMJpN5mSJ3pucyqefGMkXuMfOwv2dwLJgiAABMZ/6mqJe7Q2WK15xxn/S2frXLn8fTMyxDFwAA8MXTsimWecz3GGkhTlEaE0KLKqzgAbSQsaJxncfIYlSd3fH++Nmc6pn1DM1MvDLFj5xxn/S23hnlcZ/0+v0eIf0xP/huq0f6Y7PRuC9U9sdqjYe+2+ppddla1JXe3231zFZamK7nI++uP7a6GfdJb2vMj6ljs7RY+jyCAQBgCSEu6rOtbp8qblPQOC+rR4+K54mKUmQFVR2UNxIWxw+rVdmLbKmIKKjqyLWNGgmbmeL9/f0Z52CNrGyenJ2dnZ1srojiwRoRxTrgYI2sHdRtRNFIIrNp5YO1+qjW/mBtZWWlOnWyuSK6EcmlIFvPyeaKCDPVHKwREa0MyZJqn/MLBgCApcRwRPXU/f393F+0EYaj3Le5bsqmlkWhzGP17R2jqoVJrxPG58psZmhEZYp/c0arcmCrI3kwGhwb5dEqDxitqic5dYw4dzyI1Emrc1enosFxlWhUlcWh40GkhIouTT1RJOtVR7KqBUvRplS9oymCAQBgWakXLeP4HE3RchndpaywxqZYJ5N+q1ZnN0VXwqlUpviBM0pINDj6oKMelOWjQRQNjqq/vE6SkTyjN5Rnbar4URINjj4cDaJkVCfQW42SqmLoIVFk5j4aRITYwSKdLdWWFxIMAADLCyHEPtimKWqbpXbYbKbIGCvzWK2Lqm/7VN+DdYnkGRpvn97d3Z1y9hMSbRye6qgHlfLhRhQlSZTsG2cONyJeMho6Up/WmaKobp0kiYjcTwjhHRxuRLzo0GPrPtyoEir91hkcUmVJGbVXMAAAfFnc3d21Z4r6Dupnb5/KrVlx76ft0zpftAlmthO2aoqnhxtRbVmiSgiJkoQb3Ol+QggRMeK8PHKqNlW8VtUgWzk1aP5Goo1D3mXdx35CoiSJ9G4dUmuxRLNhj2AAAPiimJcpdp/KFP/qLD9+Q6Lvflm0CgAAWCgLM0UyjTY6fQppmt7e3v7ZWX74mrxa/3nRKgAAYKHc3t7iTrERlSn+0Vm+/4q8+vanRasAAICFAlNsSpqmNzc3vwMAAOguNzc3MMVGZFl2fn5+fX39GwAAgC5yfX19fn6eZVnYDmCKjDE2HA53dnYuLi5uAAAAdJGLi4udnZ3hcBi2A5giZ3t7O8uyFAAAQBfJsmx7e3uqF8AUAQAAAA5MEQAAAODAFAEAAAAOTBEAAADgwBQBAAAADkwRAAAA4MAU3SifqpqRMo9n/shxqzT7UMjS8fyyn9Jjk7Yz5l+6CwmAFwFM0UWZxzGl8TMsSc+w9MMUn6HHFkxxDg0BADMDU3RQfaDY+O5xO8AUfcAUn94QADAzMEUb4YZuVywoifOCf/FYnC8oiSmNCaEFX8LKPFb2X92fQJY1Hio/pKxt3Ra0rutfXTZbaWG6Hsa7o4XVjXNE1veenfo8gp3nrIQFJXGe86PWTLtV+Xt0fsu6geCy7iJ3eI9nbi3ZoR/dP6IG8aVxkfhn3JIavGw8k+/40eoLCYAXAUzRQnqh0xULWq8i8qlPQc310VyT9EVFNSp7KWesoObyKNaoOI7rzmufVVZ8nx5l/TXVOEdkS7XP+QWHHojZJu18hOubZ1+Prpl0jNRoLjsu89iyZu/cWrIb/ujWiGa9SKygkNRpl413FPr84C4VvChgiiaqE+r/yVdo/8+LZcfpbeqaZN9/Weud8p++eSMgV7I4L6qycjur32w49cSqRZnLv3NEllR7LsKC7cU7MHbHDqFLVaBHZzZjpHZz7d8eS0OzudXH4vrRQ/PcJN68SBwu5ZQauGz806VPL3ZuwYsDpmig7Fa5t6nUZaJeitzru/lsUq5crrXJaSSs7ijOy2rdLPOYFnWCRgs3iWO3o1nBIp0t1W2KHsGh4OC6HJ7n0BR5s8mROlXN2RQDD6SdV06TeFOY8tuFpfovG68pBq52AF4EMEUd1/pjb4JZJudZkflbrNaTHed+YHCrqsxjdQeM0vq+wtg38+qxlzd1J80ckUOqc/vUJ9gKnj52x9ala55DPSr3uOav6NkMnGn7NPBb2z+6LdM5onC82xSZ4eZeqeHLxjkK/w45DBK8DGCKGk7nsLfpKI31u0jf2lHm2jsK9UsdchHkd6bWKzPmv+yqyxiOI1s5NWh2RGL11Q3jZQq1W4dU9Tbaem/FfhXDCLYTTr9TtFQFe6w7pFQ+4TNC7eYiZtqLNuG5NbdGXTe0nhEF482LxB5RSGrgsvH/G6fND0wRvDhgirPSvaWheyNaMPK5bDvxAID2gCnOSvcspHsjWijOd5bnGA8AaBOY4qx0z0K6N6JFUW0+Np/MWeMBAK0DUwQAAAA4MEUAAACA8z90bqLf8WaQSgAAAABJRU5ErkJggg==&quot; width=&quot;487&quot; height=&quot;37&quot; /&gt;
&lt;p&gt;which you can use to change this setting. The set permissions are&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Private workspace - only the owner can use the workspace&lt;/li&gt;
	&lt;li&gt;Public workspace (limited) - all other valid team members have the Read and Use permissions&lt;/li&gt;
	&lt;li&gt;Public workspace - all other valid team members have all the Read, Use, CheckIn and Administer permissions&lt;/li&gt;
&lt;/ul&gt;
You cannot finetune the permissions either via the GUI or the tf command. It&#39;s however possible to change them using the TFS API.
&lt;p&gt;Seemed like setting the workspace as non-limited public should work, but I faced another problem. The other user would be able to use the workspace and checkout the files, but it would not be able to check them back in again&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;TF14098: Access Denied: User DOMAIN\\OtherUser needs Checkin, CheckinOther permission(s) for $/somepath/somefile.txt.&lt;/pre&gt;
&lt;/blockquote&gt;
This one was trickier to resolve because nobody in my company had ever used the CheckinOther permission for any project and such a permission did not appear in the project security tab. After a little bit of googling, though, I found out that these permissions actually reside in  the &lt;em&gt;folder&lt;/em&gt; security settings. So I added the other user to the Builders group, went to the folder which I needed the other user to be able to use, right-click, Security, selected the group and gave it the &lt;strong&gt;Check in other users&#39; changes&lt;/strong&gt; permission (this has to be done by an administrator account)
&lt;img class=&quot;aligncenter&quot; alt=&quot;&quot; src=&quot;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAhMAAAAVCAIAAABzB/tHAAAFOUlEQVR4nO2czXLaVhSA9VpK3yad6BXSbbrrTKdKF6637o6ZTuveJqM2xYRx6hq72HUcI2MjMAEEAiRZP0hCwIIuBPq9AoEth7jnG40H8NXR4XrmfNxzkQk1hm++3ZrOcV/86edXUwAAAOBRY9v29va2aZqGYVjWkHr27MedHTQnl8sRq5pjBwAAAHjU+M1hGKZhmIPBQNN0QejxfKfZ5Fc2x6fwHwAAAPBwhNYcXzx58uXTp189f+4c3798CeYAAAAAAoTM8fWLF7/u7r6dUygUwBwAAABAAOhWAQAAPAQoGWlc+juaTnIkD+g3h6bpt7eKJMm9nnhdqbLs1fl5CcwBAABwDyCEooVU0zRd1weDgWEYpmmmZw5jGZtmDo4miRkkzU2n0ylDzR+tSPyJHE2uGTPxJT4BDLU8l41KGACAWKLmcLRRLpeLxaJpmmmb45dXb0LH7us/X7/JZd/ub5g5OJokCIrxntLMNBVz3Al/2I0qxGAOAHg8uOa49aHr+v7+fjabtSzLsqy0zVE8Y93j/cUVe1XlavX9v/7eKHNwNOnThgeYIyFgDgB4PETNoet6vV7PZrOFQsG2bdu2H8Ycp+eXH9jKFXdTqzeaLf6wcLRJ5ogTh1PsmFkTyyt7XlvLPSv0klslGco/ahr6FUnTFBEKHsgqFNP/PGFuDEWQFEUGk8AaKPKuFoXCTEEE3JxEEvbe1SxQzLRw7om0l3w4iyRZAQCwBISQpmmapimKommaqqqmaR4cHORyOZ7nR6PRaDRK2xyn5+X3petSmeNq9Uaz1e50ut3uyenp2uYYDAaqqkmS3O+L3W6vXK5cXFyenX24mznwn4YZyq1eDOUvoLPRs4/a0b0LZwzWSDipeMEDl/ZVcJ9s/CV3eW4MhdESzhwMFWM4XKjw4CjYOYkmnHBavEccTRLR2XAyXJ4VAADLQQg5O+GCIHAcZ5omz/PO3Q+j0Wg8Ho/H41TN8dvve+xVtVKtf2y0ut2uJEmyLMuyXGIv1zOHYRiONnq9viD02m3h4oI9Ozsvnvyb2pojVGF9S4HZh1vM6QxFkCR+Kzy45ohrPQVjzkti3CnxueF7RLHn4tYuuFChwVFi5gSTvLfoiJ+WgNoX/yGgIwYAdwUh5HyB6vj4eG9vTxTFo6OjfD7P8/x4Tqrm+CObr9UbfLvd7/cVRdHnVGs3a5gjk8nwPK9p2u2tIkmSKEr9vlir3VQq1esKl/Y+h79gBcfiqyRBktigaZtjQb1e+L7cyzqaSBDKGxwloTm8Ya4cVjIH5uKLsgIAIAEIIcuyhsOhoijOvdb5fP7w8NDpUz2AOfby71p8u9frybKs67qjMcMwGs3mGuYoFAqZTGbrhy3scbfvVoX2IzDfrQq0U6JlHtetwpbtZOYId6sizaikuWHN4Su6kTPmVTpRqNg+X/ycBB4HNlkWTEtctwq/wojPCgCA5SCEhsOhbduGYbAs65ij2WxOJpPxeDyZTCaTSarmeHdw6GhDVVXDMKw5nU5nDXO0Wi1BEGRZVnyoqur8vPP9HP7uB+Z+jnCvJrKvG9kNdredA2UsoTn8Vwl83sa1oRbkFvONJjdfivKKeGh3eUGo6GAMcXMSmR+CIEiKWrDm8AWL2SEnCIpJlhUAAEtACNm27S4vSqUSy7KTIKma45/iSanEclz1Y6PREYS+KIqSJIpSr9ffPHMAnwWxm1IAANwPCCFXGw6TCJ/RPeRgDiC+RQUAwD3xyP5vFZjjfwumPwgAALAUMAcAAACwGmAOAAAAYDWWmuM/qlCKaBa0kxkAAAAASUVORK5CYII=&quot; width=&quot;481&quot; height=&quot;19&quot; /&gt;
&lt;p&gt;Click ok and you are good to go!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Using Java Mail API with untrusted certificates</title>
    <link href="https://marcosilva.eu/blog/2012-11-06-using-java-mail-api-with-untrusted-certificates/"/>
    <updated>2012-11-06T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2012-11-06-using-java-mail-api-with-untrusted-certificates/</id>
    <content type="html">&lt;p&gt;Today I was playing around with the Java Mail API using channel security and hit a snag. Our SMTP server supports no security and TLS. Everything was great using no security, but using TLS we get&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;javax.mail.MessagingException: Can&#39;t send command to SMTP host;
&lt;p&gt;nested exception is:&lt;/p&gt;
&lt;p&gt;javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target&lt;/p&gt;&lt;/pre&gt;&lt;p&gt;&lt;/p&gt;
&lt;/blockquote&gt;
The problem here was the SMTP server certificate: it was untrusted. This will happen every time with self-signed certificates. In my case, the certificate was signed by an untrusted certificate authority (the CA certificate itself was self-signed.)
&lt;p&gt;I had two problems: I need to trust the server certificate, but more difficult than that was that I needed to actually obtain the certificate because I didn’t have it.&lt;/p&gt;
&lt;h3&gt;Problem one: obtaining the SMTP server certificate&lt;/h3&gt;
The easiest way to obtain these certificates is to use openssl’s &lt;strong&gt;s_client&lt;/strong&gt;. s_client is provided with openssl to debug SSL/TLS servers. You are able to observe the entire protocol execution and obtain most of the information you need to resolve whatever problem you’re facing. In my case, for the SMTP + TLS scenario, I just ran
&lt;blockquote&gt;
&lt;pre&gt;openssl s_client -connect mail.example.com:25 -starttls smtp &amp;gt; smtp.txt&lt;/pre&gt;
&lt;/blockquote&gt;
This will take a long time to complete and will seem stuck, but you can cancel it soon after the beginning of the execution as you’ll already have the certificate.
&lt;p&gt;For the SMTP + SSL scenario, I ran&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;openssl s_client -connect mail.example.com:465 &amp;gt; smtp.txt&lt;/pre&gt;
&lt;/blockquote&gt;
This actually seemed stuck earlier than the TLS command, but like that one you get the certificate right in the beginning. Feel free to cancel it.
&lt;p&gt;Open the smtp.txt file. You will see a certificate chain followed by &lt;strong&gt;Server certificate&lt;/strong&gt;. Copy the bit starting with &lt;strong&gt;BEGIN CERTIFICATE&lt;/strong&gt; and &lt;strong&gt;END CERTIFICATE&lt;/strong&gt; into a smtp.crt file. Opening this file you should be able to check the certificate properties and its respective thumbprint.&lt;/p&gt;
&lt;p&gt;Congratulations, you now have the server certificate. Now you just need to trust it.&lt;/p&gt;
&lt;h3&gt;Problem two: trusting the certificate&lt;/h3&gt;
There are two options for trusting this certificate: you can add it to the cacerts keystore in your JVM so that all java apps can trust it or you can add it to a separate keystore and specify in your code to use this keystore.
&lt;p&gt;I followed the first approach as this certificate was actually ok to be trusted. So to trust this certificate, open a terminal window, go to &lt;em&gt;&amp;lt;jre_home&amp;gt;/lib/security&lt;/em&gt; and type&lt;/p&gt;
&lt;blockquote&gt;
&lt;pre&gt;keytool -import -keystore cacerts -alias &amp;lt;alias&amp;gt; -file smtp.crt&lt;/pre&gt;
&lt;/blockquote&gt;
No need to specify alias, but the default is &lt;em&gt;mykey&lt;/em&gt; which made it nearly certain I wouldn’t remember what certificate this was supposed to be. It can be anything, though.
&lt;p&gt;And you’re done. Remember, you need to execute the keytool import into the cacerts for the target JVM!&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Creating a patch in WinMerge</title>
    <link href="https://marcosilva.eu/blog/2012-09-20-creating-a-patch-in-winmerge/"/>
    <updated>2012-09-20T00:00:00Z</updated>
    <id>https://marcosilva.eu/blog/2012-09-20-creating-a-patch-in-winmerge/</id>
    <content type="html">&lt;p&gt;Today a colleague was a bit puzzled by how I generated a patch in &lt;a title=&quot;WinMerge homepage&quot; href=&quot;http://winmerge.org/&quot; target=&quot;_blank&quot;&gt;WinMerge&lt;/a&gt;. This can be useful if you&#39;re not using something like &lt;a title=&quot;Git homepage&quot; href=&quot;http://git-scm.com/&quot; target=&quot;_blank&quot;&gt;Git&lt;/a&gt; in your workflow, or if, like me, Git just isn&#39;t working for you (in my case, a unix file being edited in windows resulted in a patch that replaced the entire source file).&lt;/p&gt;
&lt;!--more--&gt;So, open both the versions of the source file in WinMerge, the one you want to be the target version to patch on the left and the current one on the right. You can do this manually or in a number of ways in Git, but in my case I used
&lt;pre&gt;&amp;gt; git difftool HEAD~3 HEAD&lt;/pre&gt;
&lt;p&gt;to produce a patch that embodies my last three commits. Note that to use &lt;em&gt;difftool&lt;/em&gt;, you need to have Git configured correctly to open WinMerge. You will see the base version on the left side and the current one on the right, just like we want it. Then, simply go into the Tools menu and click Generate Patch. A window will appear with a bunch of options. I mainly use the default, but you have three different syntaxes for the patch files, as well as options regarding context and some less interesting stuff. Browse to/type your target file for the patch and confirm the window.&lt;/p&gt;
&lt;p&gt;Voilà, a very simple way to generate patches using WinMerge.&lt;/p&gt;
</content>
  </entry>
</feed>
