in

Redwerb

Tools, tips, and techniques for software developers.

Redwerb

Tools, tips, and techniques for software developers.
  • Introducing Visual Studio Project Zipper Shell Extension

    Download VS Project Zipper

    I am releasing a beta version of VSProjectZipper. This tool will allow you to right-click on a Visual Studio project or solution in Windows Explorer and zip it up and, if desired, email it to somebody.

    VSProjectZipperScreenshot

    Zipping a project works exactly as you would expect. VSProjectZipper reads the project file and creates a zip file that mirrors the directory structure for the project.

    However, if you zip up a solution, VSProjectZipper will create it's own directory structure. Basically the sln file is in the root of the zip file and each project has it's own directory. Solution items are also included and placed into directories. Just to reiterate, it doesn't matter where projects or solution items are on the local file system, the zip file will create it's own directory structure for them.

    The installer also adds a shortcut to your start menu to configure it. There are a number of options that you can change.

    VSProjectZipperConfigScreenshot

    Before you get too excited, you should remember that this is just a beta and there are many known (and I'm sure unknown) issues. Here are the issues that I know of (at least remember at the time of writing this :):

    • Limited testing. I only tested on a single, very simple VB project and a moderately complex C# project and solution as well as a single, simple installer project.
    • Project references are not copied. If you reference an assembly, that assembly is not included in the zip file. This could give compiler errors in the extracted project.
    • Hint paths are not removed or modified. This could also give compiler errors on the extracted project.
    • Test projects can have compiler errors upon extraction. If an accessor is created for a MS test project, you will get compiler errors.

    I'm sure there's plenty more errors as well, but it seems to have worked ok for my BizArk project. I started getting bored with this project so I figured I had better release it before I decided to stop working on it.

  • BizArk updated to 1.0.1

    I've made a number of updates to the BizArk framework for another project that I'm also releasing today (stay tuned).

    New features:

    • New API for SharpZipLib. I didn't like how you had to work with streams and how the zip directory structure was built, so I created an API that hopefully makes it easier.
    • Email API. I created a simple API for sending email using the MAPI32 MAPISendMail function (no need to allocate/deallocate memory!). Supports To, CC, BCC, attachments, subject, body, and either direct send using the users email client or display the users email client.

    Updated components:

    • You can now save and restore a CmdLineObject from an xml file.
    • CmdLineObject can be displayed in a PropertyGrid. Base properties are not browsable.
    • Added ConvertEx.IsEmpty. This method determines if a value is empty. A value is empty if it is null, DBNull, or matches a MinValue, MaxValue, or Empty static field on the class (except for char which checks for '\0'. You can register empty values for any type by calling ConvertEx.RegisterEmptyValue.
    • Added ArrayExt.RemoveEmpties. This method removes empty elements in an array based on ConvertEx.IsEmpty.
    • Many other changes as well...
  • Introducing the BizArk Framework

    For a hobby, some people watch or play sports, others collect or build things. Not me. I code. I spend a large amount of my personal time (time when I'm not at work or with my family) either reading about, playing with, or writing software (it's one of the reasons I continue to write this blog even though I have few actual readers).

    Because of this, I have decided to create a framework that I will share with anybody that wants to use it. I am calling this framework the BizArk framework (if you didn't get it, BizArk is short for business architecture). You can read a full description on the BizArk Framework page.

    This initial release only includes a few things, such as command-line argument parsing, splash screen management, and some extension methods and is really more of a library than a framework. I do plan on adding to this framework, but I don't have any kind of road map or even goals for it.

    I am licensing it under the WTFPL software license. This license allows you to do Whatever The F*** you want with it. I don't really care how people use it, I'm just doing it for fun. Some day I might make it an open source project, but no real plans of that for now.

  • Copyrighting Source Code

    image Do you copyright your source code? Sorry, trick question. If you write source code, it is automatically copyrighted. According to the U.S. Copyright Office; "Copyright is secured automatically when the work is created."

    Before you read this article I feel I should mention that it is essentially a summary of Copyright Office Basics on the United States Copyright Office website. When I decided to write about copyrighting I searched for articles on it. I found a few good ones, but this one covered everything (at least everything I wanted to know) and is a highly reputable source as well (who knows copyrights better than the United States Copyright Office?). Wikipedia also has a pretty good article on it if you want more to read.

    So, back to source code copyright. The general description of works that can be copyrighted do not include source code, however, the document does have this to say about it:

    These categories should be viewed broadly. For example, computer programs and most “compilations” may be registered as “literary works”;

    You are not required to place any notice of copyright in your source code (since March 1st, 1989). However, adding a notice provides additional legal protection against copyright infringement (potentially increased penalty if infringed).

    So what constitutes legal notice? Here is the relevant text from the article:

    The notice for visually perceptible copies should contain all the following three elements:

    1. The symbol © (the letter C in a circle), or the word “Copyright,” or the abbreviation “Copr.”; and

    2. The year of first publication of the work. In the case of compilations or derivative works incorporating previously published material, the year date of first publication of the compilation or derivative work is sufficient; and

    3. The name of the owner of copyright in the work, or an abbreviation by which the name can be recognized, or a generally known alternative designation of the owner.

    Example: © 2006 John Doe

    For source code, since © is hard to type and can sometimes cause problems in source code, I recommend using the word Copyright:

    Example: Copyright 2006 John Doe

    Of course when you write code for a company, the copyright owner is the company. If the code is contracted to another company, it is a work-for-hire and the hiring company gets the copyright (unless specified otherwise in the contract, so read carefully).

    So where should you put your notice? The guidelines only suggest that it must be placed to “give reasonable notice of the claim of copyright.” For source code, this has traditionally been placed at the top of every source file as a comment.

    Compiled code should also be protected. I'm not sure about other languages, however .Net provides an assembly level attribute for copyright. If you use the standard project templates for Visual Studio, there should be an AssemblyInfo file that contains all the assembly attributes, including the AssemblyCopyrightAttribute. At least in VS 2008, you can also get to it through the Assembly Information button in the project properties (Application tab). If anybody out there knows, I would be interested in learning how other languages add copyright notice to compiled code.

    Once created, your copyright will be good for 70 years after your death. If the copyright owner is a company, the copyright is good for "95 years from publication or 120 years from creation, whichever is shorter."

    The role of a software license is to allow others to use your copyrighted material. If you are interested in reading about software licensing, check out Jeff Atwood's article, Pick a License, Any License, on Coding Horror.

  • VS 2008 and .Net 3.5 SP1 Beta

    If you haven't heard the news yet, Microsoft has released a beta of a service pack (SP1) for Visual Studio 2008 and .Net 3.5. I'm not planning on installing the beta any time soon, but I am looking forward to this SP. It looks like it will have some performance improvements, especially for launching .Net WinForm applications (Scott claims up to 40% improvement in startup time) as well as a new installation package for those that don't want the full .Net install.

    If you want to read more about this release, check out these articles (ScottGu's Blog seems to have the most complete description of the features as well as plenty of links out for more information)...

  • Type Conversions

    Note: This article contains a sample project that you can download from the Downloads section of this website - Converting Types Code Example. The code is described towards the end of this article.

    .Net provides many different ways to convert from one type to another. The simplest way to convert one type to another is to use the System.Convert class. This class provides a number of methods to convert to common types such as Boolean, Integer, etc or to any type as long as the type you are converting from implements the IConvertible interface and defines the appropriate conversion.

    You can also use TypeConverters to convert from one type to another. A TypeConverter is a class that defines a bunch of methods that allow you to convert from one type to another. TypeConverters are used extensively in the property browser control (a control that allows you to view properties of a class - used extensively in Visual Studio) and is used primarily to convert from a string to a object and back again. However, TypeConverters can also be used in your code to perform conversions.

       1:  MyTypeConvertTest tcTest = new MyTypeConvertTest("Hello from tcTest");
       2:  TypeConverter converter = TypeDescriptor.GetConverter(tcTest);
       3:  MyTest test6 = (MyTest)converter.ConvertTo(tcTest, typeof(MyTest));
       4:  Console.WriteLine(test6);

    Of course this code only works if you have defined a TypeConverter for MyTypeConvertTest that can convert a MyTypeConvertTest instance to MyTest. Converters aren't too difficult to write, as long as they are simple (they can become somewhat complex when you are writing them for Visual Studio and are using some of the more advanced features).

    Another common method is to provide methods on your class to convert to and from other types. For example, if you wanted to convert a string into a particular type, you might define a static Parse method on your class that takes a string and returns an instance of the class. To convert the object to another type, you can define ToXxx methods on your class (eg, ToBoolean, ToInteger, etc).

    Unfortunately the System.Convert class does not use TypeConverters when doing conversions nor can it handle conversion methods so you are stuck with having to know exactly how the developer intended for the type to be converted (did they implement the IConvertible interface? a TypeConverter? conversion methods?).

    Download Converting Types Code Example

    I have created a sample project that demonstrates using the IConvertible interface, TypeDescriptors, and conversion methods. This project also provides a class that is similar to Microsoft's System.Convert.ChangeType method, but can also handle TypeDescriptors and conversion methods (Microsoft's Convert.ChangeType method only handles classes that implement the IConvertible interface).

  • How Things Work: Events in .Net

    Ever take the time to learn how events work in .Net? They are pretty basic, but unless you have taken the time to discover how they work, they may seem to be a bit like magic.

    Events are a very powerful way to reduce coupling in your application. Events in .Net are based on the Observer pattern identified in the classic Gang-of-Four book, Design Patterns: Elements of Reusable Object-Oriented Software.

    The first part of this article discusses how VB.Net hides some of the complexity of dealing with events. The second part explains how events work in .Net in general.

    What VB.Net Hides From You

    Compared to C#, event handling in VB.Net requires fewer lines of code to both publish and subscribe to events. However, this is because the VB.Net compiler hides the actual implementation from the developer. If you were to look at the code that the compiler generates, you would see that events in VB.Net work pretty very much the same as C#.

    Let's create a couple of simple classes to use as an example. One is called MyPublisher and it defines an event called MyEvent. The other is called MySubscriber which creates an instance of MyPublisher and listens for MyEvent. You can download the example code here (in the download section of this website).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Event MyEvent(ByVal sender As Object, ByVal e As EventArgs)
       8:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
       9:          RaiseEvent MyEvent(Me, e)
      10:      End Sub
      11:   
      12:  End Class
      13:   
      14:  Public Class MySubscriber
      15:   
      16:      Public Sub New(ByVal publisher As MyPublisher)
      17:          mPublisher = publisher
      18:      End Sub
      19:   
      20:      Private WithEvents mPublisher As MyPublisher
      21:      Public ReadOnly Property Publisher() As MyPublisher
      22:          Get
      23:              Return mPublisher
      24:          End Get
      25:      End Property
      26:   
      27:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs) Handles mPublisher.MyEvent
      28:          Console.WriteLine("Hello World!")
      29:      End Sub
      30:   
      31:  End Class 

    Pretty basic code, easy to understand, and one of the reasons why I like VB.Net. However, if you really want to understand what's going on, you should open this code up in Reflector. What you see is that the VB.Net compiler hides a lot of the complexity for you. What seems like a simple line of code actually get's broken down into many lines of code.

    NOTE: Reflector shows some code that is automatically generated that doesn't have anything to do with events so I removed it from the examples, as well as it doesn't always generate the code correctly (for example, Reflector starts line 12 in the publisher with RaiseEvent which is incorrect).

       1:  Public Class MyPublisher
       2:   
       3:      Public Sub ForceMyEvent()
       4:          Me.OnMyEvent(EventArgs.Empty)
       5:      End Sub
       6:   
       7:      Public Delegate Sub MyEventEventHandler(ByVal sender As Object, ByVal e As EventArgs)
       8:      Public Event MyEvent As MyEventEventHandler
       9:      Protected Overridable Sub OnMyEvent(ByVal e As EventArgs)
      10:          If MyEventEvent IsNot Nothing Then
      11:              MyEventEvent(Me, e)
      12:          End If
      13:      End Sub
      14:   
      15:  End Class 

    If you are familiar with the way C# handles events, you will notice that VB.Net is compiled into something very similar. IMHO, VB.Net is more elegant in that you can declare the event and the delegate in a single line and you can raise the event in a single line.

    The subscriber is a bit more interesting.

       1:  Public Class MySubscriber
       2:   
       3:      Public Sub New(ByVal publisher As MyPublisher)
       4:          Me.mPublisher = publisher
       5:      End Sub
       6:   
       7:      <AccessedThroughProperty("mPublisher")> _
       8:      Private _mPublisher As MyPublisher
       9:      Private Property mPublisher() As MyPublisher
      10:          Get
      11:              Return Me._mPublisher
      12:          End Get
      13:          Set(ByVal WithEventsValue As MyPublisher)
      14:              Dim handler As MyEventEventHandler = New MyEventEventHandler(AddressOf Me.mPublisher_MyEvent)
      15:              If (Not Me._mPublisher Is Nothing) Then
      16:                  RemoveHandler Me._mPublisher.MyEvent, handler
      17:              End If
      18:              Me._mPublisher = WithEventsValue
      19:              If (Not Me._mPublisher Is Nothing) Then
      20:                  AddHandler Me._mPublisher.MyEvent, handler
      21:              End If
      22:          End Set
      23:      End Property
      24:   
      25:      Public ReadOnly Property Publisher() As MyPublisher
      26:          Get
      27:              Return Me.mPublisher
      28:          End Get
      29:      End Property
      30:   
      31:      Private Sub mPublisher_MyEvent(ByVal sender As Object, ByVal e As EventArgs)
      32:          Console.WriteLine("Hello World!")
      33:      End Sub
      34:   
      35:  End Class 

    In the original code, we declare mPublisher using the WithEvents keyword. What this keyword does is change the field that we defined into a property and creates a new field by prefixing the original name of the field with an underscore. By doing this, when we set mPublisher in our code, what we are really doing is setting the property. This causes the AddHandler/RemoveHandler code to be invoked (if you develop in C#, this is a very useful pattern to follow).

    How Events Work

    In the Publisher class in the above example, MyEventEvent (line 11) is being called as if it were a method, but it is actually what is called a multi-cast delegate. A delegate is basically a reference to a method (in the case of events, this would be the event handler). A multi-cast delegate is essentially a list of delegates that can be called in the same way as a single delegate. Refer to the Code Project article, A Beginner's Guide to Delegates, for a good description of delegates and multi-cast delegates.

    So basically when we raise an event, we are simply iterating through the list of event handlers and calling them one at a time (synchronously). All of the event handlers get called unless one of them throws an exception.

    If you want more control over how events are raised, for example, you want to stop calling additional event handlers when one of them has handled or canceled the event, you can explicitly call each event handler in the list. Let's take our example from above and tweak it so that we are manually calling the methods.

       1:  Protected Overridable Sub OnMyEvent(ByVal e As CancelEventArgs)
       2:      If MyEventEvent IsNot Nothing Then
       3:          For Each handler As MyEventEventHandler In MyEventEvent.GetInvocationList()
       4:              handler(Me, e)
       5:              'If e.Cancel Then Exit For
       6:          Next
       7:      End If
       8:  End Sub 

    In this example we are iterating through the list of delegates (the references to the event handlers) and calling each method in turn. If the event arguments were CancelEventArgs, we could check e.Cancel after calling the delegate and if it was true, we could exit the for loop. You can also use this to add asynchronous event handling to your project (if you do, make sure you document it well!).

  • My Worst Fear

    My worst fear is getting some form of dementia. I think I can handle losing limbs or other serious injuries, but losing my ability to solve problems or communicate would be terrible. The reason I became a software developer was because I enjoy solving problems and my ability to do so is a major way that I define myself.

    The professor of the usability class that I recently started was diagnosed with Parkinson's disease. Parkinson's disease primarily affects the motor skills of an individual. However there are also symptoms that effect the brain, including dementia and short-term memory loss. There is currently no cure for Parkinson's disease. Michael J. Fox suffers from Parkinson's disease.

    Although I am sure the professor is brilliant, he was unable to communicate very effectively due to this disease. One of the symptoms is hypophonia or soft speech. The room was deathly silent for 4 hours during the lecture, any noise (such as changing position in a chair) was a distraction.

    Another symptom that I noticed was short term memory loss.  The professor frequently paused during the lecture, often times in the middle of a sentence, trying to remember what he was talking about. He also went off subject often. Normally this wouldn't bother me, but I was having a hard time paying attention already and I didn't really know what the course was about, so I was often confused about what he was talking about and whether it was part of the course, or something else.

    For a class called Visual Media in Technical Communication, I found it a bit ironic that there was no visual presentation for the class. Perhaps before the professor contracted Parkinson's disease he wrote on the white board or something, however, he sat while he did the lecture (I've never had a professor sit while they did a lecture). Of course, symptoms involving motor skills are the most common symptoms of Parkinson's disease and is probably the reason he sat through it.

    As you can probably imagine, I dropped the class. I feel guilty about dropping the class. It's not the professors fault that he wasn't able to perform his job very well and I'm sure he isn't ready to leave a job that he's been doing for many years. Considering that this is my greatest fear, I am certainly sympathetic to his condition.

    If you are interested in learning more about Parkinson's disease, there are a number of organizations out there. The following list is from the Wikipedia article...

  • 2 down, 1 to go

    Sorry I haven't been posting recently. I've been very busy with work and school and any down time I've had I've been trying to spend with my family and friends or just relaxing .

    I recently finished my second quarter of my user-centered design certificate program and will be starting my last quarter next week. Hopefully I will be able to get back to blogging regularly once I get my certificate.

  • 5 Steps To Managing Your Database In Development

    DBCatI have come across the question of managing databases during development in a number of forums and I thought I would outline the way my company manages the database for our product. We build an ERP (Enterprise Resource Planning) system for manufacturing companies. As you can imagine, the database is an important part of our product.

    1. Each Developer Should Have Their Own Database

    The first thing to mention about our database environment is that every developer has SQL Server installed on their development machine and develops on a local copy of the database. This allows the developer to make changes without having to worry about how it will effect other developers. It also allows them to test using stable data (it's difficult to test your code if other people are making changes to data that you need).

    2. Script Database Changes

    When a developer needs to make a change to the database they make their changes to a script and check it into VSS. These scripts are named in a way to ensure that they run in order. We use the product version (<major>.<minor>.<maintenance>) followed by a script number and then a readable name (eg, 1.0.0.100 My Script.sql). The naming conventions allows us to just process the scripts alphabetically instead of having to create a build configuration file for the order. We leave gaps in the numbering so that we can add scripts without having to rename all of the scripts that come after it. For example, if we add another script to our build after 1.0.0.100 My Script.sql, we would call it 1.0.0-110 Another Script.sql (see screenshot below).

    image

    3. Scripts Should Only Run Once

    In order to prevent a script from running multiple times, we keep track of what scripts have been run in the database. The table is fairly simple, the key field being the name of the script (the name of the file without the extension).

    Our table looks something like this (we actually have more columns, but these are the most interesting ones):

    image 

    Before a script does anything interesting we make sure that it has not been run yet by checking this table. If it has been run, it should just exit gracefully. The sql for this looks something like this:

    DECLARE @ScriptName NVARCHAR(255) 
    SET @ScriptName = '1.0.0.100 My Script' 
    
    IF (SELECT COUNT(*) FROM VersionHistory WHERE ScriptName = @ScriptName) > 0
    BEGIN
        PRINT 'Script ' + @ScriptName + ' has already been run.'
        RETURN
    END 
    
    PRINT 'Run script ' + @ScriptName + '.' 
    
    INSERT INTO VersionHistory (ScriptName, StartTime)
        VALUES (@ScriptName, GETDATE()) 
    
    -- Your SQL here. 
    
    UPDATE VersionHistory
        SET EndTime = GETDATE()
        WHERE ScriptName = @ScriptName

    Once a script has been released to production it should never be modified (not all of the developers at my company agree with me on this point). This makes testing the script much simpler. Of course, if there is a bug in the script, you need to fix the bug, but you should do that in another script.

    There are a couple of different options you can pick from to fix a bug in a script, the one you choose will depend on the severity of the bug.

    1. If the bug is easily correctable the simplest solution would be to leave the buggy script alone and create another script to hotfix it.
    2. If the bug is not easily correctable (eg, it irretrievably destroys data) you should remove the script from the installation process and replace it with a corrected script with a new name (just add 1 to the order; eg, 1.0.0-101 My Script.sql). This new script is not intended to fix the error for people that have already run the original script. If the buggy script was already run on the database, the new script should report an error.

      If customers have already run the bad script and are unable to rollback their database (perhaps the bug wasn't noticed until months later), you will probably need to create another script for those customers. This script should only run if the bad script was run. If it hasn't, it should exit gracefully.

    4. Script Objects Separately

    There are some database objects that can easily be recreated without having an impact on data such as stored procedures, functions, views, etc. We place each one in a separate file so they can be easily maintained.

    During the build process we place them all in a single file per type (eg, a single script for all stored procedures). This ensures that they are run in the correct order (we place them in order based on dependencies to other objects). It also makes it easier to manually upgrade databases when necessary (it's easier to run a single script then a hundred or more).

    5. Create Your Database With Your Scheduled Build

    We have a nightly build process that creates the database. The build basically grabs a copy of the database from the previous release to production and runs the latest version scripts on it. When we release a new version of the product, the scripts are removed from the current branch in source control so that the script directory only contains scripts for the current release.

     

    We have recently released version 8.1 of our product and have been using this process for many years. Although there may be better ways of managing your database while in development, this process has worked well for us.

  • It's official, .Net FX code now available!

    Scott Guthrie announced the release of the .Net framework code today (comments and all!). Now you can debug right into Microsoft's code and see what is really going on.

    For the original announcement, check out .NET Framework Library Source Code now available.

    If you want to learn how to enable this feature, check out Configuring Visual Studio to Debug .NET Framework Source Code.

    I can't wait to try this out tomorrow!

  • Measuring Subscriber Counts

    Scott Hanselman put out an interesting post today about measuring blog traffic. This has been a topic that has interested me for awhile. FeedBurner provides a lot of great information that I couldn't have gotten otherwise, but there are some critical pieces of information missing (or perhaps I just haven't completely figured out how to read the stats yet).

    It is a well known fact in retail that it costs more to get new customers than keeping the ones you have. However, it is also known that no matter what you do, you will lose customers. People move, die, find something else, etc. A key indicator about the health of the business is the rate at which you are losing customers. A dramatic change in that can be a major indication that something is going either right or wrong in your business.

    I am not in retail, but it seems the same holds true for blogs as well. Although I may not pay for marketing, it does take work to try to attract subscribers. I read blogs about blogging, I try to write interesting articles, I try to participate in community forums, etc. I haven't been hugely successful with my blog, and likely never will be, but it does take a lot of effort to try to increase my subscriber count anyway. It would be great if FeedBurner was able to provide me with information about how many new subscribers I have vs how many subscribers I lose.

    So, here is my proposal for what kind of information I would like to see for my subscriber stats:

    1. A subscriber is a person who has subscribed to a blog feed and continues to get updates. The updates could be every 5 minutes or every other week.
    2. A new subscriber is (obviously) one that has never requested the feed before.
    3. A lost subscriber is one that has not requested an update in over 2 weeks (or some configurable amount).
    4. A regained subscriber is one that requests your feed after not having received updates in over 2 weeks (or some configurable amount).
    5. Each of these stats should be displayed prominently with drill-downs to help see what is going on.

    Of course, I suspect I'm being a bit naive in what kind of information can be provided. Scott mentions a couple things that would prevent FeedBurner from being able to record this information, such as NewsGator retrieving the feed once and then delivering it to all subscribers (I don't think FeedBurner can know who the subscribers are in this situation).

  • My Dell has Arrived

    image I ordered a new custom built Dell XPS on Monday and it arrived Thursday! I was a bit worried because their website ate my first two orders (one of those times it gave me an error on the confirmation page!) and I ended up having to contact Dell by phone to get the computer ordered (and make sure I wasn't ordering two).

    I did a little bit of investigation before I bought my new computer including pricing out the components for The CodingHorror Ultimate Developer Rig. The interesting thing is that article was posted in June, just 6 months ago, and when I priced everything it was almost half the price. However, the price on the Dell XPS was comparable, the specs were pretty decent, and I didn't really feel like going through all the hassle of putting together my own machine.

    The highlights of my Dell XPS include:

    • Intel Core2 processor Q6600 (2.40Ghz,1066FSB) w/QuadCore Technology and 8MB cache
    • 3GB DDR2 SDRAM at 667MHz (don't really know much about RAM specs other than 3GB is good)
    • 256MB NVIDIA GeForce 8600 GTS
    • Dell 19 in 1 Media Card Reader with Bluetooth
    • Microsoft Windows Vista Ultimate 32-bit Edition English
    • 4 Year Limited Warranty

    I don't typically purchase the extended warranty, but it was a condition of the coupon that I used. Basically I got $500 off of the computer but I had to purchase the warranty (plus 3 year Trend security, whatever that is) for $338. It was still a better deal than any other coupon I was able to find and now I've got a 4 year warranty to boot!

    I would have written this last night, but I was a bit busy installing software (Firefox 2, Visual Studio 2008 - Trial :(, Slick Run, GoodSync, RoboForm, Live Writer, Office 2007, etc).

  • Developer Express Release Notes Viewer

    If you use Developer Express components and need to see what has changed between versions, I have built a tool that will display all the issues that they have included in their release notes between version 6.1.0 to 7.3.5 (you can add additional release notes if you want to) in a grid. This allows you to filter, sort, group, etc them so you can see exactly what has changed.

    The following link provides additional information about this tool...

    Download the Developer Express Release Notes Viewer

  • Community Server Snafu - Favorite Tools

    If you tried to read my Favorite Tools article after I published my last blog post that talked about it (also titled Favorite Tools), you were probably not able to get to the actual article. I've fixed that now.

    Apparently Community server doesn't differentiate blog posts from articles and if a blog post has the same name as an article, one takes the place of the other.

More Posts Next page »
Copyright Brian Brewder, 2007. All rights reserved.
Powered by Community Server (Non-Commercial Edition), by Telligent Systems