Thursday, September 11, 2014

SharePoint Saturday, Cape Town 2014

I'm very fortunate to have been the opportunity to talk at SharePoint Saturday.   This year I'm going slightly more technical than last year, and hopefully get in a few demo's as well.  My topic, "Practical SharePoint 2013", will deal with specific issues that I had come across the past few months, and hopefully will give a few people in the audience ideas in how to tackle problems they face themselves.

I'll be uploading my slide-deck and any examples here, so please feel free to download them, when they become available.

Happy coding, and see you at SPSCPT14!!

Tuesday, September 18, 2012

Setting the Value for a SharePoint DateTimeField not working?

Some day's I stand amazed by the simplicity and rich features the SharePoint API gives to the developer.  But some days (they seem to pop up more and more these days), I can only shake my head at the pure stupidity it seems from the Microsoft SharePoint team.

Problem:

Take the DateTimeField.  I'm busy rending controls (from a list) in order to build a custom edit form.  Everything seems to render perfectly, including the DateTimeField. Normally you'd do something like this :
private void CreateControl(SPList list, string internalName, object val)
{
 SPField field = list.Fields.GetField(internalName);
 if (field == null)
  return;
 
 BaseFieldControl fieldRenderingControl = field.FieldRenderingControl;
 fieldRenderingControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");
 fieldRenderingControl.ControlMode = SPControlMode.New;
 fieldRenderingControl.ListId = list.ID;
 fieldRenderingControl.FieldName = field.InternalName;
 fieldRenderingControl.RenderContext = SPContext.GetContext(HttpContext.Current, list.DefaultView.ID, list.ID, adapter.Web);
 
 // Per example only.  Set the Value, cast to type if necessary.
 fieldRenderingControl.Value = val;
 
 this.Controls.Add(fieldRenderingControl);
}
This renders basic controls (excluding the Taxonomy and Custom FieldType controls) in a fairly straight forward and easy way. The problem comes in when you try and set the Value of a DateTimeField control. You'll end up with "an Object reference not set" error. I haven't had the time to fire up Reflector, so I'm not exactly sure what's happening here.

Solution :

I've ended up creating a DateTimeControl, whenever the DateTimeField pops up. My code ended up looking something like this:
private void CreateControl(SPList list, string internalName, object val)
{
 SPField field = list.Fields.GetField(internalName);
 if (field == null)
  return;

 if (field.FieldRenderingControl.GetType().Equals(typeof(DateTimeField)))
 {
  DateTimeControl dateTimeControl = new DateTimeControl();

  SPFieldDateTime sp = (SPFieldDateTime)field;
  if (sp.DisplayFormat == SPDateTimeFieldFormatType.DateOnly)
  {
   dateTimeControl.DateOnly = true;
  }
  dateTimeControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");

  // Set the value
  dateTimeControl.SelectedDate = (DateTime)val;

  this.Controls.Add(dateTimeControl);
 }
 else
 {
  BaseFieldControl fieldRenderingControl = field.FieldRenderingControl;
  fieldRenderingControl.ID = "fld_" + field.Id.ToString().Replace("-", "_");
  fieldRenderingControl.ControlMode = SPControlMode.New;
  fieldRenderingControl.ListId = list.ID;
  fieldRenderingControl.FieldName = field.InternalName;
  fieldRenderingControl.RenderContext = SPContext.GetContext(HttpContext.Current, list.DefaultView.ID, list.ID, adapter.Web);

  // Per example only.  Set the Value, cast to type if necessary.
  fieldRenderingControl.Value = val;
  
  this.Controls.Add(fieldRenderingControl);
 }
}
Not the perfect solution, but it works. In my next post I'll reveal the entire control that will render the Taxonomy controls as well. Happy programming!

Important and Useful Links:



Wednesday, August 29, 2012

SharePoint 2010 CodePlex Projects

The following SharePoint 2010 CodePlex projects have helped me creating wonderful solutions for my clients.  Here are the ones that stood out for me (so far):   

SharePoint Manager

Overview:
The SharePoint Manager is a SharePoint object model explorer. It enables you to browse every site on the local farm and view every property.

Comments:
First and foremost! Indispensable, and a must have for every SharePoint developer and administrator.

SharePoint Developer Tools for Visual Studio 2010
and
CKS: Development Tools Edition


Overview:
This project extends the Visual Studio 2010 SharePoint Project system with advanced templates and tools.

Comments:
Attended an SharePoint evangelism by Wouter van Vugt a couple of years ago, and have been a keen user of CodeCounsel's Visual Studio tools ever since.  Highly recommended!

SharePoint 2010 Fluent Ribbon API

Overview:
An API that lets you create Ribbon buttons for application pages and even contextual ribbon buttons for WebParts.

Comments:
Wow, if you're involved with custom application building for SharePoint as much as I am, this was a true blessing in disguise.  Very easy to understand, and simple to use.

Documentation :
http://markeev.com/sharepoint/ribbon/
http://amarkeev.wordpress.com/2012/01/06/sharepoint-ribbon-togglebutton/


MiniCalendar Web Part

Overview:
A small web part to display links to events stored in a list (or document library) in a mini calendar (in month view mode).

Comments:
Really simple little webpart.  Gave us a great head-start in creating a mini calendar that we could use in a masterpage.

SharePoint Property Bag Settings

Overview:
The Property Bag Settings can store any metadata as Key-Value pairs. This SharePoint administrative application page(s) provides a hierarchical configuration manager that can safely store and retrieve configuration settings at Farm, Web, Site Collection, Site and List level.

Comments:
Simple and clean interface lets you easily manage the Property Bag.  Becomes very useful once you start building custom applications within the SharePoint platform.

SharePoint Batch Edit

Overview:
A Bulk an Batch updating for list and document properties. The ribbon button makes it possible to update multiple items with a single click, supporting the common used column types like Managed Metadata, Enterprise Keyword, People Picker and many more.

Comments:
As the description says on the site, "wonder why this wasn't-in-the box".  I've extended mine with ability to select a content type, if the list has more than one.

Starter Master Pages for SharePoint

Overview:
Starter Master Pages for SharePoint are a clean, commented starting point for creating your own SharePoint 2010 branding.

Comments:
It's done by Randy Drisgill... Need we say more?

Tuesday, August 28, 2012

Programmatically create a SharePoint XsltListViewWebPart, with Cross-Site support

Since I've found a few very helpful pieces of code this week, including the SharePoint 2010 Batch Property Edit control, that my friends of Tam Tam generously uploaded to CodePlex, I though that I'll share the XsltListViewWebPart that I've recently built for a client of ours.
 
After Googling for days it seemed, I couldn't find a good example of a programmatically created XsltListViewWebPart.  Below I'll share a few thoughts on what I did to get the control up and running.  I've also added the functionality to display a "Add new item" link, the same way the OOTB SharePoint List WebPart does.
 
Although by no means perfect, I hope this does help someone in desperate need of answers.  Remember, this is not a copy-paste exercise, but a gentle nudge in the right direction!
 
Public and Private properties
Nothing too special here.  Give the user the ability to select a Web, List and View combination, plus the option to show or hide the "Add new item" link.  
 
 
// User can set the WebId
public string WebId { get; set; }

// User can set the ListId
public string ListId { get; set; }

// User can set the ViewId
public string ViewId { get; set; }

// User can set a custom XslFile path
public string XslLink { get; set; }

// User can choose to display the "Add item" link
public bool HideAddLink { get; set; }

// Check if all requirements are met to display the "Add item" link
private bool HasValidButtonProperties
{
 get
 {
  return base.HasWebIdAndListIdAndViewId && !this.HideAddLink;
 }
}

// Unique key generation
private string OpenScriptedDialog
{
 get
 {
  return string.Format("OpenXsltListViewerControl{0}", this.ClientID);
 }
}

// Use panel/updatepanel to add the XsltListViewWebPart
protected UpdatePanel updatePanel;
protected Panel panel;
 
OOTB not working?  Aaaaaaargh!
TIP:  I've tried setting the XSL Link on a OOTB SharePoint list web part, but it doesn't seem to work!?  Is it just me or does anyone else have issues with this?  By rendering this custom XsltListViewWebPart and setting its XslLink property I could get the XslLink rendering working.  But not the OOTB list web part?
 
UPDATE (01/10/2012) : The problem (bug if you will) with using the XSL Link on a List Part, is better explained over at Glyn Clough's blog.  Just follow the these two links.
 
Overrides
The only real override to take note of, the the CreateChildControls method.  Here I use a few helper functions to render all the plumbing necessary for the SP.UI.ModelDialog.  This is needed to display the "Add new item" dialog.  I've used a series of fixed values, but obviously you can make them all dynamic and have the user set them in your EditorPart.
 
protected override void OnInit(EventArgs e)
{
 // Init update panel
 updatePanel = new UpdatePanel();
 updatePanel.ChildrenAsTriggers = true;
 updatePanel.UpdateMode = UpdatePanelUpdateMode.Conditional;
 updatePanel.ID = string.Format("updatePanel_{0}", this.ClientID);

 // Init panel
 panel = new Panel();

 base.OnInit(e);
}

protected override void CreateChildControls()
{
 // WebPart base ensures selected variables 
 base.CreateChildControls();

 // Register Scripts
 StringBuilder sb = new StringBuilder();

 if (HasValidButtonProperties)
 {
  // Use helper function to inject javascript for the SP.UI.ModalDialog add functionality 
  sb.Append(SPUtilities.GetModalDialogScript(this.ListId + "/NewForm.aspx",
              "New Item",
              625,
              525,
              this.OpenScriptedDialog));
 }
 // Helper function to register script
 base.RegisterScript(base.UniqueScriptsKey, sb.ToString());

 // Add the control to the controls collection, not the panel, 
 // this will ensure that the "Add link" is shown at the bottom of the control.
 if (HasValidButtonProperties)
 {
  Use a helper function to render the "Add link"
  this.Controls.Add(new LiteralControl(SPUtilities.GetModalDialogAddButton(this.OpenScriptedDialog)));
 }
}

protected override void OnLoad(EventArgs e)
{
 RefreshXsltListViewer();
 base.OnLoad(e);
}
 
Helper functions
I've included the SP.UI.ModelDialog helper functions.  They're all but perfect (but works!), so feel free to dice and slice them according to your own needs. Again I've included them just to give you an idea of what I've done.
 
// Method injects javascript to handle the SP.UI.ModalDialog functions 
public static string GetModalDialogScript(string url, string title, int width, int height, string functionName)
{
 var sb = new StringBuilder();
 var _width = width > 0 ? width : 625;
 var _height = height > 0 ? height : 325;

 sb.Append(" ");

 return sb.ToString();
}

// Method renders the 'Add new item link'
public static string GetModalDialogAddButton(string addLinkKey)
{
 return GetModalDialogAddButton(addLinkKey, string.Empty);
}

// Method renders the 'Add new item link'
public static string GetModalDialogAddButton(string addLinkKey, string addLinkText)
{
 if (string.IsNullOrEmpty(addLinkKey))
  return string.Empty;

 if (string.IsNullOrEmpty(addLinkText))
  addLinkText = "Add new item";
 
 StringBuilder sb = new StringBuilder();
 sb.Append("<table width='100%'>");
 sb.Append("  <tr>");
 sb.Append("    <td class='ms-partline'>");
 sb.Append("      <img height='1' width='1' alt='' src='/_layouts/images/blank.gif'>");
 sb.Append("    </td>");
 sb.Append("  </tr>");
 sb.Append("  <tr>");
 sb.Append("     <td style='padding-bottom: 3px' class='ms-addnew'>");
 sb.Append("       <span class='s4-clust' style='height:10px;width:10px;position:relative;display:inline-block;overflow:hidden;'>");
 sb.Append("           <img style='left:-0px !important;top:-128px !important;position:absolute;' alt='' src='/_layouts/images/fgimg.png'>");
 sb.AppendFormat(" </span>&nbsp;<a href='javascript:{0}()'>{1}</a>", addLinkKey, addLinkText);
 sb.Append("     </td>");
 sb.Append("  </tr>");
 sb.Append("</table>");

 return sb.ToString();
}
 
Private methods
So here comes the juicy bits.  First its important to notice that the CreateXsltListViewer method runs with an elevated privilaged SPWeb and UnsafeUpdates set to true.  I've created a series of extension methods to handle this for me. (If your'e a bit confused about this, see the helpful links section at the bottom of this page for more information.)
 
In order to create and render a cross-site list, you'll simply need to include the WebId, ListName, ListId and ViewGuid properties.  Personally thought it might be a bit more complex, but that was it...
 
Since the toolbar itself becomes way too much of a problem in its complexity, I've decided not to display it.  All the elements inside the list can still be served by its dropdown menu, but unfortunately not the Ribbon.  If you're in dire need of this functionality, happy hunting, and do drop me a line if you've figured it out! ;-)
 
private void RefreshXsltListViewer()
{
  // Run the CreateXsltListViewer method with an 
  // elveated privilaged web, that also caters for
  // unsafe-updates.
  SPWeb web = SPContext.Current.Site.OpenWeb(WebId);
  web.UnsafeUpdate(CreateXsltListViewer);
}

private void CreateXsltListViewer(SPWeb web)
{
 // Use helper function to get the SPList
 SPList list = SPUtilities.GetSPList(ListId);

 // Use list acquired from AllowUnsafeUpdates web
 SPList viewList = web.Lists[list.ID];
 
 // Create the control
 XsltListViewWebPart xsltControl = CreateXsltListViewerInstance(viewList, ViewId);

 // Add control to the update panel
 if (xsltControl != null)
 {
  panel.Controls.Add(xsltControl);
 }
 else
 {
  panel.Controls.Add(new LiteralControl("There was an error creating the XsltListViewer."));
 }
}

private XsltListViewWebPart CreateXsltListViewerInstance(SPList list, string viewName)
{
 XsltListViewWebPart xsltListViewWebPart = new XsltListViewWebPart();

 // First check if view acutally exists
 if (list.Views.Exists(viewName))
 {
  SPView defaultView = list.Views[viewName];

  xsltListViewWebPart.ID = "wpListView";
  // We're displaying this WebPart inside a WebPart. Disable the 
  // XsltListViewWebPart's own Title and ChromeType.
  xsltListViewWebPart.Title = string.Empty; 
  xsltListViewWebPart.ChromeType = System.Web.UI.WebControls.WebParts.PartChromeType.None;
  
  // Set all these properties to allow for Cross-Site lookups
  xsltListViewWebPart.WebId = list.ParentWeb.ID;
  xsltListViewWebPart.ListName = list.ID.ToString("B").ToUpper();
  xsltListViewWebPart.ListId = list.ID;
  xsltListViewWebPart.ViewGuid = defaultView.ID.ToString("B").ToUpper();

  // If required, set the XSL file link
  if (!string.IsNullOrEmpty(XslLink))
  {
   xsltListViewWebPart.XslLink = this.XslLink;
  }

  defaultView.Update();
  
  // I never show the toolbar
  SetToolbarType(xsltListViewWebPart, "None");
 }

 return xsltListViewWebPart;
}

public void SetToolbarType(XsltListViewWebPart lvwp, string viewType)
{
 try
 {
  MethodInfo ensureViewMethod = lvwp.GetType().GetMethod("EnsureView", BindingFlags.Instance | BindingFlags.NonPublic);
  object[] ensureViewParams = { };
  ensureViewMethod.Invoke(lvwp, ensureViewParams);
  FieldInfo viewFieldInfo = lvwp.GetType().GetField("view", BindingFlags.NonPublic | BindingFlags.Instance);
  SPView view = viewFieldInfo.GetValue(lvwp) as SPView;
  Type[] toolbarMethodParamTypes = { Type.GetType("System.String") };
  MethodInfo setToolbarTypeMethod = view.GetType().GetMethod("SetToolbarType", BindingFlags.Instance | BindingFlags.NonPublic, null, toolbarMethodParamTypes, null);
  object[] setToolbarParam = { viewType }; //set the type here
  setToolbarTypeMethod.Invoke(view, setToolbarParam);
  view.Update();
 }
 catch { }
}
 
Conclusion
So there it is.  Hope this will give you some ideas on your own version of a custom XsltListViewWebPart, that supports cross-site lookups, and have the ability to have custom XSL applied to it (see below).
 

 
Important and Useful Links:
 
 
 

Friday, August 24, 2012

401 Error (Unauthorized) When Accessing SharePoint Web Services

We've created application helper classes that accesses all SharePoint lists via the integrated web services (/_vti_bin/*.asmx).   One of the miserable errors we sometimes get when moving through the deployment stages (Development, QA then Production) is that, even with administrative privileges, we still get a 401 Unauthorized error.

Our code goes something like this:
protected WebServiceSPLists.Lists _lists;
const string CClassName = "DataContextSharePointList";

private string GetListNameByTitle(Connection connection, string listTitle)
{
 const string CProcName = "GetListNameByTitle";
 string response = "";
 XmlNode listsNode;
 XmlNode node;

 try
 {
  this.InitConnection(connection);
  _lists.Credentials = ((Connection)connection).Credentials;
  _lists.Url = ((Connection)connection).SiteUrl + "/_vti_bin/lists.asmx";
  Trace.Write(CClassName, CProcName, "GetListCollection");
  listsNode = _lists.GetListCollection();    // <-- 401 error occurs here
  Trace.Write(CClassName, CProcName, "GetListCollection OK");
  
  // Code omitted //
 }
 catch (Exception ex) 
 {
  Trace.Write(CClassName, CProcName, "Error: " + ex.Message);
 }
}

The way we fix this is by either specifying the host names or disabling the loopback check and EACH of the application servers.  See this post for more details.

Important and Useful Links:


Upgrading SharePoint Content Types: General Guidelines, Ideas and Issues.

Microsoft introduced the "SharePoint Content Type Lifecycle Management" for better management of already deployed content types. Although simple in theory, in practice there are a number of issues to be aware of. The whole process of upgrading the Content Type Feature is done by following these steps.

(a) Create the New Fields. 

Personally I prefer to keep my Field Definitions elements.xml separate to my Content Type elements.xml. So whenever I update an existing project, I simply slot in a new manifest with all the new Field definitions (as per version).

Some prefer to add the new FieldRefs into the existing Content Types manifest, but this is not necessary.  However, this does make life simpler for new deployments.

In my example I've created a new Managed Metadata Field:
  <Field ID="{498D906E-1C7F-4493-8F28-3400654F4292}"
  Name="ArtifactClassification"
  StaticName="ArtifactClassification"
  DisplayName="Classification"
  Group="CII Projects Columns"
  Type="TaxonomyFieldType"
  ShowField="Term1033"
  EnforceUniqueValues="FALSE"
  Required="TRUE"
  Overwrite="TRUE"
  DisplaceOnUpgrade="TRUE">
    <Customization>
      <ArrayOfProperty>
        <Property>
          <Name>TextField</Name>
          <Value xmlns:q6="http://www.w3.org/2001/XMLSchema" p4:type="q6:string" xmlns:p4="http://www.w3.org/2001/XMLSchema-instance">{CFB09262-ED43-45b0-9E4F-A44D5256858C}</Value>
        </Property>
      </ArrayOfProperty>
    </Customization>
  </Field>
  <Field ID="{CFB09262-ED43-45b0-9E4F-A44D5256858C}"
    Name="ArtifactClassificationTaxHTField0"
    StaticName="ArtifactClassificationTaxHTField0"
    DisplayName="Classification_0"
    Group="CII Projects Columns"
    Type="Note"
    ShowInViewForms="FALSE"
    Required="FALSE"
    DisplaceOnUpgrade="TRUE"
    Overwrite="TRUE"
    Hidden="TRUE"
    CanToggleHidden="TRUE"
    RowOrdinal="0">
  </Field>

If you prefer to add the FieldRef to the Content Type, it would look something similar to this:
  
<ContentType ID="0x01010008a7b1b7ae814926b4a6a7754d7f9d08"
     Name="CII Projects Document Artifact"
     Group="CII Projects Content Types"
     Description="The CII Projects Document Artifact Content Type."
     Inherits="TRUE"
     Overwrite="TRUE"
     Version="0">
<FieldRefs>
<!-- FieldRefs omitted -->
    <FieldRef ID="{498D906E-1C7F-4493-8F28-3400654F4292}" Name="ArtifactClassification" Required="TRUE" DisplayName="Classification"/>
    <FieldRef ID="{CFB09262-ED43-45b0-9E4F-A44D5256858C}" Name="ArtifactClassificationTaxHTField0" />
</FieldRefs>
</ContentType>

(b) Modify the Existing Feature Element Manifest.

Now comes the bulk of the work. Update the existing content type deployment feature, by adding the UpgradeActions element to the manifest.  Right off the bat I can tell you that the intended functionality doesn't exactly work as intended.  By adding the PushDown="TRUE" property to the AddContentTypeField element, the Upgrade should push the added Fields down to any inheriting Content Types from Sites below the Parent.  This does not work.

The only way I got this working was by following Charles Chen's method of adding a CustomUpgradeAction and forcing the pushdown.  His excellent blog on SharePoint Content Type Lifecycle Management can be found here.  In his post, he explains that by deleting and re-adding the Field to the Content Type, the Field is finally pushed down.

So basically, my UpgradeActions element looks something like this:

<UpgradeActions
    ReceiverAssembly="CII.Projects.Provisioning, Version=1.0.0.0, Culture=neutral, PublicKeyToken=5442323e733bd5e1" 
    ReceiverClass="CII.Projects.Provisioning.Features.CIIProjects_Provisioning.CIIProjects_ProvisioningEventReceiver">
    <VersionRange BeginVersion="0.0.0.0" EndVersion="1.0.0.0">
      <ApplyElementManifests>
        <ElementManifest Location="CIIProjects_Fields_v2\Elements.xml"/>
      </ApplyElementManifests>
      <AddContentTypeField ContentTypeId="0x01010008a7b1b7ae814926b4a6a7754d7f9d08" FieldId="{498D906E-1C7F-4493-8F28-3400654F4292}" PushDown="TRUE"/>
      <AddContentTypeField ContentTypeId="0x01010008a7b1b7ae814926b4a6a7754d7f9d08" FieldId="{CFB09262-ED43-45b0-9E4F-A44D5256858C}" PushDown="TRUE"/>
      <CustomUpgradeAction Name="AddFields">
          <Parameters>
             <Parameter Name="add.field.1">0x01010008a7b1b7ae814926b4a6a7754d7f9d08,{498D906E-1C7F-4493-8F28-3400654F4292}</Parameter>
             <Parameter Name="add.field.2">0x01010008a7b1b7ae814926b4a6a7754d7f9d08,{CFB09262-ED43-45b0-9E4F-A44D5256858C}</Parameter>
          </Parameters>
      </CustomUpgradeAction>
    </VersionRange>
</UpgradeActions>

The code from my ReceiverClass looks very similar to the one described in Chen's article, so I'm not going to repeat it here.

TIP : When adding the ReceiverClass via Visual Studio, the class references is automatically added to the <Feature> element and not the <UpgradeActions> element.  I could'nt trap any of my System.Diagnostic Traces in DebugView, and found that moving the ReceiverAssembly and ReceiverClass references manually to the <UpgradeActions> element was the only way I could get this working.  Does this indeed matter, or did I stuff up?  Comments welcome!

What is important however is to keep the version numbering constant.  In my case, the Version range starts with "0.0.0.0" (since I didn't include a version number with my original deployment) to "1.0.0.0".  Remember to set your Features' version number before packaging!


(c) Deploy the Update

After packaging, deploy the feature by whichever way is your poison.  My preferred method is a simple PowerShell cmdlet:
Update-SPSolution -GACDeployment -Identity "CII.Projects.Provisioning.wsp" -LiteralPath "E:\Deployment\SharePoint\CII\Projects\CII.Projects.Provisioning.wsp"

Be sure to check the 14-hive that your feature was indeed deployed!



(d) Activate the Upgrade

This is the part where everybody runs into issues [duh!].  After updating, the only way to enable the Feature Upgrade, is to get access to the QueryFeatures [SPFeatureQueryResultCollection] collection, and upgrade the features via their object model.

Two common way's we can accomplish this.  Either via C# code, or via a PowerShell cmdlet.  a Simple C# console application might look something like this :
static void Main(string[] args)
{
 using (SPSite currentSite = new SPSite("http://server"))
 {
  foreach (SPFeature feature in currentSite.QueryFeatures(SPFeatureScope.Site, true))
  {
   Console.WriteLine("Feature found : " + feature.DefinitionId.ToString());
   if (feature.Upgrade(true) != null)
   {
    Console.WriteLine("Upgrade " + feature.Definition.Name + " FAILED!");
   }
   else
   {
    Console.WriteLine("Upgrade " + feature.Definition.Name + " UPGRADED!");
   }
  }
 }
 Console.WriteLine("Press Enter to Continue...");
 Console.ReadLine();
} 

Or via a PowerShell cmdlet:
# This (as per 1000's of other examples) I couldn't get working
$featuresToUpgrade = $site.QueryFeatures("Site", $true)
foreach ($f in $featuresToUpgrade)
{
    Write-Host -ForegroundColor Yellow "Upgrading feature " $f.Definition.DisplayName -NoNewline
    $f.Upgrade( $false )
    Write-Host -ForegroundColor Green " DONE"
} 

# This worked
foreach ($f in $site.QueryFeatures("Site", $true)) {
   Write-Host -ForegroundColor Yellow "Upgrading feature " $f.Definition.DisplayName -NoNewline
   $f.Upgrade( $true ) 
   Write-Host -ForegroundColor Green " DONE"     
}

TIP : I ran into an issue where I update my upgraded feature, but couldn't access the feature via my PowerShell cmdlet (see above).  The QueryFeatures (true) collection simply did'nt return any of my upgraded features.  To make matters worse, this was a random occurrence. Sometimes everything ran perfectly smooth, and sometimes, no luck.  After 2 days of hair pulling I finally got to the actual reason...  I normally run the Update PowerShell cmdlet from the SharePoint 2010 Management Shell.  When the update completes, I run the Upgrade cmdlet from the SAME SHELL WINDOW.  This is when QueryFeatures "returns nothing".  Took me 2 whole days to figure out that the workaround this is to simply CLOSE THE SHELL WINDOW, and reopen it.  Voila.  My Upgraded feature starts showing up, and are ready for upgrading...  [facepalm!].

So that's how I got Content Type Upgrading working.  The client is happy, and my hair is coming back nicely.

Happy programming!

Important and Useful Links:



Tuesday, December 7, 2010

Top 5 : Boys Night Action Movies

1. Terminator 2: Judgment Day (1991, James Cameron)
Terminator 2 features by no means a stellar cast, yet Cameron manages lift these characters into movie immortality. Very few people will disagree that T2 set the benchmark for all action movies to follow, yet very few have manage to exceed it (so far). Ahnuld was born to play the Terminator, and this movie was the source of my crush on Linda Hamilton for most part of the 1990’s.

2. Aliens (1986, James Cameron)
Cameron took the brilliant concept given to us by the equally impressive Alien (1979, Ridley Scott), and gives it his own spin. The result is my everlasting fear of ever having to venture into an air-duct, and anything that emits a “beep-beep-beep” sound. Unfortunately another example of bad movie franchise management. I’ll simply ignore the fact that Alien 3, Alien Resurrection, the and the god awful "Alien v Predator" spinoffs ever existed.

3. Leon (1994, Luc Besson)
Two words. Gary Oldman.

4. Die Hard (1988, John McTiernan)
Kick-started Bruce Willis’movie carreer, and is still one of his best. No action movie is complete without a villainous Jang to the good-guy’s Jing, and here Alan Rickman truly sets the standard. I’ve said it a million times: an action movie is only as good as it’s villain, hence the disastrous failure of Die Hard 4.0.

5. Saving Private Ryan (1998, Steven Spielberg)
From the opening Normandy invasion to the final battle in the village of Ramelle, what I personally find amazing about this film is how Spielberg captures the human emotion during these brutal engagements. Not for the faint of heart, but genuinely rewarding film. The Spielberg and Hanks collaboration followed this up with the excellent "Band of Brothers" (2001), and the (unfortunate) mediocre “The Pacific” (2010).

Should have won the Oscar for Best Picture in 1998 (went to Shakespeare in love), but we’ll settle for Best Director...

6. [Honorable mention] First Blood (1982, Ted Kotcheff)
Set the Hollywood one-man-army-action blueprint for eons to come. Hard to believe this came out the same year Rocky got slapped around by Clubber Lang. (Not to spoil it for you, but in this one, Rocky wins it in the end...)

Monday, November 29, 2010

And you thought your job was tough?


1st Ashes Test finished. 5 Observations...

1. No Johnson, whacking your arm with a wet Spiderman comic doesn’t significantly improve your bowling.

2. Ponting still doesn’t believe in the use of technology to rule in disputed catches. But only during the opposition batting innings.

3. Marcus North (like JP Duminy) is fast becoming Englands best player.

4. Yes, Stuart Broad is still a tool.

5. Test cricket remains a funny game. A Hat-trick, 4 centurions (including Cook's double), records smashed (including Don Bradman’s highest score at the Gabba), and still the game plays out to a mind dumbing draw.

Thursday, November 25, 2010

Top 5 : Laugh Out Loud Movies

1. This is Spinal Tap (1984, Rob Reiner)
Hands down my favorite comedy. This movie just seems to get better with each viewing. We follow “the world’s loudest band” Spinal Tap on their doomed “Smell the glove” comeback tour. From perfect casting (Christopher Guest in particular) to great humor, I’m still amazed about the little in-jokes and humor I still discover (even after 15+ viewings).

2. Blazing Saddles (1974, Mel Brooks)
My favorite Mel Brooks film. Harvey Korman (as per usual) steals the show as the scheming Hedley Lamarr, with great performances by Gene Wilder, Cleavon Little and the beautiful Madeline Kahn.

3. The Pink Panther Strikes Again (1976, Blake Edwards)
This one still makes me laugh out loud. From the classic Ceto fight scenes, thru the house-staff interrogation, up to the grand storming of the castle, nobody brought Clouseau to life like Sellers did.

4. Stir Crazy (1980, Sidney Poitier)
Although suffering from a terrible 3rd and final act, the entering of the prison up to the actual rodeo are amongst the funnies experiences ever brought to screen by Pryor and Wilder (in my opinion anyway). As a bonus, make sure to watch Richard Pryor’s “Live on Sunset Strip” for his comments on their filming experience at the actual prison.

5. The Party (1968, Blake Edwards)
Sellers plays the bumbling extra, with the unpronounceable name, accidentally invited to a party. The dining scene alone is worth the admission, and just thinking about the chicken stuck on the tiara makes me start giggling. Sellers and Blake Edwards were a match made in heaven.

6. [Honorable mention] Top Secret! (1984, Jim Abrahams et al.)
I’ll simply leave this one as an “in-joke” to the people who went to High School with me…

Remember, this list is LAUGH OUT LOUD comedies. Discuss...

Thursday, July 26, 2007

One fine morning (aka "How to dismantle an atomic bomb")

Captains log - 22.7.2007
Bemanningslid AJ kry nou net bottel as voeding. Die melk uit die nice verpakkinge is voorlopig weer terug in storage, en word weer gebruik vir sy oorspronklike doel: om Pa se aandag van die TV te herlei. Anyway die aand verloop soos normaal, 65% slaap word vir die ouers geklok.

Captains log - 23.7.2007
Dis een dag sedert daar laas vyandige aktiwiteite in AJ se luier gespot is. Ma en Pa maak nie veel sorge nie, siende dit normaal is vir kideo's wat pas oorgeskakel het bottel toe. AJ vertoon geen sprake van ongemak nie, en die ouers klok 'n byna rekord 68% nagrus.

Captains log - 24.7.2007
Twee dae laas sedert enige teken kommunistiese beweging. Daar word voldoende gekonsumeer en ge-"slash", maar die "Brown-Army" bly ongesiens rondsluip. Ouers vertoon enkele tekens van sorg, maar maak dit nie aan die res van die bemanning bekend nie. AJ vertoon relatiewe tekens van ongemak, en maak homself meer vokaal daardeur bekend. Ouers log 45% slaap.

Captains log - 25.7.2007
Drie dae verder en geen teken van Fatah of Hamas Guerilla vegters. Voedinge verloop soos klokslag, maar die stryd duur underground voort. Ouers sigbaar geworried. Skeeps-dokter word ingeskakel, maar word gerus gestel dat "terwyl die NFU eet en plas", hy nog alright is. Word egter gewaarsku dat as daar nie binne die volgende 24/48 uur 'n "Invasion USA" plaasgevind het nie, die huis-arts ingeskakel sal moet word. Ouers nou sigbaar geworried. Obviously "what goes in, must come out". Die vraag is net, watter bemanningslid gaan die kort strooitjie trek as "Superman Returns"? AJ is ook markbaar ongesteld, of besig met 'n geniale plan. Hy het nog nie 'n "Evil Laugh", nie maar hy kan al sy een wenkbrou lig. Dit word deur die bemanning geinterpeteer as 'n vyandige komplot. Battlestations. Ouers log 'n rekord lae 30% slaap.

Captains log - 26.7.2007
Dag vier in die soektog na die vermiste Kruger-Rande. AJ is sommer al by die ontwaak slag moeilik, en 'n sigbaar onstelde en sleep-deprived Ma soebat co-chief Pa om die oggend voeding waar te neem. No problemo. 150ml Nestle Baby Milk coming right up, en troep AJ begin sonder probleme drink. Glipsie. Pa moes die tekens vroeer gespot het. Die "albei voete in die lug vir beter airflow", die "geligte wenkbrou drol druk pose", die "dis nou of nooit gekreun" en die beroemde "100 meter anderkant die kakhuis-deur staar". AJ het hulle almal vertoon. Klaarblyklik was Pa net nie wakker genoeg om hulle te spot nie. Raai wie trek die kort strooitjie. Survice to say, toe bemanningslid AJ die vier-dag-oue opgehoopde SWAPO forces te voorskyn bring, skyt hy met laser-guided presisson, en Irakese genadeloosheid.

Heeltemaal onkant - een hand agter AJ se kop, en die ander nog met 'n houvas op die bottel, 'n stench wat muishonde reg oor die wereld tros sou maak, en 'n "warm gevoel" wat oor Pa se been begin kruip, magteloos, outnumbered, simply put, gefok. Iewers kry master-chief Ma snuf in die neus en Pa word alleen deur 'n sagte gelag ingelig oor die stand van sake. Due to the "You fed him, you clean him" policy, is Pa verantwoordelik vir die opruimings aktiwiteite. Onthou, ons praat nie hier van 'n uur of twee se opgehoopte kriminele nie, VIER FLIPPEN DAE s'n!! Nog nooit in die bestaan van Pa het hy so gesmag na gasmasker of twee van daai pinetree-car-airfreshers (een vir elke neusgat) nie. Vir 'n oomblik of twee was egskeiding en adopsie 'n genuine opsie. Met 'n bruin streep oor die linker- arm en been word AJ met die nodige spoed, ge-"gag" en toe oe verskoon. Met 'n amper matching kots-streep oor die regter- arm en been, word die crime scene finaal opgeruim. Vuil nappie word net so die airlock uitgeblaas, om iewers op 'n ver weg planeet 'n gesin van sy eie te kultiveer.

'n Glimlag is weer terug op AJ se gesig. Nie seker of dit was oor die verminderde druk, of die gesigte wat Pa gemaak het tydens die "Italian Job" nie. Pa se pajamas word verbrand en Ma word ge-"ban" om hierdie verhaal ooit weer oor te vertel.

An interview with...


Ons verslaggewer stel 'n paar vra aan die NFU (new family unit) van die Burger clan.

Naam : Adriaan Jacques
Clan : Burger-Joubert
Noemnaam : AJ
Geboortedatum: 15 mei 2007
Nationaliteit : (49%) Nederlands, (51%) Suid Afrikaans
Gunsteling kleur : Lig of donker
TV program : Enigeiets met beweging.
Akteur : Die blur wat vanoggend op was.
Sport : Weet nie wat die naam was nie, maar die ou toppie raak baie onsteld as hulle speel.
Kos : Nie seker oor die naam nie, maar jislaaik ek's mal oor die verpakking.
Boek : "L'Homme aux quarante ecus" deur François-Marie Arouet

Dinsdag 15 mei 2007, 'n dag in review

01:56am -
Diep gewikkel in ’n droom waarby ek besig was om ’n splinternuwe Aston Martin te test-drive, laat weet die verkoopsman my in ’n surrealistiese moment dat ek na die “lig moet loop”. Doodsbevange en met ’n sweetdruppel wat oor my voorkop loop waag ek dit al hoe nader aan die uitgewyse spot. In ’n korte moment van utter dissapointment was die “wit lig” die bedlamp en exit point van my droom. Trouwens ook die begin van my worst nightmare. Dik deur die poep, maak ek net die silluete van Marinice uit waar sy op die rand van die bed sit. “No way” probeer ek myself flous dat dit alleen maar een van haar voet kramp episodes was, maar tevergeefs uiter sy daai ubermost frightening woorde : “my water het gebreek”...

02:05am -
Die gevoel in my onderlyf keer terug.

02:06am -
Gedagtes van water kook en komberse haal skiet my binne, maar gelukkig vertoos Marinice my dat die kontraksies nog nie begin het nie. Nou almal weet dat ek nie die oggend-tipe mens is nie. So realiteit het nog nie 100% sy lelike kop by my uitgesteek nie. In feite sou die nuus dat ek die 20 miljoen euro lottery gewen het, basies die selfde reaksie by my ontlok het. Maak natuurlik ’n poephol van myself toe ek haar vra : “laat weet my as ek iets vir jou kan doen”. Duh! In my defence, ek is 34% wakker op hierdie stadium.

03:36am -
Volgens intellegence reports gedurende die volgende paar dae, het ek verneem dat Marinice onder voor die TV gaan le het en ’n movie gekyk het. Ek, on the other hand, het verder bly le en besin of ek besig was om te droom, en of ek tog later hierdie oggend ’n “mad dash” na die hospitaal moet gaan maak. Ek is nou 39% wakker.

05:36am -
Dit was assof ek my oe geknip het, en twee ure was verby. Iewers in my onderbewusyn het daai stemmetjie wat jou altyd waarsku of jy iets verkeerd doen gelukkig die situasie opgesom, en beheer oorgeneem. Wat gevoel het soos iemand wat my met ’n pap snoek deur die gesig moer, skrik ek uiteindelik wakker. Ek is nou 90% wakker, en funksioneel genoeg om te besef, dat daar kak op pad is. Brein-aktiwiteite is gelukkig ook nominaal en inderhaas onthou ek dat daar onmiddelik ’n emergency tas (klere vir ma, bottels en pajamas vir kind en ’n air-sick-bag vir pa) ingepak moet word. Gelukkig woon ons al lank genoeg in die huis dat ek nie my tone teen die bed, klerekas en TV-stand te breek nie. In egte “poetry-in-motion” is die tas vir Marinice gepak. Op hierdie stadium is Marinice nou onder op die bank besig om ’n egskeiding te bedink, en die feit dat (as man) ek obviously al die verkeerde klere ingepak het sonder haar toesig.

05:42am -
Marinice join my weer bo om my te kalmeer en te assisteer in my asemhaling. Kalm word daar met militere presiesie vertel wat sy alles benodig, en met die onderdanigheid van ’n goeie soldaat rekkie ek die huis vir die benodigde (regte) spulle vir die emergency bag. Nou om die situasie meer tricky te maak is skoonma en skoonpa op besoek, en slaap in, “yes you’ve guessed it”, in junior se kamer. Nou vir die observerende onder julle sal julle weet dat daar vir die kleine ook stuff ingepak moet word. Here’s the problem. Hoe kry jy alles uit die kinderkamer sonder om die outlaws wakker te maak? Enter Hannes the Ninja. Met cat-like-stealthness word deur die kaste en laaie gesnuffel met skoonma se neus wat amper aan my boude raak. Deels deur die-kak-geit van my kant, kos dit my 3 keer die kamer deursoek omdat ek elke keer aan Marinice moes gaan vra waar die flippen sokkies nou al weer weggepak was. In my defence. Skoonma like dit om Tetris met klere te speel. Eers nadat ek 3 miljoen pare sokkies uitmekaar gehaal het (ek dink ek het al ’n Rubix-cube vinniger uitgesort) was die regte paar blou sokkies in my grip. Mission accomplished? No way broer... Kos my toe nog 5 trips om die regte baby-grow te gaan haal. Thanks aan Sanet vir die baby-grow wat amper my huwelik gekos het...

05:57am -
Ek kan in Marinice se oe begin sien dat die kontrakies met al sy maatjies opgedaag het. Daar is iets aan ’n vrou wat wydsbeen op ’n bed gaan hurk wat jou as man een van twee keuses gee. Either jy raak lucky, OF as jy aan haar gaan try raak, blaksam (ja dis bliksem met ’n A) sy jou net daar dood. Vir ’n split sekonde oorweeg ek dit nogal om my luck te try, maar ek merk aan haar gesig dat Marinice nou volledig gepossess is deur iets wat beslis nie meer afrikaans praat nie. No way vat ek aan haar sonder permissie vandag nie.

06:03am -
Ek het die verloskundige aan die lyn. Dis nou nadat ek 4 verkeerdes wakker gebel het. Sy is binne ’n halfuur daar.

06:16am -
Mens kan jou luck net so lank try. In ’n laaste pogin om die "beast wat my vrou possess" te please, try ek vir ’n laaste keer ’n kombersie uit die baba kamer haal. Nou teen die tyd het ek heeltemaal te mak geword, en was hopeloos te overconvident in my Ninja skills. Die kleinste squeeck van die kasdeur, rammel soos ’n Joburg donderstorm deur die doodstil kamer. Gefok. Ma en Pa sit regop in die bed. Soos ’n Springbok by die watergat wat onraad merk daar in die Serengethi kon hulle my soos ’n boek lees. Ek try my pose hou, maar Skoonma het snuf in die neus, en bee-line vir Marinice. Vir ’n oomblik oorweeg ek dit om haar te tackle, maar skoonpa besit 2 (ja 2) haalgewere, en ons kom nog Desember doop. Ek hou my in. Gelukkig gryp die "gewetens-mannetjie" weer in, en byt ek maar op my lip. 3 Steke verder...

06:25am -
Marinice kry amper ’n solo standing ovation van my toe sy haar Ma begin uitkak. Ek weet nie waar daai kontraksies geproduseer word nie, maar ek soek ’n hele bottel vol.

06:48am -
Verloskundige maak haar verskyning. Marinice hover nogsteeds oor die bed soos UFO wat ’n koei of iets wil opbeam na die mothership. Gelukkig sien die verloskundige hierdie soort dinge gereeld, en weet presies in watter tale en handgebare met die Alien (wat my vrou possess) kontak te maak. Nou volg een van die scary gedeeltes van die dag. Na ondersoek konstateer sy dat junior pophol eerste die wereld binne wil kom. 'n Soort van "brown-eye" re-entry. Ek is 110% wakker. Mense met kinders weet dis nie wat jy wil hoor as die water reeds gebreek het nie. Beide ek en Marinice kry gelukkig 'n bitch-slap van die vrou en word uitgele dat alles gelukkig vroeg opgetel is, en dat daar weinig risiko vir junior is. Op pad by die trap af word daar iets vanuit die baba-kamer geskree, maar Marinice gooi 'n flattie. Ek moet net brande blus, om die PR tussen ma en dogter in stand te hou.

07:03am -
Jaag hospitaal toe. Ek try met my kak humor die Alien te paai, maar dit help nie. Hy't nou volle beheer oor Marinice, en hy gaan nie prisinors vat nie. By elke traffic lig en stopstraat gooi ek 'n skiet-gebed dat hy my ook nie moet saamvat as die priester hom later met Holy-water moet gaan uitwis nie (sien film "The Exorsist"). Verloskundige bel die hospitaal onder weg, so die paramedics weet hulle moet flugsout en rolstoel gereed he vir my.

07:17am -
Die 4 van ons arriveer (heel) by die hopsitaal. Dit was assof die trip hospitaal toe in slow motion gebeur het. Klaarblyklik is onmoonlik vir mans om vinniger as 15km/h te ry met 'n kramende vrou in die kar. Go figure.

07:47am -
Die volgende halfuur verdwyn in 'n blur. Alles te make met papierwerk, bloeddtrek en sulke groceries. Verloskundige is nou alleen by in die rol van "tolk" tussen Alien en die res van die hospitaal personeel. Marinice word gewire met die selfde toerusting waarmee die destydse Kremlin die Pentagon skelm beluister het. Alles (hardklop en contractions) word nou oor 'n luidspreker gebroadcast. Die luister-apparaat is so sensitief dat toe ek 'n flou poep probeer los het van stress, almal onmiddelik in my rigting gekyk het. Doodse stilte volg terwyl almal luister hoe 'n ou 3 vloere onder ons bacon en eiers vir breakfast bestel. Gelukkig vir my gee "Radio Contractions FM" my 'n heads-up wanneer 'n kontraksie gaan begin. Net genoeg vir my om te koes of te brace vir die daaropvolgende geweld.

07:54am -
Chief on-duty ginyko.. gyniko... gieneko... man daai dokter wat ’n man nooit in sy lewe sal besoek nie, maak haar verskyning met die opsies. Normale bevalling, of C-section. 'n Split sekonde se "lapse in concentration" mis ek 'n waarskuwing oor die luidspreker en gryp die Alien my om die nek. My lewe flits voor my oe verby. Goodbye gruel world. Gelukkig kom die verloskundige tot my redding soos een van daai referees op WWF. Een vir een verwyder die ER dokter Marinice naels uit my bo-arm. Gevoel keer terug in my gesig.

07:55am -
Marinice is nie gepla oor hoe of wat nie. Al wat sy wil weet is "waars die drugs?".

08:07am -
Die oomblik van die groot besluit is met ons. a-la-Naturel, of operasie saal in. Op hierdie stadium maak dit nie meer vir my saak nie, so lank hulle MY net wil drug. Saam word daar in die interrese van junior besluit op 'n keisersnee. Nogal scary, maar ons glo dat dit die regte besluit is. Ons word gecoach terwyl die OK (operasie kamer) geboek word. Alles word vertel, en daar word seker gemaak dat ek "guts en gore" kan handle, siende dat hulle (hospitaal) nie nog 'n law-suite kan handle nie. Just in case word ek die korste pad na die toilet gewys. Marinice breek intussen nog een van my vingers. Waar bly die drugs!?

08:15am -
Ons kry die eerste oop spot in die OK. Marinice word afgehaak van die afluister-apperaat. Pitty, want ons was net lekker aan luister na 'n iPod iewers op die 2de verdieping. Net voor sy om die hoek verdwyn kyk Marinice nog vir ’n laaste keer my rigting net asof om te se “jy kan flippen bly wees”... Iewers in die gang gee die Alien sy laaste shrill.

08:21am -
Voor ons die operasie kamer binne mag gaan word ek eers agter gehou terwyl Marinice solank geprep kan word. Ek kry ’n groen suite om aan te trek en ’n wit maskter waaragter ek die bekommerde uitdrukking op my gesig kan verberg. 08:34am -
Nou vir die 2de beste ding van die dag. Ek wil baie graag die ou ontmoet wat die epiduraal ontdek het. Nog nooit het ek ’n exorsism so vinnig sien gebeur nie. In ’n kwessie van 10 minute was die abduction van Marinice verby en kon sy actually sonder enige geskree en kru taal met my praat. Mr Epiduraal, jy kort ’n medalje.

08:37am -
Vir oulaas word my uitgewys waar die toilette is, terwyl ek my plek by Marinice se kop inneem. Kry selfs ’n stoeltjie. Gooi twee keer in my mond op, maar ek hou my pose. Niemand kan tog my gesig sien agter die wit masker sien nie. Hoop ek.

08:46am -
Noudat meeste van die stof gaan le het, kan ek die scenery begin inneem. Ek tel 15 mense in die operasie kamer, ons ingesluit. Ek begin wonder waarom daar soveel mense nodig was vir so klein mensie. Was dit almal vir hom, of was die meeste net op standby om my uit te dra as ek flou sou word? Op hierdie stadium worry ek nie meer nie, siende dat ek nou op my mediese fonds se tyd is. Die dokter maak sy verskyning met sy geskrope handjies. Hy gooi eers daai Derick Hougaart move met sy hande (voor hy pale toe skop), pause vir 3 sekondes en een van die nurses klap die rubber gloves aan hom. Kon nooit daai een lekker vang nie. Wat help al die geskrop van jou vingers, as jy anyway met die rubber gloves eers jou gat lekker gaan krap voor jy iemand oopsny? Anyway, net soos in die movies buk hy oor sy pasient, en bulk aan die naaste nurse “scalpel!”. Die show gaan begin.

08:53am -
Dis aan my oorgelaat om running commentary aan Marinice te gee, siende haar view met ’n skerm geblok is. Ek verstel my seat so dat ek ’n birds-eye view het van die speelveld. Vir oulaas word deur die narkotiseer gecheck of sy genuine geen gevoel het in haar onderlyf nie, en die go-ahead word aan die dokter gegee.

08:55am -
Dis asof hierdie dokter ’n golf afspraak vir 9uur gehad het. Met oe verblindende spoed, en met wat op ’n stadium 6 hande gelyk het, is die sny gemaak, klamps gesit, 2 hande in haar maag gepositioneer en die suigslang ingespan. Dit was gross, exiting, scary, weird, bietjie snaaks en verskriklik intens. Amper soos Trevor Manual se begroting aankondiging. Al die gewoel en gewerksaf het genuine soos sekondes gevoel, want ek het my bes probeer om Marinice op hoogte te hou. Op ’n stadium wou ek vra dat hulle asseblief vir haar ’n periskoop moet gee om oor hierdie Berlin Wall te kan kyk, maar ek het die situasie korrek opgesom deur te besef hierdie was nie die beste tyd vir my kak jokes nie. En voor ek my kon kry...

08:58am -
...hoor ek daai skree. Emosies van lag, huil en kots kom by op toe hulle my seun te voorskyn bring. Mens sien dit op TV en in films, maar hierdie was die real deal. Geen special effects nie. Geniune bloed en snot. Ek gee Marinice ’n vet soen op die voorkop, toe ek gevra word om 2 van die nurses na buite te volg om junior uit te gaan check. Binne gaan die dokter eers ’n paar dinge nog verwyder, en double check of daar geen illigale immigrante in die hoeke van haar baarmoeder skuil nie.

09:01am -
Al die nurses wens my geluk. Ek voel bietjie sleg siende dat Marinice meeste van die werk hier verrig het. Maar then again, vir die volgende 21 jaar gaan ek die een wees wat suffer. Ek geniet my 5 minutes of fame. Nurses check-check-double-check of alles goed vasgeskroef is aan junior, en stop ‘n sker in my hand. Dis nou om die koord te knip. Vir ‘n oomblik dink ek by myself of hulle nie iemand meer gekwalifiseerd benodig vir sulke jobs nie. Met die presiesie van ’n Rabbi sny ek die serimonial lint deur. Ek verklaar hierdie basaar geopen.

09:06am -
Ek kry vir die eerste keer geleentheid die kans om ’n foto te snap, en maak volle gebruik van die geleentheid om die oulike nurses af te neem.

09:36am -
Die span wonderlike verpleegsters vat junior weg om geweeg, gemeet en gepoke te word, terwyl ek by my vrou, "the artist formaly known as The Alien", aansluit. Narkose is besig om stadig maar seker uit haar lyf te trek, maar ek kan in haar oe sien dat sy nie kan wag om junior in haar arms te hou nie. Ek word na ’n kort briefing weer weggevat om haar kans te gee om te herstel.
10:17am -
Uiteindelik is die roller coaster ride verby. Kalmte keer terug in my gemoed, en ek word vir ’n oomblik alleen gelaat met my gedagtes. Ek maak gebruik om my Pa te bel, en die goeie nuus te deel. Ma is nie daar nie, maar latere gerigte dui op pandemonium wat losgebars het by haar biduur toe my Ma ’n SMS van my Pa gekry het. 7 Prozacs later was sy weer alright. Paar ander mense word ook ingelig oor die blye tyding, waaronder die skoonouers. My seun sluit by my aan, lekker toegedraai in ’n kombers en ingetuk in sy mobiele bedjie.

10:56am -
Soos ek daar staan en na hom kyk terwyl hy slaap, kan ek nie glo dat so iets moois van my genes kan kom nie. En dis net daar waar paniek insak. Wat as ek nie ’n goeie Pa is nie? Wat as hy my nie gaan like nie? Wat as hy groot word tussen die verkeerde vriende? Wat as hy my geld op Stellenbosch gaan mors? Wat as hy vir die Bulle rugby gaan speel? Al my vrese skiet in ’n fits voor my verby, maar weet jy - toe junior sy ogies vir ’n oomblik oopmaak, ‘n diep gaap gee, en uit die hoek van sy mond ’n glimlaggie trek, weet ek dat daai ’n ander dag se worries is.

Welcome, Willkommen, Bienvenue, Benvenuto and Howzit!

Finally we've decided to enter the world of Blogging. Hopefully we'll not fall into the same trap as years gone by and neglect to inform our fan base world-wide.

I'll try and update the blog regularly with bits, pieces, bobs and knobs of information on our life here in Holland.

To our Afrikaans illiterate readers, my humble apologies beforehand. Some of the blogs may contain Afrikaans-only text, and cannot be interpreted by use of BabelFish. Last time someone tried to translate one of my Blogs from Afrikaans to English, he almost brought down the site due to the complexity of the words used. So be warned... ;)

Anyway, here goes...