Thursday, August 25, 2016

C++ Programming Tips

For 2 decades now I have been a professional C++ developer.  Along the way I have learned a lot about programming in C++.  I've made a lot of mistakes and learned from them.  There are thousands of other C++ developers out there of all skill levels who could benefit from this knowledge.  So below is a list of tips I've learned that will help you to write better C++ code.  For each tip I include a brief explanation why that tip is worth remembering and using.


Consistent Coding Style
Every developer has their own coding style.  I'm not going to tell you to use one style over another.  But it is important that you are consistent in your coding style.

Reasoning:  If you are consistent in your coding style it makes things like global searches more effective.


Virtual Destructors
Always make your class destructors virtual.

Reasoning:  Without virtual destructors you can introduce bugs and memory leaks.  I wrote an entire post on this topic alone.  There is one exception.  If your class has no other virtual functions, and if your class does not derive from a base class, and if you mark your class "final" then you can safely omit the virtual destructor.


Const Function Parameters
Whenever possible, function parameters should be made "const."  If a given parameter is not modified by the function, then the parameter should be marked const.

Reasoning:  It's great self-documenting code.  Just by looking at a function declaration you can tell if a parameter will be modified.  It also can help you catch bugs in your code because the compiler may warn you if you accidentally try to violate the const variable.


Const Member Functions
Whenever possible, class member functions should be marked "const."  If a given function does not modify a class member variable or call another non-const member function, then the function should be marked const.

Reasoning:  It's great self-documenting code.  Just by looking at a function declaration you can tell if the class object will be modified.  It also can help you catch bugs in your code because the compiler may warn you if you accidentally try to violate the const function.


Static Member Functions
If a class member function does not modify a class member variable nor call a non-static member function, then that function should be marked as "static."

Reasoning:  Again, it's great self-documenting code, and it can help you catch bugs in your code because the compiler may warn you if you accidentally try to violate the static function.


No Classes without Member Variables
If you have a class that has no member variables, instead turn that class into either standalone functions or use a namespace to group the functions.

Reasoning:  A class with no member variables is not an object at all.  By using a class you are wasting a small amount of runtime memory because of things like the "this" pointer.


Properly Size Integers and Floats
When declaring a new integer or (to a lesser degree) a float, consider the range of possible values for that integer and choose accordingly.  For example, if the variable will store a person's age then all you need is an 8-bit integer, don't just type "int" and be done with it.

Reasoning:  Choosing properly sized variables will help to minimize memory usage during runtime.


Use Signed and Unsigned Integers Appropriately
Most developers seem to use signed integers when an unsigned integer is what they really should have used.  For example, a variable to hold a percentage should be an unsigned 8-bit integer since the valid range is 0 - 100.

Reasoning:  If you properly use signed and unsigned variables, the compiler will usually generate warnings if you try and improper operation.  This helps to prevent bugs in your code.


Use Pre-operators Instead of Post-Operators
Whenever possible use pre-increment (++itr) and pre-decrement (--itr) instead of post-increment (itr++) and post-decrement (itr--).

Reasoning:  It turns out that pre-operators are faster than post-operators if the object in question is a class.  For simple data types like integers there is no difference.  The reason pre is faster than post is because post must make a copy of the original object before performing the operation, but pre does not need to make a copy of the object.


Avoid Large Array Variables
Do not declare large array variables, for example:  char buffer[8192].  Instead large arrays like this should be allocated using malloc/new.

Reasoning:  All function variables, include arrays, are allocated against the stack not the heap.  It's well known the dangers of using a recursive function, you might blow the stack.  But large arrays like this could also lead to a stack overflow.  So avoid large arrays and malloc/new them instead.  It's alright to use small arrays in this way.


Use "bool" and "nullptr" instead of "BOOL" and "NULL"
If your compiler supports them, then use the newer data types bool and nullptr.

Reasoning:  By using native types instead of the older #defines the compiler can help you to catch mistakes.  For example, if you accidentally type the following the compiler should give you a warning: bool bResult = (n = 5);  You meant to type "n == 5" but make a common mistake.  Since you used "bool" the compiler should catch this.  But if you used "BOOL" the compiler sees this as valid code.


Don't Compare Against TRUE
Do not test for true like this:  if(func() == TRUE) or this:  if(func() != TRUE)  Instead test like this:  if(func() != FALSE) and this:  if(func() == FALSE)

Reasoning:  "TRUE" is defined to be 1, but a function could return something other than 1 to represent true.  The only way to guarantee a correct comparision is to only test against FALSE.  Of course the best option is to use the newer native type "bool" if it's available.


Use malloc/free Instead of new/delete for Simple Types
If you are allocating memory for native types (ints, floats, chars, enums, or structs containing only these types) then use the older C malloc instead of the newer C++ new.  If you are allocating memory for a class object, or a struct containing one or more class objects, then you must use new.

Reasoning:  Calling malloc is faster than new.  They both allocate memory on the heap, but new then checks for and calls constructors.  This means for simple data types malloc is faster.


Do Not Test for NULL After Calling new
If you allocate memory with new, do not test the result to verify the allocation was successful.  For example:

CMyClass *p = new CMyClass;
if(p)
{
     ...
}

Reasoning:  This test is a complete waste of time and code.  The new operator already tests the allocation.  If the allocation fails then new throws an exception.  So testing the result yourself is redundant and a waste.  Note this is not true of malloc which does not test the result.  So if you use malloc or other similar allocator, be sure to verify the result.


Know When to Test for NULL Before Freeing Resources
Some release/free functions test the input before attempting to deallocate them, others do not.  For example, CloseHandle on Windows does not test the handle against NULL first.  On the other hand, "delete" does test the pointer against NULL.

Reasoning:  Not testing first may result in an application crash if the release function does not check.  If the release function does check and your code also checks, that is wasted CPU cycles.  Learn which functions to check first before calling.


Size Versus Length
When naming things like functions and variables, be aware of the difference between size and length.  Size is the number of bytes an item requires whereas length is the count of or the number of items.  This is really a problem when it comes to strings (character arrays).  With "char" arrays size and length ARE the same, so many developers use "size" and "length" interchangeable.  But with newer Unicode and wide strings size and length are different.  So name functions and variables accordingly.

Reasoning:  Properly named functions and variables reduce the chance of bugs.  Since size and length are not always the same, using the wrong one would be a bug.


Do Not Put Conditional Statements on One Line of Code
Do not simplify your code by condensing things down to one line of code.  For example:

if(p) delete p;

Instead this should be:

if(p)
    delete p;

Reasoning:  When you condense code like this it makes it harder to debug.  When debugging line by line it is harder to tell if the conditional statement succeeded or failed.



Do Not Use "catch(...)"
Never use "catch(...)" in your code!  This form of exception handling catches all exceptions.

Reasoning:  Catching all exceptions prevents your code from ever crashing, which is a good thing right?  Wrong.  In the event of an exception your code continues to execute but it is now running in a "compromised" state.  Memory may be corrupted, variables or registers may be wrong.  So what ends up happening is your program will crash randomly some place else.  These random crashes are impossible to debug postmortem.  It is best to remove "catch(...)" and let the original crash occur.  Then you can debug and fix the original problem.


Do Not Use Exceptions for Flow Control
Do not use exceptions as a simple way of transferring flow to a different part of the code.  For example, if you are deep inside nested loops and it's time to exit, you could throw an exception and catch that exception before leaving that function.  Instead you should exit each loop or even use a goto.

Reasoning:  When it comes time to debug your code often times it's nice to attach the debugger and tell the debug to break on all exceptions (handled or otherwise).  But if you used exceptions for flow control then the debugger will constantly break when no problem has occurred.  Exceptions should be reserved for just that, an exceptional condition has occurred that needs special attention.  Flow control is not "exceptional."


Only Include Required Files in Your Headers
Do not #include a lot of extra things in your header files.  Only include what that file must have.

Reasoning:  First, it reduces compile time as the compiler has to open up and parse fewer files.  Secondly, if that file gets included somewhere else or in another project, it prevents you from having to pull in a lot of extra unnecessary files.


Forward Declare What You Can in Header Files Instead of Including More Headers
If your header file references a pointer to a class object only, do not #include the header for that class.  Instead forward declare the object and put the #include into the CPP file.

Reasoning:  The benefits are the same two as the previous.  First, it reduces compile time as the compiler has to open up and parse fewer files.  Secondly, if that file gets included somewhere else or in another project, it prevents you from having to pull in a lot of extra unnecessary files.


Only Include Required Files in Your CPP File
Do not pull in extra unused headers in your source code files.  Make an effort to only include required files, which means removing old headers as code changes over time.

Reasoning:  It reduces compile time as the compiler has to open up and parse fewer files.


Avoid Putting Function Bodies Into Header Files
Header files should be for class and function declarations.  All the function bodies should be located in CPP files.  There are two exceptions; inline functions and templatized functions - both of which many compilers do not allow you to split them across header and source code files.

Reasoning:  Again, it decreases the time it takes to compile your code.  It also simplifies your headers meaning you do not need to pull in as many files if the header files are used in another project.


Use "#pragma once"
In all of your header files use "#pragma once" and not the older #ifndef guards.

Reasoning:  Using pragma once is the only way to guarantee a file is included only once.  Problems can occur with guards such as copy and paste bugs (you copied from one file to another and forgot to make the guard unique).  Also, if your guard matches a guard from another file (perhaps from an SDK) then a bug might occur.


Beware of Unsafe Macros
As a general rule, do not pass a function into a macro.  For example, assume a macro MAX(a,b)  Do not do something like this:  n = MAX(1000, crypt.CalcCryptoHash());

Reasoning:  Do you see the problem with the call to MAX above?  Probably not, because the macro hid the details from you.  If I expand the macro as the compiler would, the above becomes:  n = (1000 < crypt.CalcCryptoHash() ? crypt.CalcCryptoHash() : 1000) ;  Now the problem should be obvious, the function CalcCryptoHash() is potentially called twice.  At best this is a performance hit, at worst depending on what this function does it could be a bug in your code.  So be careful when using macros.


Learn When and Where to Use References
If you are writing a function that takes a pointer (*) as an input, consider using a reference (&) instead.  In fact, probably the only time to use pointer instead of a reference is if the caller of the function might pass in NULL/nullptr.  But if the parameter can never be NULL/nullptr, then use a reference instead.  Also, if the item being passed to a function is an object (class or struct) or even a native type that is larger than the system architecture (e.g. a 64-bit integer on a 32-bit system) then pass by reference as well.

Reasoning:  References are more efficient and make for cleaner code compared to regular pointers.  When passing things by reference it becomes even more important to use "const" for variables the function will not modify.

Wednesday, August 17, 2016

Raspberry Pi Weather Station - part 4

In the last post I covered the hardware for the sensors.  In this post I want to talk about the software that ties this all together.  There are several goals with the software.  Obviously it needs to read the sensor data.  I would like it to output that data to a local web page so I can access it with a web browser.  I also want it to export the sensor data to a Personal Weather Station (PWS) account registered with WeatherUnderground.  And lastly, I would ideally like it to record or save the data to a database in case I want to analyze the data later on.

Doing searches on the Internet I quickly found WeeWX, an open-source project that does all of this.  It reads sensor data, generates a web page, and can optionally log to WeatherUnderground.  I was ready to go with this option, but then I discovered it was written in Python which gave me pause for concern (more on that later).

I next found wview which, like WeeWx, is an open-source weather station project.  It's written in C which is good, but it sounds like the project has grown rather large over the years.  It's become a huge behemoth that's capable of doing almost everything when all I want/need is a simple targeted application.

In the end I decided to write my own weather station application.  After all, isn't that was software engineers do, write software?  I wrote a small simple program that reads all the sensors and outputs the data in 3 different ways.
  1. It generates a local HTML file which can be viewed from another computer using a web browser.  My code is not a web server, it just outputs an HTML file.  So you still need a web server such as Lighttpd or nginx.
  2. It sends all sensor data off to WeatherUnderground so the results can be viewed on their web site.
  3. The sensor data is written locally to a SQLite file for later analysis.

I wanted to go back and talk about my opposition to the use of Python in WeeWX.  The main problem is I do not consider Python to be a "real" programming language.  It is a scripting language, and scripting languages have their place.  But not in final applications in my opinion.  I also do not like the extreme performance hit Python incurs.  And remember, this is running on a Raspberry Pi which is not a powerful machine to begin with, so any unnecessary overhead is exaggerated.  How much of a performance hit are we talking about?  Using the sample Python code from Adafruit, reading the temperature sensor takes approximately 5 seconds.  Most of that overhead is spent loading the Python libraries and creating the runtime environment.  Compare that to the C++ code I wrote to read the temperature sensor which is instantaneous.  To me writing this application in C++ was not only the only way to go, but it was a fun project!


I have uploaded my C++ code to GitHub for anyone to download, use, or modify.  Bear in mind this code was written specifically for my weather station.  So it assumes the sensor hardware I'm using connected to the Raspberry Pi on the GPIO pins I'm using.  But this could be a great reference for anyone doing a similar project.

And finally, the results.  Here's a link to my PWS on WeatherUnderground.

Monday, August 1, 2016

Raspberry Pi Weather Station - part 3

Next I wanted to talk about the hardware for the sensors my weather station will employ and how each sensor is wired to the Pi's GPIO pins.

BME280
As I previously said the BME280 can be access via either SPI or I2C.  I decided to use I2C.  In order to wire to the Pi you will need to connect 4 wires.  The first is the power wire which connects to the 3.3V pins on the Pi.  The second is ground which connects to one of the ground wires on the Pi.  And lastly are the two I2C data lines which get connected to the I2C pins on the Pi.  Wiring this sensor up is not hard, it just requires a little bit of soldering and time.

The rain, wind speed, and wind direction sensors were a single package and clearly not designed specifically for the Pi.  The output wires have RJ11 connectors (telephone connectors) on the end of them.  I believe they were originally designed to plug into a specific weather module that reads the sensors.  Since I am using the Raspberry Pi as my homemade weather module, I will need to modify each sensor.

Rain Gauge
The rain gauge is an interesting sensor.  It literally has two buckets side by side.  When one side fills with water it gets too heavy and tips over.  The other side then fills up and eventually tips back.  Each time this bucket tips over a magnet passes by a reed switch.  This causes a momentary close in the switch which can be detected by the Raspberry Pi.  This only requires 2 wires, power in and the signal detect line coming out.  For power in I used the same 3.3V pin as the BME280 sensor, and for the signal wire I picked any available GPIO pin.

Wind Speed
For wind speed there are 3 cups that are free to spin as the wind hits them.  Each time it spins another magnet passes by a read switch.  As with the rain, the Pi can detect these events and use that to calculate the wind speed.  Again, only 2 wires are necessary, one for power (the same 3.3V pin) and a signal detect line which is any available GPIO pin.

Wind Direction
The wind direction sensor works using magnetic reed switches, but unlike the previous sensors it contains 8 reed switches.  Each reed switch corresponds to a direction; N, NE, E, SE, S, SW, W, and NW.  As the magnet moves around according to wind direction it closes different switches which allows you to determine direction.  To complicate matters, it is possible for the magnet to close two neighboring switches at the same time.  This gives you a total of 16 possible bearings.

Reading the wind direction was by far the hardest.  The problem is the wind direction sensor is designed to be read using analog and only has 2 wires, power in and signal out.  So if you apply 5V in then the output voltage will be one of 16 different values between 0 and 5V.  The Raspberry Pi however cannot read analog values, it only reads digital signals.  One possible solution is to use an analog to digital converter which requires additional hardware.  But there is a cheaper way, hard wire the 8 reed switches directly to the Pi.  To do this I had to open the wind direction sensor and remove the circuit board.  On this circuit board are 8 small surface mount resistors which had to be desolder.  In their place I soldered 8 wires, one for each switch.  Lately I soldered a power wire to the outside ring which ties all reed switches together.  This allows me to provide power in (again, 3.3V) and read each sensor one at a time using the 8 signal wires I attached to available GPIO pins.  This required a lot soldering on a small circuit board, but the end result is a digital wind direction sensor that was originally designed to be analog.

Monday, July 25, 2016

Raspberry Pi Weather Station - part 2

Continuing this project, in this post I will talk about preparing the Raspberry Pi to become a weather station.  I won't go into the details about installing Raspbian onto the SD card or using raspi-config to set the time zone and locale info for your system.  You can read my previous Pi posts for those details.

For this project the Raspbian group has released something new - a "lite" version of Raspbian.  This is perfect, I can get a clean bare bones Pi right out of the box.  Getting wifi setup on the Pi zero is a little more complicated because there is no ethernet port.  So it's a multi-step process.  First you must use a keyboard and monitor and manually edit the /etc/wpa_supplicant/wpa_supplicant.conf file to add info for your wifi network.  Then power down the Pi, remove the keyboard and monitor, attach the wifi adapter, then power up the Pi and connect via SSH.  This is where I ran into my first problem.  The RNX-N180UBE I've used in the past and ordered for this project did not work.  I quickly discovered Rosewill is now making "version 2" of the adapter which uses a different chipset and Linux does not have drivers for this adapter.  After much searching I found this forum post with details on where to download drivers specific to the type or Raspberry Pi and version of Raspbian you are running.

For the BME280 sensor I bought, it can be accessed via SPI or I2C.  The Pi supports both, but is one better than the other?  From what I can tell, SPI is a faster connection, but I2C is a better designed interface with more control.  Since reading this sensor won't involve large amounts of data, I decided to go with I2C.  But in order for this to work you need to enable the I2C bus inside of raspi-config.

Another step was to solder in the header to the Pi Zero.  This isn't hard, and in fact it's kind of fun.  But if your soldering skills are lacking then save yourself the trouble and use a Pi 1, 2, or 3.

Raspberry Pi Weather Station - part 1

My latest Raspberry Pi project is a home weather station.  My original goal was a have a useful set of sensors connected to the Pi, and to make the results accessible over the Internet.  That said, this process took several twists and turns along the way, probably because there are fewer people out there doing this type of project than say my previous projects of a homemade DVR or home theater.  This project, unlike my previous Pi projects, is less a step-by-step guide.  This is for several reasons.  First, this project morphed and changed several times so it was harder for me to document as I went.  And secondly, I had less free time to work on it, so I gave up on documenting while I worked.

When I decided to make a homemade weather station, I wanted to do as much "homemade" as possible.  So all my sensors are connected to the Raspberry Pi's GPIO pins.  The more common solution for people is to buy an off-the-shelf weather station and connect that to the Raspberry Pi's USB port.  I purchased all the hardware necessary for this project (more on that later) before I even knew how it would fit together.  I just had faith it was possible to do what I wanted to do.  The major missing link was the software.  I did not know how to read the sensors and display it meaningfully.  And it was researching the software solutions available is where this project deviated from my initial thoughts.  But I'll get into all that in a future post.  First let's look at the hardware I used.

Raspberry Pi Zero:
For this project I went with the new Raspberry Pi Zero.  Any Pi would do, but I chose the Pi Zero for several reasons.
  1. The smaller size, so the weatherproof enclosure doesn't need to be as large.
  2. The extremely low-power consumption.  As a weather station this won't need the processing power of the Pi 2/3, so save on electricity use.
  3. It's new and cool.  I've worked with the original Pi and the Pi 2, so this was something new to try.
However, working with the Pi Zero did have several drawbacks.  First and foremost was obtaining the Pi itself.  Pi Zero's are in VERY short supply and hard to get.  It took 2 weeks of waiting for Adafruit to get a shipment in before I could order one.  And even then, they only sold the Pi Zero in a "kit" with other things I didn't need like power supply, memory card, USB adapters, etc.  Another issue with the Pi Zero is you have to manually solder the header connector onto the Pi.  I like soldering so this was no problem for me, but others might find the regular Pi models more appealing since the GPIO pin headers are soldered on at the factory.

Temperature / Humidity / Pressure
For basic atmospheric measurements I went with the Adafruit BME280.  This sensor measures temperature, humidity, and pressure.

Wind / Rain
For the final set of sensors I went with the SparkFun weather sensors.  These sensors measure wind speed, wind direction, and rainfall.  But at $77 they are by far the most expensive item in this build.

Miscellaneous
To complete the project I needed a bunch of smaller items.  I bought a Samsung Pro micro SD card because it's one the fastest cards available and I've had good luck with them in the past.  For wireless I went with the Rosewill RNX-N180UBE.  For power I selected an Anker wall charger (I selected a dual-port model because this single charger will power a couple of my Raspberry Pi's) as well as a 10' long Anker power cord.  Lastly I purchased a waterproof electrical case at Home Depot originally designed for running conduit outside, but houses the Pi nicely and has openings on the bottom where I can run wires into the housing.

Thursday, July 14, 2016

Programming Languages

As a computer programmer the language I prefer to program in is obviously an important subject.  In my opinion C/C++ is the best all-around programming language.  When I was learning to program in the mid '90s, C/C++ was the undeniable king of programming languages.  However, in the time since then I feel like the industry has moved away from C/C++ to the point where some developers consider me to be a "dinosaur" for using such an old language.  But I don't think I'm a dinosaur, so I wanted to talk about languages in general and defend my preferences.

There are literally hundreds if not thousands of programming languages.  If you're learning programming for the first time or if you're starting a new project, how do you know which language to select?  Programming languages breakdown into 4 categories; 1 low-level category and 3 high-level categories.

Assembly:
Assembly is the only low-level language where the developer writes code targeted at a specific hardware platform.  Whereas hand-written assembly can be used for general purpose programming, it's very difficult to manage and nowadays assembly is mostly reserved for very specific cases, typically firmware and embedded programming systems.

Native Machine Languages:
Native machine languages are high-level languages that are compiled to target a specific platform.  That is to say, if your code will run on different platforms you must compile your code once for each platform it will run on.  This category includes languages like C/C++, Pascal, Fortran, Cobol, and Ada.

Virtual Machine Languages:
Virtual machine languages are similar to native in that they are compiled.  But the output is not hardware or platform specific.  Instead the output is "virtual" machine code that must be converted at runtime to the native machine code for the platform where your code is running.  The benefit is the developer compiles once and releases a single binary, but it can run on multiple platforms.  This category includes Java and C#.

Interpreted Languages:
Interpreted languages (often times called scripted languages) are not compiled.  Instead at runtime a program called the interpreter converts the code from human-readable to machine code.  Interpreted languages have the benefit of not needing the slow compilation process and can be quickly changed or tweaked.  This category includes Python, Perl, PHP, Javascript, Ruby, and many more.


So how do you pick a language?  What is the best programming language?  Well, the answer is the right tool for the right job.  All languages have pros and cons, so picking the best language requires an understanding of those.

Skipping assembly, because it's not really general purpose in today's world, let's talk about interpreted languages first.  I might take a lot of flak for this, but I don't consider interpreted languages to have much use outside of academia.  Interpreted languages are perfect for learning the basics of programming.  Because these languages don't require the developer to think about things like variable types, memory management, strings, etc. they allow the person to focus on learning the basics of programming.  After all, pilots don't fly a 747 as their first plane, they start on small propeller planes.  To me the only use for interpreted languages is when used as a scripting language to speed up tasks and eliminate human errors.  For example, say an IT person needs to create a new user account, add a machine to the domain, and assign that user to the machine.  This is a perfect task for a scripting language.

But languages like Javascript, Python, PHP, and Ruby are some of the most popular programming languages, so what's wrong with these languages?  The problem is speed and efficiency, or lack thereof.  Because these languages are interpreted at runtime there are significantly slower than other languages.  A recent comparison found these languages can be as much as 400x slower than a natively compiled program.  Probably a good rule of thumb is expect between 10x and 100x slower performance compared to natively programs.  That is a huge price to pay.  I'm dumbfounded that so many server applications are running in languages like Javascript.  That's like entering a car race with a bus.


Ok, so that leaves us natively and virtually compiled programs.  Here too native programs have the performance advantage, although it's much less pronounced.  A recent study found that on average C/C++ outperforms Java/C# by 20%.  On the flip side, Java/C# can be faster and easier to develop in compared to C/C++.  For many software companies, their highest cost is developers' salaries.  So picking Java or C# may result in quicker development times which results in lower development costs.  This all assumes your application is not performance critical (which most client/desktop applications aren't).

However, there is another side to the equation which developers rarely consider.  If your application runs on the server side, that extra 20% performance increase by going with C/C++ translates directly into 20% less electricity used by the servers.  It also means less electricity for cooling the server room which saves even more money.  When you start talking about applications that run on servers, suddenly the hardware for those servers, electricity used to run those servers, and the cooling costs for the servers outweighs development costs.  So in cases like this a native language is probably your best choice.

There is another benefit to native languages - extended battery life.  In that same study above, they found that C/C++ programs ran for approx. 20% longer on a given battery charge compared Java/C#.  So anyone developing applications that will run on a laptop, tablet, or phone should seriously consider a native language.

It is true that C/C++ is not the king it once was.  However, when you group C/C++ together it's still the number 1 programming language ahead of Java.  Also, any programming field where you need performance (e.g. video games) then C/C++ is the language of choice.  Yet another example is operating systems.  Every major operating system in existence is written in C - which includes Windows, Linux, Mac, Unix.  Even "mobile" operating systems like Android are built on top of Linux which is written in C.

So without a doubt C/C++ has a place in the modern world.  I think it's unfortunate that so many developers have gotten caught up in the virtual and interpreted language hype and forgotten about the power of a native programming language.  That said, recently there has been a resurgence in native programming languages driven largely by mobile devices with their relatively low resources and battery power, they are the perfect platform for a native programming language.

Wednesday, June 1, 2016

Free Windows License Keys

In this post I wanted to give away dozens of Windows license keys for free!  No, this isn't illegal.  These are perfectly legitimate keys and they are free to use.  The catch is, these keys cannot be used to activate Windows. These keys can be used to install Windows, and once installed you'll get between 3 and 30 days of free use depending on the version of Windows (more if you "rearm" Windows).

All of these keys came from Microsoft directly.  They give these keys away.  The problem is, there is no master list you can easily download and reference.  So I've taken the time to gather all these keys into one place for you to use.

There are two types of keys in this list; Generic Volume License Keys (GVLK) and Retail Installation Keys (RIK).  The difference is GVLK keys must be used for "volume license" versions of Windows and RIK are used for regular versions of Windows.  If you don't know which one to use, then you need retail (RIK).  Chances are anyone using volume license versions of Windows knows it because you have to pay a lot more and have a special contract to have and use that version of Windows.

In order to use one of these keys you must exactly match the key below with the version of Windows you're trying to install.  So from the list below, Windows 7 Professional N (Volume) will only work on the N edition of Windows 7 Professional volume license version.  Architecture (x86 or x64) and language do not matter, these keys work on all architectures and languages.


Windows Vista
Windows Vista Starter (Retail)
X9PYV-YBQRV-9BXWV-TQDMK-QDWK4

Windows Vista Starter N (Retail)
X9PYV-YBQRV-9BXWV-TQDMK-QDWK4

Windows Vista Home Basic (Retail)
RCG7P-TX42D-HM8FM-TCFCW-3V4VD

Windows Vista Home Basic K (Retail)
RCG7P-TX42D-HM8FM-TCFCW-3V4VD

Windows Vista Home Basic N (Retail)
HY2VV-XC6FF-MD6WV-FPYBQ-GFJBT

Windows Vista Home Basic KN (Retail)
HY2VV-XC6FF-MD6WV-FPYBQ-GFJBT

Windows Vista Home Premium (Retail)
X9HTF-MKJQQ-XK376-TJ7T4-76PKF

Windows Vista Home Premium K (Retail)
X9HTF-MKJQQ-XK376-TJ7T4-76PKF

Windows Vista Home Premium N (Retail)
KJ6TP-PF9W2-23T3Q-XTV7M-PXDT2

Windows Vista Home Premium KN (Retail)
KJ6TP-PF9W2-23T3Q-XTV7M-PXDT2

Windows Vista Business (Retail)
4D2XH-PRBMM-8Q22B-K8BM3-MRW4W

Windows Vista Business (Volume)
YFKBB-PQJJV-G996G-VWGXY-2V3X8

Windows Vista Business K (Retail)
4D2XH-PRBMM-8Q22B-K8BM3-MRW4W

Windows Vista Business K (Volume)
YFKBB-PQJJV-G996G-VWGXY-2V3X8

Windows Vista Business N (Retail)
76884-QXFY2-6Q2WX-2QTQ8-QXX44

Windows Vista Business N (Volume)
HMBQG-8H2RH-C77VX-27R82-VMQBT

Windows Vista Business KN (Retail)
76884-QXFY2-6Q2WX-2QTQ8-QXX44

Windows Vista Business KN (Volume)
HMBQG-8H2RH-C77VX-27R82-VMQBT

Windows Vista Enterprise (Volume)
VKK3X-68KWM-X2YGT-QR4M6-4BWMV

Windows Vista Enterprise N (Volume)
VTC42-BM838-43QHV-84HX6-XJXKV

Windows Vista Ultimate (Retail)
VMCB9-FDRV6-6CDQM-RV23K-RP8F7

Windows Vista Ultimate K (Retail)
VMCB9-FDRV6-6CDQM-RV23K-RP8F7

Windows Vista Ultimate N (Retail)
CVX38-P27B4-2X8BT-RXD4J-V7CKX

Windows Vista Ultimate KN (Retail)
CVX38-P27B4-2X8BT-RXD4J-V7CKX


Windows 7
Windows 7 Starter (Retail)
7Q28W-FT9PC-CMMYT-WHMY2-89M6G

Windows 7 Starter K (Retail)
7Q28W-FT9PC-CMMYT-WHMY2-89M6G

Windows 7 Starter N (Retail)
D4C3G-38HGY-HGQCV-QCWR8-97FFR

Windows 7 Starter KN (Retail)
D4C3G-38HGY-HGQCV-QCWR8-97FFR

Windows 7 Home Basic (Retail)
YGFVB-QTFXQ-3H233-PTWTJ-YRYRV

Windows 7 Home Basic K (Retail)
YGFVB-QTFXQ-3H233-PTWTJ-YRYRV

Windows 7 Home Basic N (Retail)
MD83G-H98CG-DXPYQ-Q8GCR-HM8X2

Windows 7 Home Basic KN (Retail)
MD83G-H98CG-DXPYQ-Q8GCR-HM8X2

Windows 7 Home Premium (Retail)
RHPQ2-RMFJH-74XYM-BH4JX-XM76F

Windows 7 Home Premium K (Retail)
RHPQ2-RMFJH-74XYM-BH4JX-XM76F

Windows 7 Home Premium N (Retail)
D3PVQ-V7M4J-9Q9K3-GG4K3-F99JM

Windows 7 Home Premium KN (Retail)
D3PVQ-V7M4J-9Q9K3-GG4K3-F99JM

Windows 7 Professional (Retail)
HYF8J-CVRMY-CM74G-RPHKF-PW487

Windows 7 Professional (Volume)
FJ82H-XT6CR-J8D7P-XQJJ2-GPDD4

Windows 7 Professional K (Retail)
HYF8J-CVRMY-CM74G-RPHKF-PW487

Windows 7 Professional K (Volume)
FJ82H-XT6CR-J8D7P-XQJJ2-GPDD4

Windows 7 Professional N (Retail)
BKFRB-RTCT3-9HW44-FX3X8-M48M6

Windows 7 Professional N (Volume)
MRPKT-YTG23-K7D7T-X2JMM-QY7MG

Windows 7 Professional KN (Retail)
BKFRB-RTCT3-9HW44-FX3X8-M48M6

Windows 7 Professional KN (Volume)
MRPKT-YTG23-K7D7T-X2JMM-QY7MG

Windows 7 Enterprise (Retail)
H7X92-3VPBB-Q799D-Y6JJ3-86WC6

Windows 7 Enterprise (Volume)
33PXH-7Y6KF-2VJC9-XBBR8-HVTHH

Windows 7 Enterprise N (Retail)
BQ4TH-BWRRY-424Y9-7PQX2-B4WBD

Windows 7 Enterprise N (Volume)
YDRBP-3D83W-TY26F-D46B2-XCKRJ

Windows 7 Enterprise KN (Retail)
BQ4TH-BWRRY-424Y9-7PQX2-B4WBD

Windows 7 Enterprise KN (Volume)
YDRBP-3D83W-TY26F-D46B2-XCKRJ

Windows 7 Ultimate (Retail)
D4F6K-QK3RD-TMVMJ-BBMRX-3MBMV

Windows 7 Ultimate K (Retail)
D4F6K-QK3RD-TMVMJ-BBMRX-3MBMV

Windows 7 Ultimate N (Retail)
HTJK6-DXX8T-TVCR6-KDG67-97J8Q

Windows 7 Ultimate KN (Retail)
HTJK6-DXX8T-TVCR6-KDG67-97J8Q


Windows 8
Windows 8 (Retail)
FB4WR-32NVD-4RW79-XQFWH-CYQG3

Windows 8 N (Retail)
VDKYM-JNKJ7-DC4X9-BT3QR-JHRDC

Windows 8 Professional (Retail)
XKY4K-2NRWR-8F6P2-448RF-CRYQH

Windows 8 Professional (Volume)
NG4HW-VH26C-733KW-K6F98-J8CK4

Windows 8 Professional N (Retail)
BHHD4-FKNK8-89X83-HTGM4-3C73G

Windows 8 Professional N (Volume)
XCVCF-2NXM9-723PB-MHCB7-2RYQQ

Windows 8 Enterprise (Volume)
32JNW-9KQ84-P47T8-D8GGY-CWCK7

8M9BN-YB7W9-YV3­VJ-7WMGG-MKH3V

Windows 8 Enterprise N (Volume)
JMNMF-RHW7P-DMY6X-RF3DR-X2BQT

NCVKH-RB9D4-R86X8-GB8WG-4M2K6

Windows 8.1
Windows 8.1 (Retail)
334NH-RXG76-64THK-C7CKG-D3VPT

Windows 8.1 N (Retail)
6NPQ8-PK64X-W4WMM-MF84V-RGB89

Windows 8.1 Professional (Retail)
XHQ8N-C3MCJ-RQXB6-WCHYG-C9WKB

Windows 8.1 Professional (Volume)
GCRJD-8NW9H-F2CDX-CCM8D-9D6T9

Windows 8.1 Professional N (Retail)
JRBBN-4Q997-H4RM2-H3B7W-Q68KC

Windows 8.1 Professional N (Volume)
HMCNV-VVBFX-7HMBH-CTY9B-B4FXY

Windows 8.1 Enterprise (Volume)
MHF9N-XY6XB-WVXMC-BTDCT-MKKG7
FHQNR-XYXYC-8PMHT-TV4PH-DRQ3H


Windows 8.1 Enterprise N (Volume)
TT4HM-HN7YT-62K67-RGRQJ-JFFXW

NDRDJ-3YBP2-8WTKD-CK7VB-HT8KW

Windows 10
Windows 10 Home (Retail)
YTMG3-N6DKC-DKB77-7M9GH-8HVX7

Windows 10 Home N (Retail)
4CPRK-NM3K3-X6XXQ-RXX86-WXCHW

Windows 10 Home KN (Retail)
4CPRK-NM3K3-X6XXQ-RXX86-WXCHW

Windows 10 Professional (Retail)
VK7JG-NPHTM-C97JM-9MPGT-3V66T

Windows 10 Professional (Volume)
W269N-WFGWX-YVC9B-4J6C9-T83GX

Windows 10 Professional N (Retail)
2B87N-8KFHP-DKV6R-Y2C8J-PKCKT

Windows 10 Professional N (Volume)
MH37W-N47XK-V7XM9-C7227-GCQG9

Windows 10 Professional KN (Retail)
2B87N-8KFHP-DKV6R-Y2C8J-PKCKT

Windows 10 Professional KN (Volume)
MH37W-N47XK-V7XM9-C7227-GCQG9

Windows 10 Enterprise (Volume)
NPPR9-FWDCX-D2C8J-H872K-2YT43
XGVPP-NMH47-7TTHJ-W3FW7-8HV2C

Windows 10 Enterprise N (Volume)
DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4
WGGHN-J84D6-QYCPR-T7PJ7-X766F

Windows 10 Enterprise KN (Volume)
DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4
WGGHN-J84D6-QYCPR-T7PJ7-X766F

Windows 10 Enterprise 2015 LTSB (Volume)
WNMTR-4C88C-JK8YV-HQ7T2-76DF9
FWN7H-PF93Q-4GGP8-M8RF3-MDWWW

Windows 10 Enterprise 2015 LTSB N (Volume)
2F77B-TNFGY-69QQF-B8YKP-D69TJ

Windows 10 Enterprise 2015 LTSB KN (Volume)
2F77B-TNFGY-69QQF-B8YKP-D69TJ

Windows 10 Education (Retail)
YNMGQ-8RYV3-4PGQ3-C8XTP-7CFBY

Windows 10 Education (Volume)
NW6C2-QMPVW-D7KKK-3GKT6-VCFB2

Windows 10 Education N (Retail)
84NGF-MHBT6-FXBX8-QWJK7-DRR8H

Windows 10 Education N (Volume)
2WH4N-8QGBV-H22JP-CT43Q-MDWWJ

Windows 10 Education KN (Retail)
84NGF-MHBT6-FXBX8-QWJK7-DRR8H

Windows 10 Education KN (Volume)
2WH4N-8QGBV-H22JP-CT43Q-MDWWJ


Server 2008
Windows Server 2008 Standard (Volume)
TM24T-X9RMF-VWXK6-X8JC9-BFGM2

Windows Server 2008 Standard Core (Volume)
TM24T-X9RMF-VWXK6-X8JC9-BFGM2

Windows Server 2008 Standard without Hyper-V (Volume)
W7VD6-7JFBR-RX26B-YKQ3Y-6FFFJ

Windows Server 2008 Standard Core without Hyper-V (Volume)
W7VD6-7JFBR-RX26B-YKQ3Y-6FFFJ

Windows Server 2008 Enterprise (Volume)
YQGMW-MPWTJ-34KDK-48M3W-X4Q6V

Windows Server 2008 Enterprise Core (Volume)
YQGMW-MPWTJ-34KDK-48M3W-X4Q6V

Windows Server 2008 Enterprise without Hyper-V (Volume)
39BXF-X8Q23-P2WWT-38T2F-G3FPG

Windows Server 2008 Enterprise Core without Hyper-V (Volume)
39BXF-X8Q23-P2WWT-38T2F-G3FPG

Windows Server 2008 Datacenter (Volume)
7M67G-PC374-GR742-YH8V4-TCBY3

Windows Server 2008 Datacenter Core (Volume)
7M67G-PC374-GR742-YH8V4-TCBY3

Windows Server 2008 Datacenter without Hyper-V (Volume)
22XQ2-VRXRG-P8D42-K34TD-G3QQC

Windows Server 2008 Datacenter Core without Hyper-V (Volume)
22XQ2-VRXRG-P8D42-K34TD-G3QQC

Windows Server 2008 Web (Volume)
WYR28-R7TFJ-3X2YQ-YCY4H-M249D

Windows Server 2008 Web Core (Volume)
WYR28-R7TFJ-3X2YQ-YCY4H-M249D

Windows Server 2008 HPC (Volume)
RCTX3-KWVHP-BR6TB-RB6DM-6X7HP


Server 2008 R2
Windows Server 2008 R2 Web (Retail)
YGTGP-9XH8D-8BVGY-BVK4V-3CPRF

Windows Server 2008 R2 Web (Volume)
6TPJF-RBVHG-WBW2R-86QPH-6RTM4

Windows Server 2008 R2 Web Core (Retail)
YGTGP-9XH8D-8BVGY-BVK4V-3CPRF

Windows Server 2008 R2 Web Core (Volume)
6TPJF-RBVHG-WBW2R-86QPH-6RTM4

Windows Server 2008 R2 Standard (Retail)
HMG6P-C7VGP-47GJ9-TWBD4-2YYCD

Windows Server 2008 R2 Standard (Volume)
YC6KT-GKW9T-YTKYR-T4X34-R7VHC

Windows Server 2008 R2 Standard Core (Retail)
HMG6P-C7VGP-47GJ9-TWBD4-2YYCD

Windows Server 2008 R2 Standard Core (Volume)
YC6KT-GKW9T-YTKYR-T4X34-R7VHC

Windows Server 2008 R2 Enterprise (Retail)
7P8GH-FV2FF-8FDCR-YK49D-D7P97

Windows Server 2008 R2 Enterprise (Volume)
489J6-VHDMP-X63PK-3K798-CPX3Y

Windows Server 2008 R2 Enterprise Core (Retail)
7P8GH-FV2FF-8FDCR-YK49D-D7P97

Windows Server 2008 R2 Enterprise Core (Volume)
489J6-VHDMP-X63PK-3K798-CPX3Y

Windows Server 2008 R2 Datacenter (Retail)
7X29B-RDCR7-J6R29-K27FF-H9CR9

Windows Server 2008 R2 Datacenter (Volume)
74YFP-3QFB3-KQT8W-PMXWJ-7M648

Windows Server 2008 R2 Datacenter Core (Retail)
7X29B-RDCR7-J6R29-K27FF-H9CR9

Windows Server 2008 R2 Datacenter Core (Volume)
74YFP-3QFB3-KQT8W-PMXWJ-7M648

Microsoft Hyper-V Server 2008 R2 (Retail)
Q8R8C-T2W6H-7MGPB-4CQ9R-KR36H

Windows Server 2008 R2 HPC (Retail)
Q7PRR-M2WBM-RJJ99-FG393-MGY3B

Windows Server 2008 R2 HPC (Volume)
TT8MH-CG224-D3D7Q-498W2-9QCTX


Server 2012
Windows Server 2012 (Volume)
BN3D2-R7TKB-3YPBD-8DRP2-27GG4

Windows Server 2012 N (Volume)
8N2M2-HWPGY-7PGT9-HGDD8-GVGGY

Windows Server 2012 Standard (Retail)
VN93G-8PVT3-W2X3H-F3X87-FJMTW

Windows Server 2012 Standard (Volume)
XC9B7-NBPP2-83J2H-RHMBY-92BT4

Windows Server 2012 Standard Core (Retail)
VN93G-8PVT3-W2X3H-F3X87-FJMTW

Windows Server 2012 Standard Core (Volume)
XC9B7-NBPP2-83J2H-RHMBY-92BT4

Windows Server 2012 MultiPoint Standard (Retail)
32TNQ-HMFWQ-8R933-X6VYY-WHRFX

Windows Server 2012 MultiPoint Standard (Volume)
HM7DN-YVMH3-46JC3-XYTG7-CYQJJ

Windows Server 2012 MultiPoint Premium (Retail)
CBR2N-2HG39-2TGGT-GQB27-46V47

Windows Server 2012 MultiPoint Premium (Volume)
XNH6W-2V9GX-RGJ4K-Y8X6F-QGJ2G

Windows Server 2012 Datacenter (Retail)
2GMNX-8K7D2-X968C-7P62F-8B2QK

Windows Server 2012 Datacenter (Volume)
48HP8-DN98B-MYWDG-T2DCC-8W83P

Windows Server 2012 Datacenter Core (Retail)
2GMNX-8K7D2-X968C-7P62F-8B2QK

Windows Server 2012 Datacenter Core (Volume)
48HP8-DN98B-MYWDG-T2DCC-8W83P

Microsoft Hyper-V Server 2012 (Retail)
Q8R8C-T2W6H-7MGPB-4CQ9R-KR36H

Windows Storage Server 2012 Standard (Retail)
RD9XF-6N3MC-2P2R3-MK2WX-C7GCW

Windows Storage Server 2012 Workgroup (Retail)
NYGPD-KK4W6-QC3XH-HX4P4-2J824

Windows Server 2012 Foundation (Retail)
PN24B-X6THG-274MF-YHM9G-H8MVG

Windows Server 2012 Essentials (Retail)
N4PDW-9PKPK-29XQJ-42MFM-CWCQ8


Server 2012 R2
Windows Server 2012 R2 Server Standard (Volume)
D2N9P-3P6X9-2R39C-7RTCD-MDVJX

Windows Server 2012 R2 Server Standard Core (Volume)
D2N9P-3P6X9-2R39C-7RTCD-MDVJX

Windows Server 2012 R2 Datacenter (Volume)
W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9

Windows Server 2012 R2 Datacenter Core (Volume)
W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9

Windows Server 2012 R2 Essentials (Retail)
326N4-6GMBX-PD2QT-M7HX4-TVHM8

Windows Server 2012 R2 Essentials (Volume)
KNC87-3J2TX-XB4WP-VCPJV-M4FWM

Windows Storage Server 2012 R2 Standard (Retail)
H2K4M-QNKQ2-64699-FYQHD-2WDYT

Windows Storage Server 2012 R2 Workgroup (Retail)
8N7PM-D3C64-RQVYF-MX8T7-G6MB2

Windows Server 2012 R2 Foundation (Retail)
7JGXN-BW8X3-DTJCK-WG7XB-YWP26

Microsoft Hyper-V Server 2012 R2 (Retail)
Q8R8C-T2W6H-7MGPB-4CQ9R-KR36H

Thursday, April 14, 2016

Your hot water heater is set too high!

Based on my experience visiting other people's homes and businesses, most people have their hot water heaters set too high.  What's surprising, if you suggest that they consider turning down the temperature often times they get defensive.  I think people consider hot clean water to be a luxury item and so to turn it down is like losing a part of their status or livelihood.  So I hope to approach this logically and convince you it's worth turning it down.

Let's start off by looking at all the uses of hot water in your home.  Hot water is piped to two appliances, the dishwasher and the clothes washer.  It also goes to showers, baths, and sinks.  That's it.  All other places in the home with water (refrigerators, toilets, and all external hose bibs) are cold only.  So let's look at each of these places hot water is used an evaluate if we truly need scalding hot water.

Dishwasher
The dishwasher is the easiest one to analyze, because it doesn't need hot water to work.  All modern dishwasher have a built-in heater (the same one that heats up to dry off the dishes).  This heater is turned on during the wash cycle to heat the water even more.  So even if your dishwasher were connected to cold water it would wash just as effectively because it heats the water up internally.

Laundry
Many of us have been told for years to wash whites in hot water, certain clothes in warm, and dark colors in cold water.  But these are old outdated methods.  Modern efficient machines with modern laundry soaps wash almost all clothes great in cold water.  There are very few clothes that need to be washed in warm or hot water.  In fact, hot/warm water may actually cause more harm than good.  Modern soaps use enzymes that are active between 60°F (16°C) and 75°F (24°C).  Beyond that and the enzymes are less effective, and you're more likely to "set" in stains and damage fabrics.  So hot or warm should only be used on special garments with special soaps.

Showers/tubs
When you take a shower or a bath, I doubt you'll do so using 100% hot water.  Most likely you'd scald yourself.  So you mix hot and cold to get the desired temperature.  This means you could lower your hot water heater without having to take a colder shower.  I would argue the ideal hot water heater temperature is when your shower/bath is nearly 100% hot water to still get the temperature you'd like.  Anything more means you're just overheating the water.

Sinks
The primary reason people want hot water at the sink is to washing things; e.g. their hands, dishes, the floors, etc.  Hot water helps kill germs and bacteria, right?  Technically yes, but in practice no.  The water temperature and time at that temperature required to kill germs and bacteria would instantly scald and burn you!  If you've ever gone backpacking you know the rule is to boil the water for 5 minutes to kill anything in the water.  The hot water coming out of your sink is well below the temperature required to kill anything, all you're going to do is burn yourself and not kill anything.  That's what soap is for.


So hopefully I've convinced you that your hot water heater can be turned down.  But how far, what temperature do you set it to?  Few hot water heaters have an actual thermostat, most just have a high-low adjustment.  Instead the way to adjust your hot water is to go to the sink farthest from the hot water heater and turn on hot water.  Let the water flow over a thermometer.  You want the water coming out of the tap to be 120°F (49°C).  This is the industry recommended temperature to be hot enough for things like showers, but not so hot as to burn you.  If you adjust your hot water heater down then obviously you need to wait hours/days before retesting.

When I made these changes to my hot water I was shocked.  My hot water heater has an off position, vacation mode (to keep the water from freezing), and then a slider from low to high.  To achieve 120°F (49°C) at the sink I ended up setting my hot water heater to the lowest possible setting above vacation mode.  Not everyone's hot water heater will be the same, mine is only a few years old and it's a super efficient one.  You probably won't be able to go as low as I can, but I have no doubt you could lower yours with no side effects.

Lastly, let's talk about the benefits of making this change.  You'll save money, a decent amount too.  Heating water takes a lot of energy, so if you lower the temperature you'll save money pure and simple.  Between lower gas/electricity costs and using less hot water for laundry you'll probably save at least $100 per year.  You'll also extend the life of your hot water heater.  Most hot water heaters need to be replaced because of deposits that build up inside of them.  So turning down the temperature extends the life of your hot water heater, which also saves you money.  And lastly you reduce the chances of accidental burns from hot water - an even bigger concern if you have children in your home.


Hopefully reading this has encouraged you to evaluate your hot water heater.  If nothing else, put a thermometer in the sink and turn on hot water to test and see what your current hot water is coming out at.  You might be surprised!

Friday, February 26, 2016

Install Ubuntu to striped disks

Recently I needed to install Ubuntu to a striped disk set.  A striped disk set is when 2 or more hard drives are effectively merged together into a single hard drive.  So if your computer has two 1 TB hard drives, then striping them together would give you a single 2 TB hard drive.  I found a couple of guides online to do this, but they all involved starting up Ubuntu from a Live CD and performing the partitioning there, then rebooting and installing Ubuntu to the existing partition.  I wanted to just get it done during the installation.  It took several tries, but here is how I got it done from within Ubuntu setup.

I should add, this was done using Ubuntu Server 14.04 LTS x64.  The same procedure should work with Desktop, and it should work with other versions as well.  Also, before starting this both hard drives were clean, i.e. they did not have existing partitions.  First, run through setup until you get to the first screen about disk partitioning.

Step 1:  Do it manually
Move down and select "manual."

Step 2:  Create partition tables
If you move down you should see your disks (in my case, I have two 10GB hard drives).  Select each disk in turn.  You will be asked to confirm you want to create a partition table on the disk, say yes.

Step 3:  Configure RAID
Now both hard drives will show up as "free space."  Next move up to and select "configure software RAID."  You will again be prompted to commit changes to the disk, select yes.  On the next screen select "create MD device."

Select RAID0, which is stripping.  On the next screen use the space bar to check each disk that will be a part of the stripe then choose continue.  Then again choose yes to confirm your selection.

Finally select "finish" to complete the RAID setup.

Step 4:  Change partition use
Now, in addition to the multiple physical hard drives, you should see an entry for the RAID.  Select the first object under the RAID.  On the next page you need to change the "use as" to "use physical volume for LVM."  Then select "done setting up the partition."

Step 5:  Install LVM
Select up to "guided partitioning" then select "guided - use entire disk and set up LVM."  The next screen will show the two hard drives as well as the single RAID.  Select the RAID.  The confirm you want to write changes.  On the next screen verify the size of the partition and select continue.

Step 6:  Finalize and install
Select "finish partitioning and write changes to disk."  You will be prompted yet again to write changes to disk.  I promise, this is the last time.


After that the installation should continue as normal and install Ubuntu to your newly created striped disks.  Easy as pie, right?  Okay, maybe not.  But hopefully this guide helps you.

Friday, February 5, 2016

Best Sega Genesis Soundtrack

The Sega Genesis, like all consoles of the time, had a very unique and recognizable sound to it.  Many of the games I played have had a lasting impression on me and I still find myself humming a tune from 20+ years ago.  So I wanted to list my top 10 favorite Sega Genesis soundtracks.

Most Sega Genesis games had at least one good track in them, but to make this list they needed to have a lot of good tracks.  Also, these need to be so good that you would gladly listen to them outside of the game.  A lot of games, like Street Fighter 2, have great music - but it's not something I would listen to outside of the game so it didn't make my list.  I guess I should say, since the '80s I have enjoyed electronic/techno music, so the games that made my list mostly have upbeat techno sound to them (something the Sega Genesis excelled at creating more so than the Super Nintendo).  Lastly, I can only rate games that I've played, for obvious reasons.

First a few honorable mentions.

Ecco the Dolphin 1 and 2 on CD:  My list is exclusively "chiptunes" on the Genesis so I have to disqualify Ecco 1 and 2.  But I had to at least mention them somewhere because their music is awesome!  This is easily the music I listened to the most in the mid '90s.  If you haven't heard the Ecco soundtrack it's best described as ambient and relaxing.

Streets of Rage 3:  The Streets of Rage series is known for incredible music.  But sadly the third installment in the series did not live up to the high standard of previous games.  SoR3 has some really great tracks, but it also has some downright weird and awful tracks too.

Phantasy Star 2:  PS2 was an early title for the Genesis, and I would describe the soundtrack as ahead of its time.  It's probably too "electronic" sounding for mainstream listening, which I think is why many people say the music in PS2 was one of it's weak points.  But I like it.

And now onto the top 10.

10 - Revenge of Shinobi:  The music for RoS came from Yuzo Koshiro who would later go on to work on the Streets of Rage series.  RoS has a number of excellent tracks.

9 - Thunder Force 2:  TF2 was the first in a series of games that proved Technosoft knew how to write a good techno soundtrack to match perfectly with a great game.  Most people prefer the soundtrack to Thunder Force 3 instead, but for me TF2 has more memorable tracks.

8 - Wonder Boy in Monster World:  Monster World has some of the best atmospheric sound music of any game.  When you're in the jungle the music sounds like you're in a jungle.  When you're in a desert it sounds like you're in a desert.  Snow music is perfectly suited, and the Caribbean sounding beach music is one of my all-time favorite tracks.

7 - Sonic the Hedgehog 3:  With a big-budget title like Sonic the Hedgehog, you know Sega is going to give it a great soundtrack.  And Sonic 3 doesn't disappoint.  One little known fact is that Michael Jackson helped on the soundtrack for Sonic 3.

6 - Sonic the Hedgehog:  Sonic the Hedgehog was destined to be a great game even before it was released.  It has everything from great game play, great graphics, and of course a great soundtrack.  Some of my favorites are the Marble and Starlight zones.

5 - Phantasy Star 4:  PS4 has some of the best music in the PS series, it's just a shame more people didn't get to experience it.  PS4 came out late in the Sega Genesis lifetime, the game costs almost twice as much as a typical Genesis game, and it's in the RPG genre which not everyone likes.  All these together mean that few people have had the opportunity to enjoy the PS4 soundtrack.

4 - Sonic the Hedgehog 2:  With the success of Sonic 1 Sega put all it's resources behind its sequel.  Sonic 2 has the best music in the series in my opinion.

3 - Contra Hard Corps:  Contra Hard Corps has probably the best upbeat techno soundtrack on the Sega Genesis.  So many great tracks that get you in the mood for excitement.

2 - Streets of Rage:  Everyone knows SoR has awesome music.  But I think people mostly focus on SoR2 and forget about the original game.  SoR1 has tracks every bit as memorable as SoR2.  Just about every track is a masterpiece that gets you in the mood to beat people up - virtually of course.

1 - Streets of Rage 2:  By this point there can be no doubt, the best soundtrack on the Sega Genesis is SoR2.  I actually had a hard time deciding between SoR1 and SoR2.  Each game has such great music perfectly suited to the game.  But I think I have to give the overall win to Streets of Rage 2.

There you have it.  My top 10 Sega Genesis soundtracks and some honorable mentions.  If there are any great soundtracks I missed, please comment on it.  Again, I can only rate games I've played.

[By the way, if you're in the mood to experience some great Sega Genesis music, you can easily do so on your computer.  Search the Internet for "VGM" and a game title and you can download VGM or VGZ files which are the raw music ripped directly from the Sega Genesis cartridge.  You can use a number of programs to listen to VGM files including Winamp and foobar2000, both of which have plugins to play VGM/VGZ files.]

Thursday, January 21, 2016

Cable TV

Approximately 9 years ago I did something I never thought I would do - I cancelled my cable TV subscription. No, I wasn't switching to satellite TV, I was cutting the cord completely. This marked a big turn in my life. Up until that point I always had cable TV, from a child through high school and college, and into adulthood. This marked the first time I'd ever been without cable. This post is my reflection back on that past 9 years, what's changed, would I go back, etc.

First let's talk about the biggest benefit - the savings. My best guess estimate is I've saved $11,000 in those 9 years! That's a lot of money! Before cutting cable my bill was approaching $100/month. Checking current rates they appear to be about $110/month. So an average of $100/month times 9 years equals a lot of saved money.

Another benefit I've noticed is how much more time I have. When you have cable TV it's far too easy to sit down and watch TV. But without cable when your TV only gets 9 local broadcast channels you watch a lot less TV.

A big question is - would I ever switch back to cable TV? The answer is yes, but not in its current form. There are two main things I dislike about cable TV providers in their current form, neither of which is the cost of their service.

Set-top Boxes
I hate set-top boxes.  Modern TV are cable of decoding both analog and multiple forms of digital video streams, so why would I want a set-top box?  Why add another device and another remote control?  Yes, their remote controls usually work the TV too, but this usually never works just right forcing you to keep multiple remotes on hand.  Cable companies try and convince you that the set-top box is a benefit to you.  But they are deceiving you, they want the set-top box for one main reason - they make more money!  A recent government study found the average American family spends $19.32/month renting set-top boxes.  Even if you didn't have to rent the set-top box, they still make money.  A set-top box is the cable company's gateway into the world of pay-per-view and on-demand TV watching, which is yet another revenue stream for them.

There is another reason cable companies like set-top boxes.  It allows them to control both ends of the encryption.  Digital TV signals are encrypted to prevent people from stealing cable TV.  The set-top box is what decrypts this signal.  Going back 20 years, the "cable card" technology was supposed to solve that by allowing your TV to do the decryption.  But cable card was never widely adopted by the industry.

What I would love to see is TV manufacturers and cable broadcast get together and create a standard protocol.  That way the TV you buy at the store can decrypt and view broadcasts from your cable provider without the need for a set-top box.  Of course, this will never happen (unless congress passes a law forcing it to happen), simply because set-top boxes make the cable company money.  Why would they eliminate a source of revenue?

Channel Selection
The other big issue that's preventing me from going back to cable TV is channel selection.  Cable companies are out of touch with their customers.  A recent study by Nielsen TV ratings found that between 2008 and 2013 the average number of channels a cable provider offered increased from 130 to 190.  That's an average of 12 new channels per year.  However, Nielsen discovered number of channels people actually watch stayed the same at 17.  So cable companies are offering more channels which costs more money, but people aren't watching more channels.  What's more, people are watching less than 10% of the channels they are paying for.

So I would consider going back to cable if the cable companies offered the ability to pick which channels you want, or at least have more tiers so I can have finer control of what I'm paying for.  Of course this will never happen.  Broadcasters, like Discovery channel, lock cable broadcasters into contracts.  If they want to distribute their top-tier popular channels they must also offer their bottom-of-the-barrel unpopular channels as well.


The whole industry is messed up.  I can only hope that as more and more people cut cable in favor of things like Internet streaming options that cable companies will be forced to change their ways.  In the meantime I'll enjoy an extra $100 in my wallet each month that is not going to my cable company!

Tuesday, January 5, 2016

Water savings - update

Several months ago I posted about my water bill and how my water usage had gone down by installing low-flow shower heads and dual-flush toilet conversion.  That post was only 3 months in so I wanted to do a followup now that it's almost a year since I made the changes.


The above graph is taken directly from my account on my water company's website.  It shows all months usage for 2014 and 2015.  The part shaded in red is before I made any changes in my water usage.  The part in green is after installing the water saving devices in my house.  The 2 month window between the two is a transition period.  I installed one shower head and dual-flush converter to try the products out and see if we liked them before ordering more and installing them everywhere in my house.

There are 3 months before making the switch that are deceptively low; January 2014, September 2014, and January 2015.  In all 3 cases they correspond to vacations of more than a week in length, so obviously if we're not home we're using less water.  If you ignore those 3 months, than my before usage averaged exactly 5.5 units per month (a unit being 100 cubic feet of water or 748 gallons).  After the switch that average dropped to exactly 4 units.  So we're saving approximately 1.5 units per month, or 1,122 gallons per month, 37 gallons per day, or close to 14,000 gallons in a year.

From a money-savings point of view, water in my area costs $7.90 per unit, so we're saving an average of $11.85 per month, or $142 per year.  Considering the hardware for this change cost about $120 I've recouped my investment already and each month will be savings from here on out.

Again, I did not make this switch to save money.  I made this switch to save water.  Even though it's winter and it's raining outside right now, California is still in a drought and our reservoirs are at an all-time low.  Saving water is not only the right thing to do, it's extremely important.  Saving money is just an added bonus.