tag:blogger.com,1999:blog-82025431679592027432024-03-13T05:45:51.958+01:00Picky PythonMagnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.comBlogger12125tag:blogger.com,1999:blog-8202543167959202743.post-76614641962195283782019-09-03T20:04:00.001+02:002019-09-04T14:18:28.015+02:00The Mathematics of Continuous DeliveryIf you're used to traditional, i.e. fairly infrequent, software delivery, the idea of Continuous Delivery will probably seem hopelessly expensive. <i>"Maybe it works for someone else, but it won't work for us,"</i> is a common thought. If normal feature deliveries typically takes days or weeks, it seems impossible to make them every time a programmer checks in some code.<br />
<br />
You can probably deliver an emergency bug fix fairly rapidly in a pinch, but could you continuously make all your deliveries in that speed without making a mess? Those emergency fixes are special cases, and maybe done in a way which wouldn't be sustainable if all changes were made like that. Right?<br />
<br />
Of course, it would be great if emergency fixes were as reliable and well tested as ordinary releases—they certainly deserve to be that, but isn't that just a dream?<br />
<br />
Each delivery requires a substantial amount of time and resources, so surely making many deliveries, must be more costly than making fewer and bigger deliveries, right? If we rush a delivery, it's likely to turn out broken. Quality must be allowed to take time, and since the must let each delivery take a reasonable amount of time, we can't make them too often, so we need to include as many changes as we can in each delivery, right?<br />
<br />
If we imagine that we produce \(m\) deliveries each year, with \(n\) changes in each delivery, we'll deliver \(x = mn\) changes in a year regardless of if it's \(x\) deliveries of \(1\) change each, or \(1\) delivery of \(x\) changes each. How could the former be more efficient than the latter, if each delivery has some setup time etc?<br />
<br />
There are some obvious benefits with frequent deliveries, and particularly with frequent deployment, such as being able to use new features sooner rather than later. I've also explained how deploying software in baby steps might reduce risks and downtime, in <a href="https://pickypython.blogspot.com/2016/03/a-use-case-for-continuous-delivery.html" target="_blank">A Use Case for Continuous Deployment</a>. In this text, I'm focusing on costs of delivery.<br />
<br />
<i>Let's do some math!</i><br />
<br />
Call the total cost of a single software delivery \(C_{delivery}\). I don't think it matters a lot if we're thinking dollars, calendar days or person-hours here.<br />
<br />
In your normal delivery process, there are probably parts that take as much time regardless of the size of the delivery. Maybe some IT person needs to install the new verson of the software on some server for instance. Let's call that part of the cost \(C_0\).<br />
<br />
There are probably also parts of the delivery which will be proportional to the amount of changes we've made. For instance manual tests of these changes. That's \(C_1n\).<br />
<br />
If this was all, things might be different, and you'd probably not be reading this article, hoping that there migh be a better way to deliver software. In all organizations I know, big releases have almost always taken longer in practice than they should have taken if everything went according to plan. The bigger the release, the less likely to go as planned.<br />
<br />
A core issue in this is the interaction between the different changes in the release. In a delivery with \(n\) changes, each change might impact, or be impacted by the \(n-1\) other changes , so there are \(n(n-1)\) potential failure causes due to changes made in parallel, which is close to \(n^2\).<br />
<br />
Even for bugs which are caused by a single change, it might not be obvious where the problem is located (unless you only made one change...). This means that for each hard to locate bug in a delivery of \(n\) changes, the time it takes to locate each bug is proportional to \(n\), and the number of such bugs is also proportional to \(n\). I.e. more factors that are propotional to \(n^2\).<br />
<br />
It's also my experience, both as software developer and as responsible for software quality, that the time it takes to diagnose and solve a software defect, is stronly related, maybe proportional, to how long ago it was since the defect was introduced. If I mistype something and the compiler or a unit test help me discover this at once, I'll fix it in a couple of seconds. If someone reports a defect that was created months ago, it will probably take days before it's clarified that I'm the one who should fix it, and then I'm in the middle of something else that I need to finish, and after that it'll take time to reproduce that defect in some code I haven't touched in months, and I'll spend time recalling what that software was, and maybe I even have to figure out something done by someone who no longer works for us. More \(n^2\) terms, since the average age of changes when they are delivered is likely to be in proportion to \(n\) too.<br />
<br />
There are probably higher order terms too, but let us stop here, and settle for the following equation for the cost of a delivery with \(n\) changes.<br />
<br />
\begin{equation*}<br />
C_{delivery} = C_0 + C_1n + C_2n^2<br />
\end{equation*}<br />
<br />
This means that our yearly delivery costs for \(m\) deliveries are:<br />
<br />
\begin{equation*}<br />
C_{year} = mC_{delivery} = mC_0 + mC_1n + mC_2n^2<br />
\end{equation*}<br />
<br />
How can we minimize \(C_{year}\) for a certain \(x\)? How many deliveries \(m = x/n\) should we make?<br />
<br />
If we look at the middle term \(mC_1n\) first, we notice that it doesn't matter for this part of the equation if we make many small deliveries, or fewer but bigger. For a fixed \(x = mn\), this part will be \(xC_1\) per year either way. Of course it's good if \(C_1\) is as small as possible, but that's true whether we make one big mega-delivery, or many, tiny deliveries.<br />
<br />
Looking at the remaining parts, \(mC_0\) and \(mC_2n^2\), we can make some observations:<br />
<br />
If \(C_0\) is big, it seems we want to minimize \(m\) and prefer few and big deliveries.<br />
<br />
On the other hand, looking at the last term, \(n^2\) means that \(mC_2n^2\) can become the dominating term if \(n\) is large, even if \(C_2\) is small. That seems to suggest that small deliveries are better, and that Continuous Delivery becomes more important as your product grows, and get's more changes.<br />
<br />
Besides, \(C_0\) is about IT processes, which should be standardized, predictable and repetitive. Ideal for automation, making \(C_0\) as small as possible, and thus \(mC_0\) reasonably small even if \(m\) grows larger.<br />
<br />
\(C_2\) on the other hand is the surprise factor. It's the "how on earth could this cause that"-factor. While we can (and should) work to make problem solving and defect fixing systematic and controlled, it will require creativity and innovation, and we can be sure there will be some surprises and things we couldn't predict.<br />
<br />
Hopefully, looking at deliveries—continuous or not—like this, helps you figure out how to approach challenges in software delivey.<br />
<br />
Considering \(mC_0\), it's important to control and automate the repetetive steps in building, testing, configuring, installing and monitoring software, and also avoid handovers and enable development teams to deliver new versions of their products without red tape. There are plenty of good tools and practices for such things, but it also depends on a suitable system architecture.<br />
<br />
Considering \(mC_1n\), manual testing and similar tasks should be performed and automated in parallel with development, so that we have good, automated regression tests etc when it's time to deliver. <br />
<br />
The most important in dealing with \(mC_2n^2\) is to minimize \(n\), i.e. Continuous Delivery!<br />
<br />
While programming is certainly a creative and sometimes unpredictable activity, software delivery is <i>manufacturing</i>, which should be standardized and automated, and benefits a lot from concepts such as Kaizen and Just-In-Time.<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-24855329712167596202018-11-03T15:36:00.002+01:002019-09-04T14:00:16.769+02:00Building a successful software service is a lot like building a successful chain of restaurants!<i>I'm an engineer with a background in electronics and product cycle times of several years, but in building modern, cloud based software services, I realize that I might need to think more like an entrepreneur in the fast food business.</i><br />
<i><br /></i>
<br />
<h3>
Boundaries of mental models</h3>
My industrial clients are used to products which are more complicated than complex, and thus processes where design is based on thorough analysis and careful tracking of requirements. They are used to heavy investments in machinery, and high levels of precision and standardization to enable efficient, large scale production of identical products.<br />
<br />
It's almost impossible not to be shaped by the things we have done, both as individuals, and as organizations. We obviously use our previous experiences when we venture into new fields, and in my opinion, it's one of the hallmarks of intelligence to learn from whatever we do, and then utilize what we learned in new situations.<br />
<br />
A problem in this is to understand where the boundaries lie for the mental models we form, since misapplied models will lead us astray. We might use the same words, and think that we are in agreement about a system we're building, but suddenly someone says something casual, and you realize that they are seeing something entirely different than you do. Maybe it's a big eye opener for you, or maybe you suddenly feel that someone else is in need of a big eye opener...<br />
<br />
<h3>
Looking from a different angle</h3>
Some time ago, I heard a manager in a product development company talk about the upcoming first release of a cloud based software service as a <a href="https://en.wikipedia.org/wiki/Minimum_viable_product" target="_blank">Minimum Viable Product</a>, and that surprised me, because to me the planned scope was way beyond what e.g. Eric Ries describes in <a href="https://en.wikipedia.org/wiki/The_Lean_Startup" target="_blank">The Lean Startup</a>. But when he continues I understand, because he suggests that the next bunch of features would be released in a second major release, maybe six months after the first release.<br />
<br />
We've been working hard to implement a continuous delivery pipeline, with the capacity to put newly developed features into production in maybe an hour from development, and management still thinks in half year release cycles... Almost as slow as new car models...<br />
<br />
If he, with his background in heavy industry, had been charged with diversifying the company, and opening a chain of fast food restaurants, I'm pretty sure he'd suggested that we first open a single, small restaurant and learn from that, instead of opening lots of big restaurants at once. If he had been informed that a dish on the menu got massive complaints from the customers, he would never have suggested that we deal with that in a "second major release" six months from now.<br />
<br />
While planning is certainly important in the restaurant business, planning too much in detail would be like planning all the moves in a chess game before you start. That strategy will fail quickly. Same thing with the restaurants. Your ways of working need to be based on rapidly responding to feedback from a ruthless reality, with your goals constantly guiding you.<br />
<br />
<h3>
Complicaded vs Complex</h3>
People get used to their tools. If their tools are gated processes, strict separation between R&D and operations, meticulous traceability tracking etc, it might feel very careless not to use these tools in substantial investments. When they learn about "agile" they see sloppy ways of working, since their standard tools, their safety nets, are missing.<br />
<br />
A carpenter wouldn't try to use saw and hammer if had to cook meals instead of building a house. The difference would be so obvious that he'd realize that his normal tools were far from optimal.<br />
<br />
People used to traditional, plan-based development don't see that agile processes mainly are for the complex domain, and their old tools are limited to the complicated domain, since they aren't aware of the distinction. They also don't see that a lot of their tools exist to manage complications that the agile processes eliminate if applied correctly.<br />
<br />
For more about complicated vs complex, I'd suggest investigating the <a href="https://en.wikipedia.org/wiki/Cynefin_framework" target="_blank">Cynefin Framework</a>, which was first published as <a href="https://hbr.org/2007/11/a-leaders-framework-for-decision-making" target="_blank">A Leader’s Framework for Decision Making</a> in Harvard Business Review, and then <a href="https://www.youtube.com/watch?v=N7oz366X0-8" target="_blank">elaborated further by Dave Snowden</a>.Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-39357939932835526342018-04-15T16:44:00.002+02:002018-06-02T15:01:06.409+02:00Building a Smart Mirror from an old Computer Monitor and a Raspberry Pi<i>I recently built a Smart Mirror together with my son Tomas, and there has been some interest in how to do this, so I thought I'd post some notes. Please ask if you have questions or want clarifications. Don't ask me to build one for you, since a home built device like this is probably not legal to sell, and it's a bit much to ask someone to do a thing like that for free... It takes some effort...</i><br />
<h2>
Smart Mirror?</h2>
A Smart Mirror is basically a computer attached to a monitor on a wall. It's used as an information radiator. The mirror part is about having a semi-transparent mirror in front of the monitor, so that dark parts of the computer screen acts as a mirror, albeit somewhat darker than normal.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWNiVlOo1x-BAeMDTQ5mK2Ouo6ERt8NGGJyGYSx6pD0ymojc1dKrqbu7y85dCecqfLGLlKLQnCbm6x3HfsZ-5O4jbcu405nyHMkYmv0x9wtv8c-p62cWd50ai0l5jr1-9OFOzPTHeA8Q/s1600/DSC_0703.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1365" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWNiVlOo1x-BAeMDTQ5mK2Ouo6ERt8NGGJyGYSx6pD0ymojc1dKrqbu7y85dCecqfLGLlKLQnCbm6x3HfsZ-5O4jbcu405nyHMkYmv0x9wtv8c-p62cWd50ai0l5jr1-9OFOzPTHeA8Q/s640/DSC_0703.JPG" width="544" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The Smart Mirror is hanging on the wall...</td></tr>
</tbody></table>
<br />
This doesn't take much computing power, so a good computer for this purpose would be a cheap and tiny Raspberry Pi and any old flat screen monitor you have left over. The most difficult part of this is to make it look good enough to be acceptable on a wall in a home.<br />
<h2>
<span style="background-color: yellow;">Warning!</span></h2>
<span style="background-color: yellow;">Unless you really know what you are doing, building or installing a device like this could cause fire, electrocution, network security breaches, or a divorce, so don't try unless you understand the legal and practical consequences for the safety of yourself and others who might be affected. This text will not teach you any of the skills you need. It will only help you with some practical tips, assuming that you alreaady have sufficient training and skills in building electrical devices, carpentry, linux and network security. </span><br />
<span style="background-color: yellow;"><br /></span>
<span style="background-color: yellow;">I'm not going to tell you to unplug cables before tearing things apart, or to change default passwords. Unless such things are obvious, wait for consumer versions of smart mirrors to appear on the market. They will be cheaper and easier to use anyway... Be patient!</span><br />
<h2>
Parts</h2>
Your milage may vary, but this is the material I used:<br />
<ul>
<li><a href="https://www.cnet.com/products/dell-e196fp-lcd-monitor-19-series/specs/" target="_blank">An old 19" VGA monitor</a></li>
<li><a href="https://www.slojd-detaljer.se/sortiment/tra-metallslojd/plast-gummi/spegelplast/envagsspegel-akryl-6657" target="_blank">Semi-transparent mirror 40 cm * 30 cm</a></li>
<li>A VESA wall mount and suitable screws for the wall</li>
<li><a href="https://www.prisjakt.nu/produkt.php?p=3569430" target="_blank">Raspberry Pi 3 Model B</a></li>
<li>Micro SD card as "hard drive"</li>
<li>USB charger providing at least 1.5A</li>
<li>Long enough micro USB cable to power Pi</li>
<li><a href="https://www.aliexpress.com/item/EP-0073-VGA666-DPI-dtoverlays-Module-Adapter-Board-Gert-VGA-For-Raspberry-Pi-3B-2B-B/32805339645.html?ws_ab_test=searchweb0_0,searchweb201602_2_10152_10151_10065_10344_10068_10342_10343_10340_10341_10698_10697_10696_10084_10083_10618_10307_10301_10303_10059_10534_308_100031_10103_441_10624_10623_10622_10621_10620,searchweb201603_25,ppcSwitch_7&algo_expid=9660d2ae-9be5-4e62-a874-a76a5ebf171a-0&algo_pvid=9660d2ae-9be5-4e62-a874-a76a5ebf171a&transAbTest=ae803_1&priceBeautifyAB=0" target="_blank">Gert VGA666 adapter</a></li>
<li>Spacers, nuts and screws to attach Pi to back of monitor. Use <a href="https://www.aliexpress.com/premium/brass-spacers-2.5mm.html">M2.5</a>! I used M3s which are too big.</li>
<li>VGA cable</li>
<li>Power cable for monitor</li>
<li>Solid oak millwork for <a href="https://www.bauhaus.se/planhyvlat-ek-10x47x2440mm.html" target="_blank">front</a> and <a href="https://www.bauhaus.se/planhyvlat-ek-10x47x2440mm.html" target="_blank">side </a>of frame</li>
<li><a href="https://www.aliexpress.com/item/10PCS-NAIERDI-Decorative-Corner-Bracket-Antique-Jewelry-Wooden-Box-Foot-Leg-Corner-Protector-Crafts-Furniture-Fittings/32823832649.html" target="_blank">Metal Corner Brackets</a></li>
<li>Wood glue</li>
<li><a href="https://www.junckers.com/en/woodcare/oil-hardwax-oil/rustic-oil/c-100/p-552" target="_blank">Wood oil</a></li>
</ul>
<div>
Besides these parts, you obviously need suitable tools and materials, but if you passed the criteria in the warning section, you already know that...</div>
<div>
<br /></div>
<div>
If you have a suitable monitor with a HDMI connector, life will be easier for you, since the Raspberry Pi has an HDMI connector. Then you can skip the Gert VGA666 passive VGA adapter.<br />
<br />
You could also use glass and semitransparent mirror film instead of the acrylic mirror I used.</div>
<h2>
The VGA Monitor</h2>
Before you start, you should probably think about the layout on the back of the monitor:<br />
<ul>
<li>Is there a suitable space for the Raspberry? How should it be directed to make it convenient to attach power, monitor, possible USB devices and to swap micro SD card if you need to do that.</li>
<li>How are the connectors you need to use located? Will cables protrude in an inconvenient way?</li>
<li>In what direction from the mirror do you expect the cables to go?</li>
<li>If you plan to make the mirror vertical, should you rotate left or right?</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
</div>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtOT9EVTB9PzPpjUfPUjco8wrrPQV9kdBWjHNHO5lvXm4b8LuCcW6nsG9aIJKBUnsKGRMMso1JME35SqPpjgomGkkmYqMx2sIQE10g9kKvB3dW90WeZWaoq8yqydHnP5wC1aXV1QSnwQ/s1600/20111119074104cont7.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="571" data-original-width="700" height="261" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgtOT9EVTB9PzPpjUfPUjco8wrrPQV9kdBWjHNHO5lvXm4b8LuCcW6nsG9aIJKBUnsKGRMMso1JME35SqPpjgomGkkmYqMx2sIQE10g9kKvB3dW90WeZWaoq8yqydHnP5wC1aXV1QSnwQ/s320/20111119074104cont7.jpg" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Once upon a time, the monitor looked like this...</td></tr>
</tbody></table>
Your Smart Mirror will be a lot thicker than a normal mirror, so you'll want to remove all the plastic shielding from your monitor, and get it down to the thinnest possible size, just the metal. This is probably no big deal. You need a screwdriver and a suitable amount of violence.<br />
<br />
Be careful about the monitor adjustment buttons. In my case, it was a piece of PCB on a ribbon cable, and I attached it on the backside of the monitor with double sided tape in such a way that I can reach the buttons with my fingertips if I need to.<br />
<br />
Another consideration is that screws for the wall mount will no longer go through the layer of plastic you removed. This might cause supplied screws to extend further into the monitor interior than intended. That could possibly lead to damage, so beware!<br />
<h2>
The Raspberry Pi</h2>
I used a Raspberry Pi 3B, but the software I use, <a href="https://magicmirror.builders/" target="_blank">Magic Mirror 2</a>, supports both Pi 2 and Pi 3.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8JEFT3GyYrVx9yyVxQELNjZs8G8VvEjabEOzufwWisRHGDfz5qNHsbPxifqZ5jzqDWNbQPX-SrQZRLcxvRAD-3ScWPuCEyC_zBUQ_kxakB1MpaulM0SxlXC7LXgEL9y5JOQ1jxkB7QQ/s1600/pi3b.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1069" data-original-width="1600" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8JEFT3GyYrVx9yyVxQELNjZs8G8VvEjabEOzufwWisRHGDfz5qNHsbPxifqZ5jzqDWNbQPX-SrQZRLcxvRAD-3ScWPuCEyC_zBUQ_kxakB1MpaulM0SxlXC7LXgEL9y5JOQ1jxkB7QQ/s320/pi3b.png" width="320" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Raspberry Pi 3B</td></tr>
</tbody></table>
Regarding location of the Pi in the mirror, all sides matter. The power connector is the micro USB to the left on the bottom side. Considering how I mounted my Pi, I drilled a hole in my frame to connect the USB power cable. I use WiFi, so I don't need the Ethernet port on the right side, but I used USB connectors on the right side for keyboard and mouse during setup. They couldn't be blocked. The micro SD card with the OS is connected on the underside of the board from the left side. That's accessible to me if I remove the frame. The Gert VGA666 power adapter sits on the GPIO port on the top. The problem I had there was that the VGA connectors in each end of the VGA cable almost got in each others way, since the monitor VGA port and the VGA666 were so close to each other.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheB_xRRmBAgSB05sKDBLLRLT_JcX__nVdIOSzH8i0lfE8fjZWEnoVc_gUx-6N0mxgJ5qy5slBNwfggNzR7v-hfjkEbBHiMVj-p5NT97bGmVZUT2Rjh2nWwgHLJJgsbQnA-hPzpXv6g4g/s1600/DSC_0699.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="900" data-original-width="1600" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheB_xRRmBAgSB05sKDBLLRLT_JcX__nVdIOSzH8i0lfE8fjZWEnoVc_gUx-6N0mxgJ5qy5slBNwfggNzR7v-hfjkEbBHiMVj-p5NT97bGmVZUT2Rjh2nWwgHLJJgsbQnA-hPzpXv6g4g/s640/DSC_0699.JPG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The mirror from behind. The left side goes up, so the Raspberry Pi in the lower right corner will also be in the lower right corner when the mirror is in place.</td></tr>
</tbody></table>
<div class="separator" style="clear: both; text-align: left;">
I found a good place in a corner of my monitor for the Pi, and used M3 screws, nuts and 5 mm brass spacers to attach it to a piece of the monitor which could be screwed loose and drilled in. I suspect a glue gun would work. It obviously depends on what stress the Pi is exposed to, mainly from cables attacted to the connectors. M3 is really a bit big for the holes in the Raspberry Pi. The right size is M2.5.</div>
<h2>
The Mirror</h2>
I used a ready made acrylic one-way mirror from <a href="https://www.slojd-detaljer.se/sortiment/tra-metallslojd/plast-gummi/spegelplast/envagsspegel-akryl-6657">Slöjddetaljer</a>. I think my screen area inside the metal frame was 30.5 cm * 38 cm, so their 30 cm * 40 cm model was a very convenient size. The disadvantage with acrylic is that it scratches very easily, so be very careful cleaning spots. You will obviously place the reflective layer back, so front side scratches won't destroy the reflection, and you can polish them away with special polish for acrylic surfaces.<br />
<br />
To cut off the excess piece, I scratched the mirror on both sides with a sharp knife along a metal ruler, and broke off the piece I didn't want. It's not completely trivial to break 2 cm * 30 cm in one piece. Remember to be careful not to make scratches or marks in the mirror.<br />
<br />
The more scratch resistant approach is obviously to get a pane of 3 mm glass cut to the right size, and mount <a href="http://www.mdpsupplies.se/onewaymirror.asp">one-way mirror film</a> on the back side.<br />
<br />
Whether you have a glass or acrylic mirror, you want to make sure that the reflective side is on the back, and I think that the mirror should lie directly on the LED screen. You don't want refelctons to go back and forth between the mirror and the screen.<br />
<br />
The way I cut the mirror, it fit entirely inside the metal framing which surrounds the LED display, and thus lies flush to the LED. It's kept in place by the oak frame. I simply taped it to the screen with masking tape.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDRdkwAoZYqSCA92flpNtjyNjs6QRCK2s47E2O5GcUA8-ha8gL-G7Sv2mhuq7lVLPb3xO4VU2JuFGpErrv3WmW4pS3oXhguG1To6czwNM8B1DsdiHpF1r0ZGMmyvN93g53TISfN2QUwQ/s1600/DSC_0713.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1600" data-original-width="1417" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDRdkwAoZYqSCA92flpNtjyNjs6QRCK2s47E2O5GcUA8-ha8gL-G7Sv2mhuq7lVLPb3xO4VU2JuFGpErrv3WmW4pS3oXhguG1To6czwNM8B1DsdiHpF1r0ZGMmyvN93g53TISfN2QUwQ/s640/DSC_0713.JPG" width="566" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">The mirror without frame, attached to the monitor with masking tape.</td></tr>
</tbody></table>
<br />
<h2>
The Frame</h2>
Since the Monitor and the Computer hangs on the VESA wall mount, the frame only needs to be strong enough to carry its own weight, and stop the thin mirror from falling off the computer screen. The frame hangs on the "picture", in contrast to a traditional picture, which hangs in its frame.<br />
<br />
You could imagine using a frame from an old painting or mirror, and just saw it to size, but there is a problem with that. Depth! A mirror glass is just a few millimeters. The minimal depth of an old painting it determined by the wood frame which the canvas is streched on. That's tiny compared to a computer monitor plus a wall mount.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLLGvD3NqbqzDJMRNb1aDt2nj42anIQn3t917_MU_AjdVHUE2TEjQ3rHKDbCjsDZhtXKnpZ7ev5ZHUX37JBjkiV4VUiT89oFFXotCAHAusvi117-N93PlEFIDgCQFqeRfMs2EedAMXYg/s1600/DSC_0710.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto; text-align: center;"><img border="0" data-original-height="1600" data-original-width="298" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLLGvD3NqbqzDJMRNb1aDt2nj42anIQn3t917_MU_AjdVHUE2TEjQ3rHKDbCjsDZhtXKnpZ7ev5ZHUX37JBjkiV4VUiT89oFFXotCAHAusvi117-N93PlEFIDgCQFqeRfMs2EedAMXYg/s640/DSC_0710.JPG" width="118" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Mirror without frame from side</td></tr>
</tbody></table>
<br />
With the wood I selected, I have 8 mm of oak in front of the mirror, and 47 mm of oak behind the top 8 mm, streching back towards the wall. The monitor and wall mount are thicker than that. I measure 19 mm from the wall to the back of the frame. That's big enough to allow for ventilation (I hope), but small enough to hide most of the ugly technology. It's 73 mm from the wall to the front of the frame. That's a 73 - 19 = 54 mm thick frame. 47 + 8 = 55, so I have sanded down 1 mm when I worked with this, which brings us to the carpentry part...<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Unfortunately, my carpentry English is limited... Some swedish in <i>italics</i>.<br />
<br />
The front part is a 27 mm * 8 mm <i>"foglist"</i>, which means that the corners closest to one of the wide sides are rounded. This is the front of the frame. The frame sides are from 47 mm * 10 mm <i>"planhyvlad list". W</i>hile the bigger side pieces are untreated, the <i>foglist </i>was varnished, so I had to sand those down first so that they would work with wood glue and wood oil.<br />
<br />
Gluing the front and side in angle with the outsides flush, the front will provide a 27 - 10 = 17 mm cover. We want to cover four things:<br />
<ol>
<li>Sideways gap between oak frame and metal frame of sceen.</li>
<li>Metal frame besides screen.</li>
<li>Gap between metal frame and mirror pane.</li>
<li>Tape keeping the mirror in place.</li>
</ol>
<div>
17 mm should be fine for this. There was also 21 mm wide <i>foglist</i>, but 11 mm would have been too little, and it would have made the proportions of the frame worse. Running the Raspberry in console (non GUI) mode, I notice that the frame completely covers the top and bottom rows of text, and the first and last columns. Considering this, it's possible that I should have made the frame a bit bigger, and used shims to keep the monitor in the middle. It's no problem while running the magicmirror2 app though. The app is made with consideration to custom frames...</div>
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGGtML2EvbEbJ9LmE9ewqkIaiNj1wefqd4XHPUV4KbeFbhbZH9f5nEnXT_kejHmggA7FT9_Rt6IjEml1y0YmuNKJlIiFdbw6aUxdpmy1RjepqFiPLyNNJ-CBm8V5lImllRFT2Cna0nkg/s1600/DSC_0714.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="900" data-original-width="1600" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiGGtML2EvbEbJ9LmE9ewqkIaiNj1wefqd4XHPUV4KbeFbhbZH9f5nEnXT_kejHmggA7FT9_Rt6IjEml1y0YmuNKJlIiFdbw6aUxdpmy1RjepqFiPLyNNJ-CBm8V5lImllRFT2Cna0nkg/s640/DSC_0714.JPG" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Frame from behind. Hole for Raspberry power in near left corner. Piece of wood to keep frame in place on inside of top side. Stains from rejected experiment with antique wax also visible on inside.</td></tr>
</tbody></table>
<br />
This is what I did in order:<br />
<br />
<ul>
<li>Sand off the varnish from the <i>foglist</i>.</li>
<li>Cut <i>foglist </i>and <i>planhyvlad list</i> in four pieces each which are long enough to fit on each side with some margin.</li>
<li>Match the pieces, decide which sides look better, glue them and clamp them.</li>
<li>Remove excess glue and sand the L-shaped pieces so that they are straight and smooth.</li>
<li>Saw the ends to right length in 45 degree angle and sand edges.</li>
<li>Glue and clamp into the final shape.</li>
<li>Remove excess glue and sand corners slightly.</li>
<li>Measure where the hole for the power USB for the Raspberry should go, and drill that.</li>
<li>Glue a piece of wood on the inside of the top side of the frame, to keep the frame in place when it's hanging on the monitor.</li>
<li>Oil the frame twice with a night in between.</li>
<li>Mount the decorative (?) metal brackets for the corners. (I didn't want to hammer nails into the frame without pilot holes, and I was reluctant to drill freehand with thinner drills than 2 mm, so I used super glue to make sure that the thin nails for the corner brackets stuck in their holes.)</li>
</ul>
<br />
<h2>
Software and Configuration</h2>
<div>
During installation, I had a USB keyboard and mouse attaced to the mirror. Once I had set up remote access via VNC, that was no-longer needed. It also took some work to get the VGA666 drivers to work, so initially I had another monitor attached on the HDMI port. </div>
<h3>
Operating System</h3>
<div>
The Raspberry Pi is running <a href="https://www.raspberrypi.org/downloads/raspbian/" target="_blank">Raspbian </a>installed on a micro SD card.</div>
<h3>
MagicMirror2</h3>
<div>
The main piece of software is available at <a href="https://magicmirror.builders/" target="_blank">https://magicmirror.builders/</a></div>
<div>
<br /></div>
<div>
Installation and configuration is described <a href="https://github.com/MichMich/MagicMirror#installation" target="_blank">in the GitHub repo.</a></div>
<div>
<br /></div>
<div>
The application is configured in <span style="font-family: "courier new" , "courier" , monospace;">config/config.js</span>, and third party modules are installed with <span style="font-family: "courier new" , "courier" , monospace;">git clone</span> in the <span style="font-family: "courier new" , "courier" , monospace;">modules</span> subdirectory. I'n used these modules:</div>
<div>
<ul>
<li><a href="https://github.com/Alvinger/MMM-ResRobot" target="_blank">MMM-ResRobot</a> </li>
<li><a href="https://github.com/fmandal/MMM-YrThen" target="_blank">MMM-YrThen</a></li>
</ul>
</div>
<h3>
Display Rotation and VGA666</h3>
<div>
If yu are using a digital monitor via the HDMI connector, this is not an issue, but since the VGA666 adapter uses GPIO ports which are by default reserved for other use, you might have some things to deal with if you use a VGA monitor.</div>
<div>
<br /></div>
<div>
All the details you need to know are in <a href="https://www.raspberrypi.org/forums/viewtopic.php?f=91&t=94424">the Raspberry Pi Forum</a>. As I said above, you might need an HDMI monitor until you get this to work.</div>
<div>
<br /></div>
<div>
I added this to /boot/config.txt<br />
<br />
<div>
<span style="font-family: "courier new" , "courier" , monospace;"># VGA 666</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">dtoverlay=vga666</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">enable_dpi_lcd=1</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">display_default_lcd=1</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">dpi_group=2</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">dpi_mode=16</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">display_rotate=1</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">avoid_warnings=1 </span></div>
</div>
<h3>
Starting MagicMirror2 on boot</h3>
<div>
I had to fiddle with Electron to get the app to run at boot, but I hope that's now set up with the default install.</div>
<h3>
Not blanking the screen...</h3>
<div>
By default, the Raspberry turns of the screen after a few minutes of inactivity. You don't want that...</div>
<div>
<br /></div>
<div>
Add in /etc/lightdm/lightdm.conf:</div>
<span style="font-family: "courier new" , "courier" , monospace;">xserver-command=X -s 0 -dpms</span><br />
<div>
<br /></div>
<div>
In /etc/kbd/config:</div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">BLANK_TIME=0</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">BLANK_DPMS=off</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">POWERDOWN_TIME=0</span></div>
</div>
<h3>
Remote Access</h3>
<div>
The easy ways to get remote access to a Raspberry Pi is to enable either ssh or vnc in <span style="font-family: "courier new" , "courier" , monospace;">raspi-config</span>, <span style="font-family: "courier new" , "courier" , monospace;">interfacing options</span>. I used vnc.</div>
<h2>
Maintenance</h2>
To update MagicMirror2, run <span style="font-family: "courier new" , "courier" , monospace;">git pull && npm install</span><span style="font-family: inherit;">. You might need to do the same for each module. For Raspbian, it's the usual </span><span style="font-family: "courier new" , "courier" , monospace;">sudo apt update</span><span style="font-family: inherit;"> followed by </span><span style="font-family: "courier new" , "courier" , monospace;">sudo apt upgrade</span><span style="font-family: inherit;">.</span><br />
<h2>
Placing the Mirror</h2>
The main consideration regarding placement compared to a normal mirror, is that you need somewhere to connect your power cords, so that you don't stumble on them.<br />
<br />
Otherwise, besides the fact that you want a mirror placed so that you can look straight into it, it should of course be located in a place where it makes sense to see the information you radiate. For instance, weather information might be conventient where you decide whether to wear boots or loafers...<br />
<h2>
Future Work</h2>
There are some things left to do...<br />
<h3>
Dimming</h3>
<div>
Assume that you have settings so that you see yourself nicely in the mirror in the daylight, and you can see the text on the screen. Assuming that the settings are fixed, things will appear very differently at night. Without daylight, with much less light in the room, the thing that used to be a mirror, is now a black screen with very bright text that's hurting your eyes (well, almost).</div>
<div>
<br /></div>
<div>
There are two parts in this problem:</div>
<div>
<ol>
<li>How do we determine how bright the screen should be?</li>
<li>How do we change the brightness of the screen once we know what we want?</li>
</ol>
<div>
Regarding part 1, I assume there are two fundamental approaches. A) time based solution, and B) light based solution. Since I don't have a camera connected to the Pi, and the VGA666 uses up the entire GPIO bus where I could possibly have attached a light meter, I think I'll go for the time based solution. It's also a much simpler solution, so it's a good first attempt anyway.</div>
</div>
<div>
<br /></div>
<div>
I guess there are basically two fundamental approaches for part 2 too. We either change system brightness settings in the drivers or in X, or we change something in the magicmirror2 application (which covers the entire screen anyway).</div>
<div>
<br /></div>
<div>
There are a number of ways you could adjust brightness for the HDMI output in a Raspberry Pi, e.g. xbacklight or xcontrast, but they don't seem to work with the VGA666 driver. There is no such thing as an assumption of a LED backlight in a VGA connection, even though it exists in the acual device when it's a LED screen.</div>
<div>
<br /></div>
<div>
The best way forward might be to cover the entire window in magicmirror2 with a black top layer with varying transparency in CSS, or something similar...</div>
<h3>
Infrastructure As Code</h3>
<div>
As is now, I've installed the application, and done all the needed configuration by hand. something happens, e.g. the SD card break (which sometimes happens with these devices after power losses), I'll have to do it all over again.</div>
<div>
<br /></div>
<div>
It would be nice to e.g. have a git repo with an Ansible playbook containing everything needed to get us from a fresh Raspbian install to a working system.</div>
<h3>
Only One Power Cord</h3>
It would be nice to only have one power cord from the power outlet to the mirror. That assumes that we can get 1.5 A stabilized 5V from some place in the monitor without breaking it, or that we can fit an extension cord providing two power sockets behind the display in the mirror.<br />
<h3>
Interactivity?</h3>
As far as I understand, you can e.g. attach a web camera, and install additional software to get features similar to Siri or Alexa. I have no such plans...<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-12050229627502884572017-10-07T11:30:00.003+02:002022-04-29T01:04:58.399+02:00Using Xming for GUI apps in Ubuntu on Windows 10 Home EditionTo get Ubuntu GUI applications to work under <a href="http://pickypython.blogspot.se/2017/09/running-docker-in-ubuntu-on-windows-10.html" target="_blank">Windows Subsystem for Linux (WSL)</a> I installed the X server <a href="https://sourceforge.net/projects/xming/" target="_blank">Xming</a> in Windows 10. Assuming that I've actually installed some GUI apps, such as xterm or chromium-browser, I can then start them from the Ubuntu bash prompt.<br />
<br />
First of all, Xming needs to be started in Windows, and you need to set the <span style="font-family: "courier new" , "courier" , monospace;">DISPLAY </span>environment variable: <span style="font-family: "courier new" , "courier" , monospace;">export DISPLAY=:0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
You can then run <span style="font-family: "courier new" , "courier" , monospace;">xterm &</span> to start a separate terminal window. I got a warning about Xming not finding the font it looks for, but I can live with that. The more serious problem is that I don't get my Swedish keyboard settings. To fix that, I adjusted the Xming shortcut in Windows. To find the shortcut file, I went to XMing in Windows 10 start menu, right-clicked, selected "More" and "Open path" as shown below:<br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg59sd-joaR3irnLskM83nayZHMwWSPLrabxBT4mPDOomNcrMSrWeTLNL98sg1cVa1wENb59SPWQqn5xLVyEP_dpaQdcBj8LnUUXn0eoUDMlEmkz7D9uVqj-6QRxxk2-g4YqExeBWzKGg/s1600/xming_start_menu.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="318" data-original-width="820" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg59sd-joaR3irnLskM83nayZHMwWSPLrabxBT4mPDOomNcrMSrWeTLNL98sg1cVa1wENb59SPWQqn5xLVyEP_dpaQdcBj8LnUUXn0eoUDMlEmkz7D9uVqj-6QRxxk2-g4YqExeBWzKGg/s320/xming_start_menu.png" width="320" /></a></div>
<br />
I then right-clicked on the Xming shortcut in the explorer windows that appeared, and changed the path to the following:<br />
<blockquote class="tr_bq">
"C:\Program Files (x86)\Xming\Xming.exe" :0 -clipboard -multiwindow -xkbmodel pc105 -xkblayout fi -xkboptions grp:ctrl_shift_toggle</blockquote>
I actually used Finnish keyboard settings, since I read that some Xming versions have problems with the (identical) Swedish keyboard settings. If you already had Xming running, you probably have to exit it before you restart it:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTSin2LNzAAQw_wD-BgOYx6LZd2Oknj7sS4EHiSW9ef-rNMUBEIn-rVXHB1FMhDSwMayMFih8V6JksRWE2sAdo5R_yuK1R_O3ZZc5_mD7eKVcQV60gfEbniiVDUMF2yXxRyVFFLG_ZiA/s1600/xming_exit.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="232" data-original-width="351" height="211" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTSin2LNzAAQw_wD-BgOYx6LZd2Oknj7sS4EHiSW9ef-rNMUBEIn-rVXHB1FMhDSwMayMFih8V6JksRWE2sAdo5R_yuK1R_O3ZZc5_mD7eKVcQV60gfEbniiVDUMF2yXxRyVFFLG_ZiA/s320/xming_exit.png" width="320" /></a></div>
<br />
Having restarted Xming, and started an xterm again, the keyboard had all the keys in the right places! :-)<br />
<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-9394870736306251002017-09-17T15:41:00.002+02:002017-10-07T11:38:51.101+02:00Running docker in Ubuntu on Windows 10 Home EditionWith <a href="http://pickypython.blogspot.se/2017/09/running-linux-directly-in-windows-10.html" target="_blank">Ubuntu running in WSL on Windows 10</a>, I want it to be as close to a "real" Ubuntu installation as possible. One of the shortcomings with WSL is that it doesn't allow you to run docker. <span style="font-family: "courier new" , "courier" , monospace;">apt install docker</span> works as expected, and running <span style="font-family: "courier new" , "courier" , monospace;">docker </span>will give you the familiar menu, but <span style="font-family: "courier new" , "courier" , monospace;">docker ps</span> is sufficient to break the spell.<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">$ docker ps</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?</span><br />
<br />
It turns out that you can run the docker client commands in WSL ubuntu, but you can't run the docker service through WSL. The trick is to run docker in Windows, and get your client in WSL Ubuntu to talk to that.<br />
<br />
These days, there is <a href="https://www.docker.com/docker-windows" target="_blank">Docker for Windows</a> which uses Microsoft Hyper-V in Windows 10, but since my laptop only run Windows 10 Home Edition, I installed the older <a href="https://www.docker.com/products/docker-toolbox" target="_blank">Docker Toolbox</a>, which is based on VirtualBox. At first, I installed a brand new VirtualBox, and then intalled Docker Toolbox (which also includes VirtualBox). This caused a networking problem, but after I deinstalled both Docker and VirtualBox, and ran the Docker Engine installer again so that it could install its preferred version of VirtualBox, it worked fine. I didn't include Kitematic, marked alpha, in the install.<br />
<br />
The trick now, is to get the WSL Ubuntu docker client to communicate with the server in the VirtualBox. To do this, you need to define three environment variables:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">export DOCKER_HOST=tcp://XXX:2376 </span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DOCKER_TLS_VERIFY=1</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">export DOCKER_CERT_PATH=/mnt/c/Users/XXX/.docker/machine/certs/</span><br />
<br />
Of course, you should replace the <span style="font-family: "courier new" , "courier" , monospace;">XXX</span> part in the host and cert variables. <span style="font-family: "courier new" , "courier" , monospace;">DOCKER_HOST</span> should be the same as you have in Windows. I assume you know your Windows home directory...<br />
<br />
Having done this much, enables me to do:<br />
<br />
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">$ docker run -it alpine sh</span><span style="font-family: "courier new" , "courier" , monospace;">/</span> </blockquote>
<blockquote class="tr_bq">
<span style="font-family: "courier new" , "courier" , monospace;">#</span></blockquote>
The obvious remaining problem is mounting volumes. Even if I run this in WSL Ubuntu, the docker service runs in a different environment, with a different view of the file system. I assume that provided directories must be avilable from the Windows system, and presented with paths that make sense in Windows...<br />
<br />
I suspect there will be more complications, but there is basic operation at least. :-)<br />
<br />
<br />
<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-718543213735047282017-09-17T14:16:00.001+02:002017-10-07T11:34:07.003+02:00Running Linux directly in Windows 10Tools like <a href="http://www.cygwin.com/" target="_blank">Cygwin</a> and <a href="https://babun.github.io/" target="_blank">Babun</a> has made Windows somewhat bearable for people used to the power of Unix, and <a href="https://www.virtualbox.org/" target="_blank">VirtualBox</a> has enabled us to run a full Linux system in a virtual machine if we want that. Despite all this, I still have a dual boot laptop with Windows 10 and Ubuntu on separate partitions. A shell and ported applications is too weak. A virtual machine is too slow and cumbersome.<br />
<br />
A while ago, some surprising new "apps" appeared in Windows App Store: <a href="https://www.microsoft.com/en-us/store/p/opensuse-leap-42/9njvjts82tjx" target="_blank">OpenSuSE Leap 42</a>, <a href="https://www.microsoft.com/en-us/store/p/suse-linux-enterprise-server-12/9p32mwbh6cns" target="_blank">SLES 12</a> and <a href="https://www.microsoft.com/en-us/store/p/ubuntu/9nblggh4msv6" target="_blank">Ubuntu 16.04 LTS</a>! They all use the <a href="https://blogs.msdn.microsoft.com/wsl/2016/04/22/windows-subsystem-for-linux-overview/" target="_blank">Windows Subsystem for Linux (WSL)</a> which allows you to run native ELF binaries on a Windows 10 kernel. So, it's neither ported apps like Cygwin, nor virtualization. It's more like <a href="https://www.winehq.org/" target="_blank">Wine</a>, but in the other direction, and developed by people with full access to the relevant source code.<br />
<br />
To <a href="https://msdn.microsoft.com/en-us/commandline/wsl/install_guide" target="_blank">install WSL</a>, you need build 16215 or later of Windows 10 on x64, which currently (September 2017) means that you need to join <a href="https://insider.windows.com/en-us/getting-started/" target="_blank">Windows Insider</a> to get a pre-release of Windows 10. No big deal! I went along and installed Ubuntu.<br />
<br />
WSL is mainly intended as a developer tool. The idea is not to run Linux production servers on a Windows 10 kernel. I hope it's good enough for me to stop dual booting my laptop, and give the whole disk to Windows.<br />
<br />
I now have an "Ubuntu" app in the Windows 10 task bar, which provides me with a familiar bash shell, just like Cygwin and Babun does, but here I can run things like <span style="font-family: "courier new" , "courier" , monospace;">apt install docker</span> and a lot of things I could never do in Cygwin or Babun, without the sluggishness and complications of virtualization.<br />
<br />
To run Linux GUI programs, the simplest approach is probably to install <a href="https://sourceforge.net/projects/xming/" target="_blank">Xming</a> in Windows, and <span style="font-family: "courier new" , "courier" , monospace;">export DiSPLAY=:0</span> in Ubuntu. By default that gives you a US keyboard in X, but I wrote a <a href="http://pickypython.blogspot.se/2017/10/using-xming-for-gui-apps-in-ubuntu-on.html" target="_blank">blog post about fixing that</a>.<br />
<br />
WSL does not support the docker server, but with a docker server running in Windows, you can use the docker command to run client tasks in Ubuntu. Something like <span style="font-family: "courier new" , "courier" , monospace;">docker run -it alpine sh</span> works as intended. I wrote <a href="http://pickypython.blogspot.se/2017/09/running-docker-in-ubuntu-on-windows-10.html" target="_blank">a separate blog entry about getting docker working</a>.<br />
<br />
Will I drop the Linux partition on my laptop SSD and be happy with only Windows 10 on my laptop? I don't know yet, but I'm optimistic.<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-39582937725065288882016-03-04T20:32:00.004+01:002019-09-04T13:48:00.160+02:00A Use Case for Continuous DeploymentThere are a number of good reasons for reasons using Continuous Delivery and Continuous Deployment. Yesterday, <a href="http://rebelalliance.se/consultant-jeff-campbell.html" target="_blank">Jeff Campbell</a> talked about "Making the Case for Continuous Delivery" at the <a href="http://www.meetup.com/Goteborg-Continuous-Delivery-Meetup/" target="_blank">Göteborg Continuous Delivery Meetup</a>. His <a href="https://www.youtube.com/watch?v=QdtJV2YuK9M" target="_blank">talk is online</a> at Youtube.<br />
<br />
He had many good points, but I thought that I'd like to complement that with a more concrete example, of how life can get much simpler if we work this way. There are two fundamental ideas here:<br />
<ol>
<li>Complex problems usually get much simpler if we split them into several smaller problems, that we solve after each other.</li>
<li>A Continuous Deployment ability enables us to rapidly get small production changes into production, so that we can solve problems in several small steps, with real-world feedback between each step in a single working day (instead of several months).</li>
</ol>
Somewhat simplified, Continuous Deployment means that as soon as developers change your software, your system is built, tested and put in production. Continuous Delivery means that as soon as developers change your software, your system is built, tested and could be put in production if that's what you want. The benefit from the case below comes from actually putting changes into production in several small steps, but it does not depend on a practice of <i>always</i> doing Continuous Deployment.<br />
<br />
<h2>
Our Use Case</h2>
Imagine that we have a production system where we store information about customers. In the customer table, we've stored address information, but due to changes in business requirements, we'll soon need to keep track of both current and previous addresses. The old address fields won't suffice. We'll need a <span style="font-family: "courier new" , "courier" , monospace;">customer_address</span> table where we can store several addresses for different date ranges for each customer. <br />
<br />
<h2>
The Traditional Solution</h2>
In traditional development, with releases maybe every month or less often, we'd develop a new version of the software, which contained the new support for several addresses, as well as all other features expected for this release. The new software would not expect any address information in the customer table. The replacement for current features would simply display the address from the new table where <span style="font-family: "courier new" , "courier" , monospace;">end_date</span> was empty, and new features showing historical addresses, would use <span style="font-family: "courier new" , "courier" , monospace;">start_date</span> and <span style="font-family: "courier new" , "courier" , monospace;">end_date</span> to decide which address to show.<br />
<br />
The programmer would probably not think so much about the migration of data when he changed the programs. His focus would be on the new business requirements, the future behaviour. Having implemented that, he (or a DBA) would look at data migration. The migration would go in four steps:<br />
<ol>
<li>Perform a backup of the database. </li>
<li>Add the new table to the database schema.</li>
<li>Run a script to copy the address for each customer to the new table, with some (more or less correct) start date set. </li>
<li>Drop the old address columns in the customer table.</li>
</ol>
This data migration would need to happen in some "service window", when the system is not running. Downtime would be difficult to avoid. It's quite possible that other system changes in our monthly release caused additional database migrations.<br />
<br />
When the service window is over, we resume operation. If all is well, we only had a few hours of downtime. Ok? YMMV. We're not home yet though... What if some other change in the system caused a blocker bug, and we need to revert to the old version of the system? We no longer have a database that supports that. In the best case, the time needed to revert to the old software will be as long as the upgrade (reverse data migration), unless we're willing to loose the data changes done after the upgrade (restore backup).<br />
<br />
Even if we are careful and quality-minded, a traditional approach with infrequent releases will always mean that the risk for disruptions are much bigger than for a Continuous Deployment approach, since there are many changes, and each change is a risk. The consequence of each issue that occurs is also bigger, since there are more migrations to revert etc. <br />
<br />
<h2>
The Agile Solution</h2>
With a Continuous Deployment we can afford to be much more concerned with the transition of our production environment from its current state to its future state. A small, low risk change to a production environment should be a simple thing in a Continuous Delivery environment, so we can do that often without worries.<br />
<br />
Our first step, would simply be to create the new table. That is a tiny change which has minimal impact on the running system.<br />
<br />
Our second step, is to change our software, so that the code which adds, updates or removes address information, deals with the new table <i>in addition</i> to the old table. Reads are still just from the old table. This means that we duplicate data for a while. In the long run we don't want that, but in the short run, we put this in production and verify that we get exactly the content we expect in the new table. Nothing relies on the new data yet, and we haven't made any backwards incompatible changes. We can easily run the new code in parallel with the old code in the production environment, and reverting to the previous software version in case of trouble can be made with minimal impact on production.<br />
<br />
Once we're convinced that creating and updating addresses in the new table works as expected, we launch a script which goes through all customer records and add all old addresses to the new table. Yet another low impact, low risk operation.<br />
<br />
Once we have complete data in the new address table, we deploy a version of the software which reads address data from the new table. We can verify that everything works just as expected, and if there are problems, we can always revert to the previous software version. The address information in the old table is still there. We can also monitor that no code is reading address information from the old location any longer.<br />
<br />
Now it's time to remove the functionality from the software which updates the address fields in the old customer table. We put this in production and make sure that it works as expected.<br />
<br />
Finally, when we're convinced that everything works as expected, we drop the address columns from the customer table. By now, we're convinced that they are no longer used by any software. If there happens to be some legacy software we can't change which expects to find address in the customer table, we can provide that with a database view.<br />
<br />
<h2>
Conclusions</h2>
Instead of one software upgrade with a significant risk that something would go wrong, and a possibly severe impact if something went wrong, we've performed six quick, simple, very safe, low impact changes to the system. We've been able to observe how each change worked, and we've had the ability to adapt to any discoveries we made at any step in the process.<br />
<br />
In the nominal case, we have a service window of a few hours in the traditional approach, and no impact on production at all in the agile approach.<br />
<br />
If we only want to perform a production release on a monthly basis, but want similar confidence and low impact as the agile approach, we'd have to release a preparatory version now (with other, non-related features and/or bug-fixes in it), get the new behaviour into production in the next release, a month from now (if all went as expected with the preparatory release), and get the data redundancy a little more than two months from now. Isn't it better to be finished today?<br />
<br />Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-44420368640649419042015-09-24T16:25:00.002+02:002015-09-24T16:29:26.462+02:00Import style: Avoid both excessive repetition and the wildcard bugLet's says that you have a Python module with a function in it. Like this:<br />
<div>
<br /></div>
<div>
mymodule.py:</div>
<div>
<br /></div>
<div>
<div>
def myfunction(name):</div>
<div>
return "Hello %s" % name</div>
</div>
<div>
<br /></div>
<div>
You could then use it in another module like this (A):</div>
<div>
<br /></div>
<div>
import mymodule</div>
<div>
mymodule.myfunction("Dennis")</div>
<div>
<br /></div>
<div>
You could also do this (B):</div>
<div>
<br /></div>
<div>
from mymodule import myfunction</div>
<div>
myfunction("Denise")</div>
<div>
<br /></div>
<div>
Both approaches have benefits. With approach A, you only have a single line of import for a module, and when you read code using "myfunction", you can see directly that it comes from "mymodule". The downside is the repetition in your code. With Python packages like xml.etree.ElementTree your code might get tiresome to read with the repetition of that long prefix. (And tedious to type.)</div>
<div>
<br /></div>
<div>
With approach B, you don't need to repeat module or package names every time you use stuff in the modules. There are two downsides. If you use a lot of things from the module, you get a pretty noisy import. Maybe something like:</div>
<div>
<br /></div>
<div>
from xml.etree.ElementTree import Element, ElementTree, SubElement, TreeBuilder, dump, fromstring, iselement, parse, tostring</div>
<div>
<br /></div>
<div>
(Or nine separate import statements if you prefer that.)</div>
<div>
<br /></div>
<div>
The other disadvantage is that you need to look somewhere else in the program to realize where the funtion "iselement" comes from when you run across it in line 735 of some propgram listing.</div>
<div>
<div>
<br /></div>
</div>
<div>
The best choise is probably this:</div>
<div>
<br /></div>
<div>
import xml.etree.ElementTree as Et</div>
<div>
<br /></div>
<div>
That way, you get a brief import statement, and using Et.dump, Et.parse etc, still makes it easy to figure out where those functions are defined and documented.</div>
<div>
<br /></div>
<div>
Resist the temptation of using wildcards in the import. While it's possible to write "from xml.etree.ElementTree import *", it's a really bad idea. For two reasons:<br />
<br />
<ol>
<li>Someone reading your code will not be able to see where the objects you imported came from.</li>
<li>Your code might suddenly break if the imported module gets a new object which shadows a name you used. This is really nasty, since the bug might appear when someone does a regular upgrade on his computer. Nothing changed in your code, but a library your code used got updated.</li>
</ol>
<div>
<br /></div>
</div>
Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-35939568977382920962014-11-11T00:10:00.002+01:002021-05-04T01:03:07.307+02:00Crowdfunding: Dreams or Realities?<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="text-align: center;"><div style="text-align: left;"><b>UPDATE:</b></div></div><div style="text-align: center;"><div style="text-align: left;"><br /></div></div><div style="text-align: center;"><div style="text-align: left;"><blockquote><p style="background-color: white; box-sizing: border-box; color: #171e24; font-family: Georgia, "Times New Roman", Times, serif; font-size: 14px; margin: 0px 0px 1em;">"CHICAGO — A federal jury in Chicago has convicted a Silicon Valley businessman of defrauding investors in his computer companies after soliciting and obtaining some of the money via crowdfunding.</p></blockquote></div></div><div style="text-align: center;"><div style="text-align: left;"><blockquote><p style="background-color: white; box-sizing: border-box; color: #171e24; font-family: Georgia, "Times New Roman", Times, serif; font-size: 14px; margin: 0px 0px 1em;">JEFFREY BATIO, 50, of Santa Clara, Calif., was found guilty Friday of all 12 counts against him, including six counts of mail fraud and six counts of wire fraud. Each count is punishable by a maximum sentence of 20 years in prison. U.S. District Judge Rebecca R. Pallmeyer set sentencing for Sept. 3, 2019."</p></blockquote></div></div><div style="text-align: center;"><div style="text-align: left;"><a href="https://www.justice.gov/usao-ndil/pr/silicon-valley-computer-executive-convicted-defrauding-investors-after-soliciting-money">https://www.justice.gov/usao-ndil/pr/silicon-valley-computer-executive-convicted-defrauding-investors-after-soliciting-money</a></div></div></blockquote><div style="text-align: center;">
<div style="text-align: left;"><p style="background-color: white; box-sizing: border-box; color: #171e24; font-family: Georgia, "Times New Roman", Times, serif; font-size: 14px; margin: 0px 0px 1em;"></p><p style="background-color: white; box-sizing: border-box; color: #171e24; font-family: Georgia, "Times New Roman", Times, serif; font-size: 14px; margin: 0px 0px 1em;"></p></div><div style="text-align: left;"><br /> How many of the crowd-funding projects are real, and how many are somewhere between fraud and someones wild dreams? Is this one an outright fraud?</div>
</div>
<br />
<div style="text-align: center;">
<i>I wrote something all too long for Google+, so I decided to hijack my Python blog for this...</i></div>
<div style="text-align: center;">
<br /></div>
Do you think <a href="https://www.indiegogo.com/projects/the-dragonfly-futurefon--3" rel="nofollow" target="_blank">the Dagonfly Futurefön</a> will actually be produced? It seems that 1739 investors thinks it will as of 2014-11-14, or are they deliberately throwing away those $362030...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.linotech.info/wp-content/uploads/2014/10/slingshot1-1024x768.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="http://www.linotech.info/wp-content/uploads/2014/10/slingshot1-1024x768.jpg" width="320" /></a></div>
Jeff Batio has tried to build something really ground-breaking for many years, but as far as I understand, there's been no payback from investments in his inventions. He has gathered a lot of money from investors though, and at least one state has taken him to court and banned his stock sales.<br />
<br />
Note that Mr Batio decided go through with his project if he just got $10000. Could he really start production of revolutionary consumer electronics for $10000, or is he just very eager to cash in, regardless of whether the project has a chance to succeed or not?<br />
<br />
He promises something revolutionary: A very light Intel i7 laptop bundled with a smartphone/pad, the whole package weighing just one pound. This includes enough battery to run the i7 for 8.5 hours. This is less than half the weight of any current i7 laptop, and he'll also include the phone.<br />
<br />
One IDG Connect writer, Dan Swinhoe, has published <a href="http://www.idgconnect.com/abstract/5030/crowdsourcing-innovation-jeff-batio-ceo-founder-idealfuture" rel="nofollow" target="_blank">a short interview about the venture</a>. No Pulitzer Prize ambitions... Just ask some easy question and let Mr Batio create the article text with his answers. A few blogs have also reported without questioning whether this is for real.<br />
<br />
My warning bells go off when I read about Jeff Batio and his "Idealfuture Dragonfly Futurefön" (sic). It's not just the name... It all smells fishy, and the more I put my nose in it, the worse the smell seems.<br />
<br />
Look at the texts, the pictures and videos at <a href="https://www.indiegogo.com/projects/the-dragonfly-futurefon--3" rel="nofollow" target="_blank">Indiegogo</a> and <a href="http://www.idealfuture.com/" rel="nofollow" target="_blank">Idealfuture's</a> home page. Does it look real?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.indiegogo.com/file_attachments/932999/files/20141015103240-Screen_Shot_2014-07-31_at_12.23.17_AM.png?1413394360" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="108" src="https://images.indiegogo.com/file_attachments/932999/files/20141015103240-Screen_Shot_2014-07-31_at_12.23.17_AM.png?1413394360" width="320" /></a></div>
I know. They are in the middle of inventing, and no-one claims that the product is in production. But if you create a game changer, something really new, you probably need some decent prototypes to convince yourself and your investors/customers that it's even possible to produce this.<br />
<br />
Almost all detailed product pictures, and all product appearance in the videos, seem to be animations. There are some pictures of people with "the Futurefön", but is there anything to suggest that those are more than 3D printed blocks of plastic with some chrome framing?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.indiegogo.com/file_attachments/943144/files/20141019155443-images_for_igg_page1.jpg?1413759283" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://images.indiegogo.com/file_attachments/943144/files/20141019155443-images_for_igg_page1.jpg?1413759283" width="320" /></a></div>
The only visual details I find is in the collage near the bottom of the Indiegogo page, where Bridget Hogan from the video, Mr Batio's VP of Social Media, holds a mock-up with a shiny chrome look.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.indiegogo.com/file_attachments/943815/files/20141019222443-collage_of_b_with_model.jpg?1413782683" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://images.indiegogo.com/file_attachments/943815/files/20141019222443-collage_of_b_with_model.jpg?1413782683" width="320" /></a></div>
I took a close look at that picture. Note that the right screen should<br />
<ol>
<li>work like a normal, folding laptop screen,</li>
<li>swivel around, </li>
<li>detach as in the middle picture, </li>
<li>not accidentally fall off the base during transportation.</li>
</ol>
Has anyone managed to do this before? I think this is a core R&D effort, the first thing to get right.<br />
<br />
Why is Ms Hogan holding on to the phone part in the upper left and right pictures? Not quite working yet?<br />
<br />
How will this mechanism work without anything protruding from the screen or the base? (There is something protruding a bit in some of the computer simulations, and it looks as if that thing would prevent the swiveling rotation...)<br />
<br />
Will this magic joint survive a few years of handling, bumping around in a backpack? Do you need to put your Futurefön in a special, protective case they didn't mention yet?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.indiegogo.com/file_attachments/943827/files/20141019223046-2014-04-29_12.57.58.jpg?1413783046" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="223" src="https://images.indiegogo.com/file_attachments/943827/files/20141019223046-2014-04-29_12.57.58.jpg?1413783046" width="320" /></a></div>
<br />
What about the technical specs? It is to be 155.575 mm wide when folded, and weigh 452.175 grams. Considering that they are still vague about some features, such as exactly which processor to use, whether it should be waterproof, and what battery to use, it's surprising that that they have such impressive and precise measures.<br />
<br />
The "Slingshot" is a complete 7" phone, and it's supposed to weigh only 145 grams. The lightest 7" pad I can find for real weighs 239 grams. (The lightest 6" phone I find weighs 160 grams.) Don't forget that the "Slingshot" also needs some sturdy structure for the swiveling hinge. Some extending pin maybe?<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.technewsworld.com/images/article_images/79294_620x420.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="216" src="http://www.technewsworld.com/images/article_images/79294_620x420.jpg" width="320" /></a></div>
The rest of the weight is 307 grams. That's for a complete Intel i7 laptop with a tiny 7" screen, 4GB RAM, 256GB SSD and enough battery for 8.5 hours of use. It needs to be sturdy despite being so thin, narrow and light, with hinges in the middle of the keyboard.<br />
<br />
The smallest current netbooks, with 8.9" screen, weigh 0.99 kg. More than twice what a complete "Futurefön" is supposed to weigh...<br />
<br />
Compared to any other Intel i7 based laptop, it will be 40% of the weight, much more narrow, and still have strength and space for the folding, and dissipate all the generated heat. Who will provide the material to build this? Aliens?<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://img1.wikia.nocookie.net/__cb20130521224912/alienfilm/images/thumb/7/77/ThreeGreys.jpg/185px-ThreeGreys.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://img1.wikia.nocookie.net/__cb20130521224912/alienfilm/images/thumb/7/77/ThreeGreys.jpg/185px-ThreeGreys.webp" /></a></div>
Mr Batio first worked on the idea of a 2-way foldable laptop in his old company Xentex. It seems like something was actually built then, since <a href="http://www.engadget.com/2008/05/23/xentex-dual-13-3-inch-screen-laptop-surfaces-on-ebay/" rel="nofollow" target="_blank">an article in engadget</a> mentioned a prototype for sale on Ebay in 2008. The Xentex Flip-Pad press release was also mentioned in 2002 by <a href="http://www.pcmag.com/article2/0,2817,544860,00.asp" rel="nofollow" target="_blank">pcmag.com</a> (joking about the 5.7kg laptop) and by <a href="http://www.mobilemag.com/2002/07/03/xentex-dual-screen-flip-pad-voyager/" rel="nofollow" target="_blank">mobilemag.com</a>.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimjc7pu6vmfPBv7gjylfaJfgHncPzQtSFyjCbRPVPqPbGoMzu9yaWfZT-kMvul_c37-36utdgL_-w6TkzcmanlZx30fx-GTJ9gQLOQBbVmLutJHy5C0kA-Wo04hEabqLqs-lZZJV_cnA/s1600/xentex_dual_screen_laptop.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimjc7pu6vmfPBv7gjylfaJfgHncPzQtSFyjCbRPVPqPbGoMzu9yaWfZT-kMvul_c37-36utdgL_-w6TkzcmanlZx30fx-GTJ9gQLOQBbVmLutJHy5C0kA-Wo04hEabqLqs-lZZJV_cnA/s1600/xentex_dual_screen_laptop.jpg" width="320" /></a></div>
It seems it never came to production though, and Mr Batio has <a href="http://www.xentex.com/" rel="nofollow" target="_blank">a whole web site</a> dedicated to telling the story of how he was swindled by people in his own board and some investors. He makes it sound like these people got so crazy that they started to destroy a company they owned and worked for, which was just on the verge of financial success. I think such things are more likely to happen to a company close to collapse...<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.hotstocked.com/articles-img/small/charges.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://www.hotstocked.com/articles-img/small/charges.jpg" width="320" /></a></div>
Between the old bankrupted Xentex and the current Idealfuture, Mr Batio called his venture Armada Systems LLC. One of his patents on "Portable computer for dual, rotatable screens" was filed with Armada as owner. As recently as 2014-01-29, the State of Illinois, <a href="http://www.ilsos.gov/adminactionssearch/adminactionssearch?command=viewPDF&itemId=92%203%20ICM7%20PRODCMZ13%20SE_AA_MgtView59%2026%20A1001001A14B07B05244I2768318%20A14B07B05244I276831%2014%201051" rel="nofollow" target="_blank">noted</a> that Mr Batio had between 2006 and 2010 sold "memberships" in Armada to approximately 75 people, for a sum of approximately $500 000. The state also noted that he had done this without registering as demanded by the law. He was then forbidden to sell shares in the state of Illinois... Oh dear!<br />
<br />
Mr Batio has 500+ connections in <a href="https://www.linkedin.com/in/jeffbatio" rel="nofollow" target="_blank">LinkedIn</a>. The odd thing is that only 14 people of the 500+ have endorsed any of his skills. Have you ever seen such a LinkedIn profile? I didn't think that was possible. (Not that it ever happened to me that people endorsed skills they don't personally know I have. ;-)<br />
<br />
By the way, one of his 14 endorsers is a 3D and VFX artist in Moscow. I can guess their connection... Another does music for advertising, and a third is a technical writer and engineer, who shoots, produces and directs film (some technical stuff I guess). The dream team...<br />
<br />
Where are the real techies actually creating all the pieces in this puzzle? Even if you work with a lot of outsourcing, there is a lot of work to get a product to happen... Searching for Idealfuture at LinkedIn, you only get two hits: Mr Batio and Ms Hogan.<br />
<br />
The only inside clue from Idealfuture among the pictures is one where they show their prototype workshop. Here you can see Mr Batio's first wooden mock-up of a fold-able laptop. Then there is one of the Flip-Pad prototypes, and various junk. Something might be a scaled up part of a keyboard hinge, and there is a couple of big, old motherboards. In the center, maybe the most important part: The product photography studio.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://images.indiegogo.com/file_attachments/899584/files/20141002141955-collage_of_work_space.jpg?1412284795" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="240" src="https://images.indiegogo.com/file_attachments/899584/files/20141002141955-collage_of_work_space.jpg?1412284795" width="320" /></a></div>
<br />
I suspect that they don't build the next generation of computing devices there. I think they build dreams...<br />
<br />
I like Jeff Batio. He's like the inventor dad in Gremlins. I guess he believes in his overly complicated gadgets that have everything, and thinks that he can overcome all the technical hurdles. I mean, it's one item which is both a laptop and a phone and a presentation device (well if the guy you present to sits really, really close) and there is a pen in a little hole, and a Bluetooth headset behind a little hatch, and it folds so cleverly... Just like the Peltzer Bathroom Buddy! I almost expect a button for shaving foam.<br />
<br />
Still, he ought to understand that his investors are likely to loose their money, just as I guess his previous investors did...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://images.cdn.bigcartel.com/bigcartel/product_images/128203524/max_h-1000+max_w-1000/PageImage-483414-5323292-Bathroom_Buddy.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://images.cdn.bigcartel.com/bigcartel/product_images/128203524/max_h-1000+max_w-1000/PageImage-483414-5323292-Bathroom_Buddy.jpg" width="240" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
P.S. I just found something more: A year ago, <a href="https://www.indiegogo.com/projects/the-if-convertible-by-idealfuture-3-devices-2-screens-1-data-plan" rel="nofollow" target="_blank">Mr Batio did the same thing</a>! (Well almost, no videos and no Ms Hogan.) The "if convertible by idealfuture" which looks suspiciously like the Dragonfly Futurefön, collected $17945, in a campaign ending in December 2013. It was an inspiring first attempt I guess. Maybe it gave him the funding to produce the next campaign. It's not apparent to me that it lead to any production of hardware. I see no actual fold-ables for sale on ebay for instance. But there is someone who <a href="http://www.ebay.com/itm/Idealfuture-Dragonfly-Futurefon-Slingshot-WinDroid-Edition-Indiegogo-Preorder-/111509443506?pt=Laptops_Nov05&hash=item19f67b13b2" rel="nofollow" target="_blank">tries to sell</a> the one he didn't get yet...Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com5tag:blogger.com,1999:blog-8202543167959202743.post-9804016641157778672014-03-21T07:48:00.001+01:002017-10-24T10:31:12.411+02:00Call by what? Understanding Python variables<div dir="ltr" style="text-align: left;" trbidi="on">
You might run across something similar to this in a Python program:<br />
<br />
consumer_x = consume(consumer_x, banana, milk)<br />
weigh(consumer_x)<br />
<br />
def consume(consumer, food, beverage):<br />
consumer.eat(food)<br />
consumer.drink(beverage)<br />
return consumer<br />
<br />
This code is a bit more convoluted than it has to be. To understand why, we need to understand how Python variables work.<br />
<br />
<h3>
Labeled Shoeboxes</h3>
A variable in an old language like <a href="http://en.wikipedia.org/wiki/C_(programming_language)">C</a> is like a box with a label. (For some reason I thought shoeboxes when I studied C.) It has a certain size, e.g. big enough to fit an integer, or a double precision floating point number. You can write something like this in C:<br />
<br />
int a = 12345;<br />
int b;<br />
b = a;<br />
a = a + b;<br />
b = a;<br />
<br />
This roughly means the following:<br />
1. Make an integer sized box, label it "a", and place the value 12345 in it.<br />
2. Make another integer sized box and label it "b". Leave it empty for now.<br />
3. Copy the value of a into the b box. Now both a and b contain 12345.<br />
4. Calculate 12345 + 12345 = 24690 and put that in the a box.<br />
5. Let's copy the value of a into b again. Both boxes contain 24690 now.<br />
<br />
<h3>
Call by what?</h3>
If you do something like "consume(consumer, food, beverage)" in a language with C-like variables, you need to make up your mind about the semantics here. What's going on with the variable "a" if you pass it to something like consume?<br />
<br />
Will the value in the "a box" be copied into some other box inside consume? We would call this <i>call by value</i> or <i>pass by value</i>.<br />
<br />
The other option would be that the code inside consume would be able to access the "a box". We call that <i>call by reference</i>.<br />
<br />
So, what about Python? Is it call by value or call by reference? Neither I'd say. Some say <i><a href="http://effbot.org/zone/call-by-object.htm">call by object</a></i> or <a href="http://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing"><i>call by sharing</i></a>. The experienced C programmer would probably say that we're passing a pointer to "a" by value, but let me explain this with something more similar to the shoebox.<br />
<br />
<h3>
Balloon, tags and strings</h3>
For some reason, I see Python variables like balloons floating in the sky. They can take any size, and while you can't really control where they are, there are strings attached. You hold on to the other end of the string, and you've put a tag on it.<br />
<br />
Let us repeat the example from above in a Pythonic way:<br />
<br />
a = 12345<br />
b = a<br />
a = a + b<br />
b = a<br />
<br />
1. Let's make a balloon and put the integer 12345 in it. Attach a string and tag it "a" in the end you hold on to. (In fact, this balloon will never contain any other value than 12345, but we'll get back to that.)<br />
2. Let's attach a new string to the 12345 balloon, and tag that "b". Now there are two strings attached to 12345.<br />
3. Let's make a new balloon and fill it with 12345 + 12345 = 24690. Move the string tagged "a" from the 12345 balloon to the 24690 balloon. The balloons now have a string each.<br />
4. Move the string tagged "b" to the balloon with the "a" string attached, i.e. the 24690 balloon. The 12345 balloon no longer has any strings attached, so it flies away.<br />
<br />
A more technical term is that 12345 get's garbage collected (or to be particular, it will be reference counted if it's the standard version of Python).<br />
<br />
<h3>
Mutable and immutable types</h3>
All Python objects (oops, I meant balloons) have a type. Every type is either <i>mutable </i>or <i>immutable</i>. Integers are immutable, so once you've created an integer balloon (or object) it will never change its value. So, while "a = a + 1" means "change the value in the a-box" in C, it means "move the a-tagged string to a balloon with another value" in Python.<br />
<br />
That's true for both mutable and immutable types: Assigment in Python always means "move the string to a new balloon". The silly thing with the example we began with, is that it's the same balloon it was already attached to. Let's go back to that:<br />
<br />
consumer_x = consume(consumer_x, banana, milk)<br />
<br />
def consume(consumer, food, beverage):<br />
consumer.eat(food)<br />
consumer.drink(beverage)<br />
return consumer<br />
<div>
<br /></div>
<div>
Before we call consume(...), consumer_x is a tagged string attached to some balloon. When we call consume() we attach the string with a consumer-tag inside the consume() function to the same balloon. Then we call the .eat() and .drink() methods on our ballon. Then we pass our balloon back to the caller. Finally, we reuse our variable name and do consumer_x = consume(...). This means that we detatch the string from the balloon it was to connected to, and instead we ... yes that's right ... we re-attach it to the same ballon again. That's silly isn't it?</div>
<div>
<br /></div>
<div>
The crucial thing is that we don't reassign consumer in consume. Since we can't see any "consumer = ..." in the body of consume, we know for sure that we return the same object as we got as input. Not much point in that. It's as if I would visit your home, grab one of your flower pots from one of your window sills and present it to you as a gift.</div>
<div>
<br /></div>
<div>
For this function to make <i>any</i> sense at all, consumer is hardly of an immutable type, like an integer. It's probably an instance of a class. Along with e.g. lists, sets and dicts, that's a <i>mutable</i> type.</div>
<br />
The difference between immutable and mutable, is that mutable objects can change (or mutate) after their creation. This is pretty important in Python. For instance, you can only use immutable values as keys in dicts. With an object such as a list, the value can change even though it's the same balloon a.k.a. object.<br />
<br />
>>> a = 1<br />
>>> print a, id(a)<br />
1 30716560<br />
>>> a += 2<br />
>>> print a, id(a)<br />
3 30716536<br />
>>> # See, new value and new id, i.e. another object.<br />
...<br />
>>> l = []<br />
>>> print l, id(l)<br />
[] 37012744<br />
>>> l.append('x')<br />
>>> print l, id(l)<br />
['x'] 37012744<br />
>>> # New value, but still same object!<br />
...<br />
<br />
<h3 style="text-align: left;">
Let's make it a little more complicated...</h3>
If we look at the list above, it's balloon can obviously grow. A <a href="http://docs.python.org/3/library/stdtypes.html#lists">Python list</a> is a like an array or vector in other languages, so if it's a list of 100 floating point numbers, its a big balloon. It won't contain 100 floats though. It will contain 100 strings, each leading to a floating point balloon.<br />
<br />
So, the strings we attach to balloons can either end in another balloon, or they can have a tag in a location we call a <a href="http://en.wikipedia.org/wiki/Scope_(computer_science)">scope</a>. The balloons float in a part of the computer memory we call the heap, and the scopes with tags are in another part of the memory, called the stack. As long as you stick to Python, you don't really have to care about that.<br />
<br />
<h3 style="text-align: left;">
Which is the variable?</h3>
In a C-like language, it's pretty obvious what a variable is. It's a labeled shoebox of a particular size/type. It's called variable, since its content can vary (within the constrains of the type). If you declare it const, it's not a variable, but a constant.<br />
<br />
But what about Python? Which is actually the variable? The tag? The balloon? It's not the string, is it? If it's the tag, then Python variables don't have types, and that's a silly thing to claim. If it's the balloon, then Python don't have integer variables, just constants, and that would be an equally silly claim.<br />
<br />
Perhaps it's the whole arrangement which is the variable. Perhaps the term variable doesn't make so much sense in Python? Maybe it's better to just talk about objects and names?<br />
<br />
Want to know more? Take a look at Fredrik Lundh's explanation at <a href="http://effbot.org/zone/python-objects.htm">http://effbot.org/zone/python-objects.htm</a><br />
<br /></div>
Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com1tag:blogger.com,1999:blog-8202543167959202743.post-61640584431372439162014-03-20T21:06:00.001+01:002017-09-19T01:11:34.811+02:00print 0100?<div dir="ltr" style="text-align: left;" trbidi="on">
<i>Only start numbers with 0 if the second character is a decimal point!</i><br />
<i><br /></i>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEillU0nnz0lrRS7FcpVumkm6Idn-GN8HgmiQBlaIdY1DaVlRDk8Ua7wcUiOhUL8Q0bl13swI00p8cndYH-usLzvdpHekoqoHMZba1vm3liUrzhANbdXpnSPC41eXCShlihzW73y4RqqrQ/s1600/Screenshot+from+2017-09-19+01-09-56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="158" data-original-width="254" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEillU0nnz0lrRS7FcpVumkm6Idn-GN8HgmiQBlaIdY1DaVlRDk8Ua7wcUiOhUL8Q0bl13swI00p8cndYH-usLzvdpHekoqoHMZba1vm3liUrzhANbdXpnSPC41eXCShlihzW73y4RqqrQ/s1600/Screenshot+from+2017-09-19+01-09-56.png" /></a></div>
<i><br /></i>
<br />
A few days ago, I saw some Python 2 code looking like this:<br />
<br />
expval = date(2011, 03, 02)<br />
<br />
Ok, that's harmless, but only because the number was less than 8... Let me show you:<br />
<br />
>>> print 02<br />
2<br />
>>> print 03<br />
3<br />
>>> print 07<br />
7<br />
>>> print 08<br />
File "<stdin>", line 1<br />
print 08<br />
^<br />
SyntaxError: invalid token<br />
>>> print 0100<br />
64<br />
>>> print 100<br />
100<br />
<br />
If it wasn't clear to you from the beginning, you probably got it now: Numbers beginning with a 0 are seen as octal number in Python 2. (I.e. base 8 instead of base 10 as the decimal numbers we normally use.) This was probably not Guido's brightest move when he designed Python. He simply copied a common practice in other languages such as C. Prefix 0x always meant hexadeciaml, and later 0b appeared for binary (even though he rejected it when I first asked) and 0o as a saner syntax for octal.<br />
<br />
>>> print 0xff<br />
255<br />
>>> print 0b01010<br />
10<br />
>>> print 0b10010<br />
18<br />
>>> print 0o10010<br />
4104<br />
>>> print 0o100<br />
64<br />
<br />
In Python 3, 0o ithe the only way to write octal numbers. Literals consisting of digits starting with 0 is a syntax error:<br />
<br />
>>> print(0o100)<br />
64<br />
>>> print(0100)<br />
File "<stdin>", line 1<br />
print(0100)<br />
^<br />
SyntaxError: invalid token</div>
Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0tag:blogger.com,1999:blog-8202543167959202743.post-5714385965208310992014-03-15T22:57:00.000+01:002015-10-19T10:30:06.857+02:00Picky Python<div dir="ltr" style="text-align: left;" trbidi="on">
I first discovered Python back in version 1.4, in 1996. It's been my favourite programming language since then.<br />
<div>
<br /></div>
<div>
One of the things I like best with Python is that it's designed to make it easy to make things right, rather than hard to make things wrong.</div>
<div>
<br /></div>
<div>
There is still a lot of code which could be improved a lot. There are several reasons for that:<br />
<ul style="text-align: left;">
<li>One way or another, the problem is often that the programmers don't know Python so well.</li>
<li>Some seem stuck in the idioms of another language, such as C. A variant is people who try to compensate for the lack of static typing, rather than make use of dynamic typing in an efficient way.</li>
<li>Many reinvent the wheel instead of using the vast flora of libraries available in the standard and in the <a href="https://pypi.python.org/pypi">Cheese Shop</a> etc.</li>
<li>Since Python is easy to learn, it's often used by people who aren't hard-core programmers. While they will do much better with Python than with e.g. C++, they'll still make beginner's mistakes.</li>
<li>Regardless of language, there is a lot of software which was written with less care and attention than it deserved. Perhaps because the programmer didn't have to maintain it?</li>
<li>I've seen a lot of poorly written code in corporate settings, and that's really an organizational problem, rather than a personal: Companies can hire the right people, train them well, establish a culture of software quality and provide constructive goals and priorities. Or not! As <a href="http://en.wikipedia.org/wiki/W._Edwards_Deming">Deming</a> said: <a href="http://en.wikipedia.org/wiki/W._Edwards_Deming#Seven_Deadly_Diseases">Don't place blame on the workforce</a>. </li>
</ul>
<div>
<br /></div>
<div>
I thought I'd write a bit about problematic Python constructs I've come across, explain why they cause trouble, and what to do instead. That's the main thought with this blog. Hopefully, it will help someone now and then...</div>
<div>
<br /></div>
</div>
</div>
Magnus Lyckåhttp://www.blogger.com/profile/03616305267649546599noreply@blogger.com0Partille, Sverige57.7618574 12.13471839999999757.694075899999994 11.973356899999997 57.8296389 12.296079899999997