Thursday, July 28, 2011

C# recursive file counter

I am constantly surprised with how easy .NET makes things sometimes. I needed a quick recursive file counter output to a report, and was able to write this in just a few minutes, using some new methods available in .NET 4 (EnumerateFiles/Directories) (UPDATE: not sure what I was thinking here - .GetFiles()/.GetDirectories() provides pretty much the same thing - array vs. generic list):

static void Main(string[] args)
{
   string startingDir = @"C:\files";
   string reportFile = @"C:\file_count.txt";

   using (StreamWriter report = new StreamWriter(reportFile))
   {
        countFiles(startingDir, report);
   }
}

private static void countFiles(string dir, StreamWriter report) {
   DirectoryInfo directory = new DirectoryInfo(dir);
   IEnumerable<FileInfo> files = directory.EnumerateFiles();
   IEnumerable<DirectoryInfo> dirs = directory.EnumerateDirectories();

   report.WriteLine(String.Format("{0}: {1}", dir, files.Count()));

   foreach (var d in dirs)
   {
        countFiles(d.FullName, report);
   }
}


It works very quickly (100,000 files in as much as 8 directories deep in less than 30 seconds on a modest machine), and couldn't have been more straightforward to write.

BTW, if all you need is just a total file count, this works well:

DirectoryInfo d = new DirectoryInfo(startingDir);
int totalCount = d.EnumerateFiles("*.*", SearchOption.AllDirectories).Count();


After thinking about this some more, I wonder if this may even be easier/more efficient with LINQ. I've got to try that for fun, and check the performance of each.

Wednesday, July 20, 2011

Graphical Saccades

My son is working through some vision issues, and one of the exercises his vision therapist has him do is called "saccades", basically quick movements of the eyes in the same direction. She gave us a web site that had an animated gif that sequentially displayed a bunch of lines of numbers, at varying distances apart.

This was quite boring for my son, so my wife had an idea for me to make a version of this with pictures of things that he liked. He absolutely LOVES this version of the "game", and wants to play it all the time!

The exercise randomly displays 20 images at varying distances (five lines with four images per line), and can include the same image more than once. The speed can be adjusted before the run, or in progress.

From what I understand, the important part of the exercise is just to track and identify sequentially revealed items at the same pace, but at varying distances apart. I would love to hear from any vision therapists out there, though, to make sure that this is correct, and that a graphical version still satisfies the objective. Our therapist is out for a few weeks, so I can't ask her about it now, but I'll update the post when I get any new information.

If you want to try it out yourself, here's a zip file (under the Google Docs icon, click "File" --> "Download Original") with the code and a few sample images. It's set up to go with 30 random images, but it's easily customizable if you want to use your own images, or add more. To run it, just unzip the .zip file, and double-click on the .html file that best fits your screen.

In the meantime, I'm working on getting the exercise set up on its own web site, but I'm having a hard time finding a free web site provider that allows HTML.

Technically, this was a breeze to do with jQuery. I define an array of images, and use code similar to JavaScript built-in "setTimeout", but with the ability to adjust the interval in progress (thanks, Peter Bailey, for the brilliant function). The key lines are:

vi = setVariableInterval(function() {
if (currentItem == 20) {
this.stop();
}

randomSpacer = Math.floor(Math.random() * maxPixelLength) + minPixelLength;
randomPicture = Math.floor(Math.random() * pictures.length);

replacementPic = "<img class='p' src='" + pictures[randomPicture].src + "' width='100' height='75' style='margin-left: " + randomSpacer + "px;' />";
$(pics[currentItem]).replaceWith(replacementPic);

currentItem++;
}, initialInterval);

"randomSpacer" and "randomPicture" create random numbers up to the defined maximums. And the jQuery line just replaces each placeholder with a random image. "pics" lets me access via index all images that use the "p" class (they are initially set up with placeholders).

pics = $(".p");

Thursday, June 9, 2011

Avoiding the "Destination configuration already initialized" error in SAP .NET Connector 3

SAP's documentation suggests using a line similar to the following to create a connection to SAP:

RfcDestinationManager.RegisterDestinationConfiguration(new Config());

where Config() is a class that contains connection settings.

This works fine, except, you occasionally get the error, "Destination configuration already initialized", because the connection hasn't timed out. SAP's documentation that I've seen (the .chm help file and the "Overview" document) doesn't address this issue at all, and their sample code doesn't contain any examples of how to close a connection.

I've found that the following code works:

Config c = new Config();
RfcDestinationManager.RegisterDestinationConfiguration(c);
...
(processing code)
...
RfcDestinationManager.UnregisterDestinationConfiguration(c);

However, if you've just tried to connect without using "unregister", you'll have to wait until the old connection times out itself before trying the code above (the sample config code SAP provides keeps the connection open for 10 minutes).

Overall, I've found the new SAP Connector 3 to be a HUGE step up from v2, though it is quite a pain having to re-write all of my v2 applications. But I easily prefer a few months of re-writing over being tied to VS2003. Thanks, SAP, for updating this - I thought you had forgotten about us .NET developers.


Wednesday, April 13, 2011

Displaying ActiveDirectory's "whenChanged" attribute in C#

"whenChanged" comes through without the time offset. Not a big deal to fix it, but a quick Google search yielded no results on how to deal with it. Here's my solution to properly display Eastern Daylight/Standard time:
TimeZone localZone = TimeZone.CurrentTimeZone;
DateTime generalizedDate = DateTime.Parse(result.Properties["whenChanged"][0].ToString());
double hourDelta = localZone.IsDaylightSavingTime(generalizedDate) ? -4D : -5D;
DateTime lastUpdated = generalizedDate.AddHours(hourDelta);
BTW, Sysinternals' AD Explorer is great for finding out meta information (i.e. data type, property name) about AD attributes.

Tuesday, July 13, 2010

EXCEPT to compare output of two queries

Very helpful SQL Server 2005+ commands:

http://weblogs.sqlteam.com/jeffs/archive/2007/05/02/60194.aspx

I had to find the different rows of two pretty complex, non-related queries, and decided to look up if there was an easier way to do than by exploiting UNION (a technique I think I picked up from the same author, actually...). Turns out you just need to put and EXCEPT in between the queries. That's it.

I just found this last week and have probably already used it five times. It makes me want to get a book on SQL Server 2008 to see what other time-savers I can find, especially I'm analyzing LOTS of data these days.

Friday, June 25, 2010

Quick way to see what SQL data was updated

I had a crazy update query I was trying to troubleshoot, and for the life of me could not figure out why it insisted on updating some rows after they had already been updated by a prior run. Here's the quick one-time-use trigger I came up with to see exactly what was updated:


CREATE TRIGGER dbo.ViewUpdatedRecords
ON (table name)
AFTER UPDATE
AS
BEGIN
SELECT *
INTO UpdatedRecords
FROM INSERTED
END
GO


It only works one time, as SELECT INTO creates a table and will complain if a table by that name already exists. But it only took a minute to write, and helped me solve my issue very quickly.

Tuesday, April 27, 2010

New DVR, finally

I've finally put together a DVR out of spare parts. I built one before (and even got mentioned in Wired magazine), making my regular desktop do double duty, with a wireless 802.11B connection to the living room. On the TV side, a small Linux box (Hauppauge MediaMVP) decoded the video and handled the remote. It worked well about 95% of the time, but when it didn't work, it was a nightmare to troubleshoot. And you couldn't use the microwave, talk on the phone, or look funny at it... It also took me a month to build - mostly spent researching and tuning my network connection and figuring out my way around FFMPEG to compress the video.

When we moved to another house, it just wouldn't work reliably anymore, no matter what I did. I ditched the project for awhile, but picked it back up again when I got a free 10-year old computer - a Celeron 733Mhz with 64MB RAM. This was more an exercise in getting a slimmed down version of Linux (Mythbuntu/Xubuntu) to work more than anything else. I was able to get it to record shows, but not play them :-)

A few weeks ago, my neighbor gave me an old Dell 4300 1.8GHz machine. It wouldn't boot, but I found out that all it needed was a new power supply. I put an nVidia 5200 128MB card in it, a new quieter fan, and 1GB of RAM that I had saved from another dead computer, and it runs XP Media Center 2005 great (as long as you buy the $20 nVidia PureVideo software - not sure why this is required, but it is). It even runs Hulu perfectly (if you set it to medium quality) via a browser, but it chokes using Hulu desktop for some reason.

So now my kids are happy b/c they always have their PBS shows on tap, and my wife is happy, as she can watch her CBS shows. And this one only took me a few hours to set up. The thorn has been removed from my side.