March 31
I recently ran across this in an MSN article. They say that from January 1st until the time your taxes are due (April 15th) that during all of that time you are working for the government in the form of paying taxes! It turns out that it varies per state. If you live in Connecticut it's May 20 (on a leap year like 2008). In Oklahoma it's April 12th. In Utah, where I live, it's April 20th. (Calculation: 365.25/Tax burden = days + Jan 1 = Date)
I really wonder what the ideal tax rate should be. I know first-hand that tax will only increase over time and that we get less and less for it. We slowly become a socialistic society and the founding principals our forefathers came here for erode away. In the UK (at least while I was there) you pay 17.5% VAT (Value Added Tax). This is in addition to a hefty income tax. The UK may boast low unemployment rates but that is only because people don't have to work to make a decent living. The mountain of tax on the "rich" pays for the "poor" to remain "poor" (as though you could call anyone rich or poor in England). I am opposed to the division of riches into "rich" and "poor"; it is good to have a large, healthy "middle" working-class. A very large middle class is very good for a country. There are two truisms here:
- You can't create middle class by taxing the upper class.
- A tax rate has almost nothing to do with creating a middle income working class. In fact, you might say the opposite is true.
By my estimation, in the year 2050 the average tax rate will increase to 56% and with the so-called middle income squeeze, there will be far less middle-income working class around.
--Nathan Zaugg
Taxes by state | | Sales | Gas/gal. | Cig./pack | Beer/gal. | State burden | Rank | State/Fed. burden | Rank |
| Alabama | 4.0% | $0.20 | $0.43 | $1.05 | 8.8% | 46 | 28.0% | 49 |
| Alaska | none | $0.08 | $2.00 | $1.07 | 6.6% | 50 | 28.1% | 48 |
| Arizona | 5.6%* | $0.19 | $2.00 | $0.16 | 10.3% | 31 | 31.3% | 25 |
| Arkansas | 6.0% | $0.22 | $0.59 | $0.21 | 11.3% | 13 | 30.7% | 32 |
| California | 7.3% | $0.46 | $0.87 | $0.20 | 11.5% | 12 | 34.3% | 8 |
| Colorado | 2.9% | $0.22 | $0.84 | $0.08 | 10.4% | 30 | 31.8% | 23 |
| Connecticut | 6.0% | $0.44 | $2.00 | $0.20 | 12.2% | 8 | 38.3% | 1 |
| Delaware | none* | $0.23 | $1.15 | $0.16 | 8.8% | 47 | 31.2% | 26 |
| Florida | 6.0% | $0.33 | $0.34 | $0.48 | 10.0% | 38 | 33.6% | 12 |
| Georgia | 4.0% | $0.26 | $0.37 | $0.48 | 10.3% | 32 | 30.9% | 28 |
| Hawaii | 4%* | $0.33 | $1.80 | $0.93 | 12.4% | 6 | 33.0% | 16 |
| Idaho | 6.0% | $0.25 | $0.57 | $0.15 | 10.1% | 35 | 29.6% | 42 |
| Illinois | 6.3% | $0.40 | $0.98 | $0.19 | 10.8% | 22 | 33.2% | 14 |
| Indiana | 6.0% | $0.32 | $1.00 | $0.12 | 10.7% | 25 | 30.8% | 30 |
| Iowa | 5.0% | $0.22 | $1.36 | $0.19 | 11.0% | 18 | 30.6% | 33 |
| Kansas | 5.3% | $0.25 | $0.79 | $0.18 | 11.2% | 15 | 31.0% | 27 |
| Kentucky | 6%* | $0.19 | $0.30 | $0.08 | 10.9% | 20 | 30.4% | 34 |
| Louisiana | 4.0% | $0.20 | $0.36 | $0.32 | 11.0% | 17 | 29.1% | 44 |
| Maine | 5.0% | $0.29 | $2.00 | $0.35 | 14.0% | 2 | 33.9% | 10 |
| Maryland | 6.0% | $0.24 | $2.00 | $0.09 | 10.8% | 23 | 33.1% | 15 |
| Massachusetts | 5.0% | $0.24 | $1.51 | $0.11 | 10.6% | 28 | 34.4% | 7 |
| Michigan | 6.0% | $0.36 | $2.00 | $0.20 | 11.2% | 14 | 31.9% | 21 |
| Minnesota | 6.5% | $0.22 | $1.49 | $0.15 | 11.5% | 11 | 33.9% | 11 |
| Mississippi | 7.0% | $0.19 | $0.18 | $0.43 | 10.5% | 29 | 28.1% | 47 |
| Missouri | 4.2% | $0.18 | $0.17 | $0.06 | 10.1% | 34 | 30.2% | 38 |
| Montana | none | $0.28 | $1.70 | $0.14 | 9.7% | 41 | 29.8% | 39 |
| Nebraska | 5.5% | $0.24 | $0.64 | $0.31 | 11.9% | 9 | 31.8% | 22 |
| Nevada | 6.5% | $0.33 | $0.80 | $0.16 | 10.1% | 36 | 35.2% | 4 |
| New Hampshire | none* | $0.20 | $1.08 | $0.30 | 8.0% | 49 | 30.8% | 29 |
| New Jersey | 7.0% | $0.15 | $2.58 | $0.12 | 11.6% | 10 | 35.6% | 3 |
| New Mexico | 5.0% | $0.18 | $0.91 | $0.41 | 9.8% | 40 | 28.8% | 45 |
| New York | 4.0% | $0.41 | $1.50 | $0.11 | 13.8% | 3 | 37.1% | 2 |
| N. Carolina | 4.3% | $0.30 | $0.35 | $0.53 | 11.0% | 19 | 31.3% | 24 |
| N. Dakota | 5.0% | $0.23 | $0.44 | $0.16 | 9.9% | 39 | 30.2% | 37 |
| Ohio | 5.5%* | $0.28 | $1.25 | $0.18 | 12.4% | 5 | 32.4% | 18 |
| Oklahoma | 4.5% | $0.17 | $1.03 | $0.40 | 9.0% | 45 | 27.8% | 50 |
| Oregon | none | $0.25 | $1.18 | $0.08 | 10.0% | 37 | 30.7% | 31 |
| Pennsylvania | 6.0% | $0.32 | $1.35 | $0.08 | 10.8% | 24 | 31.9% | 20 |
| Rhode Island | 7.0% | $0.31 | $2.46 | $0.10 | 12.7% | 4 | 35.1% | 6 |
| S. Carolina | 6.0% | $0.17 | $0.07 | $0.77 | 10.7% | 26 | 30.3% | 35 |
| S. Dakota | 4.0% | $0.24 | $1.53 | $0.27 | 9.0% | 44 | 29.3% | 43 |
| Tennessee | 7.0% | $0.21 | $0.62 | $0.14 | 8.5% | 48 | 28.8% | 46 |
| Texas | 6.25%* | $0.20 | $1.41 | $0.19 | 9.3% | 43 | 29.8% | 41 |
| Utah | 4.7% | $0.25 | $0.70 | $0.41 | 10.7% | 27 | 30.3% | 36 |
| Vermont | 6.0% | $0.20 | $1.79 | $0.27 | 14.1% | 1 | 35.1% | 5 |
| Virginia | 5.0% | $0.20 | $0.30 | $0.26 | 10.2% | 33 | 32.9% | 17 |
| Washington | 6.5%* | $0.36 | $2.03 | $0.26 | 11.1% | 16 | 34.0% | 9 |
| West Virginia | 6.0% | $0.32 | $0.55 | $0.18 | 10.9% | 21 | 29.8% | 40 |
| Wisconsin | 5.0% | $0.33 | $1.77 | $0.06 | 12.3% | 7 | 33.3% | 13 |
| Wyoming | 4.0% | $0.14 | $0.60 | $0.02 | 9.5% | 42 | 32.1% | 19 |
*State collects Gross Receipts Tax applied before retail level.
Updated March 27, 2008
Source: http://articles.moneycentral.msn.com/Taxes/Advice/TheBestAndWorstStatesForTaxes.aspx?page=2
March 26
You know you've done something wrong when it takes 30+ seconds to run a full-text query. The most annoying part of this bug is the fact that it is something very small and inconsequential that "triggers" the bug. It's a lot like an murder investigation where the killer turns out to be a Nun.
Here is the setup---
- I have a full text index on a text field in my database. This table happens to be our Phrase table (for data localization)
- I do a very simple full text search on that field in a SQL Server proc
- I want to test my proc so I add some fixed input
- Setting a value after the fact causes my full text to be *very* slow!!!
Here is the code
ALTER
PROCEDURE
[dbo].[AdvancedTrackSearch_TEST] (
@TrackTitleCrit xml
,
@TrackDescCrit xml
,
@RecordLabelCrit xml
,
@CategoryCrit xml
,
@ComposersCrit xml
,
@TrackDuration int
,
@TrackDurationOperator int
,
@LangID int
,
@PageSize int
,
@PageNumber int
,
@UserID int
)
AS
BEGIN
-- Temporary input
DECLARE
@TrackTitleStr nvarchar
(2000) SET
@TrackTitleStr =
'"booty poppin"'
-- *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
-- *
THIS LINE CAUSES THE PROBLEMS *
-- *
BY SIMPLY REMOVING THIS LINE *
-- *
THE QUERY TIME WILL GO
FROM
30+ *
-- *
SECONDS TO LESS THAN 1 SECOND! *
-- *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
SET
@LangID =
66 DECLARE
@TitlePhrases TABLE
(
PhraseID int
,
DictionaryID int
)
INSERT
INTO
@TitlePhrases SELECT
PhraseID, DictionaryID FROM
[dbo].[Phrase] WHERE
--PhraseID NOT IN (SELECT
PhraseID FROM
@TitlePhrases) CONTAINS
(
[TEXT] ,
@TrackTitleStr) --[Text] like @Phrase
AND
LanguageID =
@LangID -- Check the output
SELECT
*
FROM
@TitlePhrases END
-- *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
-- NOW WE TRY TO EXECUTE THE PROC
-- *
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
DECLARE
@return_value int
EXEC @return_value =
[dbo].[AdvancedTrackSearch_TEST] @TrackTitleCrit =
NULL
, @TrackDescCrit =
NULL
, @RecordLabelCrit =
NULL
, @CategoryCrit =
NULL
, @ComposersCrit =
NULL
, @TrackDuration =
NULL
, @TrackDurationOperator =
NULL
, @LangID =
NULL
, @PageSize =
NULL
, @PageNumber =
NULL
, @UserID =
NULL
GO
It seems so simple and stupid but setting the LangID (even if we pass null into the actual query) causes the query to take a substantially longer time doing the full text search.
I hope someone finds an explanation!
--Nathan Zaugg
UPDATE:
As a matter of fate, me and my friend Phil Gilmore stumbled on the answer. The trick is to "SET ARITHABORD ON" for one of the first things that you do in the query. This is usually linked to arithmetic exceptions and overflows, but for some reason with out it there is little chance your query will perform. If you look at the difference between the execution plans before setting that variable vs. after you can see that the execution plan changes a lot! After ARITHABORT is ON the execution plans are again identical! Check out my post on MSDN forums.
-- Nathan Zaugg
March 21
You have no idea how it got there but one day you start your computer and get several new "accounts" you can login as. This is very annoying and frustrating! Fortunately there is a way to "hide" those accounts without affecting the applications that added them.
Here is the process:
- Open up the "Run" dialog. (Windows Key + R)
- Type "Regedit". Note: Vista Users will require Administrative approval
- Navigate the registry keys to: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList
- Right click in the window New -> DWORD(32-bit Value)
- Type the name of the account you wish to ignore as the name of the value
- Leave the "Data" at what it defaults to.
When you are done it should look like this:

March 11
I've come across this several times. You build a custom control inside of your web_code folder and you can't reference it from your project because you can't figure out what assembly your supposed to reference (as your web code doesn't normally have a set assembly name). I finally figured out how to do this recently.
Normally you're tempted to put something like this:
<%
@ Register Assembly="MyWebComponent" TagPrefix="as" %> When really you need to put something like this:
<%
@ Register Namespace="NSM.WebControls" TagPrefix="as" %> The only trick is that you need to make sure you put your custom class inside of a set Namespace. Normally any class inside of a web project doesn't belong to a specific namespace.
Now we can reference our control:
<as:MyWebComponent ID="MyControl1" runat="server" />
--Nathan Zaugg
March 08
Last week our camera card filled up. Like most people, we'd almost rather buy a new, bigger card rather than try to go through the process of getting the photos onto the computer, processed, and burned to CD's. We decided that with about 2GB of pictures and videos on our cards we better download them. My wife, Tiffany, likes to rename all of the photo's from their naturally intuitive name like "DSC0001253.JPG" to something a little more clear like "February 2008-01.JPG" and so on.
With literally hundreds of images to rename (and she did this all by hand) I literally felt pain as I watched he do this for only a minuet or two. I got an idea for a program and I was sure I could have it written before she could finish her current folder. Well, it was a tie but now we have this nifty little application that will rename the files for us.
Here is a screen shot:
Instructions:
- Select the path of the photo's you wish to rename. If, for example, you want to rename a months worth of photo's, move them into their own folder first.
- You may use the "..." button to browse to the folder.
- Select a name format. This is the way the photo's will be renamed. The tricky part is to make sure and put the "{0:000}" in the string. This is where the number is going to go. The first zero indicates that is is the first (only) parameter passed into the string format function. The "000" after the colon is the numeric formatter. The formatters are explained here.
- Select the type of file you wish to rename. For example if your camera is like ours it will also take videos. You don't want to accidentally rename a .AVI to a .JPG because it will no longer work.
- When you are done, press the "Run" button. Before it renames any file it will verify the format with you (see below).
- You will see full progress indicators and it should only take a second or two even to do thousands of files.
As always, please drop me a line when you download it and let me know if you like it, hate it, or whatever!
Thanks!
Nathan Zaugg
March 03
I am a little behind on my Blog but I wanted to be sure and post my notes from January's NUNUG meeting on Visual Studio 2008 and the new features in the C# 3.0 framework.
I also wanted to post notes from a remoting presentation I did for STG a year or so ago.
Enjoy!
I have decided to open source a project that I have been working off and on since 2003. I have always been a big fan of code generation and felt like I knew what it takes to do it right. iGen is actually the second separate attempt. My original attempt is named SmartDAL and is also included in the downloads below.
What is iGen?
iGen is simply a fancy XSLT processing engine. It works by having 2-3 main concepts.
- XML Provider - The XML provider is responsible for providing XML to the XSLT templates. Currently it has Oracle provider and SQL Server provider. Each of these will generate SQL that will be used in the XSLT transformation.
- XSLT Transformations - The XSLT transformations are a set of files that will transform the XML that is generated from the XML Provider. The transformations also use a standard set of variables and accepts custom variables.
- File Splitter - The result of an XSLT transformation results in a single file only. If you wish for multiple files as the output then you need to use the built-in splitter.
This is the main screen. The top portion is our XML Providers. You can see that both SQL Server and Oracle are there. This is where you configure which tables, proc's, and database relationships will be used to generate the XML data. It may be desirable to leave out certain tables or proc's so you can choose which ones you wish to include.
The options screen is used to setup project workspaces. The idea behind this concept is that ever developer has their favorite place they like to develop code. I like to have a D:\Projects\[Client]\[Project] structure. Others use C:\Source. Whatever the path it's nice to keep those different and still be able to generate code! We will use these workspaces in later screens.
This next screen shot is of the XSLT settings dialog. Let me go through the controls one by one.
- Settings Description - This is simply the text that will be displayed in the parent dialog. Generally a short description of what you this template does is best.
- XSLT Template - This is the location of the template you wish to process. Notice that there is a drop-down box and a partial path. This is part of the workspaces mentioned above. Of course the path does not need to be part of the workspace provided. This should always be a valid XSLT transformation.
- Data Provider - This selects which XML Data Provider will be used for this transformation. Because the XML that is generated does not have to follow any specific schema you are required to select a provider that is compatible with the XSLT.
- Filename Extension - This gives the user the ability to name the file output. If you are generating a single file then type the entire file name here. If you are generating multiple files then put a suffix if desired and the filename extension. In the example above the files will end with "_INSERT.sql". The rest of the filename is generated by the XSLT transformation.
- Workspace / Path - This is the output directory for the transformation. Again, you can see that we are using a different workspace than defined above. If you browse to a directory that is inside of the selected workspace path then you will only see a partial path in this box. Otherwise you will see a full path.
- Parameter Window - This is where you can add custom parameters for your XSLT. These parameters can be found inside of the XSLT defined at the top of the file. These parameters can be optional but it really depends on how the XSLT was written.
You press the generate button and away we go. You will see what is happening and how long until it finishes. When you are done you may choose to save your settings (after all it can be a lot of work setting these templates up).
This is an XSLT template. You can see from the screen shot (params highlighted in yellow) that this transformation expects 5 params. ProcPrefix, FileNameExtension, DatabaseSchema, DatabaseName, and DatabaseUserName (in no particular order). The FileNameExtension parameter is provided by the XSLT properties window in the "Filename Extension" fields. The rest are custom parameters and the XSLT generation engine will not know if they are required or not. As you can see from the screen shots above I have defined all but the "ProcPrefix". This template is designed to make ProcPrefix optional. It will run just fine without it. But for those who like all of their stored procs to start with "proc_" or "sp" then they may choose to set a value for this parameter in the Parameter window in the XSLT properties dialog.
Note also the use of "#[<xsl:value-of select="@name" /><xsl:value-of select="$filenameextension" />]#" in the example. The #[ and ]# are used by the file splitter. The value inside of the tokens is used as the filename. Ex: #[proc_USERS_INSERT.sql]#
If you wish to create a custom XML Provider you simply need to implement the correct interface and place the DLL in the application directory during startup.
Known Issues:
- The Oracle XML provider is a little more advanced than the SQL XML provider. The oracle provider will provide relationship information that the SQL provider does not yet.
- The Oracle provider is dog slow! This is actually a performance issue with querying relationship information from an Oracle database. For those who have to use this, I am sorry! If it makes you feel better the XML data is cached once it is created so if you goof up on the first run the second one will be much faster.
- The generated classes are somewhat geared toward an Oracle Smart-Client application. These templates and classes were all "perfected" with the Oracle client. I much prefer to use Microsoft SQL Server 2005/2008 but sometimes you don't get to choose! If you wish to modify the templates to work for SQL Server it probably isn't a lot of work.
- .tmp files are left over after generation. These are the original results from the transformation. They can be useful for debugging.
- There is a "lib" directory inside of the templates directory. This is an open source XSLT function library. We use it to mainly make sure the case of our objects is what we need it to be.
Screen Shot of SmartDAL:
I hope you enjoy it! Please drop me a line if you download it and if you are using it.
Downloads:
Thanks!
Nathan Zaugg
Credits
I wasn't alone in working on iGen. I had a lot of help from the team that used it. Bret Cutler, Richard Brower, and Garth Harris. An awesome team -- I would love to work with these guys on another project!