tag:blogger.com,1999:blog-50605512514658395752024-03-14T12:12:42.667+08:00Dodgy Coder"I encourage you to change all your data types to boolean. Whenever there's a data quality issue, it can only be wrong by 1 bit." - AnonymousDodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.comBlogger47125tag:blogger.com,1999:blog-5060551251465839575.post-43059556069917801812022-05-15T22:54:00.005+08:002022-05-16T21:46:57.234+08:00What the LUNA cryptocurrency has in common with a Thanksgiving Turkey and the LTCM hedge fund<p>A classic black swan event has just happened to the LUNA cryptocurrency.<br /><br />A black swan event is characterised by a spectacular run up in price, followed by the price falling off a cliff to near zero. <br /><br />It famously happened to a hedge fund named LTCM (Long Term Capital Management) back in 1998. The resulting loss temporarily destabilised Wall Street, requiring a bail out to be organised by the US Federal Reserve.<br /><br />For LUNA, as with LTCM, a group of the smartest people in the room had banded together based on the unstoppable winning formula of:<br /><br />(new technology + maths + programmers + marketing + chutzpah) = profit<br /><br />Then claimed they'd solved a previously hard and intractable problem, and that everyone who doesn't believe them can just STFU, or in the case of Do Kwon (the founder of LUNA), "enjoy being poor". Oh the karma.<br /><br />The risk with crytocurrency in particular is that if there's a bug in the algorithm or protocol, the result can be both an immediate financial loss, and a catastrophic loss of confidence in the currency. The bug can go unnoticed for months or years, before someone finds it and then patiently sets things up to exploit it for maximum profit.<br /><br /></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeHELBLsbfhIIn7XPu62cQudyk2CUYzFLQ40YnifsFsAmJ4CO30r6rpB4ZrmLzlClE2dvDTGD92r5iIyAR784U_BZk-s8S4DIO5t9NomVsATW5cIl-AS5DuTDLf-0lEF2BJdMGMIy5zdBt42QgNZZJv6hx-ffEFP1CiUtwsPP6_HKbav6Zs6CmcZoL/s800/turkey.webp" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="800" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjeHELBLsbfhIIn7XPu62cQudyk2CUYzFLQ40YnifsFsAmJ4CO30r6rpB4ZrmLzlClE2dvDTGD92r5iIyAR784U_BZk-s8S4DIO5t9NomVsATW5cIl-AS5DuTDLf-0lEF2BJdMGMIy5zdBt42QgNZZJv6hx-ffEFP1CiUtwsPP6_HKbav6Zs6CmcZoL/w640-h480/turkey.webp" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiTJjh7ltEFOfKi3yJAoQDWmP6uKANfb03k6RJ3qU6867hWZY09O8Y8nps_UGntWjxhbjtG2nPrlDPZllCCyX-5-4KXVOUazqn2rvU6FjdZAVNsimuDHFmYwfduly95lBCy0NOhhSaOw7PEhqGAnBFYtTnctAZvSYrjKZ27LybZX80VuvQK9k04OZo/s480/ltcm-long-term-capital-management-crash.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="424" data-original-width="480" height="566" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjiTJjh7ltEFOfKi3yJAoQDWmP6uKANfb03k6RJ3qU6867hWZY09O8Y8nps_UGntWjxhbjtG2nPrlDPZllCCyX-5-4KXVOUazqn2rvU6FjdZAVNsimuDHFmYwfduly95lBCy0NOhhSaOw7PEhqGAnBFYtTnctAZvSYrjKZ27LybZX80VuvQK9k04OZo/w640-h566/ltcm-long-term-capital-management-crash.jpg" width="640" /></a></div><br /><p></p><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs5U3a8eqOY6gCy4nveqiaZMKSuWsw67SuWxWfg2zphXvqQnE7g9FLR5fqw63CyJkSeLNsDFS5KZuxXJTZLxNnxMCyEfJHoNy3JdYPX3Wpz_KvGlZLD2vtJh0HMe6zBzhpQQLXwiVeHHvzWHPRjt0IzPU6OMSjsi3Hr_bddk3ldw6_w3ESoc1Ow1j8/s1068/terra-luna-price-crash.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="828" data-original-width="1068" height="496" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhs5U3a8eqOY6gCy4nveqiaZMKSuWsw67SuWxWfg2zphXvqQnE7g9FLR5fqw63CyJkSeLNsDFS5KZuxXJTZLxNnxMCyEfJHoNy3JdYPX3Wpz_KvGlZLD2vtJh0HMe6zBzhpQQLXwiVeHHvzWHPRjt0IzPU6OMSjsi3Hr_bddk3ldw6_w3ESoc1Ow1j8/w640-h496/terra-luna-price-crash.PNG" width="640" /></a></div><br /><a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a><br /><br />More reading:<br /><a href="https://decrypt.co/100402/how-terra-ust-luna-imploded-crypto-crash">How Terra's UST and LUNA Imploded (Decrypt)<br /></a><a href="https://fortune.com/2022/05/13/terra-ust-stablecoin-crash-suspicious-potential-attack-george-soros/">Roundup of theories on the LUNA crash (Fortune)<br /></a><a href="https://www.abc.net.au/news/2022-05-13/bitcoin-crypto-terra-ust-luna-stablecoin-evil-genius-plot/101062388">'Evil genius' may have caused Terra and Luna to crash in a 'death spiral' (ABC Australia)</a><br /><a href="https://www.thebalance.com/long-term-capital-crisis-3306240">Long-Term Capital Management Hedge Fund Crisis (The Balance)</a><br /><a href="https://www.getstoryshots.com/books/the-black-swan-summary/">The Black Swan by Nassim Nicholas Taleb - Summary and Analysis (Get Story Shots)</a><br /><a href="https://en.wikipedia.org/wiki/Black_swan_theory">The Black Swan Theory (Wikipedia)</a><br /><br /><p> </p>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-33660203531946958722022-03-21T20:21:00.001+08:002022-05-15T22:58:54.469+08:00Cheaper alternatives to Mind Lab Pro, Alpha Brain and other Nootropics in Australia<p><a href="https://adf.org.au/drug-facts/cognitive-enhancers/">Nootropics</a> are a popular new type of dietary supplement that claim to enhance brain function in a number of ways including better memory, sharper thinking, alertness, improved verbal ability, more clarity and the elimination of 'brain fog'.<br /></p><div dir="auto">I started looking into some options available that deliver to Australia and came across this brand called <a href="https://au.mindlabpro.com/products/mind-lab-pro">Mind Lab Pro</a>. Their tablets contain some of the same ingredients to standard vitamin supplier <a href="https://swisse.com.au/swisse-ultiboost-memory-focus">Swisse's Ultiboost Memory+Focus</a> or even a <a href="https://swisse.com.au/swisse-ultivite-mens-50-multivitamin">Swisse's men or women's multivitamin for ages 50+</a>. The reason its in the 50+ and not their standard multivitamin product is that the 50+ age group are considered more in need of brain enhancing ingredients due to the age related decline.<br /></div><div dir="auto"> </div><div dir="auto">With the 50% discount offered by a popular chemist retail chain, the
Swisse Ultiboost Memory+Focus tablets come down to AUD 32c each.. (AUD $16 for 50 tablets). Compare this to Mind Lab Pro at AUD $1.11 per tablet, working out to a 247% premium in price! And remember, you only get this price with Mind Lab Pro if you buy 4 bottles in your first order.</div><div dir="auto"><br /></div><div dir="auto">Another option with more herbal extracts than Swisse Memory+Focus, but with no B vitamins, is <a href="https://www.orientalbotanicals.com.au/oriental-botanicals/shop/energy-and-performance/memory-and-concentration/p/memory/OB-MEMORY.html?lang=en_AU#start=1">Oriental Botanicals Memory</a>. This product comes in bottles of 60 tablets and after a standard chemist discount costs AUD $37, or 62c each tablet - about double the Swisse option, but still significantly cheaper than Mind Lab Pro.<br /></div><div dir="auto"> </div><div dir="auto">Many nootropic suppliers exploit a psychological effect known as the <a href="https://thedecisionlab.com/biases/the-sunk-cost-fallacy">Sunk Cost Fallacy</a>. Where
the more you have invested in something (the sunk cost - effort, time or money) the less likely you are to stop
doing it, even when there are no further benefits to you continuing to do it.<br /><br /></div><div dir="auto">By
supplying 4 months to you in your first order, the Nootropic company knows you’ll become
invested in it and will not want to admit to yourself at the end of 4
months that you're not seeing the promised benefits.</div><div dir="auto"><br /></div><div dir="auto">Its likely many nootropic products are overhyped and overpriced. Famous
US blogger Joe Rogan actually requested one popular US supplements brand
(Onnit) to prepare a new product, called <a href="https://www.onnit.com/alphabrain/">Alpha Brain</a>. Check the list of all the other <a href="https://jrelibrary.com/articles/joe-rogans-supplement-stack/">supplements Joe Rogan takes</a> by the way - its pretty much a list of every supplement known to man, I'm surprised he has room left to eat any actual food!</div><div dir="auto"> </div><div dir="auto">Final note, <a href="https://www.alphabrainaus.com/">Alpha Brain here in Australia</a> costs AUD$119.90 for 90 tablets, or $1.33 each tablet, so about 22c more per tablet than Mind Lab Pro. </div><p></p><p><a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a></p><div class="separator" style="clear: both; text-align: center;"></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9jzzhxuIxoWEqxaur9SCbHadjJ1ELtNWof3rmOJAhph7vIbHd5SE_sbPhUny1vxQGy5tFVykHW2W2okG8gqfWlvk4AjLB-rBOW6r7GBxKQFXlKqyiD_qwBPDD0lGDICMSnlHXu67kYbPs8_b1Sg3fHmojV9sOuAx7KvCjpwMPsyH-NRi6wQ_lm-l0/s1315/mind-lab-pro-final.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="1315" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9jzzhxuIxoWEqxaur9SCbHadjJ1ELtNWof3rmOJAhph7vIbHd5SE_sbPhUny1vxQGy5tFVykHW2W2okG8gqfWlvk4AjLB-rBOW6r7GBxKQFXlKqyiD_qwBPDD0lGDICMSnlHXu67kYbPs8_b1Sg3fHmojV9sOuAx7KvCjpwMPsyH-NRi6wQ_lm-l0/w640-h311/mind-lab-pro-final.png" title="Mind Lab Pro" width="640" /></a></div><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlFQemuGI9_qiIG6qpCHsxFJcO73FMzl6qdlqLp6x1_XQxPh3hFlznf_ob21o2tiNG2i607tEnNHrYWmtfw7n_1PzTmjxvmqdjqS30R8whfMNrt1-TvxSm4X9q0ykGwpVQcevmpIxiEJxZhznX0r0a7RzeKYxr8Ab8DH3vdcKCQpiNR7FsZzdGCnLe/s909/alpha-brain-final.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="909" height="450" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlFQemuGI9_qiIG6qpCHsxFJcO73FMzl6qdlqLp6x1_XQxPh3hFlznf_ob21o2tiNG2i607tEnNHrYWmtfw7n_1PzTmjxvmqdjqS30R8whfMNrt1-TvxSm4X9q0ykGwpVQcevmpIxiEJxZhznX0r0a7RzeKYxr8Ab8DH3vdcKCQpiNR7FsZzdGCnLe/w640-h450/alpha-brain-final.PNG" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjVoc4uIhD1bjkYpzFRLtqI3T2iLwDMFV_0iBvgZCvyM14_FYmfzpsVCHnaFA11AhXASt4elGec2shSaXg8GfEPCIv1bWStjaTWjtcX7Xk0o0YosGc7MwIvOqM8MEAIrNMO8YOgfNEg0Z8F3ZLqBxsBjyrjcZoloaWRLN_UKdhMNf1mpz4z2fT5dUs/s1110/swisse-memory-focus-final.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="1110" height="370" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjVoc4uIhD1bjkYpzFRLtqI3T2iLwDMFV_0iBvgZCvyM14_FYmfzpsVCHnaFA11AhXASt4elGec2shSaXg8GfEPCIv1bWStjaTWjtcX7Xk0o0YosGc7MwIvOqM8MEAIrNMO8YOgfNEg0Z8F3ZLqBxsBjyrjcZoloaWRLN_UKdhMNf1mpz4z2fT5dUs/w640-h370/swisse-memory-focus-final.PNG" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1nwI7jpHyJlfbN4WaxMiBzg3XXH7xRlV9Rj09V9xObOZOB6sb2Ovgl5iwgp-JQxu4jEEPwyYHz5FnoxdwOYXB2347H7uGIgNw0NFIqhbEx8BiiBfu5lzwwZ_EUVTmUOK22Tmlp4lAgcGW2lW0RnctTCtprCaf0rmL4FqwdPkWPX_A3Y0WxSM1B0v5/s1136/ob-memory-final.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="640" data-original-width="1136" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1nwI7jpHyJlfbN4WaxMiBzg3XXH7xRlV9Rj09V9xObOZOB6sb2Ovgl5iwgp-JQxu4jEEPwyYHz5FnoxdwOYXB2347H7uGIgNw0NFIqhbEx8BiiBfu5lzwwZ_EUVTmUOK22Tmlp4lAgcGW2lW0RnctTCtprCaf0rmL4FqwdPkWPX_A3Y0WxSM1B0v5/w640-h360/ob-memory-final.PNG" width="640" /></a></div><br /><p><br /></p>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-16003438950178252812021-10-23T16:44:00.003+08:002021-10-23T17:56:56.689+08:00Review: InMotion S1 Electric Scooter (AUD$1299)<p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://1.bp.blogspot.com/-gaIH4bBSfkc/YXO0cXJq3SI/AAAAAAAASsY/rMb_asn5qDM7VGLnD8eEBfrwDmm9popugCNcBGAsYHQ/s2048/IMG_0602.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2048" data-original-width="1839" height="640" src="https://1.bp.blogspot.com/-gaIH4bBSfkc/YXO0cXJq3SI/AAAAAAAASsY/rMb_asn5qDM7VGLnD8eEBfrwDmm9popugCNcBGAsYHQ/w574-h640/IMG_0602.JPG" width="574" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The InMotion S1 electric scooter. At the front is my wife's scooter, the VSETT 8.<br /></td></tr></tbody></table><br /><p></p><p>Electric kickscooters are really popular right now. Their sweet spot in terms of usefulness is probably for people living in urban and inner city areas, or in areas which have good bicycle paths. I live in an inner city suburb of Perth, Western Australia, and work near the Swan river - my reason for buying one was to have some fun while commuting to work. My commute on the scooter is about 14km (9 miles) and takes me 40 minutes.</p><p>Four weeks ago I bought the InMotion S1 scooter for AUD$1299 (~ USD$970). In my review here I compare the manufacturers <a href="https://inmotionaustralia.com/">promotional material</a> and claimed specifications to my real life experience of the scooter.<br /></p><p><span style="font-size: medium;"><b>Scooter model history</b></span><br />The S1 is InMotion's latest model scooter, launching in Australia in September 2021. It has been adapted from the InMotion L9 model, which was crowdfunded on IndieGogo successfully back in May 2020. The S1 seems to be targeted at markets outside of the US, such as Canada, Australia and Singapore. The L9 and S1 look very similar, they share the same controls and share the same smartphone application.</p><p><span style="font-size: medium;"><b>Smartphone app</b></span><br />First thing to do is to pair the smartphone app with the scooter. This was easy and I didn't run up against any problems. I used the iPhone app, and there's an Android app available too. There was only one tricky thing I found with the app - changing the distance units from the default (miles) to kilometres. To do this, you need to first change it under the vehicle settings - this will ensure the speedo on the scooter reads out in km/hr instead of miles/hr. But in the app itself, it still displays the battery's remaining range in miles. To get this into km too you need to press on the "ME" link at the bottom, then settings, then "metric/imperial" units.</p><p><span style="font-size: medium;"><b>Speed limiter</b> </span><br />The speed of the S1 is by default limited to 25 km/h (15 miles/h), but its easy to go into the app and turn this limit off (under vehicle settings). Doing this lets your scooter achieve the max speed of 30 km/h (18 miles/h). Unlike other scooters, this is purely a software setting and doesn't require any wires to be disconnected or anything to remove the speed limiter.</p><p><b><span style="font-size: medium;">Braking</span><br /></b>The S1 has an automatic electric brake on the back wheel, which kicks in automatically if you are going downhill and picking up speed rapidly, or have exceeded 30 km/h. The maximum speed I've achieved on the scooter is around 30.9 km/h while going downhill.<b></b> The automatic brake is kind of jerky and not really smooth - it feels weird the first time you experience it. There's a toggle setting in the app related to the automatic brake, so I tried turning it both on and off but couldn't feel any difference. There is only one manual brake lever - for your left hand - this is hooked up to the front wheel drum brake. Drum brakes are actually preferable to disk brakes on a scooter because it means no parts are exposed, and so there are less mechanical parts to maintain.<br /></p><p><span style="font-size: medium;"><b>Control panel & display</b></span><br />One of the best things about this scooter is the easy to use control panel and the large display in the middle of the handlebars. There's only one button, and it can perform the functions of power on/off, headlights on/off and to toggle through the three riding modes (Eco, Drive, Sport). Long press is power on/off. Single click is headlights on/off and double click is to toggle the riding mode. Compared to other scooters (like the VSETT range), these controls are intuitive and easy to remember. The throttle is thumb based - you push downward with the thumb of your right hand. Compared to the VSETT scooter throttle which uses your forefinger in a trigger action, I find it to be more natural and better suited to long commutes.</p><p><span style="font-size: medium;"><b>Bling LED lighting and auto turn signals</b></span><br />The scooter has a strip of roadfacing LED lights down each side of the deck, these stay blue while riding and automatically flash red when you are turning to the left or right. This is a great idea, because when riding a scooter its not recommended to take one hand off the handlebars to indicate your turn manually (as per a bicycle) due to instability. The only downside to the auto turn lights is that they don't activate until you either tilt the scooter or turn the handlebars in the direction you are going, so in other words anyone behind you only sees the indication when you are actually turning. Other lights on the scooter are the dual headlights and rear light / brake light. The headlights are positioned at handlebar height, making them extremely visible at night to oncoming traffic. With the LED lights, the scooter really turns heads at nighttime.<br /></p><p><span style="font-size: medium;"><b>Riding modes - Eco, Drive, Sport</b></span><br />The Eco mode is a beginner mode - you won't go faster than 12 km/h (7.5 miles/h) and the acceleration is really soft. The Drive mode is supposed to be a standard commute mode, which limits your top speed to about 20 km/h (12.5 miles/h) and also limits the acceleration responsiveness to about 80% of maximum. Sport mode means no limits, on a full charge you'll get up to the top speed of 30km/h (18 miles/h) with the fastest possible acceleration. I keep it on Sport mode all the time - once you get used to the speed and the handling of the scooter I think most riders will do the same. These modes of course will impact on the range you'll get out of your battery charge, Eco will use the least amount of battery and Sport will use the most.</p><p><span style="font-size: medium;"><b>Range</b></span><br />In the promotional material the claimed range on a full charge is 95 km (59 miles). But in the manual it lets you know that this was achieved on level ground, in Eco riding mode, with a 65 kg weight rider and zero wind. So in other words, nowhere near real world conditions. In real world riding - in Sport mode the entire time, hills, wind, myself being 80kg, I found that the range ended up being 55-60 km (34-37 miles). But this is still a really good range - it easily handles my 28km round trip daily commute, and leaves some spare for other short journeys nearby to work or home.<br /><br /><span style="font-size: medium;"><b>Score card</b></span><br /><br /><span style="font-size: medium;"><b>Good points</b></span><br /><span style="color: #04ff00;"><b>+</b></span> Large display, intuitive controls, comfortable throttle<br /><span style="color: #04ff00;"><b>+</b></span> The app tells you the estimated distance left on the battery charge<br /><span style="color: #04ff00;"><b>+</b></span> Cool underdeck LED lights, auto-turn signals, dual headlights<br /><span style="color: #04ff00;"><b>+</b></span> Large non-slip silicon deck<br /><span style="color: #04ff00;"><b>+</b></span> Big real world range<br /><span style="color: #04ff00;"><b>+</b></span> Front and back suspension<br /><br /><span style="font-size: medium;"><b>Bad points</b></span><br /><span style="color: red;"><b>-</b></span> Its too big to take onto public transport like a bus or train<br /><span style="color: red;"><b>-</b></span> Height of the handlebars is not adjustable and is high compared to other scooters<br /><span style="color: red;"><b>-</b></span> A couple of poor quality fixtures like the bell and the charging port dust covers<br /><span style="color: red;"><b>-</b></span> Jerky automatic electric brake kicks in when going downhill<br /><br /><span style="font-size: medium;"><b>Conclusion</b></span><br />A great long range commuter scooter with decent performance, cool LED lighting, a solid feel, easy to use controls and a large display. If you don't need to take it on public transport, then this scooter will be perfect for your medium to long distance commute, given its large 55km (34 miles) real world range.<br /><br /><span style="font-size: medium;"><b>Where to buy?</b></span><br />As of writing, this model scooter is sold out around most of Australia. Due to high demand and shipping delays I recommend contacting the shop where you intend to buy first to confirm when stock will arrive before paying anything upfront for a scooter.<br /><br /><a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a><br /><br /></p><p><br /></p><p><br /></p>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com8tag:blogger.com,1999:blog-5060551251465839575.post-59180333795925552972020-10-17T21:27:00.005+08:002020-10-18T11:44:52.834+08:00Does Xamarin owe its existence to Unity & Apple?<p><i></i></p><div class="separator" style="clear: both; text-align: center;"><i><a href="https://1.bp.blogspot.com/-fVogBkFtqcw/X4uocpcaIjI/AAAAAAAAOnA/OoolAwKwndYftybZNb-5bKu4-yA984y_QCNcBGAsYHQ/s1937/xamarin-logo-set.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="300" data-original-width="1937" height="100" src="https://1.bp.blogspot.com/-fVogBkFtqcw/X4uocpcaIjI/AAAAAAAAOnA/OoolAwKwndYftybZNb-5bKu4-yA984y_QCNcBGAsYHQ/w640-h100/xamarin-logo-set.png" width="640" /></a></i></div><i><br />Yes, Xamarin owes its existence to two other bits of technology that were huge around 2008 - the Unity Game Engine and the iPhone. The reason is that a confluence of events around 2008 provided the push to get the Mono project into mobile app development. This resulted in MonoTouch (for iOS) and Mono for Android, which eventually became Xamarin as we know it today.</i><p></p><p>The Mono project was founded in 2001 as a free open source implementation of Microsoft's .NET framework on Linux. But Mono had struggled since its inception to find its reason for being. According to Mono's founder, Miguel De Icaza, the hardcore free open source community never fully got behind Mono. The FOSS community feared that Microsoft would eventually cause problems for Mono, due to Microsoft being the creator of .NET. </p><p>Outside of the Linux world however were other more pragmatic people from the MacOSX world who had no problem with Mono. One of these people was Joachim Ante, from Unity. Around 2005 the Unity game engine was just starting out and had a performance problem - their original scripting language of Python was far too slow - they needed something that was an order of magnitude faster. So Unity decided to replace the Python scripting with Mono/C# and immediately got all the performance they needed. This was the early days when the Unity Game Engine ran on MacOSX only. Mono filled the need of being a free open source JIT compiler with the modern language of C#.</p><p>Fast forward to 2008 when the iPhone App Store launched; Unity quickly set their sights on being able to compile games for the iPhone. Unity wanted to use Mono, but the additional requirement was that it had to be statically compiled for iOS, because Apple had banned the use of JIT (Just In Time) compilers in iOS Apps.</p><p></p><blockquote><i>Unity comes back to us and says “Hey, we have this product on iOS, we need .NET to be statically compiled. Can you do that?” We were like, “Oh, that’s kind of impossible. Well, let’s think about it.”<br /><br />One of our guys, Zoltán Varga - they went and made a static compiler for .NET, and it was amazing. We gave it to Unity. At this point, Unity is probably four or five employees.<br /> <br />They were working at somebody’s garage. And they shipped their product for iOS, built games for iOS using this thing, this 3D tech. They were the kings of this space.<br /> <br /></i>- Miguel De Icaza (Xamarin)</blockquote><p>Within a year of the iPhone App Store launch, Unity went from 4-5 employees to 80 employees. The iPhone and the App Store had launched Unity's massive growth, and along with this the Mono project had finally found its reason for being - mobile apps. The Mono developers realised there was interest in using .NET for mobile apps - so using the same tech given to Unity, they built their own product - MonoTouch, which allowed developers build native iOS apps using C#. Soon afterward, Mono turned its attention to Android and created Mono for Android.</p><p>Mobile app development was new and there were many developers who wanted to get into mobile apps but didn't really want to have to learn Objective-C and Java. So Mono now had a C# based cross platform app development platform with truly native performance. This was the killer combination that ensured Mono would take off in popularity.</p><p>The developers behind Mono founded the Xamarin company in 2011, MonoTouch became Xamarin.iOS and Mono for Android became Xamarin.Android. Xamarin was acquired by Microsoft in February 2016 and became a subsidiary of Microsoft, fully focused on the development of Xamarin's open source projects.</p><p>Inspiration for this article:<br /><br /><i>The History of GNOME, Mono, and Xamarin</i><br /><a href="https://changelog.com/podcast/275">https://changelog.com/podcast/275</a><br /></p><a href="http://twitter.com/dodgy_coder"><br />Follow @dodgy_coder on Twitter</a><a href="http://www.dodgycoder.net/feeds/posts/default"><br /></a><br /><p></p>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-80501736403943494232020-05-24T17:00:00.001+08:002020-10-18T11:06:14.981+08:00Breakout: a Circuit Breaker implementation in C#A circuit breaker can help you improve the stability of your
application by protecting calls to third party services; e.g. a web
service, a network resource, a database, or any other component which
can intermittently fail.<br />
<br />
Its a fundamental pattern for protecting your system from all manner
of integration point problems. It is a way to fail fast while there is a
known problem with an integration point.<br />
<br />
The circuit breaker pattern was first described in detail by Michael Nygard in the Stability Patterns chapter of his book <b>"Release It!"</b> <i>Design and Deploy Production-Ready Software</i>.<br />
<br />
<a href="https://github.com/harvey-green/breakout">Breakout</a> is a C# .NET implementation of Michael Nygard's Circuit Breaker state machine, using the Gang of Four's STATE design pattern. I've created a NuGet package for it <a href="https://www.nuget.org/packages/Breakout.CircuitBreaker/">here</a>.<br />
<br />
This implementation is thread safe, lightweight and easily adapted
into your existing codebase. Unlike other circuit breaker
implementations, it leaves the responsibility for calling the third
party service with your client code. Your code only needs to inform the
circuit breaker of the success or failure of every call to the third
party service, via <code>OperationSucceeded()</code> and <code>OperationFailed()</code>. Check the <a href="https://github.com/harvey-green/breakout">README on github</a> for example usage.<br />
<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://1.bp.blogspot.com/-uGbtIMEDK_Q/Xso2CoSvSHI/AAAAAAAANdU/Ni4aIEZqi9w1LLGHIma-WUuVDC5x5v_mgCNcBGAsYHQ/s1600/circuit-breaker-state-machine.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="392" data-original-width="684" height="364" src="https://1.bp.blogspot.com/-uGbtIMEDK_Q/Xso2CoSvSHI/AAAAAAAANdU/Ni4aIEZqi9w1LLGHIma-WUuVDC5x5v_mgCNcBGAsYHQ/s640/circuit-breaker-state-machine.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Breakout - State Machine Diagram</td></tr>
</tbody></table>
<h3>
State Machine Explanation</h3>
<br />
The state machine starts in the <b>CLOSED</b> state. While in the <b>CLOSED</b> state, calls flow through as normal to the third party service.
If the operation succeeds, the failure count is reset.
If the operation fails, the failure count is incremented.
When the failure count threshold is reached, the trip breaker action is performed,
which transitions the state to OPEN.<br />
<br />
While in the <b>OPEN</b> state, no calls flow through to the third party service.
The caller just returns immediately, without performing the service call.
After the open timeout has passed, the attempt reset action is performed,
which transitions the state to HALF OPEN.<br />
<br />
While in the <b>HALF OPEN</b> state, only one call is let through to the third party service.
If the operation succeeds, we reset the circuit breaker which transitions the state to CLOSED.
If the operation fails, the trip breaker action is performed,
which transitions the state to OPEN.<br />
<br />
<h3>
UML Design</h3>
<br />
The design uses the Gang of Four's STATE design pattern.<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://1.bp.blogspot.com/-PSycwfDQ6S4/Xso2M7SHmDI/AAAAAAAANdY/fKwUEMBhO0MNIw_VpKukQa26pdFkmceuQCNcBGAsYHQ/s1600/circuit-breaker-uml-design.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="895" data-original-width="964" height="594" src="https://1.bp.blogspot.com/-PSycwfDQ6S4/Xso2M7SHmDI/AAAAAAAANdY/fKwUEMBhO0MNIw_VpKukQa26pdFkmceuQCNcBGAsYHQ/s640/circuit-breaker-uml-design.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Breakout - UML diagram</td></tr>
</tbody></table>
<br />
<a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-7849267671890630482020-02-23T20:01:00.002+08:002020-10-18T11:07:49.753+08:00Programming an Ethereum Smart Contract with Vyper<span style="color: lime;"><span style="color: lime;"><span style="color: red;"><span style="color: lime;"><b>and deploying it with MetaMask and MyEtherWallet (MEW) </b></span></span></span></span><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Introduction </span></b></span></span><br />
<br />
Ethereum has a vast amount of <a href="https://ethereum.org/developers">developer resources</a> available, such that for a beginner its hard to know where to start.<br />
<br />
If you go with the recommended approach you'd probably choose Solidity along with either JavaScript or golang. JavaScript and golang are traditionally the most well supported languages for the developer tooling around Ethereum. The original Ethereum node software, <b>geth</b>, is written in golang. There's a version of the Solidity smart contract compiler, <b>solcjs</b>, written in JavaScript, and available as a Node.js NPM package.<br />
<br />
The other Smart Contract language that is supported by the Ethereum Foundation is <a href="https://vyper.readthedocs.io/en/latest/">Vyper</a>. Vyper is a python-like language that was designed for security, simplicity and testability. In my view this makes Vyper ideal for a beginner. Vyper foregoes some of the power of Solidity (for example, class inheritance and function modifiers) in order to uphold the Vyper principles of being <b>simple and secure</b>.<br />
<br />
In this article I'll be stepping you through creating a smart contract with the Vyper programming language, deploying it to the Ethereum test network, and then interacting with the contract - calling its two externally accessible functions. The contract deployment and contract interaction are achieved using two in-browser tools - MyEtherWallet (MEW) and MetaMask.<br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Background reading </span></b></span></span><br />
<br />
Before you start I would highly recommend this article to get up to speed with the Ethereum ecosystem as a whole.<br />
<a href="https://medium.com/@mattcondon/getting-up-to-speed-on-ethereum-63ed28821bbe">https://medium.com/@mattcondon/getting-up-to-speed-on-ethereum-63ed28821bbe</a><br />
Its from 2017 but the content is still valid today.<br />
<br />
Along with the Ethereum whitepaper, which is a must-read if you're a developer:<br />
<a href="https://github.com/ethereum/wiki/wiki/White-Paper">https://github.com/ethereum/wiki/wiki/White-Paper</a><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Installing the Vyper compiler </span></b></span></span><br />
<br />
There's a number of options available to you as documented here:<br />
<a href="https://vyper.readthedocs.io/en/latest/installing-vyper.html">https://vyper.readthedocs.io/en/latest/installing-vyper.html</a><br />
<br />
One of the simplest options is to install it using python's package manager (pip). I'll start by ensuring you have the python development environment setup correctly.<br />
<br />
<br />
<u>Installing a recent version of Python and Pip with Pyenv</u><br />
<br />
If you don't have already have a recent version of Python installed, or don't even know, I would highly recommend that you start by installing pyenv. <a href="https://github.com/pyenv/pyenv">Pyenv</a> is a tool for python version management.<br />
<br />
I followed the <a href="https://github.com/pyenv/pyenv#installation">Pyenv installation instructions</a> for a MacOS installation via homebrew, but there are instructions for other OSes given.<br />
<br />
After installing pyenv, you can install the latest version of python with<br />
<br />
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">% pyenv install 3.8.0</span></span><br />
<br />
You will now have an up to date version of both python and pip available from your terminal command prompt.<br />
<br />
Check what version of python is installed:<br />
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">% python -V<br /><br />Output:<br />Python 3.8.0</span></span><br />
<br />
Check what version of pip is installed:<br />
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">% pip -V<br /><br />Output:</span></span><br />
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">pip 19.2.3 from /Users/hg/.pyenv/versions/3.8.0/lib/python3.8/site-packages/pip (python 3.8)</span></span><br />
<br />
<br />
<u>Installing the Vyper compiler</u><br />
<br />
Once you have python and pip installed aready, you can install the Vyper compiler with:<br />
<br />
<span style="font-size: small;"><span style="font-family: "courier new" , "courier" , monospace;">% pip install vyper</span></span><br />
<br />
Check what version of Vyper is installed:<br />
<span style="font-size: small;"><br /><span style="font-family: "courier new" , "courier" , monospace;">% vyper --version<br /><br />Output:<br />0.1.0b16+commit.5e4a94a</span></span><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Writing a smart contract in Vyper </span></b></span></span><br />
<br />
For the first contract, we're going to keep things very simple and go with a public storage contract.<br />
All the contract does is stores a single number in its storage area, and implements two public accessor functions - a getter and a setter.<br />
<br />
Use a text editor and open a new file named <span style="font-family: "courier new" , "courier" , monospace;">storage.vy</span><br />
<br />
Note that <b>vy</b> is the file extension for Vyper source code.<br />
<br />
Here's the Vyper code:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">stored_data: uint256<br /><br />@public<br />def set(new_value : uint256):<br /> self.stored_data = new_value<br /><br />@public<br />@constant<br />def get() -> uint256:<br /> return self.stored_data</span><br />
<br />
Line 1 declares a variable named 'stored_data' of type 'uint256'. This is the only thing that the contract will store on the blockchain.<br />
<br />
Line 3 (<i>def set...</i>) declares the public set function, to update the 'stored_data' variable.<br />
<br />
Line 9 (<i>def get...</i>) declares the public get function, to get the 'stored_data' variable.<br />
<br />
Its important to note that these two functions get and set are marked public and so can be 'called' by anyone - by using Ethereum client software like MyEtherWallet, or programmatically via the web3 or by other library.<br />
<br />
Calling a public function on a smart contract actually consists of sending a transaction to the deployed contract's address - but this is an implementation detail hidden that is hidden by client software or libraries.<br />
<br />
Further reading about the structure of contracts in Vyper:<br />
<a href="https://vyper.readthedocs.io/en/latest/structure-of-a-contract.html">https://vyper.readthedocs.io/en/latest/structure-of-a-contract.html</a><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Compiling the Vyper smart contract </span></b></span></span><br />
<br />
To compile the contract into EVM bytecode:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">% vyper -f bytecode storage.vy > storage.bin</span><br />
<br />
To generate the ABI for the contract:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: small;">% vyper -f abi storage.vy > storage.abi</span></span><br />
<br />
The ABI is a JSON format interface specification file, and it is needed to be able to interact with the smart contract (i.e. call its functions).<br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Deploy the smart contract to the Rinkeby test network </span></b></span></span><br />
<br />
<u>Install MetaMask<b><br /></b></u><br />
If you haven't already, now is a good time to install the MetaMask plugin/extension into your browser - <a href="https://metamask.io/">https://metamask.io/</a><br />
Setup MetaMask with a seed phrase and it will create an in-browser Ethereum wallet that you can use for real transactions, or in this case, test transactions.<br />
<br />
When MetaMask is setup, at the top right you should see the network dropdown.<br />
<br />
Change this to 'Rinkeby Test Network'. Press the DEPOSIT button, then press the GET ETHER button under the TEST FAUCET option.<br />
<br />
After opening <a href="https://www.rinkeby.io/#stats">https://www.rinkeby.io/#stats</a> use the 'Crypto Faucet' button on the left and follow the instructions. The minimum option (3 ETH) will be more than enough for test purposes and to deploy this contract.<br />
<br />
The second thing you'll need to do is to setup MyEtherWallet (MEW). This will let you deploy and interact with your smart contract.<br />
<br />
<br />
<u>Setup MyEtherWallet (MEW)</u><br />
<br />
Go to <a href="https://www.myetherwallet.com/">https://www.myetherwallet.com</a> and setup the seed phrase.<br />
<br />
Now you'll need to give MyEtherWallet (MEW) access to your MetaMask wallet, which contains the 3 ETH for testing.<br />
<br />
Go to <a href="https://www.myetherwallet.com/access-my-wallet">https://www.myetherwallet.com/access-my-wallet</a> and press the <b>browser extension</b> option.<br />
<br />
It should come up with a 'Access via MetaMask' window, and you'll need to grant it permission. Press the 'Access My Wallet' button.<br />
<br />
<br />
<u>Deploy the smart contract<b><br /></b></u><br />
Inside MyEtherWallet (MEW), press the left hand side option 'Contract' then 'Deploy Contract'.<br />
<br />
From the terminal, issue this command:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">% cat storage.bin</span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">Output:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0x6100f456600436101561000d576100ea565b600035601c52740100000000000000000000000000000000000000006020526f7fffffffffffffffffffffffffffffff6040527fffffffffffffffffffffffffffffffff8000000000000000000000000000000060605274012a05f1fffffffffffffffffffffffffdabf41c006080527ffffffffffffffffffffffffed5fa0e000000000000000000000000000000000060a0526360fe47b160005114156100c25734156100ba57600080fd5b600435600055005b636d4ce63c60005114156100e95734156100db57600080fd5b60005460005260206000f350005b5b60006000fd5b6100046100f4036100046000396100046100f4036000f3</span><br />
<br />
Using the mouse, copy the contents of the file from the terminal prompt.<br />
<br />
Inside MEW, paste the copied text contents into the bytecode field.<br />
<br />
On the terminal again, issue this command:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">% cat storage.abi<br /><br />Output:<br />[{"name": "set", "outputs": [], "inputs": [{"type": "uint256", "name": "new_value"}], "constant": false, "payable": false, "type": "function", "gas": 35315}, {"name": "get", "outputs": [{"type": "uint256", "name": "out"}], "inputs": [], "constant": true, "payable": false, "type": "function", "gas": 1181}]</span><br />
<br />
Using the mouse, copy the contents of the file from the terminal prompt.<br />
<br />
Inside MEW, paste the copied text contents into the ABI/JSON field.<br />
<br />
Enter a name for your contract, e.g. 'storage1'.<br />
<br />
Press the 'Sign Transaction' button.<br />
<br />
MetaMask will open up a window where you'll be able to confirm the deployment of your contract.<br />
<br />
You'll see the gas fee and total.<br />
You can press on the data tab and you'll see the bytecode that you pasted earlier.<br />
<br />
Press the Confirm button to proceed with the deployment of your contract.<br />
<br />
You may need to wait several seconds for the transaction to be confirmed at this point.<br />
MetaMask should give you a successful deployment popup and link you to the transaction on etherscan.io.<br />
E.g.<br />
<a href="https://rinkeby.etherscan.io/tx/0x36663b338ab0eaa7d7cdd91aa5abacdc273757ff56b81221d76a2ff0aedc9860">https://rinkeby.etherscan.io/tx/0x36663b338ab0eaa7d7cdd91aa5abacdc273757ff56b81221d76a2ff0aedc9860</a><br />
<br />
Here you can see the address of your newly deployed contract. In my case it is here:<br />
<a href="https://rinkeby.etherscan.io/address/0x7baad2f634d6bde84916e7d6db40ca2e502eaff6">https://rinkeby.etherscan.io/address/0x7baad2f634d6bde84916e7d6db40ca2e502eaff6</a><br />
<br />
<br />
<u>Side note on contract addresses</u><br />
<br />
Contract addresses are calculated deterministically, based on the account that created it. They are based on the nonce value of your account. So it is possible to know in advance what the contract address will be, if necessary.<br />
<br />
Details here:<a href="https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed"> https://ethereum.stackexchange.com/questions/760/how-is-the-address-of-an-ethereum-contract-computed</a><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Interacting with the smart contract </span></b></span></span><br />
<br />
Now that your contract is deployed, its time to interact with it - call its <b>get</b> and <b>set</b> functions.<br />
<br />
The <b>get</b> function can be called 'for free' - it doesn't cost any gas, because its just returning the current state of the blockchain.<br />
Calling the 'set' fuction however must be paid for in gas, because by calling it you are actually changing the current state of the blockchain.<br />
<br />
Go back to MEW and navigate to the left hand side 'Contract' option then 'Interact with Contract'.<br />
<br />
Paste your newly created contract address into the 'Contract Address' field.<br />
<br />
In the ABI/JSON field, past your ABI file contents.<br />
<br />
Press the Continue button.<br />
<br />
There's a dropdown which shows 'Select an item'. This lists all of the public functions on the smart contract. There's only two available - get and set.<br />
<br />
Choose get first, it will execute immediately and show the result being 0. 0 is the default value for uninitialised storage in Ethereum.<br />
<br />
Now choose 'set' from the dropdown.<br />
<br />
Enter the required value into the new_value field, e.g. 88.<br />
<br />
Leave the Value in ETH as 0.<br />
<br />
Press the 'Write' button.<br />
<br />
MetaMask will open up a window where you'll be able to confirm your contract interaction.<br />
What you're actually doing here is sending a transaction to the contract with a value in the data field - the data specifies to the EVM which function is being called (set) and the value of the parameter to it (88).<br />
<br />
Press the confirm button.<br />
<br />
You may need to wait several seconds for the transaction to be confirmed.<br />
<br />
MetaMask should give you a confirmed transaction popup and link you to the transaction on etherscan.io.<br />
E.g.<br />
<a href="https://rinkeby.etherscan.io/tx/0x42af3501fff6ddd67a97cc52c94565f149f4d7f985d223523cebae2efc693bbb">https://rinkeby.etherscan.io/tx/0x42af3501fff6ddd67a97cc52c94565f149f4d7f985d223523cebae2efc693bbb</a><br />
<br />
Press the "Press to see more" link at the bottom of this page on etherscan.io to see the detail of the function call you made.<br />
<br />
Go back to MEW and this time select the 'get' from the dropdown.<br />
<br />
Confirm that the value you set is now reflected by the get.<br />
<br />
<u><b>You have now successfully deployed an Ethereum smart contract written in Vyper, and interacted with it using MetaMask and MyEtherWallet (MEW).</b></u><br />
<br />
<u><b>Congratulations!</b></u><br />
<br />
<br />
<span style="color: #93c47d;"><span style="color: blue;"><b><span style="color: #93c47d;">Final notes - can you modify a smart contract? </span></b></span></span><br />
<br />
Note that once a smart contract is deployed, you can't modify it; it is immutable and exists on the Ethereum blockchain forever.<br />
<br />
If you need to modify or update the contract, you'll need to deploy the updated code to a new contract address.<br />
<br />
There are various techniques for handling contract "upgrades" including migrating the existing storage. There's a good article here on this topic:<a href="https://mixbytes.io/blog/storage-upgradable-ethereum-smart-contracts"> https://mixbytes.io/blog/storage-upgradable-ethereum-smart-contracts</a><br />
<br />
Note also that a contract can destroy itself (along with its storage), via the <b>selfdestruct()</b> function, as documented here:<a href="https://vyper.readthedocs.io/en/v0.1.0-beta.15/built-in-functions.html#selfdestruct"> https://vyper.readthedocs.io/en/v0.1.0-beta.15/built-in-functions.html#selfdestruct</a><br />
<br />
Once destroyed, the contract and its storage are removed from that block onwards. After destruction, it is technically still possible to see the historical contract bytecode and storage, which exists on earlier blocks of the Ethereum blockchain.<br />
<br />
<br />
<a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com2tag:blogger.com,1999:blog-5060551251465839575.post-39169077814095389662020-02-08T20:00:00.001+08:002020-10-18T11:08:26.357+08:00Programming Bitcoin Cash (BCH) with the NBitcoin .NET library and C#The <a href="https://github.com/MetacoSA/NBitcoin">NBitcoin</a> library is the most active and well supported library in .NET for working with Bitcoin and other similar cryptocurrencies.<br />
<br />
NBitcoin fully supports <a href="https://en.wikipedia.org/wiki/Bitcoin_Cash">Bitcoin Cash</a> (BCH), however the ebook and programming guide examples focus solely on <a href="https://en.wikipedia.org/wiki/Bitcoin">Bitcoin Core</a> (BTC).<br />
<br />
The problem you encounter when following the NBitcoin guide is firstly that the <a href="https://github.com/MetacoSA/QBitNinja">QBitNinja API</a> only supports Bitcoin Core and secondly that broadcasting the transaction seems to require either running a full local node or using the QBitNinja API.<br />
<br />
In this tutorial I'll show you how to spend your Bitcoin Cash using the NBitcoin library running under dotnet core, without the need for running a full local node or for accessing the QBitNinja API.<br />
<b><br />The program you write here will create a new transaction, sign it with your private key, and broadcast it to the Bitcoin Cash network.</b><br />
<a href="https://docs.microsoft.com/en-us/dotnet/core/"><br />Dotnet core</a> is the preferred programming environment for NBitcoin. Dotnet core is open source and runs under the Linux, MacOSX and Windows operating systems.<br />
<br />
Bitcoin Cash is the ideal cryptocurrency for experimenting with programming APIs and libraries - you can send small transactions for very low fees, typically for a fraction of one US cent. <br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 1: Project Setup </span></b></u><br />
<br />
Follow the setup guide as normal:<br />
<a href="https://programmingblockchain.gitbook.io/programmingblockchain/introduction/project_setup">https://programmingblockchain.gitbook.io/programmingblockchain/introduction/project_setup</a><br />
<br />
The rest of these steps 2-12 below loosely follow the "Spend Your Coin" guide:<br />
<a href="https://programmingblockchain.gitbook.io/programmingblockchain/bitcoin_transfer/spend_your_coin">https://programmingblockchain.gitbook.io/programmingblockchain/bitcoin_transfer/spend_your_coin</a><br />
<br />
Its not absolutely required, but for a more complete and in depth understanding, I would recommend you read through the "Spend Your Coin" guide above (with the knowledge that it applies to Bitcoin Core) before proceeding with the rest of the below steps.<br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 2: Add support for Bitcoin Cash </span></b></u><br />
<br />
On the command line:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">dotnet add package NBitcoin.Altcoins</span></span><br />
<br />
The code - add these <b>using</b> statements to the top of the C# source file.<span style="font-size: x-small;"><br /><br /><span style="font-family: "courier new" , "courier" , monospace;">using NBitcoin;<br />using NBitcoin.Altcoins;<br />using NBitcoin.Protocol;</span></span><br />
<br />
And at the beginning of the program, add this:<span style="font-size: x-small;"><br /><br /><span style="font-family: "courier new" , "courier" , monospace;">// Important Note - this is not test code.<br />// It is going to run in production (called the "mainnet").<br />var network = NBitcoin.Altcoins.BCash.Instance.Mainnet;</span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><br /></span></span><span style="color: #93c47d;">
</span><u><b><span style="color: #93c47d;">Step 3: (Optional) Generate a new private key and address </span></b></u><br />
<br />
The below code snippet generates a new BCH private key and BCH address using the NBitcoin library.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// Generate a random private key.<br />Key rawPrivateKey = new Key(); <br /><br />// The private key, also known as the Bitcoin secret or the WIF (Wallet Interchange Format).<br />// If you intend to use it, make sure you save the below somewhere safe!<br />BitcoinSecret privateKey = rawPrivateKey.GetBitcoinSecret(network);<br />Console.WriteLine("privateKey = " + privateKey);<br />Console.WriteLine("address (from privateKey) = " + privateKey.GetAddress(ScriptPubKeyType.Legacy));</span></span><br />
<br />
Alternatively you can generate a new private key and address using BCH wallet software.<br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 4: Setup the variables for your private keys and addresses </span></b></u><br />
<br />
To spend your Bitcoin Cash, you'll need to know the private keys of both the "destination" BCH address and the "from" BCH address.<br />
The "from" BCH address is also known as the input address or the outpoint to spend.<br />
<br />
Here's the code to setup the address and private keys of both the "destination" address and the "from" address.<br />
<span style="font-size: x-small;"><br /><span style="font-family: "courier new" , "courier" , monospace;">// Destination - private key and address. The destination of the new transaction we are creating.<br />// Note: its not strictly necessary for creating the transaction to have the private key of the destination,<br />// but its better to add it here so that you know that you have access to it, and that the money won't be 'lost'.<br />var privateKey = new BitcoinSecret("PASTE_YOUR_DESTINATION_ADDRESS_PRIVATE_KEY_HERE", network);<br />Console.WriteLine("dest privateKey = " + privateKey);<br />var address = privateKey.GetAddress(ScriptPubKeyType.Legacy);<br />Console.WriteLine("dest address = " + address);<br />Console.WriteLine("dest address scriptPubKey= " + address.ScriptPubKey);<br /><br />// Input Transaction - private key and address. The from address.<br />var inPrivateKey = new BitcoinSecret("PASTE_YOUR_FROM_ADDRESS_PRIVATE_KEY_HERE", network);<br />var inAddress = inPrivateKey.GetAddress(ScriptPubKeyType.Legacy);<br />Console.WriteLine("inPrivateKey = " + inPrivateKey);<br />Console.WriteLine("inAddress = " + inAddress);<br />Console.WriteLine("inAddress scriptPubKey= " + inAddress.ScriptPubKey);</span></span><br />
<br />
You can run the program now to make sure its working - on the command line:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">dotnet run</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 5: Determine the Transaction ID of the "from" address </span></b></u><br />
<br />
Now you need to determine the transaction ID and index number of your "from" address by looking at the transaction in a blockchain explorer and plugging in the correct TxId and index number below.<br />
<span style="font-size: x-small;"><br /><span style="font-family: "courier new" , "courier" , monospace;">// Determine the previous output that will be spent, as the Input to our new transaction.<br />// For example:</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// https://explorer.bitcoin.com/bch/tx/292f70e71f8bc2e94b7c0ac46c4e89371dc59b821639de67376f6f0b09544d92<br />string txInIdString = "292f70e71f8bc2e94b7c0ac46c4e89371dc59b821639de67376f6f0b09544d92";<br />uint txOutIndex = 0; // <== Ensure this index is correct!<br />OutPoint outPointToSpend = OutPoint.Parse(txInIdString + ":" + txOutIndex);</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 6: Create the new transaction </span></b></u><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">var transaction = Transaction.Create(network);<br />transaction.Inputs.Add(new TxIn()<br />{<br /> PrevOut = outPointToSpend<br />});</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 7: Setup the amount to spend and the miner fee </span></b></u><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// Suggested miner fee for this transaction, as of February 2020,</span></span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// is </span></span></span></span><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">0.000003</span></span> BCH or around USD 0.001 (a tenth of a cent).<br />// Check recent blocks for guidance.</span></span> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">var minerFee = new Money(0.000003m, MoneyUnit.BTC); </span></span><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"> </span></span></span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// Replace below with your amount.</span></span></span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// It is the total unspent amount of the "from" address.</span></span><br />var txInAmount = new Money(0.0021m, MoneyUnit.BTC); <br /><br />// Move to the destination address.</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">var spendAmount = txInAmount - minerFee;</span></span> </span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">transaction.Outputs.Add(spendAmount, address.ScriptPubKey);</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 8: Add a message to the transaction, using the OP_RETURN template (max 80 characters) </span></b></u><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;">var message = "Test 1: using the NBitcoin library to move Bitcoin Cash. BCH Rocks!";<br />var bytes = Encoding.UTF8.GetBytes(message);<br />transaction.Outputs.Add(Money.Zero, TxNullDataTemplate.Instance.GenerateScriptPubKey(bytes));</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 9: Sign the transaction </span></b></u><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;">// Get the ScriptPubKey from the private key of the outPointToSpend.<br />transaction.Inputs[0].ScriptSig = inAddress.ScriptPubKey;<br /><br />// Sign the transaction with the input private key.<br />var txInId = uint256.Parse(txInIdString);<br />var inCoin = new Coin(txInId, txOutIndex, txInAmount, inAddress.ScriptPubKey);<br />transaction.Sign(inPrivateKey, inCoin);</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 10: Determine the TxId of your transaction, which is just its hash </span></b></u><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"><span style="font-size: x-small;">Console.WriteLine("New TxId: " + transaction.GetHash());</span></span><br />
<br />
Now is a good time to run the code and check its all working. From the command line:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">dotnet run</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 11: Broadcast your transaction to the Bitcoin Cash network </span></b></u><br />
<br />
This is the final step and should only be attempted if your program runs fine up to step 10.<br />
<br />
Before you run it, confirm your amount to spend is correct.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">//</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">// Connect to a BCH node and broadcast the transaction.<br />// See here for the DNS Seed list:<br />// https://github.com/Bitcoin-ABC/bitcoin-abc/blob/master/src/chainparams.cpp</span></span><br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">//<br />using (var node = Node.Connect(network, "seed.bchd.cash:8333"))<br />{<br /> // Say hello to the node.<br /> node.VersionHandshake(); <br /><br /> // Advertise your transaction (send just the hash).<br /> node.SendMessage(new InvPayload(InventoryType.MSG_TX, transaction.GetHash()));<br /><br /> // Send the contents of the transaction.<br /> node.SendMessage(new TxPayload(transaction));<br /><br /> // Wait for the message to be sent.<br /> Thread.Sleep(5000); <br />}</span></span><br />
<br />
Run your program the command line:<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "courier new" , "courier" , monospace;">dotnet run</span></span><br />
<br />
<br />
<u><b><span style="color: #93c47d;">Step 12: That's it, well done for making it to the end!! </span></b></u><br />
<br />
If everything went well, your new transaction was accepted by the Bitcoin Cash network, and it will show up in a block explorer such as this one:<br />
<br />
<a href="https://explorer.bitcoin.com/bch/tx/3ecf0f0dafd26e8d788b59a433bf00e1c3c079e82dada5111e899c87a75dadff">https://explorer.bitcoin.com/bch/tx/3ecf0f0dafd26e8d788b59a433bf00e1c3c079e82dada5111e899c87a75dadff</a><br />
<br />
Replace the above TxId with yours from step 10.<br />
<br />
Your new transaction will be listed initially as having 0 confirmations, which means its in the mempool.<br />
<br />
Now you just need to wait for your transaction to be confirmed. This will happen as soon as the next block is mined and your transaction gets added to that block by the winning miner.<br />
<br />
<a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a><br />Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com5tag:blogger.com,1999:blog-5060551251465839575.post-54885083241263640202019-10-01T21:51:00.000+08:002020-03-08T20:23:18.965+08:00Counter overflows and clock drift bugs in aircraft and missile defense systemsA <b>counter overflow bug</b> happens when an unsigned integer variable storing a counter reaches its maximum value; when its already at the maximum, as soon as one more value gets added to it, the variable will reset back to 0 and continue counting up from there. If the rest of the software is not expecting this counter reset, it can result in system failures. So the longer the system is running for, the nearer the system will get to a counter overflow event.<br />
<br />
<b>Clock drift bugs</b> happen when an internal timer/clock gets calculated incorrectly, causing it to slowly drift out of sync with real time. The longer the system is running, the more the clock drifts and the bigger the error gets. When real time clocks are out of sync, all sorts of downstream calculations can become inaccurate.<br />
<br />
Both of these types of bugs typically have a workaround that requires the operator to reboot the system every X hours or days.<br />
<br />
Both counter overflows and clock drift bugs can occur in production systems when system testing didn't include a "soak test" - where you keep the system running for a very long period, typically measured in days rather than hours. The failure to pick up the bug during system testing means that a production system gets deployed with a bug, and the only workaround becomes a regular reboot of the system.<br />
<br />
<b><u><span style="color: #93c47d;">The kicker - these type of bugs have been happening in safety critical systems for at least the past 28 years </span></u></b><br />
<br />
One of the most publicized cases was the <a href="https://embeddedgurus.com/barr-code/2014/03/lethal-software-defects-patriot-missile-failure/">failure of a Patriot missile defense system in 1991</a>, in which the system failed to track an incoming Scud missile, due to a drifting and out of sync clock. Tragically, this particular failure resulted in the death of 28 U.S. soldiers based at a U.S. barracks near to Dhahran, Saudi Arabia. The workaround for this bug was to reboot the system every 8 hours, but unfortunately this had not been communicated to the base in time to avoid the disaster.<br />
<br />
Another well known case was the <a href="https://www.i-programmer.info/news/149-security/8548-reboot-your-dreamliner-every-248-days-to-avoid-integer-overflow.html">counter overflow in the Boeing 787 Dreamliner firmware</a> (2015), which meant the aircraft had to be rebooted once every 248 days to avoid a counter overflow bug.<br />
<br />
The most recent case was an <a href="https://www.gizmodo.com.au/2019/07/turn-it-off-and-on-again-every-149-hours-is-a-concerning-remedy-for-a-300-million-airbus-planes-software-bug/">internal timer bug in the Airbus A350 firmware</a> (2019), which requires that the aircraft be rebooted once every 149 hours.<span style="font-family: inherit;"> </span><br />
<br />
<span style="font-family: inherit;"><span style="color: #93c47d;"><u><b>Avoiding bugs in safety critical systems</b></u><b> </b></span> </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;">Avionics systems are among the most complex things ever built by man. There's one leading example of a successful avionics project which was built from scratch targeting high quality and zero defects. Its the <a href="https://en.wikipedia.org/wiki/Boeing_777">Boeing 777</a> - Boeing's first fly-by-wire aircraft. </span><br />
<span style="font-family: inherit;">For the 777, Boeing decided early on to standardize on the <a href="https://en.wikipedia.org/wiki/Ada_(programming_language)">Ada programming language</a>, at a time when using C was the norm. Compilers for Ada had been certified as correct, and the language itself included several safety features, such as <a href="https://en.wikipedia.org/wiki/Design_by_contract">design by contract</a> and extremely <a href="https://en.wikipedia.org/wiki/Strong_and_weak_typing">strong typing</a>. </span><br />
<br />
<span style="font-family: inherit;">Ada itself came about as a way to standardize all of the programming languages in use by the U.S. Department of Defense - before Ada they were using some 450 different programming languages. Ada was originally designed to be used for embedded and real time systems.</span><br />
<br />
<span style="font-family: inherit;">Ronald Ostrowski, Boeing's director of Engineering, claimed that the Boeing
777 was the most tested airplane of its time. For more than 12 months before its maiden flight, Boeing tested the 777's
avionics and flight-control systems continuously - 24hrs - 7days - in laboratories
simulating millions of flights. </span><br />
<br />
<span style="font-family: inherit;">The 777 first entered commercial service with <a href="https://en.wikipedia.org/wiki/United_Airlines" title="United Airlines">United Airlines</a> on 7th June, 1995. It has since received more orders than any other wide-body airliner. </span><span style="font-family: inherit;">The 777 is one of Boeing's best-selling models; by 2018 it had
become the most-produced Boeing wide-body jet, surpassing the legendary Boeing
747. </span><br />
<br />
<span style="font-family: inherit;"><a href="http://archive.adaic.com/projects/atwork/boeing.html">Further reading - Boeing flies on 99% Ada</a> </span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a></span>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-29279530661567342482019-09-28T15:47:00.000+08:002020-03-08T20:26:18.788+08:00Review of Shopify - from a developer's point of view<span style="font-family: inherit;">I setup this online shop over a couple of weekends - <a href="https://chowslow.com.au/">Chow Slow - Slow Feeder Dog Bowls</a>. After launch I continued to make various improvements and optimisations to the presentation and content of the site. Since launch three months ago, the online shop has so far taken 72 orders.<br /><br />The eCommerce SaaS product <a href="https://shopify.com/">Shopify</a> was used to build the site, on the <i>Basic Shopify</i> (monthly) plan.<br /><br />Here below are my opinions on Shopify:<br /><br /><u><b>Shopify - Good points</b></u></span><br />
<ul>
<li><span style="font-family: inherit;">Many <b>payment options </b>- I chose the Shopify Payments option. It accepts Apple Pay and Google Pay when on a mobile browser for example. You can tell that Shopify have extensive experience with taking payments - everything is really polished.</span></li>
<li><span style="font-family: inherit;"><b>Test mode </b>works well for putting through test credit card orders and seeing the customer experience end to end. Can also password protect the site while its under development.</span></li>
<li><span style="font-family: inherit;">The <b>free themes </b>are good and can be customised for most online shops. I used the free "Minimal" theme and then customised the layout of the home page, added several pages and added a blog.</span></li>
<li><span style="font-family: inherit;">Great optimisations and <b>layouts which work well on mobile</b>. More than 60% of the traffic for the site comes from a smartphone browser as opposed to a traditional desktop browser.</span></li>
<li><span style="font-family: inherit;">Really useful "<b>Timeline</b>" admin feature on the customer and order admin pages - see all the interactions that have happened with a customer in a simple timeline display, with a timestamp shown on each interaction.</span></li>
<li><span style="font-family: inherit;">Excellent "<b>Conversion Summary</b>" admin feature - see the site behaviour of your customer from when they first visited your site to when they bought something.</span></li>
<li><span style="font-family: inherit;">Comprehensive "<b>Fraud Analysis</b>" admin feature - for orders paid by Credit Card - recommendation of whether the transaction is likely fraudulent or not: probability shown as low, medium, or high.</span></li>
<li><span style="font-family: inherit;">Ability for customers to <b>sign up </b>with either their mobile phone number or email address. Shopify automatically sends communications to the customer using either mobile SMS or by email.</span></li>
<li><span style="font-family: inherit;">Easy to add <b>social media </b>accounts, which then automatically appear on the site footer.</span></li>
<li><span style="font-family: inherit;"><b>Products </b>are easy to configure and easy to change in terms of page title and content.</span></li>
<li><span style="font-family: inherit;">Ability to edit <b>raw HTML </b>in most places.</span></li>
<li><span style="font-family: inherit;">Easy to setup a <b>custom domain</b>, with TLS/SSL included (which just works).</span></li>
<li><span style="font-family: inherit;">There are <b>SEO optimisations </b>and settings available at a page level. You can change the page title, meta description and URL.</span></li>
<li><span style="font-family: inherit;"><b>Integration with Google Analytics </b>is excellent - the 'Advanced eCommerce' option should be turned on - it results in a data going straight into GA for your conversions and sales.</span></li>
<li><span style="font-family: inherit;"><b>Page load time </b>is good - bulk of the home page loads typically in 2-3 seconds.</span></li>
<li><span style="font-family: inherit;">A comprehensive <b>API </b>for writing custom integrations with other backend software and systems.</span></li>
</ul>
<span style="font-family: inherit;"><span style="font-family: inherit;"><u><b>Shopify - Bad points</b></u></span></span><br />
<ul>
<li><span style="font-family: inherit;"><b>Marketing integrations </b>- Facebook Ads for example - difficult and error prone to setup. Facebook Ads never worked for me after many headaches trying to setup. The marketing integrations seem like a quick way to lose money fast.</span></li>
<li><span style="font-family: inherit;">Inability to structure the Products, Pages and Blog sections to be within a custom <b>sub-folders</b> structure (as is typically recommended to silo a website for SEO purposes).</span></li>
<li><span style="font-family: inherit;"><b>Checkout page customization </b>is limited to Shopify Plus users.</span></li>
<li><span style="font-family: inherit;"><b>Checkout script editor</b> is limited to Shopify Plus, so any custom
logic to apply discounts has to be done through plugins.</span></li>
<li><span style="font-family: inherit;"><b>API is rate limited </b>- will be fine for most users however ERP systems which run via batch processing or via polling may have issues. You need to implement everything as event driven webhooks rather than by polling the Shopify API.</span><br /><span style="font-family: inherit;"></span></li>
</ul>
<span style="font-family: inherit;"><u><b>Shopify - Areas for improvement</b></u></span><br />
<ul>
<li><span style="font-family: inherit;">I'm not convinced of the need for many of the Shopify apps (plug-ins) that get automatically suggested. I have a feeling that they will result in bigger page sizes and slower load times. I have not needed to use any apps yet.</span></li>
<li><span style="font-family: inherit;">Its sometimes hard to find the relevant place for a setting - whether under preferences of the online shop or under settings of the account itself. I should probably make more use of the search bar at the top for this in the future.</span></li>
</ul>
<span style="font-family: inherit;"><u><b>Shopify - Conclusion</b></u><br /><br /><b>I highly recommend Shopify for setting up an online shop. When launching, your focus will be taken up with gaining your first customers, online marketing and the delivery process, so having a solid full featured website behind you is crucial.</b></span><br />
<span style="font-family: inherit;"><br /></span>
<span style="font-family: inherit;"><br /></span><br />
<i>A bit more about our online shop - <a href="https://chowslow.com.au/">Chow Slow - Slow Feeder Dog Bowls</a><span style="font-family: inherit;"><span style="background-color: #fff2cc;"> </span></span></i><br />
<i><span style="font-family: inherit;"><span style="background-color: #fff2cc;"><br /></span></span>I setup the site for my wife, who runs the business day to day. She handles the processing of orders and deliveries. We came up with the idea of selling to this niche market after finding out about this type of product in 2018. Our pet beagle (Ripley) had an issue of regular regurgitation due to eating too quickly. The slow feeder bowl product solved his problem and results in more relaxed meal times every day.</i><br />
<span style="font-family: inherit;"><br /></span>
<br />
<span style="font-family: inherit;"><a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /></a></span>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-8735832095758676892019-04-18T11:16:00.000+08:002020-03-08T20:27:37.731+08:00Inactive/Failing Mobile Apps: The Many Benefits of Regular App UpdatesThis article applies mainly to mobile apps which are not in active development. It applies equally to mobile apps on the public app stores and also to enterprise mobile apps which get distributed via other means (such as MDM software).<br />
<br />
<u><b>Example scenario of an inactive/failing app:</b></u><br />
<ul>
<li>The active marketing of your app that happened at launch has now stopped</li>
<li>Your app's last update was several months ago</li>
<li>The uninstallation rate has started rising above your installation rate month on month</li>
</ul>
<span style="color: blue;"><br /><span style="color: #93c47d;"><b>A way to prevent this happening is to release regular app updates, even when there are no major changes to your app's code.</b></span></span><br />
<u><br /><br /><b>Benefits of releasing regular app updates:</b></u><br />
<ul>
<li><b>Gain new users</b>; many users look at the last release date on the app store page before downloading your app. Anything over a year old can be immediately rejected as out of date.</li>
<li><b>Prevent uninstalls</b>; seeing your app has been updated on their phone keeps it in the user's mindshare, so they know you are still actively developing it.</li>
<li><b>Update the dependencies</b>; you will likely have several dependencies on open source libraries and mobile SDKs. The more often you release, the more often these can be updated too.</li>
<li><b>Update the toolchain</b>; Xcode / Android Studio / Visual Studio get updated once every month or two. Same applies to hybrid and cross platform toolchains such as Unity, Ionic and Xamarin.</li>
<li><b>Update the store listing</b>; since you're doing a build, take the opportunity to review and tweak the store listing and screenshots. Apple's App Store Connect website and Android's Google Play Console get updated regularly with enhancements you can take advantage of.</li>
<li><b>Less build issues</b>; there will be a lower chance of a major build issue if you regularly update your toolchain and its dependencies. In my experience, the longer you wait between app builds and releases, the greater the chance of a major build issue the next time.</li>
<li><b>Source control change visibility</b>; the project is kept active in terms of source control history; especially relevant if its an open source project with other potential developers able to see the change history on github or bitbucket.</li>
<li><b>Developer benefits</b>; you don't end up with a legacy mobile app that noone can get building anymore.</li>
</ul>
<br />
<u><b>What if there are no significant changes to your code?</b></u><br />
<ul>
<li>Have the dependencies or toolchain been updated? If yes, that means your app has gained some potential bug fixes and enhancements for free - just by doing a build.</li>
<li>There's always some minor refactoring you can do to make small improvements to your codebase. Just spend a couple of hours if that's all you can spare.</li>
<li>The release note; just use the standard "Bug fixes, performance and stability improvements" if you can't think of anything else.</li>
</ul>
<br />
<u><b>How often to release?</b></u><br />
<ul>
<li>The more often the better.</li>
<li>Aim for a regular release cycle of between 1-3 months.</li>
</ul>
<br />
<u><b>Further reading</b></u><br />
<br />
Distribution of Android apps per download range<br />
<a href="https://www.statista.com/statistics/269884/android-app-downloads/">https://www.statista.com/statistics/269884/android-app-downloads/</a><br />
<br />
Download distribution of Android apps, and lifetime growth rates per download range<br />
<a href="https://www.appbrain.com/stats/android-app-downloads">https://www.appbrain.com/stats/android-app-downloads</a><br />
<br />
Statistics about the release schedule of apps on the Apple app store<br />
<a href="https://stories.appbot.co/how-often-should-you-update-your-app-9405b85a967c">https://stories.appbot.co/how-often-should-you-update-your-app-9405b85a967c</a><br />
<br />
Best practices for Apple app store updates <br />
<a href="https://developer.apple.com/app-store/app-updates/">https://developer.apple.com/app-store/app-updates/</a><br />
<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a><br />
<br />Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-14680181960207003282016-09-18T18:33:00.000+08:002016-09-18T19:51:44.718+08:00Lightweight IoT Command and ControlMany hobbyist IoT projects running on the <a href="https://www.raspberrypi.org/">Raspberry Pi</a> (RPi) require a webserver running on the RPi which receives requests from a browser, where the client using the browser is connected either to the local WiFi network, or possibly (via a port forwarding setup), connected to the public Internet.<br />
<br />
An alternative that is easy to setup, lightweight and low cost is one that makes use of <a href="https://aws.amazon.com/sqs/">Amazon's SQS</a> (Simple Queue Service) to setup two queues. One queue is for commands - from a mobile application to the RPi. Another queue is for responses - from the RPi back to the mobile application. It results in a simple and easy to secure solution available over the public Internet. It requires no port forwarding - both endpoints make use of a client connection to Amazon AWS. Given the small amount of messages needed for typical hobbyist project, the SQS component will be covered by the AWS free tier.<br />
<br />
Here's the high level design of the system ...<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://1.bp.blogspot.com/-W-6WH6xScVk/V95nrIX2j_I/AAAAAAAAAh0/BJDE0s-FwykybdjRMBjy5dxt1GKixVhOQCLcB/s1600/IoT%2BCommand%2Band%2BControl.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" src="https://1.bp.blogspot.com/-W-6WH6xScVk/V95nrIX2j_I/AAAAAAAAAh0/BJDE0s-FwykybdjRMBjy5dxt1GKixVhOQCLcB/s1600/IoT%2BCommand%2Band%2BControl.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Lightweight IoT Command and Control </td></tr>
</tbody></table>
On the Raspberry Pi, a lightweight application is running that makes use of the excellent Python <a href="http://boto3.readthedocs.io/en/latest/guide/sqs.html">boto3</a> AWS SDK library. It is always waiting for a command to arrive in the command queue. As soon as it receives a command, it processes it and adds a response to the response queue.<br />
<br />
On the mobile device an Android application is running that makes use of the <a href="http://docs.aws.amazon.com/mobile/sdkforandroid/developerguide/setup.html">AWS Mobile SDK for Android</a>. When the user presses a command button, such as 'Open Garage Door', it adds a command to the command queue, and asynchronously waits for a response to arrive in the response queue. When it receives a response (e.g. the command's success or failure status), it updates the app's user interface.Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com1tag:blogger.com,1999:blog-5060551251465839575.post-73618828025723198032016-01-02T22:23:00.002+08:002016-01-03T10:07:25.780+08:00Custom domain for Azure Web Apps using FreeDNSThe below steps go through setting up a custom domain name on your Azure Web App, using the <a href="https://www.namecheap.com/domains/freedns.aspx">FreeDNS</a> service from <a href="https://www.namecheap.com/">NameCheap</a>. Both the www subdomain <b>www.yourdomainhere.com</b> and the naked <b>yourdomainhere.com </b>will be setup.<br />
<br />
I have an Azure S1 Small Instance App Service Plan on which I'm running 4 <a href="https://azure.microsoft.com/en-us/documentation/articles/web-sites-dotnet-get-started/">web apps</a>. Originally I had planned to use <a href="https://azure.microsoft.com/en-us/services/dns/">Azure DNS</a>, to keep everything within the same cloud service, but after some initial attempts formed the opinion that Azure DNS isn't mature enough yet to host production web sites. Azure DNS can currently only be administered from within <a href="https://azure.microsoft.com/en-us/documentation/articles/powershell-install-configure/">Azure Powershell</a> - that in itself was enough to put me off using it. If you need to make a quick change to a DNS record, you don't want to be having to run Powershell to do it. Microsoft are working on adding Azure DNS to the Azure Portal, but at the moment it's not available.<br />
<br />
I have a couple of domains through NameCheap and for those and a couple of others (with CrazyDomains) I decided to use NameCheap's DNS service. Even when your domain is not registered through NameCheap, they still offer a free DNS service, called FreeDNS.<br />
<br />
Note that in the below steps, <b>yourwebappname</b> and <b>yourdomainhere.com </b>should of course be replaced with your specific names.<br />
<br />
<br />
<span style="font-size: large;">Step 1. Reduce the TTLs to 5 minutes</span><br />
<br />
<i>Note: you only need to perform this step if you're porting from an existing DNS provider. No need to do this if you're setting up a new web app on a new domain.</i><br />
<br />
Within your current DNS service, setup all the TTL settings (Time To Live) on the DNS records to the minimum (typically 300 seconds, or 5 minutes). This may help in having the DNS changes propagate faster.<br />
<br />
After this is done, try to get a full DNS zone file listing. When you port the DNS records to FreeDNS it will help ensure that you don't miss anything. My previous VPS and DNS provider was Linode and I was porting a few web apps from Linode over to Azure web apps.<br />
<br />
<br />
<span style="font-size: large;">Step 2. Ensure your Azure web app is running</span><br />
<br />
Ensure your web app is published and running ok at http://yourwebappname.azurewebsites.net<br />
<br />
<br />
<span style="font-size: large;">Step 3. Find the IPv4 address of your Azure web app</span><br />
<br />
From a windows cmd.exe prompt ...<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:\> nslookup </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">yourwebappname</span>.azurewebsites.net</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><br />Server: UnKnown<br />Address: 192.168.1.1<br /><br />Non-authoritative answer:<br />Name: waws-prod-xxx-xxx.cloudapp.net<br />Address: 1.2.3.4<br />Aliases: </span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: "Courier New",Courier,monospace;">yourwebappname</span></span>.azurewebsites.net<br /> waws-prod-xxx-xxx.vip.azurewebsites.windows.net</span><br />
<br />
The nslookup command will provide you with your web app's IPv4 address. This is shown in the second <b>Address</b> field above, e.g. 1.2.3.4. I am running an Azure S1 Small Instance App Service Plan. I believe this method still applies to other plans including shared instance plans. <br /><br /><i>Note that if your web app is restarted or stopped this may result in it being assigned a different IP address. Be aware of this when using naked domain URLs (without the www prefix) since these rely on the A record being configured for the correct IP address of your web app (as per step 6).</i><br />
<br />
<br />
<span style="font-size: large;">Step 4. Setup FreeDNS</span><br />
<br />
On the <a href="https://www.namecheap.com/domains/freedns.aspx">NameCheap FreeDNS page</a>, enter yourdomainhere.com and click 'Get DNS'. If its eligible, then click 'Add to Cart', then click 'Set up DNS'.<br />
<br />
You get this message from NameCheap :-<br />
<br />
<i>N.B. don't go ahead and set the nameservers just yet, that step will come later.</i><br />
<span style="font-family: "Courier New",Courier,monospace;"><br /> yourdomainhere.com<br /> Congratulations! Your domain/ sub-domain is added to our DNS service.<br /> Please set the nameservers of your domain/ sub-domain to<br /><br /> freedns1.registrar-servers.com<br /> freedns2.registrar-servers.com<br /> freedns3.registrar-servers.com<br /> freedns4.registrar-servers.com<br /> freedns5.registrar-servers.com<br /><br /> Our system will periodically monitor your domain's DNS setting and will activate your domain once it is pointing to our servers.</span><br />
<br />
<br />
<span style="font-size: large;">Step 5. Verify ownership of your domain</span><br />
<br />
In NameCheap, on the Domain List page, once the yourdomainhere.com is listed as active, then need to click on "Authorize DNS" link...<br />
<br />
Select the required email, such as admin@yourdomainhere.com to use as the auth email.<br />
<br />
On the domain page, the redirect domain setting will show "Your FreeDNS domain is waiting for Authorization or Verification by domain owner."<br />
<br />
In the received email, click on the embedded hyperlink and then on the webpage, click the "I AUTHORIZE" hyperlink.<br />
<br />
A message should display "Host has been successfully activated".<br />
<br />
<br />
<span style="font-size: large;">Step 6. Setup the FreeDNS records</span><br />
<br />
At this step you'll setup all of the DNS records for your domain.<br />
For all of these I left them with the default TTL setting of 'Automatic'.<br />
In NameCheap, on the Domain List page, click the MANAGE button next to your domain, then click on the Advanced DNS tab.<br />
<br />
In the Host records, add the A record with the IP that was returned in step 3.<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">Type Host Value TTL<br />A @ 1.2.3.4 Automatic</span><br />
<br />
Add any required TXT records (often used for verification).<br />
<br />
Add the 3 CNAME records required to verify ownership of the domain to Azure.<br />
<br />
<b>1.</b> Set HOST to awverify<br />
Set Target to awverify.yourwebappname.azurewebsites.net<br />
<br />
<b>2.</b> Set HOST to awverify.www<br />
Set Target to awverify.yourwebappname.azurewebsites.net<br />
<br />
<b>3.</b> Set HOST to www<br />
Set Target to yourwebappname.azurewebsites.net<br />
<br />
If required, set the mail setting to Custom MX and add the MX server records...<br />
For example if you have Gmail enabled on the domain you'd use these MX records...<br />
<br />
Set Mail to Custom MX<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">Host Type Priority Mail server name<br />@ MX 20 ALT1.ASPMX.L.GOOGLE.COM.<br />@ MX 10 ASPMX.L.GOOGLE.COM.<br />@ MX 20 ALT2.ASPMX.L.GOOGLE.COM.<br />@ MX 30 ASPMX2.GOOGLEMAIL.COM.<br />@ MX 30 ASPMX3.GOOGLEMAIL.COM.</span><br />
<br />
<br />
<span style="font-size: large;">Step 7. Change the DNS nameservers using your registrar</span><br />
<br />
For the case when your registrar is not NameCheap, you'll need to point the nameservers for the domain to the FreeDNS nameservers.<br />
<br />
Log into your registrar's website and set the following nameservers, removing the existing nameservers if required ...<br />
<span style="font-family: "Courier New",Courier,monospace;"><br /> freedns1.registrar-servers.com<br /> freedns2.registrar-servers.com<br /> freedns3.registrar-servers.com<br /> freedns4.registrar-servers.com<br /> freedns5.registrar-servers.com</span><br />
<br />
<br />
<span style="font-size: large;">Step 8. Wait for the DNS nameserver change to propagate</span><br />
<br />
You can check whether the changes have propagated yet using nslookup from the windows command line ... <br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:\> nslookup </span><span style="font-family: "Courier New",Courier,monospace;">yourdomainhere.com<br />C:\> nslookup www.</span><span style="font-family: "Courier New",Courier,monospace;">yourdomainhere.com<br />C:\> nslookup awverify.</span><span style="font-family: "Courier New",Courier,monospace;">yourdomainhere.com<br />C:\> nslookup awverify.www.</span><span style="font-family: "Courier New",Courier,monospace;">yourdomainhere.com</span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-family: Arial,Helvetica,sans-serif;"><br />Use nslookup in interactive mode for MX and TXT record lookups ...</span><br /><br />C:\> nslookup<br /><br />set q=mx</span><span style="font-family: "Courier New",Courier,monospace;"><br />yourdomainhere.com<br /><br />set q=txt</span><span style="font-family: "Courier New",Courier,monospace;"><br />yourdomainhere.com<br /><br />exit</span><br />
<br />
Or you can also use these great online tools for checking the DNS propagation ...<br />
<br />
<a href="http://www.whatsmydns.net/">http://www.whatsmydns.net</a> <br />
<a href="https://www.ultratools.com/tools/dnsLookup">https://www.ultratools.com/tools/dnsLookup</a><br />
<br />
Or on Linux I believe the command is: dig yourdomainhere.com<br />
<br />
<br />
<span style="font-size: large;">Step 9. Bring the domains into your web app using the Azure Portal</span><br />
<br />
In the Azure portal, go to yourwebappname Web App -> Settings -> Custom Domains and SSL -> Bring External Domains<br />
<br />
Enter yourdomainhere.com into the field, and then press tab. Wait for it to verify your CNAME records.<br />
<br />
In the next field, enter www.yourdomainhere.com and press tab again. Wait for it to verify your CNAME records.<br />
<br />
It should succeed as you tab out of each field, and after you click the save button at the top, it should report "Updating hostname bindings".<br />
<br />
<br />
<span style="font-size: large;">Step 10. Test in a browser</span><br />
<br />
Open both www.yourdomainhere.com and yourdomainhere.com in a browser and confirm that they load ok.<br />
<br />
Turn on the browser's web developer tools (Network tab) to check that all the components of the web app are loading with HTTP 200 OK status, and are resolving to the new IP address.<br />
<br />
Its normal to experience some issues for the first several hours after changing nameservers, for example you may see the domain resolve to the old name server settings or flipping back and forth from new to old. Usually this will settle down after a few hours. It can be caused by the browser caching DNS results, something I've noticed particularly bad in Firefox sometimes. You may also need to flush the DNS cache on the computer you are using.<br />
<br />
<br />
Flush the DNS cache in windows via:<br />
<br />
<span style="font-family: "Courier New",Courier,monospace;">C:\> ipconfig /flushdns</span><a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /></a><br /><br /><span style="font-size: large;">Other references ...</span><br /><br />There is some additional Azure related information in the below post about this subject:<br /><a href="https://azure.microsoft.com/en-us/documentation/articles/web-sites-custom-domain-name/">https://azure.microsoft.com/en-us/documentation/articles/web-sites-custom-domain-name/</a><br /><br />
<br /><a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br />Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com6tag:blogger.com,1999:blog-5060551251465839575.post-50855569191316656742015-12-13T20:22:00.003+08:002020-10-18T10:56:42.928+08:00Low cost airlines online pricing hacksLow cost airlines are the masters of dynamic pricing, bundling and pricing psychology. <br />
<br />
Every customer who makes an online booking presents them with some new data to plug into their dynamic pricing algorithm. They also analyse the best way to present the various upgrades available to purchase before the final checkout, to maximise the customer's spend.<br />
<br />
I've just taken a look at budget carrier <a href="http://jetstar.com/">JetStar</a>'s booking experience and its use of various pricing techniques and psychology.<br />
<br />
After you've searched and selected your flights you'll be presented with a choice. Look at how unattractive they make the "<b>Starter fare</b>" default option ...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-jEV1zXFE-xc/Vm0-s_oajPI/AAAAAAAAAbQ/-OEGJONN8ag/s1600/jetstar-add-ons.PNG" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="640" src="https://2.bp.blogspot.com/-jEV1zXFE-xc/Vm0-s_oajPI/AAAAAAAAAbQ/-OEGJONN8ag/s640/jetstar-add-ons.PNG" width="634" /></a></div>
<br />
The "<b>Plus bundle</b>" at $106 is the one JetStar wants you to pick. The "<b>Max bundle</b>" at $753.49 is just there as an anchor price, to give you the impression that the middle one is good value. The "<b>Starter fare</b>" is the one they want you to avoid. They do this through the selective use of negative and positive language and the colours of grey, green and blue.<br />
<br />
<u><b>The Starter fare </b></u><br />
<br />
<span style="color: #04ff00;"><span>Comfortable leather seat</span></span><br />
<i>This is patronising ... is there so little going for this bundle option that they have to mention that you </i><i><i>actually</i> get a seat, as opposed to standing in the aisle?</i><br />
<br />
<span style="color: #04ff00;"><span>7kg carry on baggage</span><br />
<span>Strict size and weight limits apply</span></span><br />
<i>Negative tone. 7kg is not enough for most people's needs.</i><br />
<br />
<span style="color: #04ff00;"><span>Checked baggage not included</span></span><br />
<i>Repeated, negative tone.</i><br />
<br />
<span style="color: #04ff00;"><span>Starter fares are non-refundable</span></span><br />
<i>Negative tone.</i><br />
<br />
... compare this to the most popular option, the option JetStar wants you to choose ...<br />
<br />
<u><b>The Plus bundle</b></u><br />
<br />
<span style="color: #04ff00;"><span>No change fees</span></span><br />
<i>Positive.</i><br />
<br />
<span style="color: #04ff00;"><span>2,225 Qantas points</span></span><br />
<i>Free money. Only $30 credit off your next fare, but its better than nothing.</i><br />
<br />
<span style="color: #04ff00;"><span>Free standard seat selection</span></span><br />
<i>The power of free.</i><br />
<br />
<span style="color: #04ff00;"><span>Meal</span></span><br />
<i>More included stuff.</i><br />
<br />
<span style="color: #04ff00;"><span>20kg checked baggage</span></span><br />
<i>Notice they don't mention that a strict size and weight limit also applies to the 20kg baggage.</i><br />
<br />
<br />
<u><b>People are scared of change fees</b></u><br />
<br />
Most people when seeing the starter fare option will get the impression that if they need to change their flight for any reason, perhaps due to a flight delay, they are in trouble. In fact, JetStar covers you for flight delays and will make the necessary arrangements and additional bookings free of charge. But they only mention this in the <a href="http://www.jetstar.com/au/en/what-we-offer/our-guarantees/customer-guarantee#5.">fine print.</a> <br />
<br />
<b><u>Most people want checked baggage</u></b><br />
<br />
You also get the impression that you have to choose the plus bundle or max bundle if you want checked baggage. Actually, you can choose the starter fare, and then later on in the process you can optionally pay for only the specific amount of checked baggage that you need, at a rate of $46 for 15kg, $50 for 20kg and $62 for 25kg. Most customers likely don't know that these cheaper options are available, and will just choose the plus bundle, paying $106, when all they needed was checked baggage. <b>You can select the Starter fare, then pay separately for 20kg checked baggage ($50), a meal ($15) and a reserved seat ($6) and the total will be just $71, a saving of $35 on the Plus bundle.</b><br />
<br />
<u><b>Noone wants to be randomly assigned a seat</b></u><br />
<br />
When it comes to selecting a seat, its a bit disingenuous for JetStar to claim this ...<br />
<br />
<span style="color: #04ff00;"><span>"You have not selected a seat. If you do not wish to pre-select a seat one will be assigned for you randomly from what is still available at check-in."</span></span><br />
<br />
When you check in at many airports, assuming you get to the airport early and the plane isn't sold out, you'll still be able to select what type of seat you want - the check-in staff are usually more than helpful and should be able to provide your choice of a window or an aisle seat. <br />
<br />
If you're a family with children, the airline will try to assign an adult family member to be sitting close to each child in your family, even when you didn't pay to reserve a seat. If you can't be accommodated at the point of check in, you would likely be able to <a href="http://travel.stackexchange.com/questions/46028/how-old-does-a-child-need-to-be-to-sit-separately-from-parents-when-flying">work something out</a> after boarding by speaking to the cabin crew.<br />
<br />
Also, remember this inconspicuous bit of writing at the bottom ...<br />
<br />
<span style="color: #04ff00;"><span>"Jetstar will attempt to accommodate your seat preference, however due to operational considerations cannot guarantee that your seat allocation will be as your selected preference."</span></span><br />
<br />
So in other words, they ask you to pay for a seat preference, but cannot guarantee it.<br />
<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-77626465940198086522015-06-15T21:26:00.005+08:002020-10-18T11:02:21.460+08:00The Default Files Folder Pattern<span style="font-size: large;">Software installation best practices</span><br /><br />When you've got critical settings files that absolutely should never be overwritten or cleared back to defaults, this pattern has always worked well for me. It can apply to both Windows, Linux and Mac based software.<br /><br />The installation method can either be a simple file copy utility/archive or something more complex like a Windows installer.<br /><br />An example target structure might look something like this:<br /><br /><span style="font-family: "Courier New",Courier,monospace;">/MyApplication<br /> /<span style="color: #01ffff;"><span>bin</span></span> => Application binaries.<br /> /<span style="color: #01ffff;"><span>defaults</span></span> => A default version of all </span><span style="font-family: "Courier New",Courier,monospace;"><span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> files.<br /> /<span style="color: #01ffff;"><span>docs</span></span> => Documents or manuals.<br /> /<span style="color: #ea9999;"><span>settings</span></span> => Critical settings files.</span><br /> <br />The <span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> folder contains the critical settings files and is not part of the installer. The installer includes only the <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>bin</span></span></span>, <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>defaults</span></span></span> and <span style="font-family: "Courier New",Courier,monospace;"><span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>docs</span></span></span> </span>folders. So installing the software only overwrites <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>bin</span></span></span>, <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>defaults</span></span></span> and <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>docs</span></span></span>, but never the <span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span>. This applies equally to Windows installer packages - for this case, just don't include the <span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> folder in the Windows installer package. The <span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>defaults</span></span></span> folder contains the default version of all of the the files expected in the <span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> folder.<br /><br />Whenever the software accesses a particular file in <span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> the following lazy initialisation logic is used ...<br /><br /><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">- Does the </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"><span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> folder exist?<br /> - Yes: Continue<br /> - No: Create the folder and continue<br /> <br />- Does the file exist?<br /> - Yes: Open it<br /> - No: Copy the file from the </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"><span style="color: #01ffff;"><span style="font-family: "Courier New",Courier,monospace;"><span>defaults</span></span></span> folder into the</span></span><br />
<span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"> </span></span><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"><span style="color: #ea9999;"><span style="font-family: "Courier New",Courier,monospace;"><span>settings</span></span></span> folder, then open it</span></span><br />
<br />
By following the above logic, you ensure that an existing critical settings file is never overwritten.<br />
<br />From reading the <a href="http://www.theregister.co.uk/2015/06/10/airbus_a400m_probe_torque_data/">latest report on the deadly Airbus A400M crash</a>, its claimed that the cause was that their software installation procedure did the equivalent of overwriting a settings file or clearing it back to defaults. In this case, the settings file contained calibration parameters that were critical to the operation of 3 out of the 4 propeller engines.<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com1tag:blogger.com,1999:blog-5060551251465839575.post-40748468577996381632015-05-02T14:54:00.001+08:002015-05-03T17:43:54.992+08:00Taking control of a 36 year old NASA spacecraft using GNU radio<i>In 2014, Dennis Wingo and Keith Cowing formed the <a href="http://www.rockethub.com/projects/42228-isee-3-reboot-project-by-space-college-skycorp-and-spaceref">ISEE-3 Reboot Project</a>, a crowdfunded effort to attempt to gain control of the <a href="http://en.wikipedia.org/wiki/International_Cometary_Explorer">decommissioned spacecraft</a> for the benefit of citizen science. The team raised almost $160,000 in funding and assembled top space experts for the cause. In May, 2014, they began communicating with the spacecraft in advance of its August 10th 2014 lunar fly by.<br /><br />Here's an excerpt of a brilliant podcast interview between software defined radio (SDR) specialist, <a href="https://twitter.com/spenchdotnet">Balint Seeber</a>, and Infosec journalist, <a href="https://twitter.com/riskybusiness">Patrick Gray</a>, as recorded on April 24, 2015. Its the best anecdote about technology and hacking I've heard recently.<br /><br />Below transcript starts at the [47m:43s] mark of the <a href="http://risky.biz/RB363">Risky Business podcast #363</a></i><i>.</i><br />
<br />
<b>Balint:</b> It was also to set a precedent for citizen scientists from the public to essentially take over missions that ... all the missions that NASA may not want to spend its resources, its precious, you know resources and budget on. So this was supposed to be a good first example of how they could do that hand-off to a public group, and there were initial negotiations there and a Space Act agreement was signed so it was all above board and legitimate.<br />
<br />
We realised the reason they got in touch with <a href="http://www.ettus.com/">Ettus Research</a> and then with me and my former colleague, <a href="https://twitter.com/_jmalsbury">John Malsbury</a>, who funnily enough now works at <a href="http://www.spacex.com/">SpaceX</a>, so he's still in the space game, but he and I met with the guys and they basically told us the reason why we need your expertise is because NASA has thrown out all of the old equipment they used to speak to the space probe. So they put the space probe in this graveyard orbit, because the mission had finished and they ran out of funding, but there was no way for the NASA deep space network to actually send it commands to wake it back up again.<br />
<br />
And so, having done their techno-archeology, as they like to put it, retrieving all these old NASA documents, we could see the various protocols that would be necessary to re-implement, using software defined radio, in this case <a href="http://en.wikipedia.org/wiki/GNU_radio">GNU radio</a>, to achieve this, you know, recreate the modems to talk to it. And so we did that and we were fortunate enough to be able to go to the <a href="http://en.wikipedia.org/wiki/Arecibo_Observatory">Arecibo radio telescope</a> in Puerto Rico, hook our software defined radios up to their big, big telescope, and then send these commands out to the probe, which at the time I think was 15.5 million kilometres away, travelling towards the earth at about four kilometres a second ...<br />
<br />
<b>Patrick:</b> That's a long distance call...<br />
<br />
<b>Balint:</b> Its a very long distance, and I call it "not your average radio link budget". But we managed after some initial attempts to have some success there and send the commands out to turn the telemetry on. We could then assess the health of the space probe and ...<br />
<br />
<b>Patrick:</b> And you did your happy dance of course when the response came back?<br />
<br />
<b>Balint:</b> That's true, yeah, we had our unmodulated carrier suddenly become modulated telemetry and it was the first real major milestone of the project. All that preparation that we'd done, all the interpretation of the documents and taking into account the various permutations of parameters and ...<br />
<br />
<b>Patrick:</b> And the plan of course was to fire the thrusters in a way to get it into a stable orbit and they you guys could use the various sensors and things on it to quote "Do Science", uh, but it didn't quite work out did it?<br />
<br />
<b>Balint:</b> No, unfortunately the grand idealist game was to reactivate all of the operational science instruments on board and actually bring it back and do proper, public science with it, and, you know, have it available for STEM and so on, but unfortunately when we tried to fire the thrusters, in all the different configurations, because there were lots of redundancies in the propulsion system, we never observed any impulse being registered on the accelerometer and the accelerometers data was being transmitted back on the telemetry and it would always sort of flat line. And this was a big disappointment for us, no matter what we tried we just couldn't get the thing to move, and one of the running theories is that the (fuel) tanks were actually pressurised with nitrogen so that it would force the fuel out, back into the rest of the propulsion system, as in the valves and the thrusters, and you could imagine that over the three decades there might have been a very, very slow leak and that nitrogen pressure, it might have just leaked out over time and unfortunately now its left us with an inoperable propulsion system.<br />
<br />
<b>Patrick:</b> What, no backup fuel pump? (sarcastic)<br />
<br />
<b>Balint:</b> Can you believe it?<br />
<br />
<b>Patrick:</b> Bloody American engineering.<br />
<br />
<b>Balint:</b> What were those NASA boffins thinking? (laughing)<br />
<br />
<b>Patrick:</b> But you were able to actually fire up the sensors and do some science with it. What was the total budget of this project, that was crowdfunded in the end?<br />
<br />
<b>Balint:</b> They used Rockethub and I think it was on the order of $150,000, so it was quite a nice little collection there, and yeah, some of the science instruments were reactivated and we actually for a short period got some good science data out of it, which was great, and it was quite funny, when I was at <a href="https://www.defcon.org/">DEFCON</a> last time, I got the call that one of the science instruments needed to be rebooted and I had been waiting for quite a long time in line to get a good seat and there were a number of back to back presentations that I was ...<br />
<br />
<b>Patrick:</b> Excuse me I'll be back I've just got to go give the three finger salute to a satellite<br />
<br />
<b>Balint:</b> Well that's the thing though, I didn't want to leave and so, unfortunately I didn't have any cell reception so I couldn't tether to my phone, you don't get on the WiFi at DEFCON obviously because then you open yourself up to being hacked. So there's a guy next to me that I started to talk to and we're talking about software defined radio and I sort of sized him up, he was from Norway and he seemed like a good bloke and I asked whether I could tether to his phone. He said yes because he had a prepaid account with some Internet credit on there. And so I ended up tethering to his phone, SSH-ing from the third row of DEFCON into the laptop at Arecibo to send commands to the space probe that was about to fly past the moon, to reboot the science instrument on board, and then I could continue watching the presentation, so it was quite fun.<br />
<br />
<b>Patrick:</b> Its a pretty amazing time isn't it...<br />
<br />
<b>Balint:</b> Well it just goes to show you how interconnected the entire world is, I mean you've got the WiFi from my laptop to the phone, LTE from the phone to the cellular network, and then the data connection obviously across that and then down to Arecibo and then our custom link to the space probe. So it was a good testament both to SDR and commercially deployed wireless standards.<br />
<br /><br /><i>Futher information ... <br /><a href="https://www.youtube.com/watch?v=BKIJp_9--kA">Communicating with a space probe using Software Defined Radio</a></i><br />
<i>... a video of a presentation Balint gave to the <a href="http://www.mwrs.org.au/">Manly Warringah Radio Society</a> ...</i><br /><br /><br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com2tag:blogger.com,1999:blog-5060551251465839575.post-1356972287710690462015-02-28T18:31:00.001+08:002020-10-18T10:41:22.782+08:00Setting up a Bonjour (Zeroconf) service name for your Raspberry Pi and accessing it from an Android AppI have written an Android app that communicates to my Raspberry Pi over SSH (using <a href="http://www.jcraft.com/jsch/">JSch</a>) but the issue is that in the App the IP address of my Raspberry Pi has been hardcoded at 192.168.1.109 - ideally it would be good to be able to give it a local name, something like garagedoor.local - something that won't change when the DHCP assigns a different IP address.<br />
<br />
It turns out that the way to do this isn't difficult on the Raspberry Pi and most of work is in changes to the Android App needed to make it happen. I've numbered the steps 1-4.<br />
<br />
<span style="color: #04ff00;"><span><b>1. Configuration of your Raspberry Pi</b></span>.</span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;"># Get superuser privileges<br />sudo su<br /><br /># Change the host name of your Raspberry Pi from "raspberrypi" to "garagedoor"<br /># Reference: <a href="http://www.howtogeek.com/167195/how-to-change-your-raspberry-pi-or-other-linux-devices-hostname/">http://www.howtogeek.com/167195/how-to-change-your-raspberry-pi-or-other-linux-devices-hostname/</a><br /><br />sudo nano /etc/hosts # <== Replace raspberrypi with garagedoor<br />sudo nano /etc/hostname # <== Replace raspberrypi with garagedoor<br /><br />sudo /etc/init.d/hostname.sh # Commit the changes. <br />sudo reboot # Reboot<br /><br /># Install the mDNS implementation - avahi<br /># Reference: <a href="http://www.howtogeek.com/167190/how-and-why-to-assign-the-.local-domain-to-your-raspberry-pi/">http://www.howtogeek.com/167190/how-and-why-to-assign-the-.local-domain-to-your-raspberry-pi/</a><br /># Get superuser privileges<br />sudo su<br /><br /># Update the package sources<br />apt-get update<br /><br /># Ugrade the packages<br />apt-get upgrade<br /><br /># Install the mDNS implementation - avahi<br />sudo apt-get install avahi-daemon</span></span></span><br />
<br />
<br />
That's the end of the changes needed on your Raspberry Pi.<br />
<br />
<span style="color: #04ff00;"><span><b>2. Test on either Windows, Linux or Mac OSX that the Raspberry Pi is visible on the network with its new name of "garagedoor.local".</b></span></span><br />
<br />
On <b>Windows</b>, you will need to have Bonjour Networking Services installed, which comes bundled with iTunes.<br />
Run a cmd.exe prompt and type the command <span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">ping garagedoor.local</span></span> -- you should get a response from your Raspberry Pi.<br />
<br />
On <b>Mac OSX</b>, Bonjour Networking Services are installed by default.<br />
In a bash terminal window, type the command <span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">ping garagedoor.local</span></span> -- you should get a response from your Raspberry Pi.<br />
<br />
On <b>Linux</b>, first ensure you have installed the avahi-daemon package.<br />
In a bash terminal window, type the command <span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">ping garagedoor.local</span></span> -- you should get a response from your Raspberry Pi.<br />
<br />
<span style="color: #04ff00;"><span><b>3. Using NSD (Network Service Discovery) on Android to resolve the Raspberry Pi's service name.</b></span></span> <br />
<br />
Browsers and terminal programs on Android won't be able to resolve the garagedoor.local since to do this requires use of either the official Network Service Discovery library (supported by API Level 16 up) or the open source Java Zeroconf library named jMDNS.<br />
<br />
In my case, I am using a custom app I wrote to communicate to the Raspberry Pi, so I have decided just to use the Network Service Discovery library.<br />
<br />
<span style="color: #04ff00;"><span><b>4. Source code changes needed in the Android App to support NSD (Network Service Discovery)</b></span></span><br />
<br />
<b>Notes: </b><br />
<i> (1) Below is just how I decided to implement it, you may want to separate the NSD related code out of the Activity into its own class, but for me that wasn't a problem.<br /> (2) I probably need to do something related to NSD in the Application lifecycle events of onPause(), onResume(), onDestroy() and onTeardown(). I haven't done that here yet.</i><br />
<br />
<b><span style="color: #04ff00;"><span>4.A. Add some members to the Activity</span></span> </b><br />
<br />
I added this to my MainActivity but my app is small and so that's all I needed to do.<br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"><span style="font-size: small;">// Network Service Discovery related members<br />// This allows the app to discover the garagedoor.local <br />// "service" on the local network.<br />// Reference: <a href="http://developer.android.com/training/connect-devices-wirelessly/nsd.html">http://developer.android.com/training/connect-devices-wirelessly/nsd.html</a><br />private NsdManager mNsdManager;<br />private NsdManager.DiscoveryListener mDiscoveryListener;<br />private NsdManager.ResolveListener mResolveListener;<br />private NsdServiceInfo mServiceInfo;<br />public String mRPiAddress;<br /><br />// The NSD service type that the RPi exposes.<br />private static final String SERVICE_TYPE = "_workstation._tcp.";</span></span></span><br />
<br />
<span style="color: #04ff00;"><span><b>4.B. Add some init code to the bottom of the Activity's onCreate() method.</b></span></span><br />
<br />
<span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">mRPiAddress = "";<br />mNsdManager = (NsdManager)(getApplicationContext().getSystemService(Context.NSD_SERVICE));</span></span><br />
<span style="font-size: small;"><span style="font-family: "Courier New",Courier,monospace;">initializeResolveListener();<br />initializeDiscoveryListener();<br />mNsdManager.discoverServices(SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);</span></span><br />
<br />
<span style="color: #04ff00;"><span><b>4.C. Add the following two new methods to your Activity.</b></span></span><br />
<br />
<span style="font-size: x-small;"><span style="font-family: "Courier New",Courier,monospace;"> <span style="font-size: small;">private void initializeDiscoveryListener() {<br /><br /> // Instantiate a new DiscoveryListener<br /> mDiscoveryListener = new NsdManager.DiscoveryListener() {<br /><br /> // Called as soon as service discovery begins.<br /> @Override<br /> public void onDiscoveryStarted(String regType) {<br /> }<br /><br /> @Override<br /> public void onServiceFound(NsdServiceInfo service) {<br /> // A service was found! Do something with it.<br /> String name = service.getServiceName();<br /> String type = service.getServiceType();<br /> Log.d("NSD", "Service Name=" + name);<br /> Log.d("NSD", "Service Type=" + type);<br /> if (type.equals(SERVICE_TYPE) && name.contains("garagedoor")) {<br /> Log.d("NSD", "Service Found @ '" + name + "'");<br /> mNsdManager.resolveService(service, mResolveListener);<br /> }<br /> }<br /><br /> @Override<br /> public void onServiceLost(NsdServiceInfo service) {<br /> // When the network service is no longer available.<br /> // Internal bookkeeping code goes here.<br /> }<br /><br /> @Override<br /> public void onDiscoveryStopped(String serviceType) {<br /> }<br /><br /> @Override<br /> public void onStartDiscoveryFailed(String serviceType, int errorCode) {<br /> mNsdManager.stopServiceDiscovery(this);<br /> }<br /><br /> @Override<br /> public void onStopDiscoveryFailed(String serviceType, int errorCode) {<br /> mNsdManager.stopServiceDiscovery(this);<br /> }<br /> };<br /> }<br /><br /> private void initializeResolveListener() {<br /> mResolveListener = new NsdManager.ResolveListener() {<br /><br /> @Override<br /> public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {<br /> // Called when the resolve fails. Use the error code to debug.<br /> Log.e("NSD", "Resolve failed" + errorCode);<br /> }<br /><br /> @Override<br /> public void onServiceResolved(NsdServiceInfo serviceInfo) {<br /> mServiceInfo = serviceInfo;<br /><br /> // Port is being returned as 9. Not needed.<br /> //int port = mServiceInfo.getPort();<br /><br /> InetAddress host = mServiceInfo.getHost();<br /> String address = host.getHostAddress();<br /> Log.d("NSD", "Resolved address = " + address);<br /> mRPiAddress = address;<br /> }<br /> };<br /> }</span></span></span><span style="font-size: small;"><br /></span><br />
<span style="color: #04ff00;"><span><b>4.D. Make use of the mRPiAddress member where previously you used a hardcoded IP address.</b></span></span><br />
<br />
Check that its not empty before using it. If its empty, it means the RPi's name couldn't be resolved.<br />
<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a><br />
<br />
<br />
<br />Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com13tag:blogger.com,1999:blog-5060551251465839575.post-73623522352138702202015-02-21T16:21:00.000+08:002015-02-21T16:21:02.552+08:00Anders Hejlsberg: C# stands for C++++Just came across this today. Previously had heard the association with the musical sharp symbol (#) to mean a pitch higher in tone, but this was the first time I'd heard that the # symbol can also be seen as a matrix of four small + symbols, hence C# stands for C++++, i.e. an increment to C++.<span id="goog_831963089"></span><a href="https://www.blogger.com/"></a><span id="goog_831963090"></span><br />
<br />
Source: <a href="http://www.computerworld.com.au/article/261958/a-z_programming_languages_c_/?pp=2">http://www.computerworld.com.au/article/261958/a-z_programming_languages_c_/?pp=2</a><br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-1179873618896726692014-11-22T21:51:00.000+08:002014-11-24T11:05:28.520+08:00Android development is the new .NETBack in 2001 Microsoft Windows had 90% of the worldwide OS market for PCs. But desktop windows software development was dire.<br />
<br />
Developers were using tools like ...<br />
<ul>
<li>Visual Basic 6 - very productive, with the downside of ugly, primitive syntax, lacking modern features such as interfaces and classes.</li>
<li>Visual C++/MFC - serious windows developers were using this, but it was less productive and extremely verbose, with lots of boilerplate.</li>
<li>Delphi - the successor of Turbo Pascal and possibly the best of all frameworks on Windows at the time, but it never really took off.</li>
<li>Borland C++/OWL - the Open Windows Library from Borland tracked pretty closely with Visual C++/MFC, verbose + boilerplate.</li>
<li>Java - this had a reputation on Windows at the time for slow performance, bad visuals and bad tools.</li>
</ul>
At this point, Microsoft came out with Visual Studio.NET, the .NET framework and a new language named C#, with the help of former Delphi & Turbo Pascal language designer Anders Hejlsberg. Most Windows developers got on board - compared to what came before it was a breath of fresh air. Since that time, .NET has remained a large player, especially in the corporate and business market.<br />
<br />
Fast forward to 2014, Android now has an 80% worldwide market share of approx. 1.75 billion smart phones.<br />
<br />
Google has their own IDE, <a href="https://developer.android.com/sdk/installing/studio.html">Android Studio</a> and the open source <a href="https://developer.android.com/sdk/index.html">Android SDK</a>, which you can program using Java or any other JVM language. In the same way that .NET lets you use different .NET compatible languages such as C++/CLI and F#, Android supports other JVM languages like <a href="https://github.com/pocorall/scaloid">Scala</a>, <a href="https://nightweb.net/blog/clojure-on-android.html">Clojure</a> and <a href="http://melix.github.io/blog/2014/06/grooid.html">Groovy</a>, all of which let you cut down on the verbosity and boilerplate of Java.<br />
<br />
Google is attempting to bring as many developers over to Android as possible. Their <i>Head of Scalable Developer Relations</i>, <a href="https://twitter.com/retomeier">Reto Meier</a>, aims to <a href="https://medium.com/@retomeier/enabling-the-next-50-million-developers-94438cf84676">bring 50 million developers to Android</a>. <br />
<br />
Based on Android's market share and future employment prospects, Android is a decent choice for developers to try out. Compared to iOS, Android isn't as performant or profitable, but now it has a decent IDE, the weight of numbers, and the capability to use many Java FOSS libraries.<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com0tag:blogger.com,1999:blog-5060551251465839575.post-44106361099822188712014-08-30T16:55:00.000+08:002014-08-31T15:54:44.015+08:00Essential free windows softwareHere's a quick checklist of the free software I usually install on new Windows machines ...<br />
<br />
<b>Browser</b>: <a href="https://www.mozilla.org/firefox/">Firefox</a> - still the best browser in my opinion, with a wealth of developer tools. <a href="https://www.google.com.au/chrome/">Chrome</a> is also good but I found it to be prone to crashing, so gave up on it. After installing Firefox, I remove the Internet Explorer link on the task bar. <br />
<br />
<b>Email</b>: <a href="https://www.mozilla.org/thunderbird/">Thunderbird</a> - runs a bit slow sometimes, but the <a href="http://portableapps.com/apps/internet/thunderbird_portable">Thunderbird portable version</a> is great to carry around on a USB thumbdrive. Check out these tips on <a href="http://www.faqforge.com/windows/how-to-speedup-slow-mozilla-thunderbird-email-client-on-windows-7/">how to speed up Thunderbird on Windows 7</a>.<br />
<br />
<b>Anti-virus software</b>: <a href="http://windows.microsoft.com/en-au/windows/security-essentials-download">Microsoft Security Essentials</a>. Nothing fancy but gets the job done. <br />
<br />
<b>DVCS (Distributed Version Control System)</b>: <a href="http://git-scm.com/download/win">Git for Windows</a>. Includes a command line shell which features decent help for all the git commands. You can use this to pull from and push to remote repositories hosted on services such as GitHub and BitBucket.<br />
<br />
<b>SVN</b> <b>client</b>: <a href="http://tortoisesvn.net/">Tortoise SVN</a> client which integrates with Windows Explorer right click menus.<br />
<br />
<b>Flash</b>: <a href="http://get.adobe.com/flashplayer/">Adobe Flash Player</a>. Be sure to uncheck the McAfee Anti-virus
installer option. I really hate installing Adobe software onto a new
PC. My only reason for doing it is for the many websites that still rely
on flash.<br />
<br />
<b>File archive/compression tool</b>: <a href="http://www.7-zip.org/">7-Zip</a> supports many formats, such as zip, rar, gz and tar, is fast, and open source. <br />
<br />
<b>Media player</b>: <a href="http://www.videolan.org/vlc/index.html">VLC Media Player</a>. This is a great music and video player which also can be used to rip DVDs and CDs. After installing it, I remove the Windows Media player link on the task bar. <br />
<br />
<b>Text editor</b>: <a href="http://notepad-plus-plus.org/">Notepad++</a>. An excellent replacement for Notepad which supports syntax highliting for probably every known programming language, including Golang, via a simple language syntax file.<br />
<br />
<b>PDF creation</b>: <a href="http://www.pdfforge.org/pdfcreator">PDF Creator</a> installs itself as a printer on your system, so when you print to it, it prompts you for the PDF filename to create.<br />
<br />
<b>PDF viewer</b>: <a href="http://blog.kowalczyk.info/software/sumatrapdf/free-pdf-reader.html">Sumatra PDF</a>. This is an extremely fast PDF viewer, written in C++. It has a simple, uncluttered user interface. It also supports other formats such as XPS. Makes a nice change from the bloated incumbents, Adobe Reader and Foxit Reader. Refreshingly there's no adware or spyware in the installer and they also offer a portable version (no install required).<br />
<br />
<b>Office software </b>(spreadsheet, word processor, slideshow): <a href="http://www.libreoffice.org/">Libre Office</a> and <a href="http://openoffice.apache.org/downloads.html">Open Office</a> are free alternatives to the more widely used <a href="http://office.microsoft.com/">Microsoft Office</a>, which still claims top spot in the number of businesses using it. Try and get the discounted MS Office Student Edition, or a discounted MS TechNet license to save money on the standard price. <a href="http://www.heidoc.net/joomla/technology-science/microsoft/51-office-2007-direct-download-links">This site</a> offers digital downloads of the various MS Office installers, however you will still need a valid license key to install it.<br />
<br />
<b>CD/DVD burner & ripper</b>: <a href="http://www.imgburn.com/index.php?act=download">ImgBurn</a><br />
<br />
<b>Bitmap graphics editor</b>: either <a href="http://www.dotpdn.com/downloads/pdn.html">Paint.NET</a> or <a href="http://www.gimp.org/">GIMP</a>. Both are excellent alternatives to the long established Adobe Photoshop.<br />
<br />
<b>Vector graphics editor</b>: <a href="http://www.inkscape.org/">Inkscape</a> is a fully featured alternative to Adobe Illustrator.<b><br /><br />Diagram editor</b>: <a href="http://dia-installer.de/">Dia</a> is useful for creating things like flowcharts, network topology maps and block diagrams ... its an excellent free alternative to Visio.<br />
<br />
<b>Graphic file viewer</b>: <a href="http://www.irfanview.com/">IrfanView</a> is a compact and fast picture viewer for Windows. Its claim to fame is that it has been around forever (well at least since 1996) and is maintained by a humble dude from Bosnia called Irfan Skiljan (pronounced "Earfan") hence the name of the software. It has built in support for <a href="http://www.irfanview.com/main_formats.htm">many file formats</a> such as PCX, TIFF, RAW and other arcane formats such as those used on Amiga, Atari and Silicon Graphics machines. You can also use it to do batch format conversions.<br />
<br />
<b>Digital darkroom software</b>: <a href="http://lightzoneproject.org/">LightZone</a> is a great free alternative to Adobe Lightroom. You'll just need to sign up for an account on their website before getting a download link.<br />
<br />
<b>3D graphics and animation</b>: <a href="http://www.blender.org/">Blender</a> is a free and open source 3D animation suite. It supports the entirety of
the 3D pipeline - modeling, rigging, animation, simulation, rendering,
compositing and motion tracking, even video editing and game creation.<br />
<br />
<b>3D modeling</b>: <a href="http://www.sketchup.com/">SketchUp</a> is an easy to use 3D modeling program. It has uses primarily in the fields of architecture, interior design, mechanical engineering and industrial design. Its free for personal and educational use. Their website has a large <a href="https://3dwarehouse.sketchup.com/">repository of 3D models</a> that you can download.<br />
<br />
<b>Video editing</b>: <a href="http://www.blender.org/">Blender</a> mentioned above (under 3D graphics) can also do video editing, but for a standalone video editing program for Windows, one of the best available is <a href="http://www.lwks.com/">Lightworks</a>. The standard version is free, but they offer also paid pro version which has more advanced features. A decent alternative to Adobe Premiere. For only basic video editing, then the free <a href="http://windows.microsoft.com/en-us/windows-live/movie-maker">Windows Movie Maker</a> from Microsoft is a good option.<br />
<br />
<b>Password safe</b>: <a href="http://sourceforge.net/projects/keepass/">KeePass</a>. Comprehensive list of features, is open source, and is under active development.<br />
<br />
<b>File synchronisation</b>: <a href="http://www.dirsyncpro.org/">Dir Sync Pro</a>. Useful for keeping local offline backups of entire directory structures or hard disks.<br />
<br />
<b>Binary hex editor & viewer</b>: <a href="http://frhed.sourceforge.net/en/">FRHED</a> (FRee Hex EDitor) is a great little program. What's more there's no installer, just a simple .exe file you can put anywhere you want. Great for viewing, editing and searching through binary files.<br />
<br />
<b>Task manager</b>: <a href="http://technet.microsoft.com/en-au/sysinternals/bb896653.aspx">Process Explorer</a> by Windows guru Mark Russinovich is like the Windows Task Manager on steroids. You can find out which files and DLLs a particular process is using.<br />
<br />
<b>C# REPL</b>: <a href="http://cshell.net/">CShell</a> is an interactive C# interpreter, also known as a REPL (Read-Evaluate-Print-Loop). Such tools are par for the course for scripting languages like Ruby (irb). CShell lets you try snippets of C# code or call a DLL in a couple of lines, without having to fire up a heavyweight tool like Visual Studio.<br />
<br />
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a><br />
<br />Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com2tag:blogger.com,1999:blog-5060551251465839575.post-6435414068383420042014-08-22T21:12:00.002+08:002020-10-18T11:12:53.759+08:00How to setup the Gigabyte Brix (GB-BXBT-2807) Ultra Compact PC<span style="font-family: inherit;">A step by step guide, including:</span><br />
<ul>
<li><span style="font-family: inherit;">Gigabyte Brix hardware setup.</span></li>
<li><span style="font-family: inherit;">Preparing the Windows 7 installer USB boot drive.</span></li>
<li><span style="font-family: inherit;">Installing Windows 7 (64 bit).</span></li>
<li><span style="font-family: inherit;">Installing the Gigabyte Brix drivers</span>.</li>
</ul>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-W2c6H58spb8/U_c566SabmI/AAAAAAAAAWA/hMiUUmWyN7U/s1600/brix1.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="260" src="http://1.bp.blogspot.com/-W2c6H58spb8/U_c566SabmI/AAAAAAAAAWA/hMiUUmWyN7U/s1600/brix1.jpg" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-fauX2J9toDI/U_c5-cce9GI/AAAAAAAAAWI/DZFBEsVlMYM/s1600/brix2.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="160" src="http://4.bp.blogspot.com/-fauX2J9toDI/U_c5-cce9GI/AAAAAAAAAWI/DZFBEsVlMYM/s1600/brix2.jpg" width="320" /></a></div>
<span style="font-size: large;"><b><br />BRIX PRODUCT DETAILS</b></span><br />
<br />
GB-BXBT-2807 (rev. 1.0)<br />
Intel® Celeron Processor N2807 (2 core) running at up to 2.17 GHz<a href="http://www.gigabyte.com/products/product-page.aspx?pid=5038#ov"><br />http://www.gigabyte.com/products/product-page.aspx?pid=5038#ov</a><br />
<br />
Officially supported operating systems:<br />
<ul>
<li>Windows 7 (64 bit)</li>
<li>Windows 8 (32/64 bit)</li>
<li>Windows 8.1 (32/64 bit)</li>
</ul>
<span style="font-size: large;"><b><br />PARTS LIST</b></span><br />
<ul>
<li>1 x Gigabyte Brix - GB-BXBT-2807, AUD $165. Purchased <a href="http://ple.com.au/ViewItem.aspx?InventoryItemID=615598&CategoryID=760">here</a>.</li>
<li>1 x 2.5" SSD Intel 520 series, 120GB, AUD $79. Purchased <a href="http://ple.com.au/ViewItem.aspx?InventoryItemID=610580&CategoryID=355">here</a>.</li>
<li>1 x 4GB memory - SO-DIMM DDR3 1.35V 1600MHz (GEIL) green series, AUD $59. Purchased <a href="http://ple.com.au/ViewItem.aspx?InventoryItemID=614463&CategoryID=766">here</a>.</li>
<li>1 x Windows 7 (64 bit) DVD (or ISO file).</li>
</ul>
Total price of hardware: <b>AUD $303</b><br />
<br />
Purchased from : <a href="http://www.ple.com.au/">PLE Computers</a>, Bentley, WA, Australia.<br />
<br />
<br />
<b><span style="font-size: large;">EQUIPMENT REQUIRED TO SETUP</span></b><br />
<br />
<ul>
<li>1 x USB hard drive with at least 4GB free (I used an old USB 2.0, powered, 250GB 3.5" Western Digital hard drive), but you can just as easily use a small USB flash drive or a portable 2.5" USB drive.</li>
<li>1 x small Philips head screwdriver.</li>
<li>1 x desktop PC or laptop running Windows; for setting up the Windows 7 USB boot drive and copying some Brix driver files.</li>
<li>1 x monitor, either HDMI or VGA.</li>
<li>1 x wired USB Keyboard.</li>
<li>1 x wired USB Mouse.</li>
</ul>
<b><span style="font-size: large;"><br />STEP (1) BRIX HARDWARE SETUP</span></b><br />
<br />
<ol>
<li>Take off the bottom panel by unscrewing the 4 black screws.</li>
<li>Inside the unit, remove the tape holding down the SATA cable.</li>
<li>Install the low power (1.3V) RAM into the single slot - need to insert it at an angle fist, then push it downwards until it clicks into place.</li>
<li>From the bottom panel, remove the 2.5" HD cage (mine had two screws, but its meant to have 4) and install the 2.5" SSD into the cage. Connect the SATA cable to the hard disk. There's only one way it can be inserted, so you can't make a mistake. Screw the cage back onto the bottom panel. Replace the bottom panel onto the Brix.</li>
<li>Connect the power supply to the DC-in port.</li>
<li>Connect a monitor to either the HDMI or VGA port.</li>
<li>Connect a wired USB keyboard to the USB 2.0 port.</li>
<li>Turn on the Brix via the power button on the top.</li>
<li>Keep pressing the Delete (DEL) key on the keyboard about twice per second until the BIOS screen appears. Use Left/Right arrows to navigate between tabs.</li>
<li>Confirm that the RAM and SSD have been detected by the BIOS.</li>
<li>Change the operating system option to Windows 7. Note that the Brix requires the Windows 7 64-bit installer.</li>
<li>Save and exit the BIOS.</li>
<li>Switch off the Brix via the power button on the top.</li>
</ol>
<b><span style="font-size: large;"><br />STEP (2) PREPARING THE USB BOOT DRIVE FOR THE WINDOWS 7 INSTALLER</span></b><br />
<br />
The following steps to be performed on a windows PC or Laptop...<br />
<ol>
<li>Ensure you have a Windows 7 (64 bit) install disk ISO file. If you have only the DVD, as I did, you will need to rip it to an ISO file at this point, using the <a href="http://www.imgburn.com/">ImgBurn</a> software for example. Leave the ISO filename the same as the disk label (default behaviour). N.B. ImgBurn has a notoriously sneaky installer that will install "conduit" search malware and other crapware if you don't read the installer options properly, and deselect all options apart from the first one, which is ImgBurn itself.</li>
<li>Download and run <a href="http://rufus.akeo.ie/">Rufus</a> - a utility to help you create a USB boot drive from an ISO. Rufus is a standalone .exe file, no install is needed, which is awesome.</li>
<li>Connect to the laptop a USB drive with at least 4GB free space that will be formatted (erased).</li>
<li>If no drives appear at this point, its because Rufus defaults to only displaying USB flash drives. Press Alt-F to have it display all fixed USB drives.</li>
<li>In Rufus, select the target USB drive and also the source Windows 7 ISO file.</li>
<li>Select the option "create MBR for BIOS and UEFI computers" and also the NTFS file system. These should be the defaults after selecting the Windows 7 ISO.</li>
<li>Create the USB boot disk in Rufus. Leave the disk label the same as the original ISO (or DVD).</li>
<li>After Rufus has finished, disconnect the USB boot drive.</li>
</ol>
<ol>
</ol>
<span style="font-size: large;"><b><br />STEP (3) INSTALLING WINDOWS 7 FROM THE USB BOOT DRIVE</b></span><br />
<ol>
<li>Connect the USB boot drive to a USB 2.0 port on the brix.</li>
<li>Turn on the Brix via the power button on the top.</li>
<li>Keep pressing the DEL key on the keyboard about twice a second until the BIOS screen appears.</li>
<li>In the BIOS boot menu, confirm the USB boot drive is detected. If it is not detected, you may need to boot one more time by powering the brix off then on. I think this is something to do with the USB boot drive not being ready for the BIOS, which boots very quickly. In the BIOS boot menu, press the '+' key to move the USB boot drive to the top position.</li>
<li>Save and exit the BIOS.</li>
<li>Go through the Windows 7 setup. You can do this just fine with only a keyboard and no mouse, using TAB, SHIFT-TAB, UP, DOWN, LEFT, RIGHT and ENTER to make selections as required.</li>
<li>After the Windows 7 installer has finished copying files and is starting the installation it will prompt you to restart the Brix. At this point, you should go into the BIOS and restore the boot setting to boot from the SSD first (not the USB boot drive). Alternatively, you can just turn off the USB boot drive at this point, before the restart occurs.</li>
<li>Connect a wired USB mouse to the USB 2.0 port vacated by the USB boot drive.</li>
</ol>
<u><b>IMPORTANT NOTE FOR INSTALLING WINDOWS 8</b></u><br /><br />Some
commenters below have reported getting an error when trying to install
Windows 8 at this point. The message from Windows is something like <i>"windows could not update the computer's boot configuration"</i>. As suggested by commenter <a href="http://www.blogger.com/profile/06441742854504772986">Tim Bailey</a>, the solution is to update the BIOS to the latest version. You can download the BIOS update tool from the Gigabyte website.<br /><br />Here is the BIOS download page for the Gigabyte Brix GB-BXBT-2807 model:<br /><a href="http://www.gigabyte.com/products/product-page.aspx?pid=5038&dl=1&RWD=0#bios">http://www.gigabyte.com/products/product-page.aspx?pid=5038&dl=1&RWD=0#bios</a><br /><br />From the page above, instructions for updating the BIOS:<br /> For DOS, please type flash.bat in the dos mode.<br /> For Windows, please select folder and type f.bat in the windows command prompt (cmd.exe). <br />
<ol>
</ol>
<b><span style="font-size: large;"><br />STEP (4) INSTALLING THE BRIX DRIVERS IN WINDOWS 7</span></b><br />
<br />
After Windows has been installed and booted ok on the Brix, install the following drivers from the driver CD by copying everything on it to a USB thumbdrive on your laptop and then inserting into the blue USB 3.0 port on the side of the Brix.<br />
<br />
On the Brix, in Windows:<br />
<ul>
<li><b>WiFi+BT driver</b> - just double click setup.exe to install. This gets WiFi and Bluetooth up and running - you can then connect to the Internet. Requires a reboot after install.</li>
<li><b>Graphics </b>- just double click setup.exe to install. Requires a reboot after install.</li>
<li><b>USB3 </b>- just double click setup.exe to install. Requires a reboot after install.</li>
<li><b>Audio </b>- just double click setup.exe to install. Requires a reboot after install.</li>
<li><b>Chipset</b> - just double click setup.exe to install. Requires a reboot after install. A comment by a reader in the comments section below (Warren Rushby, December 10, 2014) indicates that this step was vital for his i3 model, so installing this driver is recommended.</li>
</ul>
I personally didn't bother installing the other drivers as they either weren't required by me (e.g. LAN) or they seemed to be only for Windows 8 anyway. To be on the safe side, especially if you are having issues, its recommended installing all the drivers.<br />
<br />
My boot time is 17 seconds from power on to the Windows 7 login screen. Not too bad, helped no doubt primarily by the SSD.<br />
<br />
<br />
<span style="font-size: large;"><b>STEP (5) (OPTIONAL) CONNECT A WIRELESS KEYBOARD & MOUSE</b></span><br />
<br />
<ul>
<li>In Windows, replace the wired USB mouse with a wireless USB mouse and wait for Windows to install the driver (takes a minute or two).</li>
<li>Replace the wired USB keyboard with a wireless USB keyboard and wait for Windows to install the driver (takes a minute or two).</li>
<li>I noticed a couple of times that the wireless mouse wasn't working. I had to unplug and replug its USB dongle, and that fixed it.</li>
</ul>
<span style="font-size: large;"><b><br />STEP (6) (OPTIONAL) INSTALL SOME WINDOWS SOFTWARE</b></span><br />
<br />
At this point I installed this software, which I personally find are essential in Windows, although you might have differing opinions on each category. All are free.<br />
<ul>
<li><b>Browser</b>: Run Internet Explorer to download and install Firefox. Then I remove the Internet Explorer links on the task bar and desktop.</li>
<li><b>Anti-virus</b>: Microsoft Security Essentials. Nothing fancy but gets the job done.</li>
<li><b>Flash</b>: Adobe Flash Player. Be sure to deselect the McAfee A/V installer option. I really hate installing Adobe software onto a new PC. My only reason for doing it is for the many websites that still rely on flash.</li>
<li><b>Media player</b>: VLC Media Player. Then I remove the Windows Media player link on the task bar.</li>
<li><b>Editor</b>: Notepad++. An excellent replacement for Notepad which supports probably every known programming language, including Golang.</li>
</ul>
<i><br />Small snippet of trivia to finish with ... the Gigabyte Brix was named after <a href="http://tech.firstpost.com/news-analysis/qa-gigabytes-colin-brix-talks-motherboards-brix-pcs-and-staying-relevant-in-a-mobile-world-227780.html">Colin Brix</a>, who is a marketing director at Gigabyte's Motherboard Business Unit.</i><br />
<br /><a href="http://twitter.com/dodgy_coder">Follow @dodgy_coder on Twitter</a><br />
Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com93tag:blogger.com,1999:blog-5060551251465839575.post-56238970198094426302013-08-31T16:49:00.000+08:002013-08-31T16:49:29.331+08:00Evil User Interface DesignThanks to <a href="http://twitter.com/harrybr">Harry Brignull</a> from <a href="http://darkpatterns.org/">Dark Patterns</a> for bringing up the interesting topic of evil user interfaces; UIs designed to trick you into spending more money, or buying a product you don't want. Here's the best example from their <a href="http://www.slideshare.net/harrybr/ux-brighton-dark-patterns">slidedeck</a> - the Ryanair booking form. I've added some explanatory comments below each screenshot.<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="http://4.bp.blogspot.com/-IqOOdQaKDv4/UiGqFSK4shI/AAAAAAAAATU/ntJvIAlBp30/s1600/Ryanair-booking-ui-1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="457" src="http://4.bp.blogspot.com/-IqOOdQaKDv4/UiGqFSK4shI/AAAAAAAAATU/ntJvIAlBp30/s640/Ryanair-booking-ui-1.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b><span style="font-size: small;">1. Ryanair home page.</span></b></td></tr>
</tbody></table>
Loads of sale fares for just £5, looks great ... lets buy a ticket ...<br /><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="http://2.bp.blogspot.com/-WxAjOlmn-ro/UiGqEbNOj0I/AAAAAAAAATI/-MSvy3QzIrg/s1600/Ryanair-booking-ui-2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="638" src="http://2.bp.blogspot.com/-WxAjOlmn-ro/UiGqEbNOj0I/AAAAAAAAATI/-MSvy3QzIrg/s640/Ryanair-booking-ui-2.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b><span style="font-size: small;">2. The booking form.</span></b></td></tr>
</tbody></table>
Looks straightforward so far, no issues yet.<br />
<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;"><img border="0" height="122" src="http://2.bp.blogspot.com/-x2NepnX5znA/UiGqEirqWiI/AAAAAAAAATQ/CyiqUi9DMqE/s640/Ryanair-booking-ui-3.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small;"><b>3. Passenger details section.</b></span></td></tr>
</tbody></table>
Notice the default option for the insurance dropdown is "Please select a country of residence".<br />If you're not paying attention, you'll assume it is just an address question, and so you'll select your country of residence. In doing so, you are actually selecting to pay for travel insurance ... its designed to trick you into selecting it by mistake.<br /><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="http://2.bp.blogspot.com/-30mv01EWarg/UiGqFfaeu1I/AAAAAAAAATk/RbVz_X0JQVU/s1600/Ryanair-booking-ui-4.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="400" src="http://2.bp.blogspot.com/-30mv01EWarg/UiGqFfaeu1I/AAAAAAAAATk/RbVz_X0JQVU/s640/Ryanair-booking-ui-4.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small;"><b>4. Travel insurance dropdown.</b></span></td></tr>
</tbody></table>
If you don't want travel insurance, then you have to select the correct option, "No Travel Insurance", <br />which is listed between Latvia and Lithuania.<br /><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="http://3.bp.blogspot.com/-oRj35-hd-P8/UiGqF34C_ZI/AAAAAAAAATo/7OxBZLIt0jc/s1600/Ryanair-booking-ui-5.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" height="184" src="http://3.bp.blogspot.com/-oRj35-hd-P8/UiGqF34C_ZI/AAAAAAAAATo/7OxBZLIt0jc/s640/Ryanair-booking-ui-5.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small;"><b>5. On error, the dropdown clears your selection.</b></span></td></tr>
</tbody></table>
If you make a mistake anywhere on the form, such as shown above, forgetting to select "Yes" or "No" for the priority boarding question, then when you try and submit it, the insurance dropdown will default back to its original option, which was "Please select a country of residence". They really want you to pay for travel insurance, and this is their last chance of getting an extra few percent of users to buy it.<br /><br /><br /><a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com4tag:blogger.com,1999:blog-5060551251465839575.post-38876482349781541832013-06-22T16:16:00.000+08:002013-06-22T16:22:17.393+08:00Hyperlink vs Button in AndroidAfter installing the <a href="https://play.google.com/store/apps/details?id=com.google.android.music">Google Play Music app</a>, the first screen allows you to choose which Google account to associate with it.<br />
<br />
Seems straightforward enough; but have a look at the screen - what you would press?<br />
<br />
<span id="goog_869745375"></span><span id="goog_869745376"></span><a href="http://1.bp.blogspot.com/-cfZ_f4z1aIs/UcVaRiBvgLI/AAAAAAAAAQ0/aKNCQqF7KIg/s1600/Hyperlink_vs_Button_in_Android.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="http://1.bp.blogspot.com/-cfZ_f4z1aIs/UcVaRiBvgLI/AAAAAAAAAQ0/aKNCQqF7KIg/s400/Hyperlink_vs_Button_in_Android.png" width="240" /></a><br />
<br />
Looks like there's a choice of two commands, either <b>Add account</b> or <b>Not now</b>. But there's another command there ... the email address is a clickable hyperlink, but there's no indication that it is - no underline or radically different font. The <b>Add account</b> button actually prompts you to type in a new email address, i.e. not the one listed. One of the most confusing UI designs I've seen lately.<br />
<br />
As discussed in this <a href="http://ux.stackexchange.com/questions/5493/what-are-the-differences-between-buttons-and-links">StackExchange.UX post</a>, there's no strict rule about it, but buttons usually perform a command and hyperlinks usually take you somewhere new.<br />
<br />
To improve it, maybe there should be a "Use" button to the right of each email address.<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Follow @dodgy_coder</a><a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;"><br /><br />Subscribe to posts via RSS</a>Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com4tag:blogger.com,1999:blog-5060551251465839575.post-5316326768836735962013-02-20T13:04:00.000+08:002013-02-20T19:35:47.769+08:00Google's fiber leeching caperBack in 2000, Google only had data centers on the US west coast and were planning an expansion over to the east coast, to reduce latency to end users. At the time, Google was not hugely profitable like today, and were very conscious of costs. One of the biggest costs of the move was duplicating the data contained in their search indexes over onto the east coast. Google had <a href="http://web.archive.org/web/20000711012924/http://www.google.com/pressrel/pressrelease26.html">just passed indexing 1 billion web pages</a>, and had around 9 terabytes of data contained in their indexes. They calculated that even at the highest speed of 1 Gigabit per second, it would take 20 hours to transfer all the data, with a total cost of $250,000. <br />
<br />
Larry and Sergey had a plan however, and it centered on exploiting a loophole in the common billing practice known as <a href="https://en.wikipedia.org/wiki/Burstable_billing">burstable billing</a>, which is employed by most large bandwidth suppliers. The common practice is to take a bandwidth usage reading every 5 minutes for the whole month. At the end of the month, the top 5% of usage information is discarded, to eliminate spikes (bursts). They reasoned that if they transferred data for less than 5% of the entire month (e.g. for 30 hours), and didn't use the connection at all outside that time, they should be able to get some free bandwidth. <br />
<br />
So for 2 nights a month, between 6pm and 6am pacific time, Google pumped the data from their west coast data center to their new east coast location. Outside of these 2 nights, the router was unplugged. At the end of the month the bill came out to be nothing.<br />
<br />
They continued like this every month until the contract with their bandwidth supplier ended, and they were forced to negotiate a new one, which meant actually paying for their bandwidth. By this time, Google had started buying up strategically located stretches of fiber, paving the way for its own fiber network to support its increasing bandwidth needs.<br />
<br />
Source: <br /><br />
<a href="http://www.amazon.com/Plex-Google-Thinks-Works-Shapes/dp/1416596585/?tag=intsecdb-20">In The Plex: How Google Thinks, Works, and Shapes Our Lives</a> [Amazon]<br />
By Steven Levy<br />
Published: April 12, 2011<br />
See pages 187-188, Steven Levy's interview with Urs Hölzle and Jim Reese.<br />
<br />
<br />
<div>
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><br />
<br style="background-color: #fefdfa; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;" />
<a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Subscribe to posts via RSS</a></div>
Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com11tag:blogger.com,1999:blog-5060551251465839575.post-77908057916706023722013-02-02T14:29:00.000+08:002013-02-03T09:56:45.002+08:00How to learn a new programming languageHere's some tips on learning a new programming language. They aren't listed in any specific order. Hopefully you'll gain from this at least one new tip that will help you to become proficient in the next language you learn.<br />
<br />
<ol>
<li><b>Build something you actually need right now.</b> This could be either a tool you can use in your day job, or something useful you can make use of at home.<br /><br />Consider these example projects ...<br /><ul>
<li>Write a simple unit testing framework. Many new languages don't have any unit testing frameworks available when they are first introduced. This project will force you to use areas of the language like reflection and meta-programming. Once completed, it becomes useful straight away, for unit testing your future work in the language.</li>
<li>Implement a disk usage tool; it summarizes the disk usage of all directories on a disk and outputs to the console. It doesn't require overly complex algorithms but touches a lot of the basics: recursion, filesystems, command line parsing and output formatting.</li>
<li>Implement a backup/archive script which has command line switches to exclude certain file extensions. It should place the backup into a single .zip or .tar.gz file. The project will touch on the following: recursion, filesystems, command line parsing, compression libraries and regular expressions.<br /></li>
</ul>
<ul>
</ul>
</li>
<li><b>Port an existing, well known program to the new language.</b> Since you are porting it, you already have the application design work done. This frees up your mind to focus on the specifics of the new language. After you've finished you'll then have a good reference to which you can refer back to, when comparing the old with the new language.<br /><br /></li>
<li><b>Find a decent book on the language and read through it all as fast as you can.</b> The goal is not to memorize everything, but to soak up the ideas and idioms of the language. Then write some small but non-trivial project. When you get stuck, hopefully it'll trigger a memory of something from the book, and you can go back to refer to it. <br /><br />Many of the "in a Nutshell" and "Head First" series of books, both published by O'Reilly, are highly rated by readers - they are available for many popular languages (C, C++, C#, Java, Python, JavaScript, PHP).<br /><br /></li>
<li><b>Mix action with equal parts learning (reading books/tutorials).</b> Too much action without learning, and you get a lot of poor quality code. Too much learning without enough action, and you fail to absorb the material to a deep enough level.<br /><br /></li>
<li><b>Study reference works on public repositories.</b> Find a medium sized project on GitHub which is written 100% in the language. Read though the code and try to understand it. Look for projects written by the language designers or an acknowledged expert. <br /><br />As an example, with <a href="http://golang.org/">Go</a>, the standard libraries for the language are written in Go and are open source, e.g. here is part of the <a href="http://golang.org/src/pkg/strings/strings.go">strings package</a>. In addition, Brad Fitzpatrick and other members of the Go team have several projects on GitHub that you can read and learn from, e.g. here is a <a href="https://github.com/bradfitz/gomemcache">Go client for Memcache</a>. <br /><br /></li>
<li><b>Devote large, uninterrupted chunks of time</b>, at least half a day, to learning the new language. Brief, half hour sessions over the course of the week aren’t really useful, because most of the time would be spent just getting back up to speed on what you previously studied.<br /><br /></li>
<li><b>Learning a language shouldn’t just be a solitary endeavor.</b> There are plenty of people who have made the same mistakes that you have, so asking for help is a great way to overcome problems when you get stuck. Some possible sources of help online: Language-specific IRC channels, StackOverflow, Twitter, Facebook groups, Quora, Google+, Google groups. You can also submit your finished code to these forums after you've completed a project; people more experienced with the language than you will often be able to identify areas which can be improved or simplified.<br /><br /></li>
<li><b>Use an editor with syntax highlighting.</b> Perennial favorites such as Vim and Emacs, plus newer editors such as Sublime Text, feature support for most if not all programming languages and are available for all major operating systems. Some languages are often associated with specific IDEs; these are a good idea when learning a new language. These are generally ...<br /><ul>
<li>Eclipse IDE for Java and Android development.</li>
<li>Xcode for Objective-C and iOS development (on Mac OSX only).</li>
<li>Visual Studio IDE for C#, C++, VB.NET, F# (on Windows only).</li>
</ul>
All of the IDEs and editors listed above are either completely free or have an unlimited trial version available.<br /><br /></li>
<li><b>Working on a real project with real customers and deadlines</b> is a white hot crucible for learning a new programming language. If you really need to learn a language quickly, then consider taking on a new job which requires it. Once you've got the job, you'll have no other choice but to learn it quickly.<br /> </li>
<li>Finally, a tip from <a href="http://www.amazon.com/gp/product/020161622X/ref=as_li_tf_tl?ie=UTF8&tag=intsecdb-20&linkCode=as2&camp=217145&creative=399369&creativeASIN=020161622X">The Pragmatic Programmer</a>, Tip #8 "<b>Invest Regularly in Your Knowledge Portfolio</b>":<br /><blockquote>
"Learn at least one new language every year. Different languages solve the same problems in different ways. By learning several different approaches, you can help broaden your thinking and avoid getting stuck in a rut. Additionally, learning many languages is far easier now, thanks to the wealth of freely available software on the Internet." </blockquote>
<br />
<div>
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><br />
<br style="background-color: #fefdfa; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;" />
<a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Subscribe to posts via RSS</a></div>
</li>
</ol>
Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com3tag:blogger.com,1999:blog-5060551251465839575.post-76589918379495515082013-01-15T20:23:00.001+08:002013-01-16T21:06:36.334+08:00Big Ball of Mud Design Pattern<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-YdDLm3rxKjo/UPUhZa54S0I/AAAAAAAAAPQ/4xTlq26fm_8/s1600/big_ball_of_mud.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="307" src="http://2.bp.blogspot.com/-YdDLm3rxKjo/UPUhZa54S0I/AAAAAAAAAPQ/4xTlq26fm_8/s320/big_ball_of_mud.jpg" width="320" /></a></div>
<br />
In "Big Ball of Mud", Brian Foote and Joseph Yoder propose that the default (and most
common) software architecture in use is the "Big Ball of Mud" pattern and go on to
discuss six additional patterns and activities that it gives rise to: "Throwaway Code", "Piecemeal Growth", "Keep it Working", "Shearing Layers", "Sweep it Under the Rug" and "Reconstruction".<br />
<br />
Their original article is <a href="http://www.laputan.org/mud/mud.html">located here</a> and can be downloaded in PDF form here: <a href="http://www.laputan.org/pub/foote/mud.pdf">Big Ball of Mud by Brian Foote and Joseph Yoder [PDF download]</a><br />
<br />
I have picked out what I think are the highlights of their article ...<br />
<br />
<br />
<span style="font-size: large;">Big Ball of Mud ... alias <i>Shantytown </i>or <i>Spaghetti Code</i></span><br />
<br />
<a href="http://en.wikipedia.org/wiki/Shanty_town">Shantytowns</a> are usually built from common, cheap materials with simple tools and using unskilled labor. The construction and maintenance of the shantytown is labor intensive, and there is little or no labor specialization - each builder must be a jack of all trades. There's no overall planning, or regulation of future growth. <br />
<br />
Too many of our software systems are, architecturally, little more than shantytowns. Investment in tools and infrastructure is often inadequate and the tools that are used are primitive. Parts of the system grow unchecked, and the lack of architecture and planning allows problems in one part of the system to erode and pollute adjacent portions. Deadlines loom like monsoons, and architectural elegance seems unattainable. <br />
<br />
The time and money to chase perfection are seldom available and there is a survival at all costs attitude, to do what it takes to get the software working and out the door on time. The biggest cost borne by the Big Ball of Mud development is the lack of a decent architecture.<br />
<br />
<br />
<span style="font-size: large;">Common features of Big Ball of Mud Code</span><br />
<ul>
<li>Data structures are haphazardly constructed, or non-existent. </li>
<li>Everything talks to everything else. </li>
<li>Important state data is global. </li>
<li>State data is passed around though Byzantine back channels that circumvent the system's original structure. </li>
<li>Variable and function names are uninformative and misleading. </li>
<li>Functions use global variables extensively, as well as long lists of poorly defined parameters. </li>
<li>Functions themselves are lengthy and convoluted, and perform several unrelated tasks. </li>
<li>Code duplication. </li>
<li>The flow of control is hard to understand, and difficult to follow. </li>
<li>The programmer’s intent is next to impossible to discern. </li>
<li>The code is simply unreadable, and borders on indecipherable. </li>
<li>The code exhibits the unmistakable signs of patch after patch at the hands of multiple maintainers, each of whom barely understood the consequences of what he or she was doing. </li>
<li>Did we mention documentation? What documentation?</li>
</ul>
<br />
<ul>
</ul>
<span style="font-size: large;">Working with Big Ball of Mud Code</span><br />
<br />
Some software engineers come to regard life with the Big Ball of Mud as normal and become skilled at learning to navigate these quagmires, and guiding others through them. Over time, this symbiosis between architecture and skills can change the character of the organization itself, as swamp guides become more valuable than architects. <br />
<br />
As per <a href="http://en.wikipedia.org/wiki/Conway%27s_law">Conway's Law</a>, architects depart in futility, while engineers who have mastered the muddy details of the system they have built, prevail. The code becomes a personal fiefdom, since the author care barely understand it anymore, and no one else can come close. Once simple repairs become all day affairs, as the code turns to mud.<br />
<br />
<br />
<span style="font-size: large;">Throwaway Code ... alias <i>Quick Hack</i> or <i>Protoduction</i></span><br />
<br />
While prototyping a system, you're normally unconcerned with how elegant or efficient your code is. You plan that you will only use it to prove a concept and once the prototype is done, the code will be thrown away and written properly. As the time nears to demonstrate the prototype, the temptation to load it with impressive but utterly inefficient realizations of the system’s expected eventual functionality can be hard to resist. Sometimes, this strategy can be a bit too successful. The client, rather than funding the next phase of the project, may slate the prototype itself for release. <br />
<br />
This quick-and-dirty coding is often rationalized as being a stopgap measure. More often than not, the time is never found for this follow up work. The code languishes, while the product flourishes. It becomes a protoduction - a prototype that gets used in production.<br />
<br />
Once it becomes evident that the throwaway code is going to be around for a while, you can turn your attention to improving its structure, either through an iterative process of Piecemeal Growth, or via a fresh draft, as discussed in the Reconstruction pattern below. <br />
<br />
<br />
<span style="font-size: large;">Piecemeal Growth ... alias <i>Refactoring</i></span><br />
<br />
Successful software attracts a wider audience, which can, in turn, place a broader range of requirements on it.<br />
<br />
When designers are faced with a choice between building something elegant from the ground up, or undermining the architecture of the existing system to quickly address a problem, architecture usually loses.<br />
<br />
In the software world, we deploy our most skilled, experienced people early in the lifecycle. Later on, maintenance is often relegated to junior staff, and resources can be scarce. The so-called maintenance phase is the part of the lifecycle in which the price of the fiction of master planning is really paid. It is maintenance programmers who are called upon to bear the burden of coping with the ever widening divergence between fixed designs and a continuously changing world.<br />
<br />
Piecemeal growth can be undertaken in an opportunistic fashion, starting with the existing, living, breathing system, and working outward, a step at a time, in such a way as to not undermine the system’s viability. You enhance the program as you use it. Massive system-wide changes are avoided - instead, change is broken down into small, manageable chunks.<br />
<br />
<br />
<span style="font-size: large;">Keep It Working<span style="font-size: large;"> </span></span><span style="font-size: large;">... alias <i>Continuous Integration</i></span><br />
<br />
Businesses become critically dependent on their software and computing infrastructures. There may be times where taking a system down for a major overhaul can be justified, but usually, doing so is fraught with peril. Therefore, do what it takes to maintain the software and keep it going. Keep it working.<br />
<br />
This approach can be used for both minor and major modifications. Large new subsystems might be constructed off to the side, perhaps by separate teams, and integrated with the running system in such a way as to minimize disruption. <br />
<br />
A development build of each product can be performed at regular intervals, such as daily or even more often via an automated build tool. Another vital factor in ensuring a system's continued vitality is a commitment to continuous testing, which can be integrated into the automated build process.<br />
<br />
<br />
<span style="font-size: large;">Shearing Layers</span><br />
<br />
Software never stands still. It is often called upon to bear the brunt of changing requirements, because, being as that it is made of bits, it can change.<br />
<br />
Over time, the software's frameworks, abstract classes, and components come to embody what we've learned about the structure of the domains for which they are built. More enduring insights gravitate towards the primary structural elements of these systems and change rarely. Parts which find themselves in flux are spun out into the data, where users can interact with them. Software evolution becomes like a centrifuge stirred by change. The layers that result, over time, can come to a much truer accommodation with the forces that shaped them than any top-down planning could have devised. <br />
<br />
<br />
<span style="font-size: large;">Sweeping It Under The Rug</span><br />
<br />
At first glance, a Big Ball of Mud can inspire terror and despair in the hearts of those who would try to tame it. The first step on the road to architectural integrity can be to identify the disordered parts of the system, and isolate them from the rest of it.<br />
<br />
Overgrown, tangled, haphazard spaghetti code is hard to comprehend, repair, or extend, and tends to grow even worse if it is not somehow brought under control. If you can’t easily make a mess go away, at least cordon it off. This restricts the disorder to a fixed area, keeps it out of sight, and can set the stage for additional refactoring.<br />
<br />
<br />
<span style="font-size: large;">Reconstruction ... alias <i>Total Rewrite</i></span><br />
<br />
One reason to start again might be that the previous system was written by people who are long gone. Doing a rewrite provides new personnel with a way to reestablish contact between the architecture and the implementation. Sometimes the only way to understand a system it is to write it yourself. Doing a fresh draft is a way to overcome neglect. Issues are revisited. A fresh draft adds vigor. You draw back to leap. The quagmire vanishes. The swamp is drained. <br />
<br />
When a system becomes a Big Ball of Mud, its relative incomprehensibility may hasten its demise, by making it difficult for it to adapt. It can persist, since it resists change, but cannot evolve, for the same reason. Instead, its inscrutability, even when it is to its short-term benefit, sows the seeds of its ultimate demise. <br />
<br />
<br />
<i>The above are highlights from the original article, which is located here ... <a href="http://www.laputan.org/pub/foote/mud.pdf">Big Ball of Mud by Brian Foote and Joseph Yoder [PDF download]</a></i><br />
<br />
<br />
<b>Some further reading on Programmers.StackExchange ...</b><br />
<br />
<a href="http://programmers.stackexchange.com/q/155488/36473">I've inherited 200K lines of spaghetti code — what now?</a><br />
<a href="http://programmers.stackexchange.com/q/87757/36473">How to convince my boss that quality is a good thing to have in code?</a><br />
<a href="http://programmers.stackexchange.com/q/129327/36473">How to keep a big and complex software product maintainable over the years?</a><br />
<a href="http://programmers.stackexchange.com/q/66438/36473">Techniques to re-factor garbage and maintain sanity?</a><br />
<a href="http://programmers.stackexchange.com/q/94007/36473">When is code “legacy”?</a><br />
<a href="http://programmers.stackexchange.com/q/103807/36473">What is negative code?</a><br />
<br />
<br />
<b>Some related books ...<br /></b><br />
<a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052/?tag=intsecdb-20">Working Effectively With Legacy Code ... by Michael Feathers</a> [Amazon]<br />
<a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/?tag=intsecdb-20">Refactoring: Improving the Design of Existing Code ... by M. Fowler, K. Beck, et al.</a> [Amazon]<br />
<a href="http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/?tag=intsecdb-20">Design Patterns: Elements of Reusable Object-Oriented Software ... by the Gang of Four</a> [Amazon]<br />
<a href="http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420/?tag=intsecdb-20">Patterns of Enterprise Application Architecture ... by Martin Fowler</a> [Amazon]<br />
<a href="http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215/?tag=intsecdb-20">Domain Driven Design: Tackling Complexity in the Heart of Software ... by Eric Evans</a> [Amazon]<br />
<a href="http://www.amazon.com/First-Design-Patterns-Elisabeth-Freeman/dp/0596007124/?tag=intsecdb-20">Head First Design Patterns by E. Freeman, E. Freeman, et al.</a> [Amazon]<br />
<br />
<br />
<div>
<a href="http://twitter.com/dodgy_coder" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Follow @dodgy_coder</a><br />
<br style="background-color: #fefdfa; color: #333333; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px;" />
<a href="http://www.dodgycoder.net/feeds/posts/default" style="background-color: #fefdfa; color: #7d181e; font-family: Arial, Tahoma, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 18px; text-decoration: initial;">Subscribe to posts via RSS</a></div>
Dodgy_Coderhttp://www.blogger.com/profile/14418022725678218844noreply@blogger.com1