Friday, December 16, 2011

DotNetNuke Lesson Learned

There are still modules out there using the old setting style for connection strings:
 <appSettings>  
   <add key="SiteSqlServer" value="Server=(local);Database=DNN;Integrated Security=True" />  
 </appSettings>  
I spent the better part of a day and a half trying to diagnose why all the modules from one particular 3rd party vendor wouldn't work on my box... lesson learned.

References NOT Available Upon Request

After receiving a promising resume for a job request, I scheduled an interview with the candidate. The interview itself was fairly straightforward, having all the standard questions about .NET, C# and SQL Server.

The candidate seemed fairly knowledgeable although I would probably get them to do a technical interview if we decided to move forward.

I thanked the individual for coming in, and asked them to forward me 2 or 3 references.

I was somewhat taken aback by their response. “I prefer to get my jobs on my own. I don’t like to bother my former employers with those details.”

I explained to them that we require references to verify their employment, skills and experience. Again, they responded with “I prefer to get my jobs on my own.”

I wasn’t exactly sure what to say, so I simply told them that it’s standard practice and that we would not be able to consider them for a position without references. Begrudgingly, I was told that they'd be sending an email with some references.

Needless to say, I never received a follow-up email.


The Messy Vacation Request

I've worked as both an employee and as a director, so I know how important it is to be sensitive to people's need to take time off and decompress.  Vacations are an inconvenience of course, because they impact project timelines, but booked far enough in advance and approved prior to scheduling and incurring travel expenses will ensure that the impact is minimized.

That is, until you’ve met a certain character whom I had in my employ. As a senior software developer, in charge of a key component to our system, and like everyone else in the company, this individual was expected to book their vacation well in advance (3 months or more).

I received a vacation request email from the individual around the end of April.  The request was for the first 18 business days of September off, as this individual and their family would be flying to Europe.

I had no problem with the request, and after checking with their PM, I sent an approval email. I also cc:’d HR and entered the time into our timesheet system.

Now, fast forward a couple of months.

It's now mid-August, and this individual had been having some troubles on a particular project they were working on.  Things were definately NOT going well, they were well behind and burning through our budget like there was no tomorrow.

It was a Tuesday afternoon, and we’d just finished having a management meeting to discussed the situation. We felt that if he remained heads down for the next 2 weeks, there was a good possibility we’d be able to meet the required deadline and this individual could enjoy their vacation knowing things were well in hand.

That is, until about 2:30pm, when this individual stopped by my desk to remind me that they were starting their vacation at the end of the day.

At first I was rather puzzled. I remarked that I understood this individual to be taking vacation at the start of September. The response was, “No, I asked to start my vacation end of day today.” Considering the circumstances, I was taken a back somewhat. I reiterated my previous statement and assured them that I had approved the dates, and added them to the timesheet system.

They looked at me rather blank faced for a moment, then said, “Well I’ve already booked the tickets for my family and we leave tomorrow morning so….”

I told them I would have to review things and would get back to  them shortly.  As they went back to their desk, I quickly reviewed my emails, and sure enough, the dates I approved were for the beginning of September for 18 days.

I discussed the matter with both our Senior PM and the department head, both of whom were take aback somewhat.  In the midst of this, the individual came back over and informed us that they'd gotten their dates mixed up and was it all right to take the time off starting end of day today instead.

We discussed the matter, but we pretty much knew we couldn't simply deny this individual the timeoff considering the situation, so the decision was made to adjust the schedule and allow the individual to take the time off.

Fast forward 18 business days.

Monday morning comes around, and this individual is nowhere to be found.  I checked my email, and there’s a message saying “Hi, enjoying my vacation, wow this has been great.” Our plane will be leaving this evening at such and such a time, I’ll see you Tuesday. Funny, I don’t remember approving a 19th vacation day off.

So Tuesday morning comes around, and again, this individual is nowhere to be found.  All day, no emails, no phone calls, nothing. Funny, I don’t recall approving a 20th vacation day off either.

So now we’re on to Wednesday… you keeping up? Around noon, I get an email: “Hey there, we’re in Seattle and I’ll be in tomorrow.” Funny thing was, the email message didn’t come from this person's private email account like it had previously, instead it came from their company account. We didn't have webmail, and the only way it’s accessible from the outside is through our VPN... hmmm.  Well, maybe the person brought their laptop to Europe with them, or maybe they were already at home?

Okay, this is no longer funny, I definately did NOT approve a 21st vacation day off.  This individual  finally made it into work on Thursday. Four full weeks (plus a day) since they last graced us with their presence. Needless to say, their tenure at our organization did not last too many weeks longer.


Thursday, December 1, 2011

Creating an Editable GridView inside a ListView in XAML

So it's been a while since I posted last, but recently I had the opportunity to do some serious XAML binding stuff, which I thought I'd share with you. If you've ever wanted an easy way to create an editable gridview inside a listview, it can seem like a pretty daunting task, but actually, it's really not that tough. You can setup a binding scenario that will do 80% of the work for you. Try the following out for size: First, the XAML code:
 <Window x:Class="EditableGridViewExample.Window1"  
     xmlns:local="clr-namespace:EditableGridViewExample"  
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
     Title="Window1">  
  <Window.Resources>  
   <local:BoolToVisibilityConverter x:Key="b2v" />  
   <Style TargetType="{x:Type TextBlock}" x:Key="TextBlockStyle">  
    <Setter Property="Visibility">  
     <Setter.Value>  
      <MultiBinding Converter="{StaticResource b2v}" ConverterParameter="False" >  
       <Binding ElementName="EditModeCheckBox" Path="IsChecked" />  
       <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}" Path="IsSelected" />  
      </MultiBinding>  
     </Setter.Value>  
    </Setter>  
    <Setter Property="VerticalAlignment" Value="Center" />  
   </Style>  
   <Style TargetType="{x:Type TextBox}" x:Key="TextBoxStyle">  
    <Setter Property="Visibility">  
     <Setter.Value>  
      <MultiBinding Converter="{StaticResource b2v}" ConverterParameter="True" >  
       <Binding ElementName="EditModeCheckBox" Path="IsChecked" />  
       <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}" Path="IsSelected" />  
      </MultiBinding>  
     </Setter.Value>  
    </Setter>  
    <Setter Property="VerticalAlignment" Value="Center" />  
   </Style>  
  </Window.Resources>  
  <Grid>  
   <Grid.RowDefinitions>  
    <RowDefinition Height="Auto" />  
    <RowDefinition Height="*" />  
   </Grid.RowDefinitions>  
   <CheckBox x:Name="EditModeCheckBox" Content="Edit Mode" />  
   <ListView Grid.Row="1" x:Name="WindowListView" ItemsSource="{Binding}">  
    <ListView.View>  
     <GridView>  
      <GridViewColumn>  
       <GridViewColumnHeader Tag="ColumnA" Content="Object" />  
       <GridViewColumn.CellTemplate>  
        <DataTemplate>  
         <Grid>  
          <TextBlock Text="{Binding Path=ColumnA}" Style="{StaticResource TextBlockStyle}" />  
          <TextBox Text="{Binding Path=ColumnA}" Style="{StaticResource TextBoxStyle}" />  
         </Grid>  
        </DataTemplate>  
       </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
      <GridViewColumn>  
       <GridViewColumnHeader Tag="ColumnB" Content="Type" />  
       <GridViewColumn.CellTemplate>  
        <DataTemplate>  
         <Grid>  
          <TextBlock Text="{Binding Path=ColumnB}" Style="{StaticResource TextBlockStyle}"/>  
          <TextBox Text="{Binding Path=ColumnB}" Style="{StaticResource TextBoxStyle}" />  
         </Grid>  
        </DataTemplate>  
       </GridViewColumn.CellTemplate>  
      </GridViewColumn>  
     </GridView>  
    </ListView.View>  
   </ListView>  
  </Grid>  
 </Window>  
Now, the codebehind (I put everything in one file to make it easy to use):
 using System;  
 using System.Collections.ObjectModel;  
 using System.Windows;  
 using System.Windows.Data;  
   
 namespace EditableGridViewExample  
 {  
  public class ListItems : ObservableCollection<ListData>  
  {  
   /// <summary>  
   /// Initializes a new instance of the <see cref="ListItems"/> class.  
   /// </summary>  
   public ListItems()  
   {  
    this.Add(new ListData() { ColumnA = "apple", ColumnB = "fruit" });  
    this.Add(new ListData() { ColumnA = "jaguar", ColumnB = "animal" });  
    this.Add(new ListData() { ColumnA = "lullaby", ColumnB = "music" });  
    this.Add(new ListData() { ColumnA = "monkey", ColumnB = "animal" });  
    this.Add(new ListData() { ColumnA = "orange", ColumnB = "fruit" });  
    this.Add(new ListData() { ColumnA = "whale", ColumnB = "mammal" });  
    this.Add(new ListData() { ColumnA = "coathanger", ColumnB = "other" });  
   }  
  }  
   
  public class BoolToVisibilityConverter : IMultiValueConverter  
  {  
   /// <summary>  
   /// Converts source values to a value for the binding target. The data binding engine calls this method when it propagates the values from source bindings to the binding target.  
   /// </summary>  
   /// <param name="values">The array of values that the source bindings in the <see cref="T:System.Windows.Data.MultiBinding"/> produces. The value <see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the source binding has no value to provide for conversion.</param>  
   /// <param name="targetType">The type of the binding target property.</param>  
   /// <param name="parameter">The converter parameter to use.</param>  
   /// <param name="culture">The culture to use in the converter.</param>  
   /// <returns>  
   /// A converted value.If the method returns null, the valid null value is used.A return value of <see cref="T:System.Windows.DependencyProperty"/>.<see cref="F:System.Windows.DependencyProperty.UnsetValue"/> indicates that the converter did not produce a value, and that the binding will use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> if it is available, or else will use the default value.A return value of <see cref="T:System.Windows.Data.Binding"/>.<see cref="F:System.Windows.Data.Binding.DoNothing"/> indicates that the binding does not transfer the value or use the <see cref="P:System.Windows.Data.BindingBase.FallbackValue"/> or the default value.  
   /// </returns>  
   public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)  
   {  
    bool param = bool.Parse(parameter as string);  
    bool combined = true;  
    foreach (bool val in values) combined &= val;  
    return combined == param ? Visibility.Visible : Visibility.Hidden;  
   }  
   
   public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)  
   {  
    throw new NotImplementedException();  
   }  
  }  
   
  public class ListData : DependencyObject  
  {  
   public static readonly DependencyProperty ColumnAProperty =  
    DependencyProperty.Register("ColumnAProperty", typeof(string),  
    typeof(ListData), new UIPropertyMetadata(null));  
   
   public static readonly DependencyProperty ColumnBProperty =  
    DependencyProperty.Register("ColumnBProperty", typeof(string),  
    typeof(ListData), new UIPropertyMetadata(null));  
   
   /// <summary>  
   /// Gets or sets the column A.  
   /// </summary>  
   /// <value>  
   /// The column A.  
   /// </value>  
   public string ColumnA  
   {  
    get { return (string)GetValue(ColumnAProperty); }  
    set { SetValue(ColumnAProperty, value); }  
   }  
   
   /// <summary>  
   /// Gets or sets the column B.  
   /// </summary>  
   /// <value>  
   /// The column B.  
   /// </value>  
   public string ColumnB  
   {  
    get { return (string)GetValue(ColumnBProperty); }  
    set { SetValue(ColumnBProperty, value); }  
   }  
  }  
   
  public partial class Window1 : Window  
  {  
   /// <summary>  
   /// Initializes a new instance of the <see cref="MainWindow"/> class.  
   /// </summary>  
   public Window1()  
   {  
    InitializeComponent();  
   
    // bind datacontext of the list view to a new listitems observable collection  
    this.WindowListView.DataContext = new ListItems();  
   }  
  }  
 }  
   
Oh, and if you're wondering how I got it to format so nicely, I'm using this the following blogspot source code formatting tool.

Wednesday, October 5, 2011

Ok, so you crashed your plane and had to be rescued, now what?

I live in the Western Communities on Vancouver Island, in British Columbia. I recently heard this story and I think it's a great argument why public services like search and rescue should charge for rescues if the person(s) being rescued break the law:

The story starts with a plane crash landing on the beach at the Carmanah Point Lighthouse back in February. The pilot and one passenger, were flying his little plane (apparently something he built himself from a hobbyist kit) when they crash landed on the beach. After climbing to the lighthouse to seek help, the Canadian Armed Forces sent out a helicopter which picked them up and took them to Victoria.

Two days later, the pilot, along with his two brothers, headed back to the plane. Apparently they planned to repair the plane and fly it out before the wind and ocean tides tore it apart. The trek was roughly 16km and the terrain made it extremely difficult to navigate. The three lugged in their tools, a gun for protection (from bears and cougars I imagine), and a replacement propeller.

You ready for this? Guess what, they got lost. When they didn't show up at the lighthouse, they were reported missing and a search began. They eventually made it to the lighthouse, but were not allowed to fly the plane out. The coast guard flew them out by helicopter the next day.

The crown has charged the pilot with unlawfully landing an aircraft in a park and for firearms possession. Additionally, both he and his two brothers, are also charged with trespassing in a closed area.

Uh, hold on a minute, why don't they make them pay the cost of BOTH rescues? It costs the taxpayers money.

As a footnote, from what I understand, the pilot did manage to get a helicopter to hoist the plane off the beach so it could be salvaged.

...and in case you're curious where this happened, here's the location of Carmanah Point Lighthouse:


View Larger Map

Friday, September 16, 2011

ArcGIS Desktop API: Finding a Style in the ESRI Style Gallery

Here's a handy piece of code for finding a style in the ESRI Style Gallery. You simply pass in the style and the category and it returns the appropriate object (if it exists):
 public static object FindEsriWidget(string style, string category)  
 {  
   try  
   {  
     // style comparision is case insensitive, without leading/trailing spaces  
     string normalizedStyle = style == null ? "" : style.Trim().ToUpper();  
     // these are our interfaces and coclasses  
     IStyleGallery gallery = new StyleGalleryClass();  
     IStyleGalleryItem item = new StyleGalleryItemClass();  
     IStyleGalleryStorage storage = (IStyleGalleryStorage)gallery;  
     IEnumStyleGalleryItem list = null;  
     // get the gallery storage item  
     string path = storage.DefaultStylePath + "ESRI.Style";  
     // what we're interested in  
     list = gallery.get_Items(category == null ? "" : category, path, null);  
     // reset our cursor  
     list.Reset();  
     // enumerate the list as required  
     for (item = list.Next(); item != null; item = list.Next())  
     {  
       // if we find a match, use it  
       if (item.Name.Trim().ToUpper().Equals(normalizedStyle))  
       {  
         return item.Item;  
       }  
     }  
   }  
   catch (Exception ex)  
   {  
      // do something here  
   }  
   // not found  
   return null;  
 }  

ArcGIS Desktop API: Finding a point intersect along a polyline

So here a simple way to find a point's intersect along a polyline. The code includes the ability to include buffer distance. So if the point doesn't actually intersect, but is within X meters it will also return intersection for the point. Very handy little piece of code. Enjoy.
 public static double GetPointCollectionIntersectIndex(  
   IPointCollection points, IPoint point, double? bufferDistanceInMeters)  
 {  
   object Missing = Type.Missing;  
   PointClass queryPoint = new PointClass();  
   Polyline testPolyline = new Polyline();  
   // first see if point is in collection  
   for (int i = 0; i &lt; points.PointCount; i++)  
   {  
     // get the point in the collection  
     points.QueryPoint(i, queryPoint as IPoint);  
     // we've found our point along the polyline  
     if (queryPoint.Compare(point) == 0) return i;  
   }  
   // time to do some intersect checks  
   for (int i = 1; i &lt; points.PointCount; i++)  
   {  
     // remove old points if reusing  
     if (testPolyline.PointCount &gt; 0) testPolyline.RemovePoints(0, 2);  
     // create first point  
     points.QueryPoint(i - 1, queryPoint as IPoint);  
     testPolyline.AddPoint(queryPoint as IPoint, ref Missing, ref Missing);  
     // create second point  
     points.QueryPoint(i, queryPoint as IPoint);  
     testPolyline.AddPoint(queryPoint as IPoint, ref Missing, ref Missing);  
     // get the relation operator for the target geometry and topological operator for buffering  
     ITopologicalOperator bufferOperator = testPolyline as ITopologicalOperator;  
     // get the row cursor  
     IRelationalOperator relationOperator =   
       (bufferDistanceInMeters == null ?  
         (IGeometry)testPolyline :  
         bufferOperator.Buffer((double)bufferDistanceInMeters)) as IRelationalOperator;  
     // a disjoint indicates a non-intersection, so if it's false, we have our intersect point  
     if (relationOperator.Disjoint(point) == false) return ((double)i) - 0.5;  
   }  
   // return -1  
   return result;  
 }  

Contract Software Development Opportunities

FYI, if you happen to be in the market for someone with over 21 years experience in Microsoft related technologies, I'm available on contract as a consultant.  Just send me a message through LinkedIn (http://www.linkedin.com/pub/ted-neustaedter/7/a1a/761), mention me in a twitter post @chessknught or email me through one of my webites:  http://www.ProductLair.com (at the bottom) or http://www.slow-pc.com.

I will ALWAYS respond to every inquiry, regardless of whether I'm interested or not, it's just polite to do so.  So if I don't get back to you within 24 hrs, try again 'cuz sometimes I miss stuff.

I don't want my email posted here 'cuz I get tonnes of spam daily and it drives me crazy.

Converting SqlReader rows to Hashtable array


Sometimes you don't want to use LINQ or some other domain type structure to hold your rows of data.  Here's a quick way to convert your SqlReader rows to a Hashtable array and it works for pretty much any row.  


Just keep in mind this doesn't work well if you've got thousands of rows to return, but it's great if you know your dataset is small and want something that's easy to use and ensures that the rows are stored by field name.
 public Hashtable SqlReaderRowToHash(SqlDataReader reader)  
 {  
   Hashtable results = new Hashtable();  
   // read each column  
   for (int i = 0; i &lt; reader.FieldCount; i++)  
   {  
     string orgFieldName = reader.GetName(i);  
     string fieldName = orgFieldName;  
     // append index to name if field appears multiple times  
     for (int index = 0; ; index++)  
     {  
       // the first item does not get an index  
       if (index == 0)  
       {  
         // leave the fieldname as is  
         if (results.ContainsKey(fieldName) == false) break;  
       }  
       else  
       {  
         // update the fieldname  
         fieldName = String.Format("{0}{1}", orgFieldName, index);  
         // use this name if it doesn't exist already  
         if (results.ContainsKey(fieldName) == false) break;  
       }  
     }  
     // add the field to the hashtable  
     results.Add(fieldName, reader[i] == DBNull.Value ? null : reader[i]);  
   }  
   // return the results  
   return results;  
 }  
...and now for a little Silverlight/XAML. I tend to use combos and listboxes a lot, so I thought it would be good to include this little code snippet. It's a simple datatemplate for a combobox that will use a binding path to reference the KEY field in the KeyValuePairs<> generic. This way, when I set the combobox's ItemsSource to point to an ObservableCollection<keyvaluepairs<>>of whatever type, it only shows the KEY field in the drop down. FYI, you should use an ObservableCollection<> because then you can modify the ItemsSource list at any time even if the combobox is in use and it will auto-update the list for you. So here's what the template looks like:
 <combobox itemssource="{Binding}" x:name="MyComboBox">  
  <combobox.itemtemplate>  
   <datatemplate>  
    <textblock text="{Binding Key}">  
   </textblock></datatemplate>  
  </combobox.itemtemplate>  
 </combobox>  

Thursday, September 8, 2011

C# - Excel Workbook Wrapper

This is a nice little wrapper class around the Worksheet COM automation interface in Excel.  You'll need the Excel Office extensions installed.  I use it to open and modify excel worksheets that I've tagged with specific values in certain cells. It's by no means complete, and is a great starting point for building out your own Excel workbook utility class. It makes light work of modifying excel workbooks.
 public class ExcelWorkbook : IDisposable  
 {  
   private Application _app = null;  
   private Workbook _workbook = null;  
   private string _filename = null;  
   public Worksheet ActiveWorksheet  
   {  
     get { return _workbook.ActiveSheet as Worksheet; }  
   }  
   public ExcelWorkbook(string filename)  
   {  
     _app = new Application();  
     _app.Visible = false;  
     _filename = filename;  
     _workbook = _app.Workbooks.Open(filename);  
   }  
   public Range FindItem(string tag)  
   {  
     return FindItem(tag, true);  
   }  
   public void DeleteRow(Range range)  
   {  
     range.EntireRow.Delete(XlDeleteShiftDirection.xlShiftUp);  
   }  
   public void DeleteColumn(Range range)  
   {  
     range.EntireColumn.Delete(XlDeleteShiftDirection.xlShiftToLeft);  
   }  
   public Range FindItem(string tag)  
   {  
     object missing = Type.Missing;  
     Range range =  
       ActiveWorksheet.Cells.Find(  
       tag, ActiveWorksheet.Cells[1, 1],  
       Microsoft.Office.Interop.Excel.XlFindLookIn.xlValues,  
       Microsoft.Office.Interop.Excel.XlLookAt.xlPart,  
       missing,  
       Microsoft.Office.Interop.Excel.XlSearchDirection.xlNext,  
       false, missing, missing);  
     return range;  
   }  
   public void Save()  
   {  
     _workbook.Save();  
   }  
   public void SaveAs(string filename)  
   {  
     _workbook.SaveAs(filename);  
   }  
   #region IDisposable Members  
   public void Dispose()  
   {  
     // nothing to do if there's no app object  
     if (_app == null) return;  
     // close app and wait for finalization  
     _app.Quit();  
     _app = null;  
     GC.Collect();  
     GC.WaitForPendingFinalizers();  
     GC.Collect();  
     GC.WaitForPendingFinalizers();  
   }  
   #endregion  
 }  

C# - Quick and Easy Debugging StopWatch

Here's a quick and easy way to create a "stopwatch" object that you can put in a using() {} block as follows. I just needed something quick and dirty to dump time trial results for some of my tests, so I built this IDisposable extension class. Ya, it's simple, but sometimes that's handy:
 using(DebugStopWatch stopWatch = new DebugStopWatch()  
 {  
 }  
Here's the code:
 public class DebugStopWatch : IDisposable  
 {  
   private DateTime _start;  
    public DebugStopWatch()  
    {  
     _start = DateTime.UtcNow;  
     System.Diagnostics.Debug.WriteLine("Starting..."));  
    }  
    #region IDisposable Members  
    public void Dispose()  
    {  
     TimeSpan ts = DateTime.UtcNow.Subtract(_start);  
     System.Diagnostics.Debug.WriteLine(String.Format("Done: {1:0.00} sec", _prefix, ts.TotalSeconds));  
    }  
    #endregion  
 }  

C# - Round To Significant Digits

Here's a quick and easy way in C# to round a double value to the nth significant digit:
 double RoundToSignificantDigits(double d, int digits)  
 {  
   // nothing to do if the value is zero  
   if (d == 0.0) return d;  
   double scale = Math.Pow(10, Math.Floor(Math.Log10(d)) + 1);  
   return scale * Math.Round(d / scale, digits);  
 }  
Or as Chris R. pointed out in the comments (thanks Chris), you may want to include Math.Abs(d) to ensure it works for negative values:
 double RoundToSignificantDigits(double d, int digits)  
 {  
   // nothing to do if the value is zero  
   if (d == 0.0) return d;  
   double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(d))) + 1);  
   return scale * Math.Round(d / scale, digits);  
 }  

Windows 7 (and Vista) Godmode

So Windows Vista and Windows 7 have a nice little undocumented feature you might enjoy. They call it Godmode. The point of Godmode is to give you full access to all configurable settings in the system from a single screen.
Simply create a folder anywhere in the system (I put mine on the desktop) and rename it to: GodMode.{ED7BA470-8E54-465E-825C-99712043E01C} and it instantly becomes a shortcut to the Godmode view. You will be able to see every single configuration setting available, categorized, in the same window (see the screenshot below).
Godmode Snapshot
Enjoy.

O!Play HDP-RD1 and HDP-RD3 Firmware Upgrade How To

I have an ASUS O!Play HDP-R3 media player. Works great! It has HDMI 1080p output, UPnP and Samba network sharing, 802.11n wireless and 10/100 ethernet and multiple external inputs including USB (external drives/flash drives), memory cards and eSATA devices. Only trouble was, finding the firmware and the upgrade instructions. So, I figured I'd better blog them for posterity sake. These instructions apply for both the ASUS O!Play HDP-R1 and HDP-R3 units. Just be sure and download the appropriate firmware for your unit. There is different firmware for each of the units.
  1. Basically, got to the FTP site, find the appropriate version of your hardware, and grab the zip file.
  2. Copy it to a USB stick (just drop it in the root folder).
  3. Plug the USB stick into your O!Play box (you don't have to turn it off or anything).
  4. Press the Setup button on the remote
  5. Go to the System section
  6. Select System Update
  7. Choose System Reinstall - don't ask me why they name it that
  8. Now you'll see it show your current and new firmware versions. Choose OK
  9. Wait for the firmware upgrade to take place (might take a few minutes). DO NOT TURN OFF THE UNIT DURING THIS TIME PERIOD
  10. Update your system settings and you're golden

Understanding Enterprise Architecture

Introduction

The term "Enterprise Architecture" has multiple meanings. From a design/IT perspective, it's the process of capturing an organization's enterprise level business processes in the architecture of a system. Secondly, from a business perspective, it can be thought of as a current snapshot of an organization's existing IT infrastructure, business functions or processes, it's communication mechanisms and how data/information is shared throughout the organization. The function then, of an "Enterprise Architect" is to analyze the latter and use this information to implement or improve the former.

Technically Incorrect

The majority of IT professionals today include this term in their resume in reference to a particular web application, component or database solution, without ever taking the time to consider how the web application or component they are developing truly impacts the enterprise level organization for which it is being designed. This doesn't mean their contribution isn't enterprise worthy, but it does beg the question of how many of these individuals really understand what's involved in an enterprise project. There's really no mystery here as to why either. It's unfortunate that, in most cases, programmers aren't provided with the bigger picture so they don't have a clear understanding of what constitutes an Enterprise application or solution. In many cases, the tools they use for development, include so many extras that their assumption is, if they've written a certain application using a particular framework, they must be designing an enterprise level application or component. Keeping it simple has definitely gone out the window in a lot of cases, especially when one considers that in most cases all this extra infrastructure is really unnecessary, especially when you're designing a simple information website for a friend. And no, just because you hooked DRUPAL to a backend MySQL server (case in point - this website) it's not an enterprise level web application. And then of course there are all the websites out there that teach or provide you with code snippets in for JEE or .NET SOA style programming or show you how to design your app or component using UML and other "enterprise" tidbits. They walk you thru the creation of an EJB or a .NET web service, demonstrate the deployment to whatever flavour of application server you're using and even discuss such things are clustering, mirroring and disaster recovery. Unfortunately though, they don't spend a whole lot of time discussing the bigger picture of how this fits into the needs of the enterprise. But hey, they're talking about creating EJB's, so this must be enterprise level architecture type stuff right?

Asking Yourself the question: "Why?"

Enterprise Architecture is about a whole lot more than simply creating a bunch of web applications, web services and/or databases. One needs to understand WHY it is that these applications or components have been put together the way they have, and not just focus on the building blocks. Understanding what drives the business is equally, if not more important. In discussions with most developers about customer relationship management (CRM), they can usually cite a list of examples. The same holds true with regards to image scanning and document/photo management systems. The problem is, they can't tell you WHY they're important. They don't understand the underlying business processes and rules driving the use of these types of tools. One needs to take several steps back from the planning table and begin to study these business processes and rules. An organization isn't comprised of merely one person or department in an organization, but rather the sum of all the collective parts. In the same way, the Enterprise Architecture isn't merely a bunch of web apps and components thrown together without purpose, but rather involve the careful consideration of how such tools help with the interaction between people, departments and business units.

High Level Thinking

I'm a programmer, so yes, I'm often faced with the difficult task of separating my technical thinking from the business perspective. At the top level, the Enterprise Architecture consists of the business processes and rules that permit the interaction and sharing of data/information between departments, individuals and business units. It doesn't matter whether the enterprise is non-profit, not-for-profit or for-profit. In all cases information exchange is key. This, together with the insurance of Business Continuity despite undesired interruptions, are the keys to success.

Business Process Analysis

The first step in understanding an organization's business function, and therefore what type of solutions can be implemented, is to understand it's business processes. Departments and individuals share information and/or data in a number of ways including:
  • telephone
  • emails
  • documents or memos
  • instant messaging
  • presentations
  • demos
  • blogging (i.e. twitter, wordpress)
  • publications or newsletters
  • web portals
It's important to understand the driving force behind these different modes of sharing information and identifying the implications of each type of sharing mechanism. Many considerations are necessary as follows:
  • security or sensitivity of information (intellectual property, customer privacy, etc.)
  • easy access
  • ease of collaboration within a group/team setting
  • data access or change tracking
  • time sensitivity of data
These considerations are important in understanding the different business processes and rules that departments, individuals or business units implement and adhere to. Another aspect is workflow. This is the routing of data or information between departments, individuals or business units for the purpose of completing a business objective. A very common and simple example is the Human Resources resume workflow:
  1. A resume is received via email/fax/mail, scanned where appropriate and added to the company's DMS (document management system)
  2. The HR Manager delegates work to HR personnel to filter and remove unqualified resumes from the system, processing qualified resumes by skills matrix and making these searchable on the company's intranet.
  3. The HR Manager searches for qualified applicants, sending them to the HR Manager for scheduling of interviews.
  4. Initial interviews are held over the phone to pre-screen applicants based on department needs and this is fed back to the department manager.
  5. HR Manager receives back a narrowed down list of applicants for 2nd interview, and schedules each one - reviewing online calendaring system to ensure schedule of applicant and department manager are acceptable.
  6. Department Manager and/or subordinates meets with each candidate and narrowing down the candidate list until finally choosing a winning candidate. This information is sent back to the HR Manager.
  7. HR Manager contacts candidate and negotiates salary and benefits
  8. Upon acceptance by candidate, HR Manager creates a new entry in the employee system for candidate and information Payroll.
  9. etc...
Wait! Did I say simple? I meant super COMPLEX. And this is just a resume workflow. I didn't include any of the steps payroll and HR have to go through to get the person hired, into a cubicle, using a computer, etc.

Business Continuity

Most developers understand some of the basic concepts behind continuity planning. More senior developers have probably been burned by, and therefore understand why source code control systems are so crucial to software development. The same is true for the enterprise. A critical component in an organization's enterprise architecture, is it's continuity during times of disaster. Disaster recovery is often an after thought, but without a proper DR plan during the planning phase, the interruption of business is a very real possibility.

Business Practices

In order to understand an organization's business, it is necessary to dissect the business into various practices or disciplines. The organizational goals, which include such things as the mission statement, are important because they are meant to provide the "guiding light" for the organization. An organization's operating model is essentially the high level blueprint showing the bridging between the business and it's adapted technology. ITIL (Infomration Technology Infrastructure Library) is becoming one of the standard operating models being adopted by many of today's organizations. The organizational model, which describes the breakdown of the company into business units, with operational boundaries, is also important to understand. This can give an architect insight into the communications required and/or gaps which need to be bridged in order for the organization to successfully function.

Business Processes

Business processes are at the heart of every organization. Goverened by a set of business rules, they are the functional highway that the organization uses to be profitable. Business processes are included in every operational area of an organization including:
  • project management
  • research and development
  • quality control
  • product delivery
  • billing and accounts receivable
  • finance and accounts payable
  • human resources/payroll
  • accounting
  • operations
  • technology and infrastructure
  • procurement
  • inventory and warehousing
  • customer service/support
  • warranty servicing/RMA
  • sales and business communications
Each of these operational units requires information both internally and externally in order to properly function within the organization:
  • Project management has no useful function without the RFQs, RFPs and eventual work generated through the sales process
  • clientèle would not provide repeat business without the assistance of customer service, which would be unable to perform it's job without technology and infrastructure such as telephones, a webste and email
  • warranty service can not function without inventory and serves no useful purpose without warranty work/RMAs generated through customer service requests

Business Information

Business information/data is a key component to successful business process execution. Information is routed between individuals, departments, business units and management. This information is used for every level of decision making, without which, business processes would halt and/or break down. The sample given earlier was a simple resume routing process. Even this simpe example included many rules, stakeholders, actions, states and boundaries of responsibility. In order to properly track and route information/data, it is necessary to create logical and eventually physical data models which illustrate and tie together information in a meaningful way. As an example:
  • An organization has many employees
  • Each employee has both personal and professional information (i.e. salary, start date, employee number)
  • Payroll must keep a record of each pay period per employee, including total salary earned YTD, and for the period, total deductions, contributions, etc.
  • Each employee belongs to a department within the organization
  • Each employee will work on many projects during his tenure
  • Each project has multiple employees and must manage their workload
This example illustrates the logical associations between organizations, employees, payroll and projects. These are but a few of the relationships within an organization. Each relationship has a number of data points (i.e. yearly salary, birthdate, name, etc.). A logical data model must be created that attempts to link the relationships and documents the data points/attributes of each. Logical data models reflect the business information and not necessarily the technical level details. As an example, a project manager within an organization's Canadian services branch is paid $100 CDN per year (this is business information). At a technical level, this may require currency conversion (with history tracking) if the organization's payroll department processes salaries in US funds.

(...to be continued...)

How to Create One or More Nested ConfigurationElementCollection items within your Custom ConfigurationSection

So recently I was trying to create nested ConfigurationElementCollection items within my custom ConfigurationSection like this:
 <Custom>  
   <Apps>  
    <App path="...">  
     <Methods>  
      <Method name="..." />  
      <Method name="..." />  
      <Method name="..." />  
     </Methods>  
    </App>  
    <App path="...">  
     <Methods>  
      <Method name="..." />  
      <Method name="..." />  
      <Method name="..." />  
     </Methods>  
    </App>  
    <App path="...">  
     <Methods>  
      <Method name="..." />  
      <Method name="..." />  
      <Method name="..." />  
     </Methods>  
    </App>  
   </Apps>  
  </Custom>  
Needless to say, I was pulling my hair out.  Finally, I found what I was looking for, so I figured I'd post my findings in such a way that you can copy/paste it straight into your code and away you go.

I modified my app.config file as follows (I've changed the names to protect the innocent):
  <configSections>  
   <section name="Custom" type="MyCustom.Custom, MyCustom" />  
  </configSections>  



and then added the above XML as well.

Then, I used the following code to implement the custom configuration:
   public class Custom : ConfigurationSection  
   {  
     [ConfigurationProperty("Apps")]  
     public AppElementCollection Apps  
     {  
       get { return this["Apps"] as AppElementCollection; }  
     }  
   }  
   public class AppElementCollection : ConfigurationElementCollection  
   {  
     protected override ConfigurationElement CreateNewElement()  
     {  
       return new AppElement();  
     }  
     protected override object GetElementKey(ConfigurationElement element)  
     {  
       return ((AppElement)element).LocalName;  
     }  
     public override ConfigurationElementCollectionType CollectionType  
     {  
       get { return ConfigurationElementCollectionType.BasicMap; }  
     }  
     protected override string ElementName  
     {  
       get { return "App"; }  
     }  
     public AppElement this[int index]  
     {  
       get { return (AppElement)BaseGet(index); }  
       set  
       {  
         if (BaseGet(index) != null)  
         {  
           BaseRemoveAt(index);  
         }  
         BaseAdd(index, value);  
       }  
     }  
     new public AppElement this[string employeeID]  
     {  
       get { return (AppElement)BaseGet(employeeID); }  
     }  
     public bool ContainsKey(string key)  
     {  
       bool result = false;  
       object[] keys = BaseGetAllKeys();  
       foreach (object obj in keys)  
       {  
         if ((string)obj == key)  
         {  
           result = true;  
           break;  
         }  
       }  
       return result;  
     }  
   }  
   public class AppElement : ConfigurationElement  
   {  
     [ConfigurationProperty("path", IsRequired = true, IsKey = true)]  
     public string LocalName  
     {  
       get  
       {  
         return this["path"] as string;  
       }  
       set  
       {  
         this["path"] = value;  
       }  
     }  
     [ConfigurationProperty("Methods")]  
     public MethodElementCollection Methods  
     {  
       get  
       {  
         return this["Methods"] as MethodElementCollection;  
       }  
     }  
   }  
   public class MethodElementCollection : ConfigurationElementCollection  
   {  
     protected override ConfigurationElement CreateNewElement()  
     {  
       return new MethodElement();  
     }  
     protected override object GetElementKey(ConfigurationElement element)  
     {  
       return ((MethodElement)element).LocalName;  
     }  
     public override ConfigurationElementCollectionType CollectionType  
     {  
       get { return ConfigurationElementCollectionType.BasicMap; }  
     }  
     protected override string ElementName  
     {  
       get { return "Method"; }  
     }  
     public MethodElement this[int index]  
     {  
       get { return (MethodElement)BaseGet(index); }  
       set  
       {  
         if (BaseGet(index) != null)  
         {  
           BaseRemoveAt(index);  
         }  
         BaseAdd(index, value);  
       }  
     }  
     new public MethodElement this[string employeeID]  
     {  
       get { return (MethodElement)BaseGet(employeeID); }  
     }  
     public bool ContainsKey(string key)  
     {  
       bool result = false;  
       object[] keys = BaseGetAllKeys();  
       foreach (object obj in keys)  
       {  
         if ((string)obj == key)  
         {  
           result = true;  
           break;  
         }  
       }  
       return result;  
     }  
   }  
   public class MethodElement : ConfigurationElement  
   {  
     [ConfigurationProperty("name", IsRequired = true, IsKey = true)]  
     public string LocalName  
     {  
       get  
       {  
         return this["name"] as string;  
       }  
       set  
       {  
         this["name"] = value;  
       }  
     }  
   }  
I think that should be enough information to get you going.  :)

Tuesday, August 16, 2011

New Hashtags I'm Starting (#AmIFiredYet)

So as of this moment, I'm starting a new hashtag called #AmIFiredYet which I'm hoping will eventually trend.  It's an experiment I thought would be lots of fun.  Let's see what happens.

Monday, August 15, 2011

My Moto Is..

You're only young once, but you can be immature forever.