Friday, June 30, 2006

I was in the process of downloading Cygwin to in order to get the wc command (among others) in order to do some file verification work.  I stopped for a second and thought why not use PowerShell?  I found a good source for this so here is the command:

PS C:\Scripts\AMA> gc test.134.* | Measure-Object

Count    : 395587
Average  :
Sum      :
Maximum  :
Minimum  :
Property :
Notice that I'm using gc as an alias for Get-Content.  gc, type and cat all work as aliases for Get-Content.  
test.134.* is just a typical DOS file mask to get all files that start with test.134.
Now let's get a word count:
PS C:\Scripts\AMA> gc test.134.23.00 |  Measure-Object -word
Lines                             Words Characters          Property
-----                             ----- ----------          --------
                                   8391
How about a character count:
PS C:\Scripts\AMA> gc test.134.23.00 |  Measure-Object -char
Lines               Words                        Characters Property
-----               -----                        ---------- --------
                                                    1670774
How about an explicit line count:
PS C:\Scripts\AMA> gc test.134.23.00 |  Measure-Object -line
              Lines Words               Characters          Property
              ----- -----               ----------          --------
               8391
Keep in mind that Measure-Object can also be used with objects but we'll save that for another post.  Also it might be nice to try to create a nice short alias like wc to save me some typing.
Friday, June 30, 2006 1:40:55 PM (Central Standard Time, UTC-06:00)  #    Comments [1]
 Thursday, June 29, 2006

I discovered content fitlers today in dasBlog.  They are little macros that save you some typing.  The documentation says the google search macro supports multiple terms but in practice I can only get it to support one term.

Example:

dasblog content filter

should take you to a google search page dasblog content filter as search terms but only dasblog is passed through.  What am I doing wrong?

Content Filter Documentation

Update:

$g(dasblog\+content\+filter) doesn't work

$g(dasblog+content+filter) doesn't work

$g(dasblog\scontent\sfilter) no worky

hmmmm...

Thursday, June 29, 2006 9:51:58 PM (Central Standard Time, UTC-06:00)  #    Comments [1]

http://dasblog.info/CategoryView,category,Customization,Content%20Filters.aspx

Kinda funny how the documentation for this is the seventh result returned: dasblog content filter 

Thursday, June 29, 2006 9:24:30 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
I've had a problem with Captcha images not showing up in the comments section of this blog.  I checked around to see if others have had this problem and apparently they have.  The solution?

It seems you just have to repeatedly refresh the page you are trying to mak the comment on until it works.  I noticed some references to managed hosting and Web Host 4 Life (WH4L) which I am using to host this blog.  I will have to keep on eye on this.  Not that my comments section was swamped before but I have seen 0 (ZERO!) comments since upgrading to the new version and know I think I know why.

This morning at work I kept refreshing the page but didn't get anything.  I'm at home this evening and now everything appears A-OK.  Hmmm...

Thursday, June 29, 2006 6:06:19 PM (Central Standard Time, UTC-06:00)  #    Comments [2]

This is useful when you want to group records by date but your datetime column has a time value also.  This code converts your date to a varchar in a specified format.

--101 is "mm/dd/yyyy"

SELECT CONVERT(varchar,DateField,101)

-- 1 is "mm//dd/yy"

SELECT CONVERT(varchar,DateField,1)

-- 108 is "hh:mm:ss"

SELECT CONVERT(varchar,DateField,1)

-- An example query

Select convert(varchar,CallDateTime ,101), count(*)

FROM [DBName].[dbo].[TableName]

where

CallDateTime between '04/21/2006' and '05/21/2006'

group by convert(varchar,CallDateTime ,101)

Thursday, June 29, 2006 2:22:36 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, June 27, 2006

I'm developing a set of server controls in ASP.NET 2.0 that use several JavaScript, image and stylesheet (CSS) files.  One of the problems with distributing controls is that you usually have to send along these files and tell the end user to install them in the appropriate directory.

Along comes ASP.NET 2.0 and the ability to embed resources right into assemblies and then access these resources via URLs.  My first impression is that this seems like a good idea but I'm wary because I've been burned by MS's good ideas in the past.  My main concerns are debugging and the effect this embedding has on caching. 

Caching

One of the problems with frameworks like ASP.NET is that they sometimes take you too far away from the underlying system.  HTTP and HTML is rather straight forward.  Embedded resources in ASP.NET call the the resources via URL's and  use cache headers to insure the browser caches the content correctly.  Also the output cache in the form of disk output cache is automatically used to cache these resources.  So these embedded resources should still allow a fairly performant solution.  My question is still whether this is as good as a plain static file and the caching IIS can perform on these files.  I still need to research this.

Debugging

One of the problems I've run into involves debugging.  When a JavaScript file is embedded and it contains an error, Visual Studio.NET 2005 will open a file dialog asking for the location of the file.  This is a pain as you lose the precious JavaScript debugging ability that we gained with VS 2005.  Is this behavior by design or is there something I'm missing in regards to debugging JavaScript as an embedded resource?  My tempo ray solution is to keep the JavaScript files in a static folder while I'm debugging and then switch them to Embedded Resources when I'm deploying the control. 

However on the plus side of debugging when you change the JavaScript file it is automatically picked up the next time you do a build.  The URL of the embedded resource is changed and thus the browser grabs the newer file.  However this has a downside in that you must stop the running project to make changes to the JavaScript file and then rebuild the project to have the changes show up.

I've found that the static file path is much easier for debugging.

 An excellent article that I've referenced for this post:

http://www.nikhilk.net/WebResourceAttribute.aspx

 |  |  | 
Tuesday, June 27, 2006 3:45:02 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 22, 2006

I've upgraded the GreaseMonkey Google Navigator script to fix some minor issues with the next and previous keys in groups.google.com and I've added the "open link in new tab" functionality via the 't' key.  Check it out:

http://userscripts.com/scripts/show/3984

Or right here at:

http://www.pragmaticprose.com/content/binary/googlenavigator.user.js

Thursday, June 22, 2006 8:36:30 PM (Central Standard Time, UTC-06:00)  #    Comments [1]

This JavaScript Code will cycle through all elements on a page and find the next one that should recieve the focus.  This worked well in IE6 but the results in FireFox where mixed.  I don't have time right now to clean it up but I wanted to post it as this is one of those gems that you know you will want in the future.

Original Source: http://www.codecomments.com/message290822.html

Original Author: Daniel Kirsch

// returns the next focusable object for a given one
function getNextFocusElement(elm,restart,dir,_looped) {
var allElm = document.getElementsByTagName('*');
var found = false; //(start == true);
var allowedElements = 'input,textarea,a,button';
if (!dir) dir = 1;
var start = dir > 0 ? 0 : allElm.length-1;
var end = dir > 0 ? allElm.length : -1;
jslog.info('start: ' + start + ' end: ' + end);

for (var i=start; i!=end; i+=dir) {
if (!found) {
if (allElm[i] == elm) {
if (_looped) return null;
found = true;
jslog.info('i: ' + i );
continue;
}
}
if (found || (restart && _looped)) {
if (allElm[i].focus && allElm[i] != elm) {
if (isInList(allElm[i].nodeName.toLowerCase(),allowedElements)
&& isVisible(allElm[i]))
jslog.info('i: ' + i);
return allElm[i];
}
}
}
jslog.info('starting next loop...');
return (_looped) ? null : getNextFocusElement(elm,true,dir,true);

}

function isVisible(elm) {
if (elm.style.visibility == 'hidden' || elm.style.display == 'none')
return false
else
return elm.parentNode && elm.parentNode.style ?
isVisible(elm.parentNode) : true;

}

function isInList(aItem,aList,aSep,aCaseSensitive) {
if (typeof aItem == 'undefined' || typeof aList == 'undefined')
return false;

// make sure, the element is a string.
aItem = String(aItem);
if (aCaseSensitive !== true && typeof aItem == 'string') {
if (typeof aList == 'string')
aList = aList.toLowerCase();
aItem = aItem.toLowerCase();
}
if (!aSep) aSep = ',';
var lString = aSep+aList+aSep;
return (lString.indexOf(aSep+aItem+aSep) > -1);

}

Thursday, June 22, 2006 1:19:21 PM (Central Standard Time, UTC-06:00)  #    Comments [1]

A new contender for the Pragmatic Toolkit is PDFCreator, a SourceForge project which allows you to print to a pdf file much like you would a normal printer.  This is useful if you want to need to capture output to a platform inpependant format.  For example, you have a web page that shows a reciept from an online purchase.  Use PDFCreator to print it to a PDF so you have a nice record of the purchase.  This also works for screen prints or any other capture operations where you have an applications that can print (basically any editor program like Word, StarOffice, PaintShop Pro, Photo Shop, etc). 

I use it to screen capture protected web pages (on sites where you need to sign in) and send it to someone who doesn't have access to the site, like my wife.  It's useful if you are going for a paperless office as you could scan your paper items and then print them to PDF (if your scanning software doesn't support it natively).  You can also create product documentation by creating the document in Word and then printing it to PDF to create a manual for distribution to customers.

Here is the link:

http://sourceforge.net/projects/pdfcreator/

Thursday, June 22, 2006 10:10:39 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Monday, June 19, 2006

Do you want to limit the imput of a text input (textbox) to valid date characters?  Here you go:

// START SCRIPT

function runKeyFilter(e) {
 if (e.srcElement.readOnly) return;

 var key_code = e.keyCode;
 var oElement = e.srcElement;
 //alert (key_code);

 try {
  if (!window.event.shiftKey && !window.event.ctrlKey && !window.event.altKey) {
   if (
     (key_code > 47 && key_code < 58) ||  // numbers on top of keyboard
     (key_code > 95 && key_code < 106)  ||  // number on numpad at right of keyboard
     (key_code > 36 && key_code < 41) ||  // arrow keys
     (key_code == 35) || // end
     (key_code == 36) || // home
     (key_code == 45) || // dashes
     (key_code == 111) || // forward slash /
     (key_code == 191) || // forward slash /                      
     (key_code == 8) || // backspace
     (key_code == 46) || // delete
     (key_code == 9) || // tab
     (key_code == 16) //SHIFT TAB
      )
   {
    e.returnValue = true;
    return;
   }      
  } 
 }
 catch (ex) {
  alert('Error Message: ' + ex.message );
 
 }
 // if we get here then we didn't have a number
 e.returnValue = false;

}  // end runKeyFilter()

//using the helper functions from prototype.js
Event.observe('|CONTROL|', 'keydown', runKeyFilter, false);  

// END SCRIPT

Monday, June 19, 2006 1:22:50 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 15, 2006

I've had to go look for this more then once so here it is:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SchedulingAgent

MaxLogSizeKB - This is max size of the log in kilobytes (duh).  Make sure you edit this using Decimal values.  The default in Windows 2000 is hexadecimal. 

Default - Notice I changed the Base to Decimal in order to edit the value correctly:

Changed to reflect a 1 MB (1024KB) size:

You can also change other values like the location of the log (LogPath) but MaxLogSizeKB is the only one I've needed to change on almost every computer.

The task scheduler log file (located by default here at %SystemRoot%\SchedLgU.Txt) keeps track of the start and finish times of all scheduled tasks.  We use the task scheduler to run almost all of our services and batch processed simply because it is ubiquitous and reliable.  However, the 32k limit is a pain as a busy scheduler will quickly fill this up and the log will begin to overwrite itself.  You'll get one of these things:
[ ***** Most recent entry is above this line ***** ]

to indicate where the latest entry is.  I've found that with our schedule it overwrites itself within an hour or so.  Your mileage may vary but with today's huge harddrives it's often beneficial to trade a small amount of space for a large amount of history.  Keep in mind thought that this does open with notepad.exe to if it gets too large notepad may choke. 

You may also want to check out my article on using the task sceduler as a poor man's Windows Service:

 http://www.pragmaticprose.com/PermaLink,guid,5cc361e3-3940-43d9-8591-fb6f5dd00036.aspx

Thursday, June 15, 2006 2:40:18 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, June 09, 2006
I do a lot of web development.  Unfortunetely at work all the folks out on the floor have Internet Exploder oops I mean Explorer.  So I do most of my testing in IE6.  The problem comes in as we start to do more DHMTL (AJAX) on our sites.  Ofter you need to view source to see what is rendered.  Well of course IE just gives you little old notepad and calls it good.  Firefox does a better job by at least highlighting syntax.  Well, I've found a good solution for IE.

Notepad++.  Two big bonuses here.  Excellant syntax highlighting and code folding.  Code folding is the ability to expand and contract sections of code so it's out of your way when you don't want to look at it.  The syntax hightlighting is great plus Notepad++ is one great editor in general.  I use it for heavy duty JavaScript development because of the code folding and the lings that line up the beginning and ending tags and code blocks. 

Give it a try.  http://notepad-plus.sourceforge.net/uk/site.htm

I believe it promts you on the install to act as the view source client for IE.


Friday, June 09, 2006 10:53:26 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
If Jerry Seinfeld were a programmer he might ask "What's the deal with configuration files having to be in XML format?".  I just find them to be incredibly hard to read and decipher.  The problem with XML is that it's just so verbose.

Java has property files which may or may not be berrer. Ruby on Rails using YAML files.  These seem fairly reasonable.  One thing an XML file does however is let you show relationships and nesting of data.  So does the complexity of .NET require that the configuration files are also complex?  The configuration file seems to be a collection of serialized objects spat out at random into a file.  Is it a result of the everything must be XML crusades at the turn of the century?  Could the files be simplified?  Could we have seperate config files for seperate concerns.  Example, I go into the config file to change a setting and I typo.  My whole site (or server) goes down.  Is this expected behavior? 

So does the nature of .NET itself demand XML configuration or is this laziness on the programmers part to simply allow them to deserialize the configuration settings in the most convenient way (for them) possible? 

 |  | 
Friday, June 09, 2006 10:43:29 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 08, 2006

IF you have a server to monitor that has many different applications, for instance an intranet server, and you want one error logging/reporting solution to rule them all then you've come to the right place.  It took me forever to find this information so I'm going to explain it. 

ASP.NET 2.0 comes with a feature called health monitoring (healthMonitoring).  This feature allows us to configure the monitoring and reporting of information related to ASP.NET.  Almost anything useful can be monitored but I was most concerned about handling server wide exceptions in a consistent manner.  Of course you should handle all errors/exceptions in each application if possible but sometimes this gets overlooked.  In Classic ASP we would route the errors (500's) to a certain page and capture them with the Server.GetLastError which worked just fine in Classic ASP.  However, in ASP.NET this doesn't work so well.  You lose the exception when you transfer to another application.  So you either have to store the exception somewhere by using the application_error or use a solution involving health monitoring.  I chose the latter as a blanket solution just in case anything got through the cracks in an individual application.  I've included a file that will help you set this up. If you want server wide coverage then these settings need to go into the web.config located at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG\.  Once you apply these settings you should be able to receive emails and log events to the event log.  You can also set up a SQL provider that will log events to an SQL database instead. 

The important things to look at in the file is the mailSettings tag under the system.net group.  This sets up your SMTP server. 

Next you want to check out the settings in the healthMonitoring section.  This should give you a good idea how to set your server up.  I've noticed that the MSDN examples and documentation is riddled with errors and inconsistencies.  I don't know why they aren't shouting this stuff from the rooftops as it makes application and server administration so much easier.

I've attached the web.config file (web.config.txt (31.22 KB)) to this post.  Here are the relevant sections:

Setting up your SMTP server:

    <system.net>

       <defaultProxy>

            <proxy usesystemdefault="true" />

        </defaultProxy>

      <mailSettings>

        <smtp >

          <network

            defaultCredentials="true"

            host="EMAIL-SERVER-NAME-OR-IP"

           />

        </smtp>

      </mailSettings>

    </system.net>

Health Monitoring (Notice that we add a provider named CriticalMailEventProvider and have the All Errors Default rule use this provider):

<healthMonitoring enabled="true" heartbeatInterval="0">

            <bufferModes>

                <add name="Critical Notification" maxBufferSize="100" maxFlushSize="20"

                    urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00"

                    maxBufferThreads="1" />

                <add name="Notification" maxBufferSize="300" maxFlushSize="20"

                    urgentFlushThreshold="1" regularFlushInterval="Infinite" urgentFlushInterval="00:01:00"

                    maxBufferThreads="1" />

                <add name="Analysis" maxBufferSize="1000" maxFlushSize="100"

                    urgentFlushThreshold="100" regularFlushInterval="00:05:00"

                    urgentFlushInterval="00:01:00" maxBufferThreads="1" />

                <add name="Logging" maxBufferSize="1000" maxFlushSize="200" urgentFlushThreshold="800"

                    regularFlushInterval="00:30:00" urgentFlushInterval="00:05:00"

                    maxBufferThreads="1" />

            </bufferModes>

 

            <providers>

                <add name="EventLogProvider" type="System.Web.Management.EventLogWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

                <add connectionStringName="LocalSqlServer" maxEventDetailsLength="1073741823"

                    buffer="false" bufferMode="Notification" name="SqlWebEventProvider"

                    type="System.Web.Management.SqlWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

                <add name="WmiWebEventProvider" type="System.Web.Management.WmiWebEventProvider,System.Web,Version=2.0.0.0,Culture=neutral,PublicKeyToken=b03f5f7f11d50a3a" />

             

                <add name="CriticalMailEventProvider"

                  type="System.Web.Management.SimpleMailWebEventProvider"

                  from="CHANGME@PRAGMATICLABS.COM"

                  to="CHANGME@PRAGMATICLABS.COM"

                  bodyHeader="Warning!"

                  bodyFooter="Please investigate ASAP."

                  subjectPrefix="Intranet Error "

                  buffer="true"

                  bufferMode="Critical Notification"

                  maxEventLength="4096"

                  maxMessagesPerNotification="1"

              />

         

            </providers>

 

            <profiles>

                <add name="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"

                    custom="" />

                <add name="Critical" minInstances="1" maxLimit="Infinite" minInterval="00:00:00"

                    custom="" />

            </profiles>

 

            <rules>

                <add name="All Errors Event Log" eventName="All Errors" provider="EventLogProvider"

                    profile="Default" minInstances="1" maxLimit="Infinite" minInterval="00:01:00"

                    custom="" />

                <add name="All Errors Default"