Saturday, June 19, 2010

Ultimate Windows Mac - Part 1

This is my first post in a series on configure a MacBook for Windows power users.

First a little history (skip next 2 paragraphs if you're in a hurry). I grew up with PC's. My dad's business Agvise used computers for data acquisition in addition to regular office use and they tended to build their own computers most of the time. Therefore the first PC he purchased for me before college in 1996 was one I got to build. It was a Cyrix 6x86 which was the budget way to get a faster chip at a lower price then what Intel had to offer. In addition to PC hardware I grew up using DOS and spent plenty of time using Windows 3.1 before Windows 95 came along. I built every desktop I ever owned and then in December of 2000 the company I had just started at, MediaDVX, bought me a laptop and then a year or so later upgraded it to a business class Compaq M500. That thing was so rock solid I never had any desire to go back to tinkering with building my own computers and continued using HP/Compaq up until fall of 2007 when my trusty beaten up NC6000 finally died. So it's September 2007 and I have never owned ANY Apple product so far (I miss you RIO MP3 players!) and for the most part I'm really not an Apple fan but a couple of co-workers began showing off their personal MacBook Pros and introduced me to Bootcamp. I thought the hardware had interesting features, I was open to exploring OS X, and being able to boot into Windows or run the same instance of Windows in VMWare sold me on purchasing a 15" MacBook Pro and it's been downhill from there. Since late 2007 I've purchased the following: iPod Touch, iPod Classic, iPhone 3G (waited in line), Apple TV, MacMini, iPhone 3GS (for Fiance), and an iPad (waited in line). The one thing about my MacBook Pro I couldn't get over is the keyboard and the lack of some features Apple is/was behind on adding like eSata, HDMI, and a swappable media bay like HP, Lenovo, and others have. Once Windows 7 came out I had pretty much stopped using OS X all together on my MacBook Pro so I was ready to switch back to a PC.

I picked out an awesome combo of power and portability in the Lenovo T410S. I had it custom built, waited a few weeks for it to show up, and began using it. It took me many hours spanned across a week or two to get all the software I need to do development installed and configured on it. Then the big day came, it was time to start using it as my primary machine. Boy was I in for disappointment. The wired NIC lost connectivity every hour. The Display Port connection seemed to have interference issues and on top of that would "black out" the screen for a second every couple minutes. I found other people on the internet who had experienced both of these issues and I decided I didn't have time to work through these bugs. (Sidebar: The T410s has a multi-touch trackpad. I hoped it was as good as Apple's. With a ton of tweaking I got it to work "better", but even then it is not even close to as polished as Apple's, contrary to what some reviewers said) This was a $1700 laptop and it shouldn't have these issues so the laptop has been RMA'd much to my disappointment. Now I needed a replacement and since Apple had stood behind their products for me in the past (my MBP died and they replaced the screen, logic board, hard drive, and some fans, all for FREE! since the root issue was a manufacturing defect) and considering I'd just started getting into doing iPhone development using MonoTouch I decided I'd once again go back to Apple and I'm now typing this on my new 13" MacBook Pro!!! Thanks to Mitch Coopet for convining me I didn't need the i5 in the 15" since I really wanted a smaller notebook.


On to the good stuff.

Here is the list of System Preferences I tweak out of the box:
  1. Add right click if your MacBook trackpad supports it:
    • Trackpad -> One Finger -> check "Secondary Click" -> Bottom Right Corner
  2. Configure Expose (probably my favorite OS X feature)
    • Expose & Spaces -> Expose -> Active Screen Corners
    • Set Bottom Left corner to "All Windows"
    • Set Bottom Right corder to "Desktop"
  3. Shrink size of dock since I won't be using the laptop from 500ft away.
    • Dock -> Size -> adjust to your comfort level
  4. While you're at it remove Dock Items you probably won't use. I remove:
    • Mail
    • iCal
    • Address Book
    • Photo Booth
    • GarageBand
    • Time Machine (I'll be using CrashPlan thank you)
  5. Configure OS X so you can tab to checkboxes and drop downs in web browser.
    • Keyboard -> Full Keyboard Access -> All controls


Here is the list of software I immediately load onto my MacBook (first two will help OS X behave more like Windows):


Configure Double Command - I check the following to make the Mac keyboard more like a PC:
  • Command Key acts as Option Key
  • Option Key acts as Command Key
  • Control Key acts as Command Key (you won't have a Control key, but as far as I can tell the Control Key is only there because Steve Jobs doesn't like mouse buttons)
  • PC style Home and End Keys


Configure Quicksilver - since we don't have a control key we need to change the hot key. I use "Option Key - Space bar". Note if you configured Double Command like above my "Option Key" is actually the "Command Key" on the physical keyboard. If you want to use the physical "Control Key" then you'll need to configure Spotlight to not use that Hot Key first under "System Preferences -> Keyboard -> Keyboard Shortcuts -> Spotlight"


This should get you by until we install Windows using Bootcamp in Part 2. In preparation for Part 2 I've decided to immediately void my warranty and do the following:
  1. Add a SSD drive. Currently debating between Intel X25-M and Crucial's RealSSD C300 due to the recommendation by The Tech Report
  2. Add the SSD drive in place of the DVD drive using a MCE OptiBay

I opted not to use Apple's SSD offering and instead save money by adding it myself. Since I'll be using 2 hard drives I plan to purchase a smaller SSD and then store most of my data (music, movies, etc) on the regular hard drive which will save even more money since SSDs are still relatively expensive.

Note, I'll be updating the software list above as I continue my build.

Thursday, June 3, 2010

Move Google Apps Domain To DiscountASP.NET

Tonight I signed up for web site hosting plan with DiscountASP.NET. Partially forced to because Google was indexing by blog at blog.cdeutsch.com as cdeutsch.com (due to the way I had Google Apps configured, D'oh!), but I also want to do some experimenting with ASP.NET MVC 2 and play around with some custom iPhone web services.

DiscountASP.NET wants you to point your domain at their nameservers for their hosting to work. This is kind of a bummer since I was happy with Google Apps handling that. The good news though is this CAN be done! I figured out how to do the CNAMES myself and had been smart enough to write down the info I needed before switching nameservers. Unfortunately I didn't write down the MX Records but with help from Steve Trefethen's blog I was able to fix them. My settings are below:

CNAME Record Manager
Canonical Name Record: Creates an alias from one hostname to another.
Use of CNAME is generally not recommended.
Domain NameDestination TTL

blog.cdeutsch.com


ghs.google.com

3600

calendar.cdeutsch.com

ghs.google.com


3600

docs.cdeutsch.com

ghs.google.com

3600

mail.cdeutsch.com

ghs.google.com

3600

sites.cdeutsch.com

ghs.google.com

3600


start.cdeutsch.com

ghs.google.com

3600






MX Record Manager 
Mail Exchanger Record: Identifies the email server that handles email for a domain.
Domain NameDestination DistanceTTL

cdeutsch.com

ASPMX.L.GOOGLE.COM

10

3600

cdeutsch.com

ALT1.ASPMX.L.GOOGLE.COM

15

3600

cdeutsch.com

ALT2.ASPMX.L.GOOGLE.COM

15

3600

cdeutsch.com

ASPMX2.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX3.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX4.GOOGLEMAIL.COM

20

3600

cdeutsch.com

ASPMX5.GOOGLEMAIL.COM

20

3600







The second part of my mission was to redirect www.cdeutsch.com to just cdeutsch.com. Due to DiscountASP.NET's awesomeness they support II7 and the IIS Rewrite extension so this is super easy. Just update your web.config with the following:

<system.webServer>
 <rewrite>
  <rules>
   <rule name="Canonical Host Name" stopProcessing="true">
    <match url="(.*)" />
    <conditions>
     <add input="{HTTP_HOST}" negate="true" pattern="^cdeutsch\.com$" />
    </conditions>
    <action type="Redirect" url="http://cdeutsch.com/{R:1}" redirectType="Permanent" />
   </rule>
  </rules>
 </rewrite>
</system.webServer>


Or if you want to do the reverse (cdeutsch.com to www.cdeutsch.com) :

<system.webServer>
 <rewrite>
  <rules>
   <rule name="Redirect to WWW" stopProcessing="true">
    <match url=".*" />
    <conditions>
     <add input="{HTTP_HOST}" pattern="^cdeutsch.com$" />
    </conditions>
    <action type="Redirect" url="http://www.cdeutsch.com/{R:0}" redirectType="Permanent" />
   </rule>
  </rules>
 </rewrite>
</system.webServer>

Now that I had that working I needed some content. What better way to start then with a fresh ASP.NET MVC 2 website. I started with the basic template built-in to Visual Studio 2010. You'll need to go to your project's References and click "Properties" on the "System.Web.Mvc.dll" and change "Copy Local" to "True" to get MVC to work on DiscoutASP.NET's servers. More info here. You'll also want to make sure you configured your web application to run using the .NET Framework 4.0. Framework 3.5 will work for MVC 2, but in my control panel it defaulted to Framework 2.0 and was throwing errors. When I went to fix it the only other option I saw was 4.0, it's possible there is a 3.5 settings somewhere, if there is feel free to try that too:  UPDATE: after talking to Michael Maddox I realized the errors I got were probably because I had my solution/project targeting 4.0. So you can either do the steps below if your project is for 4.0, or change your project to target 3.5 and then you can skip this step.
  • In your Control Panel go to "IIS Tools"
  • Under the "ASP.NET Version" tab set the version to "4.0".
  • Make sure after you hit "Update" you read the warning and click "Update" (or whatever it says) again.
If you found this helpful and you're going to sign up for DiscountASP.NET, please use my referral code: CDEUTSCH

Saturday, May 29, 2010

MonoTouch.Dialog: Improved List Documents!

After completing my last example on listing Documents using MonoTouch, Miguel de Icaza pointed out that MonoTouch.Dialog could make it easier. He was right and below are the results.

Two ways to start off, you can add an "IPhone Window-based Project" and then add a "UINavigationController" to the "MainWindow.xib", or do the route I took and create a "iPhone Navigation based Project" and just delete the extra "RootViewController.xib" we won't be needing.



If you haven't already, download MonoTouch.Dialog (use the "Download Source" link at the top) and then add a reference to it in your project and also be sure to add a "using MonoTouch.Dialog" at the top of "Main.cs"

Below is all the code I need to place in Main.cs to do exactly what my last blog post did which used a TON of extra auto generated code. The code I added starts under the "EDITED" comment.

public class Application
 {
  static void Main (string[] args)
  {
   UIApplication.Main (args);
  }
 }

 // The name AppDelegate is referenced in the MainWindow.xib file.
 public partial class AppDelegate : UIApplicationDelegate
 {
  // This method is invoked when the application has loaded its UI and its ready to run
  public override bool FinishedLaunching (UIApplication app, NSDictionary options)
  {
   
   window.AddSubview (navigationController.View);

   
   //EDITED: this is it!!! Takes care of generating the whole Table View!
   var menu = new RootElement ("Documents"){
    new Section("") {
     from ff in System.IO.Directory.GetFiles(Environment.GetFolderPath (Environment.SpecialFolder.Personal)).ToList()
      select (Element) new StringElement (new System.IO.FileInfo(ff).Name)
    }  
   };
   var dv = new DialogViewController (menu) {
    Autorotate = true
   };
   navigationController.PushViewController (dv, true);    
   dv.Style = UITableViewStyle.Plain;
   
   
   window.MakeKeyAndVisible ();
   
   return true;
  }

  // This method is required in iPhoneOS 3.0
  public override void OnActivated (UIApplication application)
  {
  }
  
 }

You'll need to read my last blog post if you need to add some files to the "Documents" directory (there aren't any by default).

Here are the results or those 12 lines of code (yes, the last sample only had 5 lines added but these extra 7 lines eliminated LOTS of auto generated code and is much simpler):



Amazing! Miguel de Icaza and the Mono/MonoTouch crew didn't stop at the awesome achievement of bringing C# and the .NET Framework to IPhone development; with MonoTouch.Dialog they've outright made Apple and their ancient Object-C language embarrassing. If you can't see the ROI on the $400 a MonoTouch license costs, then your time isn't worth money.

Be sure to visit the MonoTouch.Dialog page on Github and Miguel's blog post on it for more amazingness!

MonoTouch - List Documents

Use the following MonoTouch code to easily list all the files in your Applications Documents folder. First create a regular IPhone Navigation based Project.


Open "RootViewController.xib.cs" and add the following code. I only added five lines of code. I've put a "//EDITED:" comment in front of each line that I added. Make sure to add a "using System.Linq" to the top of the file as well.


partial class RootViewController : UITableViewController
 {
   //EDITED: list to hold file names.
  private System.Collections.Generic.List&lt;string> dataItems = null;

  public RootViewController (IntPtr handle) : base(handle)
  {
  }

  public override void ViewDidLoad ()
  {
   base.ViewDidLoad ();
   //Show an edit button
   //NavigationItem.RightBarButtonItem = EditButtonItem;
   
     //EDITED: build list of files.
   string path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
     dataItems = System.IO.Directory.GetFiles(path).ToList();
   
   this.TableView.Source = new DataSource (this);
  }

  /*
  public override void ViewWillAppear (bool animated)
  {
   base.ViewWillAppear (animated);
  }
  */
  /*
  public override void ViewDidAppear (bool animated)
  {
   base.ViewDidAppear (animated);
  }
  */
  /*
  public override void ViewWillDisappear (bool animated)
  {
   base.ViewWillDisappear (animated);
  }
  */
  /*
  public override void ViewDidDisappear (bool animated)
  {
   base.ViewDidDisappear (animated);
  }
  */

  /*
  // Override to allow orientations other than the default portrait orientation
  public override bool ShouldAutorotateToInterfaceOrientation (UIInterfaceOrientation toInterfaceOrientation)
  {
   //return true for supported orientations
   return (InterfaceOrientation == UIInterfaceOrientation.Portrait);
  }
  */

  public override void DidReceiveMemoryWarning ()
  {
   // Releases the view if it doesn't have a superview.
   base.DidReceiveMemoryWarning ();
   
   // Release any cached data, images, etc that aren't in use.
  }

  public override void ViewDidUnload ()
  {
   // Release anything that can be recreated in viewDidLoad or on demand.
   // e.g. this.myOutlet = null;
   
   base.ViewDidUnload ();
  }

  class DataSource : UITableViewSource
  {
   RootViewController controller;

   public DataSource (RootViewController controller)
   {
    this.controller = controller;
   }

   public override int NumberOfSections (UITableView tableView)
   {
    return 1;
   }

   // Customize the number of rows in the table view
   public override int RowsInSection (UITableView tableview, int section)
   {
    //EDITED: return count of files.
    return controller.dataItems.Count();
   }

   // Customize the appearance of table view cells.
   public override UITableViewCell GetCell (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    string cellIdentifier = "Cell";
    var cell = tableView.DequeueReusableCell (cellIdentifier);
    if (cell == null) {
     cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);
    }
    
    // EDITED: Configure the cell.
       cell.TextLabel.Text = (new System.IO.FileInfo(controller.dataItems[indexPath.Row])).Name;
   
    return cell;
   }

   /*
   // Override to support conditional editing of the table view.
   public override bool CanEditRow (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Return false if you do not want the specified item to be editable.
    return true;
   }
   */
   /*
   // Override to support editing the table view.
   public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    if (editingStyle == UITableViewCellEditingStyle.Delete) {
     controller.TableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
    } else if (editingStyle == UITableViewCellEditingStyle.Insert) {
     // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view.
    }
   }
   */
   /*
   // Override to support rearranging the table view.
   public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
   {
   }
   */
   /*
   // Override to support conditional rearranging of the table view.
   public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
   {
    // Return false if you do not want the item to be re-orderable.
    return true;
   }
   */

   // Override to support row selection in the table view.
   public override void RowSelected (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
   {
    // Navigation logic may go here -- for example, create and push another view controller.
    // var anotherViewController = new AnotherViewController ("AnotherView", null);
    //controller.NavigationController.PushViewController (anotherViewController, true);
   }
  }
 }

By default your app won't have any files in the documents folder but you can manually add some. In you user accounts "~/Library/Application Support/IPhone Simulator/" directory there will be multiple folders for each version of IPhone OS you can test. Pick the one you'll be test and put some files in the "Documents" folder.


Once that is done you can run your application in the simulator and it should give you the list of files you added to the "Documents" folder. Pretty simple huh?



I'll be using this code in a prototype that uploads Cycorder recordings from my IPhone 3G (I have a separate app for 3GS to use the built-in video recording) to Qwikcast, my company's WebCast presentation software. I'll be using SSH to create a symbolic link so Cycorder saves it's recordings to my applications Documents folder. Then I'll be doing a HTTP Upload to the Qwikcast web server where the video will automatically be encoded, published to a streaming media server, and then available on a "catalog" page for viewing (iPad and iPhone compatible of course) !

Friday, May 7, 2010

Custom iPhone Mount for Evo

Since I was rarely using my Griffin iPhone 3G windshield mount, due to always removing it when parked because I try not advertise I have stuff in my car and I think it's technically illegal in MN to have one, I decided I'd like my iPhone mounted on the dash. Well I think I found a pretty decent spot. See the slide show below for how it was made or if you don't have flash visit my Picasa web album. Read the captions on the photos for more details.


More discussion here on EvoMN.

Monday, April 19, 2010

Printers Suck

Tried to install a consumer, all-in-one printer for the first time in a loooonnnnggggg time tonight. All I can say is WOW! Are we moving backwards in regards to easy of use? How would someone who is not in IT ever use this thing? The printer is a HP C4580 and I'm running Windows 7 Enterprise. What a disaster install. First attempt a "fatal error" happened during the installation itself, but it "found a solution" or at least that's the lie it wanted to stick to. After I finally got the computer to connect to the printer over WiFi, I tried to launch "Solution Center" and it came up with another error and would not launch. Tried to re-run the installer like it suggested and the only option presented was to uninstall which sounded like a great idea to me! The funnest part of the process were the no-warning reboots HP decided to include with the installer. Nothing like hitting Ok and then watching all your windows close.

There is a reason I hate hard copy and avoid printing documents and it's name is HP (printers). I've hated printers ever since I stared using computers and my hatred is completely renewed for at least another 5.

Better go. I have one more program to uninstall (why it left one behind after saying it would uninstall "everything" is beyond me) which I'm guessing will cause a reboot so better publish now. Way to go HP! You suck!

Friday, April 16, 2010

Visa Fail with Authorize.NETs CIM

Just heard from a client that their "Save Credit Card" feature stopped working. They use Authorize.NET's Customer Information Manager (CIM) to securely save the credit cards.

Suddenly the application was just returning:
3,1,290,There is one or more missing or invalid required fields.
Why two, large, successful companies like VISA and Authorize.NET can't tell you which fields they want is beyond comprehension.

According to this message thread:
Visa has a mandate in place that allows us to do $0.00 authorizations to test the validity of a card, but in order to do it they require that an address be passed also. Since VISA is the only company that has this policy, the other card types will be unaffected and not experience the same error.
Up until recently they only required Card Number, Expiration, and Security Code. I tried using a dummy address like the message thread suggested. This would only work if the Authorize.NET Address Verification Service settings were configured to ignore the address, so in my case we'll likely be updating the code to pass the billing address in since we have it anyway.

Thanks for the notice on this VISA and Authorize.NET! You have to wonder how much time and money changes like this cost all the organizations affected?