Coders For Charities St. Louis

I had a great time this weekend at the first St. Louis Coders 4 Charities weekend.

Over 60 people showed up to create or revamp web sites, applications and networks for nine local charities:

Our team ported three United Way web sites to DotNetNuke: http://www.211missouri.org/, http://www.211southwestillinois.org/, and http://www.100neediestcases.org/. (Those are the “prevamp” sites – The revamp sites look about the same, but will be much easier for “normal people” to administer.)

There was plenty of food - That's me holding
the world's largest pizza box.

My teammates were:

  • Scott "DotNetNuke Kingpin" Allender
  • Shanti “Queen of CSS” Nutheti
  • Jack “Jack” Menge
  • Mark “Ace” Cooper
  • from the United Way, Jim “Full” House
  • and our team leader Scott um… “Ate a Club Sandwich” Spradlin

Some of the teams worked late into the night last night on their projects. Ours managed fairly reasonable hours – I spent a total of about 22 hours at the site over the weekend. It was a lot of work, but a whole lot of fun. It was great to get to know some other local developers and it was an honor to be part of such a worthwhile event.

Special thanks to:

  • Kevin Grossnicklaus for organizing the event:

  • Muljadi Budiman, for organizing, coordinating, and setting up the C4CSTL web site:

  • the aforementioned Scott "Kingpin" Allender. There were three teams using DotNetNuke for their projects, and Scott, leader of the St. Louis DNN User Group, was in high demand:

  • Clint Edmonson, our developer evangelist (I was a little disappointed that "the evangelist" didn't preach a sermon on Sunday morning - maybe a reading from the Book of Azure) for (I hope) not minding that I stole these pictures from his Flickr pool (more C4CSTL pictures here)

While browsing Clint’s Flickr photos (he’s a great photographer), I was struck by the similarities between two of his recent pictures:

Give this guy a laptop and some dorky glasses:

...and he'd be a dead ringer for this guy:

No animals were harmed in the making of my notebook

I get lambasted (which has nothing to do with cooking baby sheep, by the way) every time I blog about spelling, grammar or pronunciation, but…

It’s pronounced “mol-a-skeen'-a”. Those trendy Moleskine notebooks are not made from mole skin.

(Although, for all I know, Moleskine might be Italian for “mole skin” – The company’s “legendary” claims seem to be a bit hyperbolic. The brand wasn’t registered until 1996: http://en.wikipedia.org/wiki/Moleskine

Sweet TweetDeck Upgrade

I installed TweetDeck v.0.31.1 last night, and it has all of the features on my wish list:

  • keyboard shortcuts
  • control over the positioning of notifications (I moved them down to the lower-right corner – They used to be in the upper-right, and always popped up covering up the Firefox search box just as I was about to use it)
  • notifications now show the contents of new tweets, not just a count of how many there are

http://www.tweetdeck.com/beta/download/

“Classic ASP” Debug Include File

Last month, I had the “opportunity” (as we’ve been trained to say) to do some maintenance on a “Classic ASP” site.

I’d forgotten how painful that can be, but it was made a bit easier by dusting off an old tool from the dark ages.

It’s an “include” file for debugging based on a Visual Basic Programmer’s Journal article by Jonathan Goodyear from way back in February, 2001: http://support.microsoft.com/kb/288965.

It automatically dumps out cookie, form, query string, session and application variable values at the bottom of the page, and adds the ability to insert “Debug.Print” or “Debug.PrintKeyAndValue” statements in your VBScript, as seen in this sample page:

 

<% 
Option Explicit 
Response.Buffer = True 
%>
<!--#INCLUDE VIRTUAL="Include_Debug.asp"-->
<html>
<body>
    <h1>
        Welcome to my beautiful "Classic ASP" page!</h1>
    <br>
    <img src="images/ObligatoryUnderConstructionImage.jpg">
    <br>
    <img src="images/SuperfluousDancingHamster.gif">
    <br>
    <marquee width="500px"><font color="purple">Remember when people thought marquee tags were cool!?</font></marquee>
    <p>
        <font color="fuchsia">...and font tags!?</font></p>
<%
Dim intSpaceIndex 
Dim strTime 
Dim strDateAndTime 
 
strDateAndTime = Now
Debug.Print "Instead of using the VB Format command, I'm going to do unnecessary string manipulation..." 
Debug.PrintKeyAndValue "strDateAndTime", strDateAndTime 
intSpaceIndex = InStr(strDateAndTime, " ") 
Debug.PrintKeyAndValue "intSpaceIndex", intSpaceIndex 
strTime = Mid(strDateAndTime, intSpaceIndex + 1)
Debug.PrintKeyAndValue "strTime", strTime 
%>
    <p>The current time, in case you're too lazy to look down at your Windows taskbar, is <% =strTime %></p>
</body>
</html>

 

The “classic” code above results in this thrilling display:

 

Welcome to my beautiful "Classic ASP" page!




Remember when people thought marquee tags were cool!?

...and font tags!?

The current time, in case you're too lazy to look down at your Windows taskbar, is 12:45:38 PM


Request Details

Session ID: 465736891 Request Type: GET
Time of Request: 10/6/2009 12:45:38 PM Status Code: 200 OK
Session Timeout: 20 minutes Total Bytes: 0
Elapsed Time: < 1 second

Debug.Print Entries

Name Value
Instead of using the VB Format command, I'm going to do unnecessary string manipulation...
strDateAndTime 10/6/2009 12:45:38 PM
intSpaceIndex 10
strTime '12:45:38 PM'

Request.QueryString Collection


Request.Form Collection


Request.Cookies Collection

Name Value
MyCookie 'AccessLevel=4&CompanyCode=1234&UserID=303409&FirstName=BRIAN&LastName=SCHROER'
MyCookie("AccessLevel") '4'
MyCookie("CompanyCode") '1234'
MyCookie("UserID") '303409'
MyCookie("FirstName") 'BRIAN'
MyCookie("LastName") 'SCHROER'

Request.ServerVariables Collection

Name Value
ALL_HTTP 'HTTP_ACCEPT:*/* HTTP_ACCEPT_LANGUAGE:en-us HTTP_CONNECTION:Keep-Alive HTTP_HOST:localhost HTTP_USER_AGENT:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; MS-RTC EA 2) HTTP_COOKIE:MyCookie=LastName=SCHROER&FirstName=BRIAN&UserID=303409&CompanyCode=1234&AccessLevel=4; ASPSESSIONIDCQBSCBTC=DLEJCMLBCILFLEJHLJONJDIO HTTP_UA_CPU:x86 HTTP_ACCEPT_ENCODING:gzip, deflate '
ALL_RAW 'Accept: */* Accept-Language: en-us Connection: Keep-Alive Host: localhost User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; MS-RTC EA 2) Cookie: MyCookie=LastName=SCHROER&FirstName=BRIAN&UserID=303409&CompanyCode=1234&AccessLevel=4; ASPSESSIONIDCQBSCBTC=DLEJCMLBCILFLEJHLJONJDIO UA-CPU: x86 Accept-Encoding: gzip, deflate '
APPL_MD_PATH '/LM/w3svc/1/ROOT/FakeProject'
APPL_PHYSICAL_PATH 'C:\data\projects\Current\FakeProject\'
AUTH_PASSWORD ''
AUTH_TYPE 'Negotiate'
AUTH_USER 'MyDomain\BSCHROER'
CERT_COOKIE ''
CERT_FLAGS ''
CERT_ISSUER ''
CERT_KEYSIZE ''
CERT_SECRETKEYSIZE ''
CERT_SERIALNUMBER ''
CERT_SERVER_ISSUER ''
CERT_SERVER_SUBJECT ''
CERT_SUBJECT ''
CONTENT_LENGTH '0'
CONTENT_TYPE ''
GATEWAY_INTERFACE 'CGI/1.1'
HTTPS 'off'
HTTPS_KEYSIZE ''
HTTPS_SECRETKEYSIZE ''
HTTPS_SERVER_ISSUER ''
HTTPS_SERVER_SUBJECT ''
HTTP_ACCEPT '*/*'
HTTP_ACCEPT_ENCODING 'gzip, deflate'
HTTP_ACCEPT_LANGUAGE 'en-us'
HTTP_CONNECTION 'Keep-Alive'
HTTP_COOKIE 'MyCookie=LastName=SCHROER&FirstName=BRIAN&UserID=303409&CompanyCode=1234&AccessLevel=4; ASPSESSIONIDCQBSCBTC=DLEJCMLBCILFLEJHLJONJDIO'
HTTP_HOST 'localhost'
HTTP_UA_CPU 'x86'
HTTP_USER_AGENT 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; MS-RTC LM 8; MS-RTC EA 2)'
INSTANCE_ID '1'
INSTANCE_META_PATH '/LM/W3SVC/1'
LOCAL_ADDR '127.0.0.1'
LOGON_USER 'MyDomain\BSCHROER'
PATH_INFO '/FakeProject/classic.asp'
PATH_TRANSLATED 'C:\data\projects\Current\FakeProject\classic.asp'
QUERY_STRING ''
REMOTE_ADDR '127.0.0.1'
REMOTE_HOST '127.0.0.1'
REMOTE_USER 'MyDomain\BSCHROER'
REQUEST_METHOD 'GET'
SCRIPT_NAME '/FakeProject/classic.asp'
SERVER_NAME 'localhost'
SERVER_PORT '80'
SERVER_PORT_SECURE '0'
SERVER_PROTOCOL 'HTTP/1.1'
SERVER_SOFTWARE 'Microsoft-IIS/5.1'
URL '/FakeProject/classic.asp'

Session.Contents Collection


Session.StaticObjects Collection


Application.Contents Collection


Application.StaticObjects Collection

 

I know a lot of developers are stuck supporting old ASP sites. If you’re one of them, here’s the source code for my include file. I hope it helps to dull the pain:

 

<%
    Dim Debug    ' As clsDebug
 
    Set Debug = New clsDebug
    
    With Debug
        .Enabled = True
        .AutoDisplayOnTerminate = True
    End With
    
Class clsDebug
'============================================================
'  Class Name:  clsDebug
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:  VBScript ASP debug class
'                Based on article by Jonathan Goodyear 
'               in Visual Basic Programmer's Journal 
'               (February 2001, Vol. 11, No. 2, p. 68) 
'   Revisions:
'    09/12/2001    Brian Schroer
'                Added Silent logic
'============================================================
    Dim mbAutoDisplayOnTerminate    ' As Boolean
    Dim mDictionary                    ' As Scripting.Dictionary
    Dim mbDispRequestDetailsEnabled    ' As Boolean
    Dim mbDispDebugPrintsEnabled    ' As Boolean
    Dim mbDispQueryStringsEnabled    ' As Boolean
    Dim mbDispFormDataEnabled        ' As Boolean
    Dim mbDispCookiesEnabled        ' As Boolean
    Dim mbDispServerVariablesEnabled _
                                    ' As Boolean
    Dim mbDispSessionContentsEnabled _
                                    ' As Boolean
    Dim mbDispSessionStaticObjectsEnabled _
                                    ' As Boolean
    Dim mbDispAppContentsEnabled    ' As Boolean
    Dim mbDispAppStaticObjectsEnabled _
                                    ' As Boolean
    Dim mbEnabled                    ' As Boolean
    Dim mdtRequestTime                ' As Date
    Dim mdtFinishTime                ' As Date
    Dim mbShadeRow                    ' As Boolean
    Dim mbSilent                    ' As Boolean
    Dim mbSilentInitialized            ' As Boolean
    Dim msTD                        ' As String
    Dim msTD_Close                    ' As String
    Dim msTR                        ' As String
    Dim msTR_Close                    ' As String
 
Private Sub Class_Initialize()
'------------------------------------------------------------
'  Subroutine:    Class_Initialize
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    When class is initialized, initialize variables
'                and create dictionary object
'   Revisions:
'------------------------------------------------------------   
    AutoDisplayOnTerminate = False
    DispRequestDetailsEnabled = True
    DispDebugPrintsEnabled = True
    DispQueryStringsEnabled    = True
    Set mDictionary = Server.CreateObject("Scripting.Dictionary")
    DispFormDataEnabled    = True
    DispCookiesEnabled = True
    DispServerVariablesEnabled = True
    DispSessionContentsEnabled = True
    DispSessionStaticObjectsEnabled    = True
    DispAppContentsEnabled    = True
    DispAppStaticObjectsEnabled = True
    Enabled = False
    mdtRequestTime = Now
    mbSilent = False
    msTR = vbCrLf & "    <tr "
    msTR_Close = vbCrLf & "    </tr>"
    msTD = vbCrLf & "        <td"
    msTD_Close = vbCrLf & "        </td>"
End Sub
 
Private Sub Class_Terminate()
'------------------------------------------------------------
'  Subroutine:    Class_Terminate
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Before class is terminated, release objects
'   Revisions:
'    03/08/2001    Brian Schroer
'                Added AutoDisplayOnTerminate logic
'------------------------------------------------------------
    If mbAutoDisplayOnTerminate Then
        Call Display()
    End If
    
    Set mDictionary = Nothing
End Sub
 
Public Property Get AutoDisplayOnTerminate() ' As Boolean
'------------------------------------------------------------
'    Property:    AutoDisplayOnTerminate
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Automatically invoke Display method when
'                class terminates?
'   Revisions:
'------------------------------------------------------------
    AutoDisplayOnTerminate = mbAutoDisplayOnTerminate
End Property
Public Property Let AutoDisplayOnTerminate(ByVal Value)
    mbAutoDisplayOnTerminate = Value
End Property
 
Public Property Get Enabled() ' As Boolean
'------------------------------------------------------------
'    Property:    Enabled
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Enables/disabled debugging.
'   Revisions:
'------------------------------------------------------------
    Enabled = mbEnabled
End Property
Public Property Let Enabled(ByVal Value)
    mbEnabled = Value
End Property
 
Public Sub Print(ByVal Output)
'------------------------------------------------------------
'  Subroutine:    Print
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Add input to collection to be "Printed"
'                via Display method
'   Revisions:
'------------------------------------------------------------
    If mbEnabled Then
        ' save output to internal dictionary
        Call mDictionary.Add("Debug.Print#" & CStr(mDictionary.Count), Output)
    End If
End Sub
 
Public Sub PrintKeyAndValue(ByVal sKey, ByVal sValue)
'------------------------------------------------------------
'  Subroutine:    PrintEx
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Add inputs to collection to be "Printed"
'                via Display method
'   Revisions:
'------------------------------------------------------------
    If mbEnabled Then
        ' save output to internal dictionary
        Call mDictionary.Add(sKey, sValue)
    End If
End Sub
 
Public Sub Display()
'------------------------------------------------------------
'  Subroutine:    Display
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Display debug information
'   Revisions:
'------------------------------------------------------------
    mdtFinishTime = Now
    
    If Enabled Then
 
        If DispRequestDetailsEnabled Then
            Call DisplayRequestDetails()
        End If
 
        If DispDebugPrintsEnabled Then
            If mDictionary.Count > 0 Then
                Call DisplayPrints()
            End If
        End If
        
        If DispQueryStringsEnabled Then
            Call DisplayQueryStrings()
        End If
        
        If DispFormDataEnabled Then
            Call DisplayFormData()
        End If
        
        If DispCookiesEnabled Then
            Call DisplayCookies()
        End If
        
        If DispServerVariablesEnabled Then
            Call DisplayServerVariables()
        End If
 
        If DispSessionContentsEnabled Then
            Call DisplaySessionContents() 
        End If     
 
        If DispSessionStaticObjectsEnabled Then
            Call DisplaySessionStaticObjects() 
        End If    
 
        If DispAppContentsEnabled Then
            Call DisplayAppContents()
        End If
 
        If DispAppStaticObjectsEnabled Then
            Call DisplayAppStaticObjects()
        End If
    End If
End Sub
 
Public Sub DisplayRequestDetails()
'------------------------------------------------------------
'  Subroutine:    DisplayRequestDetails
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Display request details
'   Revisions:
'    03/14/2001    Brian Schroer
'                Added "no Session" logic
'------------------------------------------------------------
    Dim llSeconds            ' As Long
    Dim lsSeconds            ' As String
    Dim lsSessionID            ' As String
    Dim lsSessionTimeout    ' As String
    
    lsSessionId = "(no session)"
    lsSessionTimeout = "(no session)"
    
    On Error Resume Next
    
    If Not IsEmpty(Session) Then
        lsSessionID = Session.SessionID
        lsSessionTimeout = CStr(Session.Timeout) & " minutes"
    End If
    
    On Error GoTo 0
    Err.Clear
    
    llSeconds = DateDiff("s", mdtRequestTime, mdtFinishTime)
    
    Select Case llSeconds
        Case 0
            lsSeconds = "< 1 second"
        Case 1
            lsSeconds = "1 second"
        Case Else
            lsSeconds = Cstr(llSeconds) & " seconds"
    End Select
    
    Call msb_GroupInitialize("Request Details")
    
    With Response
        msb_DebugWrite msTR & ">"
            Call msb_ReqDtlShow("Session ID", lsSessionID)
            Call msb_ReqDtlShow("Request Type", Request.ServerVariables("REQUEST_METHOD"))
        msb_DebugWrite msTR_Close
        msb_DebugWrite msTR & ">"
            Call msb_ReqDtlShow("Time of Request", FormatDateTime(mdtRequestTime))
            Call msb_ReqDtlShow("Status Code", .Status)
        msb_DebugWrite msTR_Close
        msb_DebugWrite msTR & ">"
            Call msb_ReqDtlShow("Session Timeout", lsSessionTimeout)
            Call msb_ReqDtlShow("Total Bytes", CStr(Request.TotalBytes))
        msb_DebugWrite msTR_Close
        msb_DebugWrite msTR & ">"
            Call msb_ReqDtlShow("Elapsed Time", lsSeconds)
            If Not IsNull(.Expires) Then
                Call msb_ReqDtlShow("Expires", _
                    CStr(.Expires) & " minutes<BR>" _
                    & FormatDateTime(.ExpiresAbsolute))
            End If
        msb_DebugWrite msTR_Close
    End With
    
    Call msb_GroupTerminate
End Sub
 
Private Sub msb_ReqDtlShow(ByVal asLabel, ByVal asValue)
'------------------------------------------------------------
'  Subroutine:    msb_ReqDtlShow
'      Author:  Brian Schroer
'        Date:  03/14/2001
' Description:    Display request detail data
'      Inputs:    asLabel    = label
'                asValue    = value
'   Revisions:
'------------------------------------------------------------
    If mbSilent Then
        msb_MemberPrint asLabel, asValue
    Else
        msb_DebugWrite msTD & "><small><b>" 
        msb_DebugWrite asLabel 
        msb_DebugWrite ":</b></small>" & msTD_Close
        msb_DebugWrite msTD & "><small>"
        msb_DebugWrite asValue 
        msb_DebugWrite "</small>" & msTD_Close
    End If
End Sub
 
Public Sub DisplayPrints()
'------------------------------------------------------------
'  Subroutine:    DisplayPrints
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Debug.Print collect
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Debug.Print Entries", _
        mDictionary, _
        False)
End Sub
 
Public Sub DisplayQueryStrings()
'------------------------------------------------------------
'  Subroutine:    DisplayQueryStrings
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Request.QueryString collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Request.QueryString Collection", _
        Request.QueryString(), _
        True)
End Sub
 
Public Sub DisplayFormData()
'------------------------------------------------------------
'  Subroutine:    DisplayFormData
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Request.Form collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Request.Form Collection", _
        Request.Form(), _
        True)
End Sub
 
Public Sub DisplayCookies()
'------------------------------------------------------------
'  Subroutine:    DisplayCookies
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Request.Cookies collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Request.Cookies Collection", _
        Request.Cookies(), _
        True)
End Sub
 
Public Sub DisplayServerVariables()
'------------------------------------------------------------
'  Subroutine:    DisplayServerVariables
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Request.ServerVariables collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Request.ServerVariables Collection", _
        Request.ServerVariables(), _
        True)
End Sub
 
Public Sub DisplaySessionContents()
'------------------------------------------------------------
'  Subroutine:    DisplaySessionContents
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Session.Contents collection
'   Revisions:
'------------------------------------------------------------
    If Session Is Nothing Then
        Call msb_CollectionPrint("Session.Contents Collection", Nothing, True)
    Else
        Call msb_CollectionPrint("Session.Contents Collection", Session.Contents(), True)
    End If
End Sub
 
Public Sub DisplaySessionStaticObjects()
'------------------------------------------------------------
'  Subroutine:    DisplaySessionStaticObjects
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Session.StaticObjects collection
'   Revisions:
'------------------------------------------------------------
    If Session Is Nothing Then
        Call msb_CollectionPrint("Session.StaticObjects Collection", Session.StaticObjects(), True)
    Else
        Call msb_CollectionPrint("Session.StaticObjects Collection", Nothing, True)
    End If
End Sub
 
Public Sub DisplayAppContents()
'------------------------------------------------------------
'  Subroutine:    DisplayAppContents
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Application.Contents collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Application.Contents Collection", _
        Application.Contents(), _
        True)    
End Sub
 
Public Sub DisplayAppStaticObjects()
'------------------------------------------------------------
'  Subroutine:    DisplayAppStaticObjects
'      Author:  Brian Schroer
'        Date:  03/08/2001
' Description:    Display Application.StaticObjects collection
'   Revisions:
'------------------------------------------------------------
    Call msb_CollectionPrint( _
        "Application.StaticObjects Collection", _
        Application.StaticObjects(), _
        True)   
End Sub
 
Private Sub msb_CollectionPrint(ByVal CollectionName, ByVal Collection, ByVal abSorted)
'------------------------------------------------------------
'  Subroutine:    msb_CollectionPrint
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Print contents of collection
'   Revisions:
'    09/12/2001    Brian Schroer
'                Added abSorted logic
'------------------------------------------------------------
    Dim lvItem        ' As Variant
    
    Call msb_GroupInitialize(CollectionName)
 
    If Not Collection Is Nothing Then
        If Collection.Count > 0 Then
            If Not mbSilent Then
                msb_DebugWrite msTR & " style=""BACKGROUND-COLOR: gray"">"
                    msb_DebugWrite msTD
                    msb_DebugWrite "><small><b>"
                    msb_DebugWrite "Name"
                    msb_DebugWrite "</b></small>" & msTD_Close
                    msb_DebugWrite msTD
                    msb_DebugWrite "><small><b>&nbsp;"
                    msb_DebugWrite "Value"
                    msb_DebugWrite "</b></small>" & msTD_Close
                msb_DebugWrite msTR_Close
            End If
        End If
 
        mbShadeRow = True
            
        If abSorted Then
            If Collection.Count > 0 Then
                For Each lvItem In mfn_v_Debug_SortedDictKeys(Collection)
                    Call msb_MemberPrint(lvItem, Collection(lvItem))
                Next
            End If
        Else
            For Each lvItem In Collection
                Call msb_MemberPrint(lvItem, Collection(lvItem))
            Next
        End If    
    End If
    
    Call msb_GroupTerminate
End Sub
 
Private Sub msb_GroupInitialize(ByVal asTitle)
'------------------------------------------------------------
'  Subroutine:    msb_GroupInitialize
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Initialize display group
'      Inputs:    asTitle = group title
'   Revisions:
'------------------------------------------------------------    
    If Not mbSilentInitialized Then
        mbSilentInitialized = True
        If mbSilent Then
            Response.Write vbCrLf & "<!-- " _
                & vbCrLf & String(60, "=") _
                & vbCrLf & asTitle _
                & vbCrLf & String(60, "=") & vbCrLf
            Exit Sub
        End If
    End If
 
    msb_DebugWrite vbCrLf & vbCrLf
    msb_DebugWrite "<BR>"
    msb_DebugWrite vbCrLf
    msb_DebugWrite "<table style=""background: black; color: white;" _
        & " font-family: Verdana, Arial, Helvetica, ""Sans Serif"";" _
        & " font-size: x-small"" border=0 width=""100%"">"
    msb_DebugWrite msTR & ">"
    msb_DebugWrite msTD & "><b><p><small>"
    msb_DebugWrite asTitle
    msb_DebugWrite "</small></p></b>"
    msb_DebugWrite msTD_Close
    msb_DebugWrite msTR_Close
    msb_DebugWrite vbCrLf
    msb_DebugWrite "</table>"
    msb_DebugWrite vbCrlf
    msb_DebugWrite "<table style=""background: white; color: black;" _
        & " font-family: Verdana, Arial, Helvetica, ""Sans Serif"";" _ 
        & " font-size: x-small"" border=0 cellPadding=0 cellSpacing=0 width=""100%"">"
    
    mbShadeRow = False
End Sub
 
Private Sub msb_MemberPrint( _
            ByVal asName, _
            ByVal avValue)
'------------------------------------------------------------
'  Subroutine:    msb_MemberPrint
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Print collection/array member
'   Revisions:
'------------------------------------------------------------
    Dim llBlank        ' As Long
    Dim lsDelim        ' As String
    Dim llIndex        ' As Long
    Dim lvItem        ' As Variant
    Const llMax = 30
    Dim lsName        ' As String
    Dim lsTypeName    ' As String
    Dim lsValue        ' As String
                
    lsTypeName = TypeName(avValue)
        
    lsValue = "(" & lsTypeName & " object)"
        
    Select Case lsTypeName
            
        Case "Variant()"
            
            llIndex = LBound(avValue)
            lsName = asName
            If Right(lsName, 1) = ")" Then
                lsName = Left(lsName, (Len(lsName) -1)) & ","
            Else
                lsName = lsName & "("
            End If
            For Each lvItem In avValue
                Call msb_MemberPrint( _
                    lsName & CStr(llIndex) & ")", _
                    lvItem)
                llIndex = llIndex + 1
            Next
                
        Case Else
                
            mbShadeRow = Not mbShadeRow
        
            If mbShadeRow Then
                msb_DebugWrite msTR & " valign=top style=""BACKGROUND-COLOR: silver"">"
            Else
                msb_DebugWrite msTR & " valign=top>"
            End If
 
            lsName = asName
        
            If Len(lsName) > llMax Then
                llBlank = Instr(1, lsName, " ")
                If llBlank < 1 Or llBlank > llMax Then
                    lsName = Left(lsName, llMax) & "<BR>" & Mid(lsName, llMax + 1)
                End If
            End If
    
            If Left(asName, 12) = "Debug.Print#" Then
                msb_DebugWrite msTD & " colspan=2"
                lsDelim = ""
            Else
                If mbSilent Then
                    msb_DebugWrite lsName & ":" & vbCrLf
                Else
                    msb_DebugWrite msTD 
                    msb_DebugWrite "><small>"
                    msb_DebugWrite lsName
                    msb_DebugWrite "</small>" & msTD_Close
                    msb_DebugWrite msTD
                End If 
                lsDelim = "'"    
            End If
 
            msb_DebugWrite "><small>"
            
            On Error Resume Next
            lsValue = CStr(avValue)
            On Error Goto 0
                
            Select Case lsTypeName
                Case "String", "IStringList", "IReadCookie"
                    lsValue = lsDelim & lsValue & lsDelim
                Case "Empty"
                    lsValue = "(Empty)"
            End Select
                
            If mbSilent Then
                msb_DebugWrite lsValue & vbCrLf & vbCrLf
            Else
                msb_DebugWrite "&nbsp;" & lsValue 
            End If
            
            If lsTypeName = "IReadCookie" Then
                If avValue.HasKeys Then
                    For Each lvItem In avValue
                        Call msb_MemberPrint( _
                            lsName & "(""" & lvItem & """)", _
                            avValue.Item(lvItem))
                        llIndex = llIndex + 1
                    Next
                End If
            End If
    End Select
        
    msb_DebugWrite "</small>" & msTD_Close
    msb_DebugWrite msTR_Close
End Sub
 
Private Sub msb_GroupTerminate()
'------------------------------------------------------------
'  Subroutine:    msb_GroupTerminate
'      Author:  Brian Schroer
'        Date:  03/06/2001
' Description:    Terminate display group
'   Revisions:
'------------------------------------------------------------
    If mbSilent Then
        Response.Write vbCrLf & "-->"
        mbSilentInitialized = False
    Else
        msb_DebugWrite vbCrLf
        msb_DebugWrite "</table>"
    End If
End Sub
 
Public Property Get DispRequestDetailsEnabled() ' As Boolean
    DispRequestDetailsEnabled = mbDispRequestDetailsEnabled
End Property
Public Property Let DispRequestDetailsEnabled(ByVal Value)
    mbDispRequestDetailsEnabled = Value
End Property
 
Public Property Get DispDebugPrintsEnabled() ' As Boolean
    DispDebugPrintsEnabled = mbDispDebugPrintsEnabled
End Property
Public Property Let DispDebugPrintsEnabled(ByVal Value)
    mbDispDebugPrintsEnabled = Value
End Property
 
Public Property Get Silent() ' As Boolean
    Silent = mbSilent
End Property
Public Property Let Silent(ByVal Value)
    If Value <> mbSilent Then
        mbSilent = Value
        mbSilentInitialized = True
    End If
End Property
 
Public Property Get DispQueryStringsEnabled() ' As Boolean
    DispQueryStringsEnabled = mbDispQueryStringsEnabled
End Property
Public Property Let DispQueryStringsEnabled(ByVal Value)
    mbDispQueryStringsEnabled = Value
End Property
 
Public Property Get DispFormDataEnabled() ' As Boolean
    DispFormDataEnabled = mbDispFormDataEnabled
End Property
Public Property Let DispFormDataEnabled(ByVal Value)
    mbDispFormDataEnabled = Value
End Property
 
Public Property Get DispCookiesEnabled() ' As Boolean
    DispCookiesEnabled = mbDispCookiesEnabled
End Property
Public Property Let DispCookiesEnabled(ByVal Value)
    mbDispCookiesEnabled = Value
End Property
 
Public Property Get DispServerVariablesEnabled() ' As Boolean
    DispServerVariablesEnabled = mbDispServerVariablesEnabled
End Property
Public Property Let DispServerVariablesEnabled(ByVal Value)
    mbDispServerVariablesEnabled = Value
End Property
 
Public Property Get DispSessionContentsEnabled() ' As Boolean
    DispSessionContentsEnabled = mbDispSessionContentsEnabled
End Property
Public Property Let DispSessionContentsEnabled(ByVal Value)
    mbDispSessionContentsEnabled = Value
End Property
 
Public Property Get DispSessionStaticObjectsEnabled() ' As Boolean
    DispSessionStaticObjectsEnabled = mbDispSessionStaticObjectsEnabled
End Property
Public Property Let DispSessionStaticObjectsEnabled(ByVal Value)
    mbDispSessionStaticObjectsEnabled = Value
End Property
 
Public Property Get DispAppContentsEnabled() ' As Boolean
    DispAppContentsEnabled = mbDispAppContentsEnabled
End Property
Public Property Let DispAppContentsEnabled(ByVal Value)
    mbDispAppContentsEnabled = Value
End Property
 
Public Property Get DispAppStaticObjectsEnabled() ' As Boolean
    DispAppStaticObjectsEnabled = mbDispAppStaticObjectsEnabled
End Property
Public Property Let DispAppStaticObjectsEnabled(ByVal Value)
    mbDispAppStaticObjectsEnabled = Value
End Property
 
Private Sub msb_DebugWrite(ByVal asString)
    Dim llIndex    ' As Long
    
    If mbSilent Then
        If Right(asString, 1) = ">" Then
            Exit Sub
        End If
        For llIndex = 1 TO Len(asString)
            Select Case Mid(asString, llIndex, 1)
                Case vbCr, vbLf, vbTab, " "
                Case "<"
                    Exit Sub
                Case Else
                    Exit For
            End Select
        Next
    End If
    
    Response.Write asString
End Sub
 
Private Function mfn_v_Debug_SortedDictKeys(ByVal aDictionary)' As Scripting.Dictionary) As Variant)
'------------------------------------------------------------
'  Subroutine:  mfn_v_Debug_SortedDictKeys
'      Author:  Brian Schroer
' Description:  Build array of sorted Dictionary keys
'      Inputs:  aDictionary = Scripting.Dictionary
'     Returns:  Array of sorted Dictionary Keys
'   Revisions:
'------------------------------------------------------------
    Dim llIndex        ' As Long
    Dim lvKey        ' As Variant
    
    Execute ("Dim lvArray(" & aDictionary.Count - 1 & ")")
        
    llIndex = LBound(lvArray) - 1
    
    For Each lvKey In aDictionary
        llIndex = llIndex + 1
        lvArray(llIndex) = lvKey
    Next
    
    Call msb_Debug_ShakeSort(lvArray)
    
    mfn_v_Debug_SortedDictKeys = lvArray
End Function
 
Private Sub msb_Debug_ShakeSort(ByRef avArray)'As Variant
'------------------------------------------------------------
'  Subroutine:  msb_Debug_ShakeSort
'      Author:  Brian Schroer - based on VBPJ tip by Tan Shing Ho
' Description:  perform "shaker" sort on array
'      Inputs:  avArray = array (of any data type)
'     Returns:  (sorted avArray)
'   Revisions:
'------------------------------------------------------------
    Dim lbSwap  ' As Boolean
    Dim lvTemp  ' As Variant
    Dim llX     ' As Long
    Dim llMin   ' As Long
    Dim llMax   ' As Long
    
    llMin = LBound(avArray) + 1
    llMax = UBound(avArray)
    
    Do
        lbSwap = False
        For llX = llMax To llMin Step -1
            If avArray(llX - 1) > avArray(llX) Then
                lvTemp = avArray(llX - 1)
                avArray(llX - 1) = avArray(llX)
                avArray(llX) = lvTemp
                lbSwap = True
            End If
        Next
        For llX = llMin To llMax
            If avArray(llX - 1) > avArray(llX) Then
                lvTemp = avArray(llX - 1)
                avArray(llX - 1) = avArray(llX)
                avArray(llX) = lvTemp
                lbSwap = True
            End If
        Next
    Loop While lbSwap
End Sub
 
End Class
%>

Woohoo! I won something stupid!

Community Credit WInner

Beware of geeks bearing gifts...

I just got notification that I won one of the monthly "stupid prizes for smart people" from Community Credit.

 Thanks to David Silverlight for founding this great program.

I'm sure productivity in my office will soar once I install my new Desktop Swing Ball:

 Desktop Swing Ball

I've only started blogging regularly recently, and am working on overcoming my natural shyness to try to volunteer to help out more with the St. Louis .NET community. I hope that sometime in the near future, I'll actually do something worthy of this prestigious, silly award.

community - credit: My Community Gets Credit

“The Visual Studio Documentary”

I just watched/enjoyed “The Visual Studio Documentary” on Channel 9. It brought a tear to my eye as it rekindled memories of installing VB5 from a giant stack o’ floppies.

(Did you know that Alan Cooper’s original name for (what became) Visual Basic was “Ruby”?)

 

Edit: I posted before I actually finished the thing. It’s a bit self-congratulatory at times, but then goes turns into a full-blown commercial toward the end. Up to that point, though, it’s a fun watch.

St. Louis .NET User Group – Muljadi Budiman: “What's new in Visual Studio 2010 and .NET 4.0 Framework”

Muljadi Budiman was the top-rated speaker at the recent St. Louis Day of .NET event, and it’s easy to see why. His presentations are energetic, humorous, and packed with useful information.

At tonight’s St. Louis .NET User Group meeting, he zipped through an overview of Visual Studio 2010 and 4.0 features of C#, VB, WPF, the CLR and the DLR in a little over 90 minutes.

Highlights included:

  • VS2010:
    • multi-monitor support
    • Call Hierarchy visualizer
    • “Navigate To” improvements
    • “Consume-First Development” (greate for TDD)
    • Code Snippets for HTML, ASP.NET and JavaScript
    • Parallel Tasks
    • a WPF designer that doesn’t suck
    • “Embed Interop Types” compiler feature to avoid having to distribute big Interop DLL files
  • VB.NET
    • Auto-implemented properties (catching up to C#) with initial values (C#’s turn to catch up now)
    • Collection initializers (catching up to C#)
    • multi-line lambdas (catching up to C#)
    • getting rid of the underscore line continuation character! (catching up to every language created since 1982 or so)
  • CLR
    • Lazy<T>
    • Generic Set collections
    • Tuples

I don’t know if Mul has had an opportunity to present outside of the St. Louis area, but if you’re organizing a regional code camp or .NET event, I would highly recommend him.

Thanks to Quilogy for providing the geek fuel (pizza & soda) for tonight’s meeting. 

Phil Japikse & Hope Mongers: Giving the Gift of Technology

I just finished listening to a great .NET Rocks interview with Phil Japikse, where he talked about his experiences working on Hope Mongers, a volunteer-run asp.net-based website that brings charity projects together with donators. “Chief Monger” Sam Henry says:

Whether helping orphans on the other side of the planet or families just around the corner, so much authentic living, learning and feeling flows from the intense human connection that happens when you know you are changing someone’s life. Our goal at HopeMongers is to connect you directly with people and help you find tangible opportunities to make a lasting difference in their lives. Our unique community-centered approach focuses on the holistic, long-term needs of communities so that each project is a step toward achieving self-sufficiency, economic independence, and redemption.

As you connect with people and projects on HopeMongers, we hope to ignite a fire that will inspire you to keep giving – not just from your wallet but from your time, talent, money, gifts, your life. Our vision is to redeem the world’s poorest communities and reclaim the art of personal stewardship through microgiving. This ambitious vision is not one any of us can achieve alone but together we can be the generation that helps humanity to its feet and ends extreme poverty.

It looks like a good way to donate to worthwhile causes and know exactly what’s being done with your contribution.

You can also donate your geek skills, because Hope Mongers is an ASP.NET site, and volunteers are always welcome. To find out how you can help, email phil@skimedic.com.

 

P.S. If you’re in the St. Louis area and looking to make a difference in your community, don’t forget about the Coders 4 Charities event October 16-18: http://geekswithblogs.net/brians/archive/2009/09/19/134927.aspx

Book Review: C# in Depth by Jon Skeet

C# in Depth is not for beginners. It assumes a working knowledge of C# 1.0, and is not so much a tutorial of C# 2 and 3 features as an in-depth examination of how and why they work.

I don’t think I learned anything I didn’t know about using generics, extension methods, delegates, anonymous methods and lambdas, but Skeet does a great job of zooming in on the inner workings of each of these features, building up to the big picture of how they all snap together to make the game-changing programming paradigm that is LINQ. It’s like a DVD of your favorite movie with behind-the-scenes features that show how the cool special effects were created.

When he says “in depth”, he’s not kidding. After re-emerging from the Marianas Trench level examination of expression trees to the C# surface level discussion of LINQ, I got a case of “the bends”.

The book reminds me of Silverlight “Deep Zoom”. As we zoom in and out between high-level syntax descriptions to low-level minutiae, everything is always kept in sharp focus, thanks to the considerable skills of the author.

I understand Jon Skeet is hard at work on updates to the book for C#4. When that comes out, I wish there would be a free upgrade to the book that I could download (I don’t think that’s going to happen ;) ), but that’s one book that I’m sure will be well worth the price.

If you’re serious about C#, “C# in Depth” is a must-read.

Getting Serious About JavaScript

Like many ASP.NET developers, I’ve gotten by for years knowing just enough JavaScript to get by. I’ve spent many frustrating hours cursing the language, when the problem was not really JavaScript (although it has more than its share of weirdness), but my assumption that I knew how it worked, just because it looks like C#.

Now, thanks in large part to jQuery, I actually enjoy client-side programming.

jQuery makes things so much easier (replacing dozens of lines of code that I painstakingly figured out in the past, “Rhino book” at my side), that it almost seems like magic. I don’t trust magic though, so I’ve been making an effort to learn how JavaScript really works, and the best practices for working with it.

Douglas Crockford’s “JavaScript: The Good Parts” should be required reading for any web developer. It’s a short book, and this video is a great summary of the main points.

This presentation by Sergio Pereira is also a very good overview of JavaScript programming.

Another very interesting video is Learn jQuery with FireBug, jQuerify and SelectorGadget by Dave Ward, with Craig Shoemaker.

How do you pronounce “WPF”?

Someone asked this on Stack Overflow: http://stackoverflow.com/questions/1448995/how-do-you-pronounce-wpf

I pronounce the “W” as in the word “two”, the “P” as in “pneumonia”, and the “F” like the last letter of “off”.

St. Louis Coders-4-Charities: October 16-18

I’ve heard good things about last year’s Kansas City event, and am excited that we’re doing it in St. Louis. Thanks to the organizers for this great opportunity to help out some good organizations…


Are you interested in volunteering your time and technical talent to help our community?

On October 16th through the 18th we have organized a local charity event called Coders 4 Charities.  This event will benefit many St. Louis-area non-profit organizations by providing them IT solutions that would traditionally be outside of their budget or that they might not know are even possible.  We are accomplishing this through the volunteer efforts of talented people like yourself.  We have identified 9 charities in need of support and worked with each of them to identify a tangible project which can be completed over the course of a weekend.  These projects include such things as website redesigns and extensions, internal applications to streamline record-keeping, network configuration and maintenance, automated invoicing, and the online acceptance of donations.

For us to accomplish our goal of helping our community by helping these organizations, we need your help.  Washington Universities CAIT center has donated the use of their classrooms around the clock from Friday evening October 16th to Sunday evening October 18th.  During this time we will have full access to their computers and internet connections (including wireless).  Each of their classroom computers is already loaded with many of the design and development tools and technologies we use regularly as part of our "day jobs".  Our goal is to gather volunteers who will be organized into teams that will work throughout this weekend to provide these solutions to these organizations.

We have some generous sponsors who are providing refreshments and meals throughout the whole weekend (i.e. breakfast, lunch and dinner) and we have other sponsors providing some great prizes to be awarded at an awards ceremony on Sunday evening.

What types of people are we looking for?

We need many different types of skill sets with expertise in many disparate technologies.  From developers to designers and network engineers to project managers.  It takes a lot of people to implement great solutions and we are open to many people helping out for a good cause.  Most importantly we need enthusiastic people willing to work together with others on a team towards a common goal.  We need people who are willing to wear a lot of hats over short period of time and take the initiative to do what is necessary for your team to successfully help your assigned organization. 

How can you volunteer?  Please go to our website at http://www.c4c-stl.org and read the FAQ for answers to many of the commonly asked questions.   Then, if this sounds like something you are interested in, provide us with some basic information about yourself on our Volunteers page.  If you have any questions about this event that are not answered on our site, please do not hesitate to drop us an email at volunteer@c4c-stl.org.

If your organization is interested in sponsoring our event with food or prizes, please have them contact us at sponsors@c4c-stl.org.

Thank you for your support,

Coders 4 Charities St. Louis Organizers

organizers@c4c-stl.org

Scott Hanselman's 2009 Ultimate Developer and Power Users Tool List for Windows

Scott has updated his insanely useful list of insanely useful tools.

If you find something useful there (and it would be hard not to), please consider Scott’s request to make a tax-deductible contribution to the American Diabetes Association.

http://www.hanselman.com/tools

The origin of the names "IronPython" and "IronRuby"

I wondered a while ago where the "Iron" names came from.

According to a NxtGenUG interview with Michael Foord, John Lam says that IRON can be reverse-engineered to stand for "It Runs On .Net", which is cool, but I finally found the real story in an interview on the "Port 25: The Open Source Community at Microsoft" site, in which IronPython creator Jim Hugunin says:

I'll give you the story, but I'll give you the short version 'cause it's not very good.

At the time, I had a consulting company called "Want of a Nail Software". "Want of a Nail" is based on a children's poem. It's about the importance of small things. I've always kind of believed in the importance of small things. Part of the story of IronPython's actual performance is it wasn't one big thing - Everybody wants to know "What was the one big thing?" There were some big things, but most of it was all the small things - paying attention to performance in every place.

So, that was the consulting company and "Iron" seemed to match.

There were some obvious names: Python.Net, Python#, nPython - All of those were taken. All of the URLs for those were registered.

I didn't want to reuse any of those names, so "Iron" was just kind of a name that appealed to me at a visceral level - I like the feeling of "IronPython".

There's a little bit of "Iron Chef" in it, although I'm always reluctant to admit that.

About the "Python" part: According to the Wikipedia article on Python:

An important goal of the Python developers is making Python fun to use. This is reflected in the origin of the name (based on the television series Monty Python's Flying Circus), in the common practice of using Monty Python references in example code, and in an occasionally playful approach to tutorials and reference materials. For example, the metasyntactic variables often used in Python literature are "spam" and "eggs", instead of the traditional "foo" and "bar".

...and Wikipedia says this about the name "Ruby":

"Ruby" was named as a gemstone because of a joke within Matsumoto's circle of friends alluding to the name of the Perl programming language.

...which led me to the Perl article, where I discovered that it was originally named "Pearl".

 

I think I'll stop now before I digress into a rant about how "C#" is a cool name but J# and X# were doomed to failure not for technical reasons, but for musical ones (unless Microsoft has a much larger piano keyboard than I do).

.NET Rocks! - 423 hours and counting...

Congratulations to Carl Franklin and Richard Campbell on the upcoming 350th episode of .NET Rocks!

 I can't tell you how many hours of education & enjoyment DNR has provided me over the years.

 ...Well, actually, I can...

 I discovered the show around episode 10 or so, quickly caught up with the previous shows, and haven't missed one since.

 I added up the show runtimes, and the total is approximately 423 hours, or almost 18 days!

 A lot of people listen to DNR on their commute, and there's enough DNR that you could listen to it the entire time on a 27,000 mile road trip from Vancouver BC to New London CT and back by way of San Diego, Miami, New York City, Bangor, Yakima, Reno, Vegas, and St. Louis.

(Here's the map, if anyone would like to make that trip - Good luck paying for the gas: http://shrinkster.com/z6h)