Wednesday, May 19, 2010

Application Security Overview

Overview

I rarely find an organization who has someone whose sole job is to ensure the security of data and applications across an Enterprise.  Therefore, a lot of that job falls on the shoulders of developers.  I think security is a rather broad topic with a lot of considerations but for the purposes of this blog... I'll stick to some basic scenarios.

Really, there are two major scenarios to consider in regards to security;  the data and transport of the data.

Transport Security

The most basic and reasonable method of securing your data from point A to point B is to use a mechanism like SSL.  Normally in HTTP, data is sent in a clear text format.  Using SSL, both client and server agree on a key to use and the data is sent in an encrypted form across the wire where it is decrypted on the other end.  As you would imagine, this process does increase the size of your payload being sent and returned but prevents someone who intercepts the packets from viewing the contents without first breaking the encryption.

The performance bottleneck is one of the reasons you see merchant sites unsecured until you switch over to process a payment, at which time SSL is employed.

Data Security

When securing your data, you have options but need to choose carefully.  For example, if you encrypt data in the database that field is no longer searchable by the database engine.  Additionally, as with SSL there is the performance hit of decrypting.  Lastly, you have to consider reporting and other functionality that may have no/limited abilities to decrypt data.

Presently, Rijndael is a popular encryption algorithm and works pretty well.  You will have to specify two key values (key and IV) in order to encrypt and decrypt data.  However, both the source and destination machine must have the same keys otherwise this won't work.  A practical application of this might be to encrypt data going between two machines across the internet via a web service.  (Tho again, SSL can also be used... so Rijndael would be an added layer of protection if that was the case.)  This might also be useful when passing a token to a non-secured web service to authenticate.

On a machine, I like to use DPAPI.  This came integrated in Framework 2.0 (IE, there are objects for it you can use) and encrypts data with a key specific to the machine.  This is great for securing connection string and other components of your app or web config file.  I'm not going to go into detail but basically you can use the ProtectedData class (part of System.Security.Cryptography) with LocalMachine protection scope.

Alternately, you could do a DLLImport and use the encryption DLLs directly but this approach is frowned upon since it creates unmanaged code.

Recap

Use SSL to protect data in transit from server to client; HTTP is clear/plain text by default.
Use Rijndael to encrypt/decrypt sensitive data; remember you can't search encrypted database fields.
Use  DPAPI to encrypt data with a machine specific algorithm.

Delegates

I thought I posted this a while back but it doesn't appear on my list of blogs so I'm reposting it.

A delegate is what used to be called a function pointer in C++. What it basically allows you to do is define the method signature of a function that is going to be called at run time without knowing what the function is at compile time.


Where this is useful is in cases where you have object(s) that need to register to be notified when something happens so it can take the proper action. This may sound a lot like an event; that's because an event is basically a variant of a delegate.

Two special types of delegates are the anonymous and multi-cast.

The anonymous is where you delcare a delegate but you define the function to be called inside the delegate declaration. Example: button1.Click += delegate(System.Object o, System.EventArgs e)
{ System.Windows.Forms.MessageBox.Show("Click!"); };

So we're targeting a method that accepts object, EventArgs but we're actually defining the implemenation inside the declaration. So this delegate, when fired, would display Click! in a message box.
In the multi-cast delegate, you can target multiple method(s). But I don't recall ever using this feature so I don't have an example of it.

The most common place I use delegates is when I'm trying to filter a List of items. I normally use an anonymous delegate.

So assume I have a class, Employee with a FirstName field... and I've stored all my Employee records inside a List called MyList.

Example: List MyListOfBobs = MyList.FindAll(delegate(Employee e){return e.FirstName == "Bob";});

So here I would get back all the employees in MyList where the FirstName was equal to Bob.

I could also do something like this... MyList.FindAll(FindAllBobsMethod);

private static bool FindAllBobsMethod(Employee e)
{
if (e.FirstName == "Bob")
return true;
else
return false;
}

Tuesday, May 18, 2010

Partial Classes

The concept of the partial class came into play in Framework 2.0.  However, I've noticed that people have either forgotten or didn't notice this handy keyword.

Framework 1.0

If you used the 1.0 Frameworks you noticed when you created UI elements that all the back-end code for those controls ended up going into the form's code behind.  Typically, this resided in a region called something like "Designer Generated Code".

To me at least, this cluttered your code behind with code that was required but not it wasn't YOUR code.

Framwork 2.0

The solution to this and many other problems came in the 2.0 release of the Framework with this new keyword; partial. 

A partial class essentially is a keyword that tells the compiler "hey, my class is defined across several definitions; usually across multiple files".  It almost reminds of me header files in C++, but that's neither here nor there.

You can use partial on a class, struct, or interface.

So what?

Well, the two reasons MSDN's documentation suggests using the partial keyword are the same two reasons I like it.

1. It keeps system generated code in its own section away from your code.
2. (This is the big one...) Allows teams of developers to break a class into several logical files to reduce/prevent waiting on your code to be checked in to edit a section.

Like I said, reason 2 is my favorite.  Countless times I've needed to add an item to an enum, add an overload of a function to a class... and its checked out.  I would even say in about 90% of the cases, the other developer was changing things unrelated to what I wanted to change!

My rule of thumb is to break the code into logical chunks when using a partial class.  For example, if I had an ATM object then I might break each class into the functions the ATM can perform.  Obviously, the class name will be the same but I like to use a classname_function type name for all the partial files.

Example:

ATM.cs (maybe where I keep the constructor, declarations, and properties)
ATM_Withdraw.cs
ATM_Deposit.cs
ATM_GetStamps.cs
ATM_PrintStatement.cs

Usage

Using the partial keyword is easy!  Simply put "partial" after the scope (public, private, protected,etc) and before the type (class, interface, enum).

Example:

public partial class Form1 : Form

Note:  This would be the main declaration of the class.  A subsequent declaration wouldn't need the inherits.  So your other partials would like like this:  public partial class Form1

Other Considerations

Keep in mind that the entire class definition has to be in the SAME namespace.

All parts must have the same scope (accessibility).  IE, its public or private, etc not mix and match.

Monday, May 17, 2010

Droid 2.1 for HTC Droid Eris

The Verizon update for the HTC Droid Eris has dropped in the last few days.  Users will be prompted to install a system update.  This will bring your phone to Droid 2.1 and give it many of the features that the Motorola Droid users have been enjoying the last few months.

There are 4 features that I am excited about:

-New support for voice-to-text entry. Whenever a text-entry box appears, simply tap the microphone icon on the virtual keyboard and speak.

-Google Maps with Navigation provides free, traffic-enhanced,turn-by-turn navigation.

-Longer battery life due to power savings.

-Faster power-up time

NOTE:  You will need 25mb of free internal memory to install this update.  The easiest way to do this is go is to go tnto the System Settings -> Manage Applications and go to the "Browser" application.  There will be an option on the page labelled "Clear Cache".  If you use your browser much then this folder will probably be over 25MB and now you have the space you need to install.

On my install, I lost all my contacts.  Luckily, I do my contacts through Gmail.  All I had to do was force a sync of my contacts with Gmail and I was back in business.  One quirk was that a few contacts (Husbands / Wives who share a Facebook account) were merged into a single contact.

Friday, May 14, 2010

How To Write Clean Multi-Step Code

Scenario

You have a process with some number of steps and each step must complete successfully before the next step can continue.  A scenario I've seen before in peer reviews and production code is a nested set of IF statements to determine if the next step should be processed, etc.
I've provided a simple (yet verbose example) of what this code might look like below.



Notice that we're checking each call to see if the previous call worked.  As you also may see we are duplicating essentially the same code over and over again.

A cleaner way to do this is to implement a while loop and standardize the code.  The loop will call each item in sequence and check if it should continue processing for each step.  As you can see this is a much cleaner way to implement a multi-step piece of code.

Debugging SQL Objects

If you are using Visual Studio and open up a SQL object (proc, function, etc) you have the option to right click and set a breakpoint much like you can with C# or VB.NET, etc.

If you are a purist (I guess I would call myself one) then you want to do all your SQL stuff in SQL.

A great way to debug objects in the database is to use a statement to output the various aspects of the execution of your objects to the output window in your database tool.

In MS SQL, the command you would want to use is PRINT.  In the example below, I have a procedure that validates some number.  And my business requirement is that this number cannot be less than 0.



As you can see here, its very simple to put these print statements in code.  This is a very simple example but you can imagine having a complicated set of code where you needed to be able to run it and get meaninful information regarding the execution, this would be a great way to do that.  You could throw exceptions as well but that's another topic for another day.

This last screenshot is what the output looks like when I tested my object.


You can do the same thing in Oracle, but the command you would want to use is DBMS_OUTPUT.PUT_LINE.

Tuesday, May 11, 2010

Using IIS Locally

This is really a quick note more than anything.  I've had peers many times ask me to lend my eyes to a problem they've had when testing some web code.  Typically, the code works on the server but not on the local machine.

Without fail, 99% of the time the problem is the developer is running the ASP.NET Development Server (Cassini) on the local machine rather than running the application through IIS.

The built-in web server for ASP.NET is ok for simple things; like does a page display correctly, but lousy for testing full features of your application.

Namely, here a few things that don't work using the ASP.NET web server.  Keep in mind, I haven't tried these things in VS2010 so I'm not sure if its still an issue or not...

1. doesn't except any connections from remote machines (localhost only, so you can't have peers look at your work)
2. Server.MapPath doesn't work
3. Some File IO operations don't wory
4. IIS security type things don't work
5.Can't run non-ASP.NET pages (IE, no classic ASP and other types of scripting)
6. SSL may not work (haven't tried it)

Monday, May 10, 2010

The goto Statement

The goto statement has it roots back in Basic prior to its arrival in .NET.  The value of the goto statement is the ability to jump around in your code.  Where I find these to be most useful is in cases where you may need to re-run a portion of your code.  Or, you don't want to or can't use a recursive call.


In the example above, I'm calling an important but unpredictable web service.  Let's say that Internet connectivity is spotty and I can't always connect to my web service.

Notice above the code to connect to my service I have put a label (ReAttempt:).  You can use any name you want for your label (aside from a keyword) followed by a colon.

Now, I call my service and attempt to do something.  I've setup my example to return response object with a Failed Boolean property and an error message.  So, my request fails and I determine its due to not being able to connect to the remote server (I parsed the error message for the purposes of the demo and know that's what the message means).  I dispose of my existing web service and tell the program to "goto ReAttempt".  My code will now start back declaring the web service.  Since I increment the maxAttemptCount variable, my next attempt will be attempt 2.  (Unlike say a recursive function, I'm in the same instance of my method and so my variables don't reset, etc.)

So if by the 3rd attempt I can't connect to my service, then I'll throw an exception for my application to handle.

As you can see, I've quickly allowed my application to be fault tolerant and re-try some type of request to a resource without having to write very much code.

Doing Calculations in .NET

In the following example, I'm trying to do a basic mortgage payment calculation.  Assume that instead of hard coded values, I've collected these values from user input and validated them accordingly.

I know from doing application development for a bank before my number will be less than 1% of the loan amount and more than double the loan amount divided by the term (in months).

That means my range would be between about $1,100 (400,000 / 360) and $2,000 (200,000 x 1%).  That is a broad range but I should be somewhere in there.

But in fact, when I run my formula, I get 0.  My code is shown below.



What I like about this code is I showed what the math formula I was solving is.  That is about all I like about my code here.

The issues I have with this code:
1. Magic variables.  What do P, I, L, J, N, and M mean?  Since I have hard coded values here, it makes it easier to guess but its not very intuitive.

2. Since my formula is all bundled into one line, I can't check the intermediate steps to see where a potential problem is.

3. Some of these tasks might be useful in other areas but the code is not reusable.

4.  All my values are doubles because the Pow (Power) function requires a double as an input.  If I didn't do this, I'd end up having to cast all my variables.  Personally, I like to stick with the data type that is most reasonable for the data being contained, so I want to fix this.

Problem:  The actual problem in the code here is that I should be taking 1 - (1 + J)^N.  Instead, I'm doing (1 - (1+J))^N.  I get a number so small that it is effectively 0.

So, I've determined this code is hard to understand, test/maintain, and since I might not be the one supporting the code, I need to clean it up.

Here is an example of taking a formula and creating clean, reusable, and understandable code.

I cleaned this up by creating a top level function that wraps all the calculations (CalculateMonthlyPayment) but within that I actually break down each step of the formula so I could break point during debugging and see what the actual value(s) are.

Notice I also put the formula in the function that is calling calculate payment method.  This is so if another developer works on this, they know (without digging) what this code is doing.

Also notice that I'm able to use decimals instead of doubles now.  Tho, I do have to convert back to a decimal from a double in the CalculatePaymentRate function.

When I ran this, I found my bug and was able to fix the problem.


In summation, don't try to write calculations in one line they're hard to debug and easy to make mistakes.  Break your formula down into steps and solve each piece clearly so you can debug it.

Friday, May 7, 2010

Enums

I received an email from a former co-worker asking about enums and I thought this would be a good quick entry for today.

The question was, what is the difference between the following two enum declarations:
a.  public enum Genders { Male, Female };
b.  public enum Genders : int { Male, Female };

The answer, in this case, is there is no difference!  The reason is by default an enumeration's underlying data type is an int.

However, the underlying type can be changed to any integral type except a char. So byte, long, etc...

But, you'll have to cast your enum value to that type to get the data out

Ex. (this is from Microsoft's MSDN site)

enum Range : long { Max = 2147483648L, Min = 255L };

long x = (long)Range.Max;


Enums are also 0-based indexes by default. So the first position (Male) will be "0" in both of these cases.

You can change the starting index number by setting the value of the first item in the enum:

public enum Genders { Male = 1, Female};

Now, Male will be 1 and Female will be 2.  And as you guessed if you had a NotSpecified then it would be 3.

Lastly, you can set your own enum values as well.

public enum FoodRanking { Mexican = 1, Brazilian = 6, Italian = 2, American = 3, German = 4, French =5};

**Notice, your values don't have to be in order.

Wednesday, May 5, 2010

Microsoft Kin

In trying to keep my blog relevant, I wanted to mention that tomorrow Microsoft is releasing its entry into the social networking world with the release of the Kin and Kin Two phones.  The phones will retail through Verizon for $50 and $100 respectively.

These are not "smart phones" but rather social phones giving access to Facebook, Twitter, and Microsoft's social site "The Studio".  The Studio will feature a timeline approach where users can view their friends activities and posts on a day-by-day basis.  Since these are not a smart phone, there is no App Store and relatively few software packages beyond the things I've already mentioned.

Both models feature a physical keyboard with Kin having a Blackberry style look and the Kin Two having a slide out Motorola Droid look.  The Kin Two has double the memory at 8GB and features an HD capable camera where the base model has a regular def camera.

You can see these devices at http://www.kin.com/ and as I said they'll be released tomorrow.  While geared at teens, this product might also be good for people who want to check social media on the go but don't need the featuers of a full blown smart phone at nearly double the price.

On a minor footnote, HTC has also released the Incredible which is their more direct competitor to the Motorola Droid.  No slide out keyboard but it features a 3.7" screen, 1GHz processor, 8GB memory, and Android 2.1 OS.

Tuesday, May 4, 2010

Understanding Your Data Via SQL Objects

Prior to ASP.NET Dynamic Data and Entity Framework, I began development of a similar solution realizing I spent a lot of time writing the Database I/O logic and admin screens rather than focusing on business rules and the "meat" of the application UI.

My solution included a tool that used SQL tables and stored procedures to create a fully operational class, much like CodeSmith and other code generation tools.  But because I like to build my own solutions I still use my CodeGen tool and am in the process up updating it to use templates to allow for a more flexible implementation of my objects in future.  Eventually, I may provide this tool for free and catapult myself into Internet fame and Theoretical Dollar fortune but as of now, I don't have the new Code Gen tool in a usable state.

So, how am I doing this?  Well, its information that is already readily available in SQL.

In your SQL database you have a series of objects the define the tables,views, procs, etc that you've created.

SYSOBJECTS

The first of these tables is the SYSOBJECTS table.  This contains a top level list of basically everything you've ever created in your database.

To see what objects are in your database is as simple as Select * FROM SYSObjects

This will return all the objects in your database.  However, there is some confusing and potentially useless data so I'll walk through what is what.  ID and Name will be the two most useful items.  ID will allow you to find the columns in these objects and the Name is the actual name you specified of your object.

You'll notice that primary keys, foreign keys, etc also appear in here.  Any object that is a child of an object (such as the keys) will have a "parent_obj" ID.

The XTYPE is the indicator for what the object is.  So a user table is 'U', system (SQL) stuff is 'S', Primary Keys: PK, Foreign Keys: F, Views: V, and Procs: P.  There are a few others as well.

For the purposes of this example, to find all the user tables you'd look for an XType of 'U' and a status > 0. Without the status check, you can end up with some tables that are not yours.  I'm not sure why this is (this column is undocumented in SQL), but I found that this fixes the problem as user tables have a positive status value.

So, at this point we know we have tables.  Now what?  Now, we need to inspect each table's design.

SYSCOLUMNS

Once we have ID of the object we want to inspect, we can find out what its contents are from the SYSCOLUMNS table.

SELECT * FROM SYSCOLUMNS WHERE ID = 12345 where 12345 would be your table's object ID.

This will return a lot of stuff but only a few fields, again, are important.  Name will be the name of the column, xtype will be the data type of that column (more on that later), length is the length of the field in terms of its dataype (IE, a string type datatype's max number of characters or the number of bytes for an integer), scale and precision is there, order of the column in the table, and if the field allows null.  There is additional info but for the sake of brevity I won't discuss them.

As you can see, you can tell a lot about your data via these objects.  You do have to do some mapping from the SQL types to the .NET types, but that isn't difficult.

Speaking of types, you get that information from SYSTYPES.  Simply join the xtype of SYSCOLUMNS to the xtype of SYSTYPES.  SYSTYPES has some default information about the data type but mainly, name is what you are concerned about.  I only look for types of a status of (0,2) because otherwise you get back some funky stuff (one day I'll figure out why this is).

Misc

I should mention that for tables and views you will get back all the columns displayed.  As of yet, I haven't figured out how to relate fields of a view back to its source table.

For procs you will only get the parameters from the syscolumns table.  If you're trying to write an object around a proc you have to prompt the user in the Code Gen tool for some values so you'll get a result set back.  You can then get the column names and associated data types of the fields returned to build your class definition.

There are other tables for permissions, users, keys, indexes, etc that you might want to explore.  I would be careful of trying to modify these tables as it may have undesirable results.

Putting It Together

I didn't include any code here because it would be quite length and I encourage you to play with your own implementations.

Some things you can do with this data:
1. Build an object using the table name and create correctly typed declarations/properties for each field.  As mentioned earlier, you will have to map data types in SQL to a .NET type IE bits are Boolean and most character fields are strings, etc.

2. Using the syscolumns you could enforce some basic validation is null allowed, max length, etc.

3. Identify primary keys in your classes, etc.

4. Create CRUD operations select, insert, update, and delete.

Monday, May 3, 2010

Content Management Systems for .NET

I'm frustrated with the Content Management System (CMS) offerings for ASP.NET/SQL.

I tried to install 3; DotNetNuke, AxCMS, and Umbraco.  All three failed the initial installation.

DotNetNuke would have been the easiest if had worked.  It used the Web Platform installer.  The annoying thing with the installer is it requires a reboot which means you have to do this after hours on a production web server.  I was able to get through to the screen where I setup my IIS information for the site and the SQL database screen.  On the SQL screen, I picked my existing SQL Enterprise DB instead of using SQL Express.  During the DB installation part, it failed due to some error with the DNN database script not having something declared properly.  This caused the entire installation to fail and when I went to clean-up, nothing was written to the DB, updated in IIS, and only the files remained in my predefined folder location.
AxCMS had a command line batch install and it failed on most of the steps of the install.  Allegedly, there were configuration files you could tweak per the install prompts but the directories it indicated didn't exist.

Umbraco I extracted to a folder and then created as a website.  It fails trying to register AJAX components but when I check the bin folder I found all the DLLs and versions that the web.config specified.

There needs to be a CMS solution that is easy to install and use!?  I'm sure there is one out there but many of the sites for these products are lacking.  The feature list is vague, there is no demo site, and very few screen shots to see what the product looks like.

Building a PC -- considerations

A technology but not programming related item... building a PC.  I'm not going to talk through the steps but I had some tips and tricks that should make building and troubleshooting your next build project faster and easier.

1. Start with the motherboard first.  To me, picking the motherboard is one of the most important decisions.  Many people think having a big fast CPU is the key to performance but the motherboard is equally a factor.  (As an aside... engine building is the same way.  People focus on cams, pistons, intakes, carbs, etc... but cylinder heads are a big determining factor of performance.)

Brand wise, I like (in no order) the DFI LanParty series (if they still make that series), MSI, and Asus.  I currently run an ASRock board in my desktop but I did that because it supported two different types of RAM so I didn't have to upgrade my RAM right away.  Its been a reliable product but I don't know enough about them to endorse them. 

Expect to spend $100-$200 on a motherboard.  I tend towards $200.

I like a site like NewEgg because it allows for filtering and has reviews to help you find a good product.  I'll take it a step further and use Bing or Google to find technical reviews on the several MoBo that I'm considering.

Some boards support an older and newer memory type (like my ASRock).  You can save some money here on your build by using existing memory now and upgrading later if you're on a tight budget.

When building your machine, power up the system after the motherboard is installed.  If nothing happens, the board is probably bad and needs to be replaced.  You should get some type of POST screen and possibly a message that the processor is missing.

I've found that motherboards have a high DOA rate... in my experience in the 30-40% range.  So there is no advantage to installing everything before test firing the machine.

2. CPU.  CPUs also have a fairly high DOA rate, probably 20%.  After testing the MoBo be sure test with the CPU installed (make sure the fan is installed! See below...).  You should get an error at this point that no drive/OS can be found and all indications are your build will be successful.

Be sure to use thermal grease between the top of the CPU and the heat sink/fan combo.  It only takes seconds for the CPU to reach the 130-140 degree mark!  Not having enough (or having too much) will cause the CPU to overheat and fail.  Most BIOS systems will have an area to view the CPU temp.

3. Drive performance.  Always get at least a 7200 RPM drive... the 5400 RPMs are too slow and are typically used on laptops to save power.

4. If you want to play games, watch movies, etc... you'll need a graphics cards as the integrated card probably won't cut it.  You should be able to find something workable in the $100 range and want it to have at least 1GB of its own memory onboard.

5. Intel vs AMD?  If cost is an issue, go with AMD.  I jumped on the AMD band wagon back in the mid-2000s but I had several problematic builds.  One machine the chip blew up almost immediately after powering on the machine.  On another build, the machine would randomly shutdown.  I also noticed strange errors periodically when closing a program.  Things may have changed but it seems like the Intel platform is a little more stable.

Sunday, May 2, 2010

HTC Droid - 5 Months Later

I've had my HTC Droid for about 5 months now and have really have a good understanding of the device now and what I like and don't like about it.

For $99, I would have to say this is one of the better "smart" phones on the market.

PROS
- Gmail integration is top notch.  My "People" (contacts) syncs flawlessly with Gmail.  I prefer to edit contacts in Gmail on a PC and changes are automatically propogated.

- Facebook integration.  I'm losing interest in Facebook but the phone allows you to map Facebook profiles to contacts which means I automatically get a profile picture when someone calls without having to do anything plus I get birthday information and can quickly see any updates people have posted.  This really helps me keep in touch with what is going on with my friends, etc.

-Camera.  The camera takes great pictures (I think its a 5 MP camera).  I rarely take my 10MP Canon Rebel anywhere unless I need/want really really good photos.  The built-in album allows you to quickly and easily share pictures and video via email, Facebook, or YouTube.

- Apps.  The Market apps are comparable to many of the iPhone apps available.  Some I downloaded and haven't used (like the GPS breadcrumb app) but things like Shazam (identifies studio recorded songs by listening to the song though the microphone), IHeartRadio (Clear Channel stations), and Pandora (create a station of your favorite bands) are great.

-Phone.  The call clarity is very good on Verizon.  Phone functionality is easy to use like a phone should be.

CONS
- Memory Management.  I don't like that apps run in the background, but running Advanced Task Killer takes care of that and saves battery life.  There might also be a memory leak because after a few days the phone seems to be sluggish.

- Keyboard.  Its hard to type unless you turn the phone sideways, which requires 2 hands instead of 1.  Sometimes the phone is slow to switch the orientation as well; which sucks.

- Updates.  I really expected to see a system update already.  Specifically, I wanted to get some of the Android 2.0 OS functionality.

Saturday, May 1, 2010

Steve Jobs on Adobe Flash

This post pretains to the open letter from Steve Jobs in late April regarding Flash operating on iPod, iPhone, and the iPad.

See the letter at http://www.apple.com/hotnews/thoughts-on-flash/

It never ceases to amaze me how full of himself and his products Steve Jobs is.  In the Mac vs. PC battle for market share, Mac is 2nd place in a 2 man race... by a mile.  PC sales drawf Mac sales.  People want options and the PC platform offers them. If you don't believe that ... visit the Mac software shelf in a store and its about 1/10th the size of the Windows section.  The PC hardware section in Frys runs along almost one full wall and at least a dozen rows.  The Mac section ... two rows.

Ironically, two of the best selling products on the Mac ... Adobe Photoshop and Microsoft Office.  Steve Jobs should be thankful that these vendors reach out to Mac users and provide them some of the great software packages that PC users enjoy.  Those two rows in the store are going to look pretty empty if they lose some of these popular titles.  And you also shouldn't blame a vendor as the #1 reason for your system to crash.  Jobs basically called Adobe Flash junk not only in terms of security but performance.

Apple doesn't invent anything... they repackage ideas in their own shiny overpriced way and the Apple snobs eat it up.  But the fact is Apple products have many flaws (ex: if your battery dies on your iPad, iPhone, or iPod... you have to buy a refurbished one; no replacement batteries)  and shouldn't be throwing stones.