Friday, May 09, 2008

I found two good PDF's on the interweb of Bohr's seminal papers (Published in Phil. Mag., 1913) on atomic structure. I couldnt find part 3 unfortunately.

On the Constitution of Atoms and Molecules

Part II. – Systems containing only a Single Nucleus

Also Rutherfords papers on the gold foil experiment and large angle scattering of alpha & beta particles that led to Bohr's enunciation of the nuclear/quantized model of the atom.

The Scattering of Αlpha and Βeta Particles by Matter and the Structure of the Atom (Phil Mag 1911)

The Structure of the Atom (Phil Mag 1914)

Donald Sadoway, MIT, does a really nice job of covering the Bohr model in the following lectures (3.091 Intro to Solid State Chemistry). Requires Real Player (Or Real Alternative if you please).

Lecture 3. Rutherford model of the atom, Bohr model of hydrogen.

Lecture 4. Atomic spectra of hydrogen, matter/energy interactions involving atomic hydrogen.

Lecture 5. The Shell Model (Bohr- Sommerfeld Model) and multi-electron atoms. Quantum numbers: n, l, m, s.

Friday, May 09, 2008 5:11:49 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, May 06, 2008

Parsing a date with a custom format is as easy as pie with the DateTime.ParseExact method, check it:

DateTime.ParseExact("04292008", "MMddyyyy", null)

Where the first parameter is the value to parse, the second is a format string and for the culture info you can pass null for the current culture (Unless you need to specify one).

UPDATE:

If you need to exclude other characters in the string you can add the literal values qualified by single quotes in the format string. So for example lets say you wanted to extract the date and hour from an IIS log filename, ex08041013.log. You could pass the format string 'ex'yyMMddHH'.log' and the parse method will ignore the ex and .log portions of the string.

DateTime.ParseExact("ex08041013.log", "'ex'yyMMddHH'.log'", null)
C#
Tuesday, May 06, 2008 8:46:21 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Friday, April 25, 2008

So I had FTP setup on a Server '03 box with an FTP site configured to use user isolation mode with active directory. Everything was working great then all of a sudden users cant login and this error appears in the System events in the event log:

image

This error, while true, doesn't really pinpoint the problem... But I found this wonderful article that suggested that the account used by the FTP site to access AD was changed. "Oh yeah!", I said, "I did change that, D'OH!". Easy enough to fix; just open a command prompt and use the adsutil.vbs to update the AD account in the IIS metabase.

c:\Inetpub\Adminscripts\adsutil.vbs set msftpsvc/{FTP_SITE_ID}/ADConnectionsUserName MyDomain\MyFTPADUsername

c:\Inetpub\Adminscripts\adsutil.vbs set msftpsvc/{FTP_SITE_ID}/ADConnectionsPassword S0m3P@$$W0rd 

Remember to include the domain name with the username.

Friday, April 25, 2008 6:37:51 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Wednesday, April 16, 2008

If you happen to be using the Persits mail component and you get the 'Access is denied' exception:

Persits.MailSender.4 error '800a0011'

Access is denied.

/pages/somepage.asp, line 208

You'll probably find, from the Persits support site or elsewhere, that the queue folder needs to have increased permissions. It doesn't however tell you where this is. So here is the default install path for version 4:

C:\Program Files\Persits Software\AspEmail\Queue

As far as the permissions go I have found that granting Read and Write permissions to the accessing account on that folder is sufficient. In IIS 6 the accessing account for .NET will be the identity of the App Pool assigned to the site (if you are not doing impersonation) which is the NetworkService account by default. For Classic ASP it will be the anon account (Which by default is the IUSR_xxx) for anon access or the user/group if you are doing other types of auth.

Wednesday, April 16, 2008 3:21:07 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, April 15, 2008

I thought this line from a CNN story on the petition to keep XP around was telling:

"Others used the comments section to rail against the very idea that Microsoft has the power to enforce the phase-out from a stable, decent product to one that many consider worse, while profiting from the move."

Yeah, I totally agree. I'm the first to embrace new versions of software but aside from the new Server, .NET and Visual Studio releases I'm not at all hyped about this next generation of Windows or Office. It is pretty rotten that no matter how a new version release turns out, the masses are forced to move to it while MS makes money. It seems like instead of taking their time to produce a quality release, products are rushed to market so that there can be a profit turned (Sharepoint & Commerce Server???). So instead of getting higher quality releases less frequently we get frequent low quality releases and we're paying for it. Things like performance, documentation and general user acceptance are tossed out the window. No wonder Apples' market share has increased so rapidly in the last few years (With the help of the iPhone and iPod of course).

Monday, April 14, 2008 11:55:17 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [2]  | 
 Monday, April 07, 2008

I keep seeing this term thrown around a lot lately with all these beta releases and have had a hard time pinning down an exact definition of it, at least in layman speak anyway's. I feel a little stupid as if I should just know what it means; 'ya know a GO LIVE license, DUH'! Here is the only reference I have found (For Beta IIS 7) describing it in simple terms:

IIS 7.0 Go-Live FAQ

2. What exactly is a Go Live license? How is it different from a normal license?

A Go Live license is a license to use a Beta release of a Microsoft product in a live production environment, before the actual release of the product. It is important to also note that the Go Live license transfers from Microsoft to the licensee, liability for any unanticipated consequences, financial or otherwise, directly or indirectly caused by using the Beta technology before its official release.

Obviously license details could be different for each product but 2 things stand out in this description; 1) You're allowed to use it in production in its beta form and 2) MS is not liable for any problems the beta version may cause.

I wish there was more of a definitive source within MS for explaining licenses. I just went through this with an MSDN subscription purchase. It's almost impossible to find license details spelled out in one central place and in a way that's easy to understand without being a lawyer. And there are many licenses for the same product, so it's really hard to know what your getting into and which one is right for you.

Monday, April 07, 2008 7:19:37 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Tuesday, March 04, 2008

Common Table Expressions (CTE's) are a handy feature introduced in SQL Server 2005. Making them more handy is the fact that they can be used recursively. This opens up a number of possibilities; one of which being a set based way to build a virtual table out of a comma separated list and filter off of that virtual table. Lets say for example we have a comma separated list of ID's we want to use to filter the results of a query.

DECLARE @Filter varchar(1000)

SET @Filter = '4,8,23,56,72';

You'll notice the semicolon at the end of the SET statement. The next statement in this example will be the CTE and TSQL requires the CTE and the previous statement to be separated by a semicolon. Now for the the first rendition of the CTE.

WITH Filter(FilterId, Position) AS
(
    SELECT 
    CAST(SUBSTRING(@Filter, 1, 
        CASE CHARINDEX(',', @Filter) 
        WHEN 0 THEN LEN(@Filter) 
        ELSE CHARINDEX(',', @Filter) - 1 END
    ) AS int) AS FilterId,
    CHARINDEX(',', @Filter) AS Position
    WHERE @Filter IS NOT NULL AND LEN(@Filter) > 0
)

SELECT * FROM Filter

The CTE, so far, only contains one query which will serve as the "anchor". If you run this it only returns one result, the very first id and the current position in the string:

image

Next we will add in the recursive query. This query must come immediatly after the anchor and be separated from it by the UNION ALL operator. You can have multiple anchors and multiple recursive queries which can make use of other combination operators, but anchors must be grouped before the recursive queries and the two groups must be separated by the UNION ALL operator.

WITH Filter(FilterId, Position) AS
(
    SELECT 
    CAST(SUBSTRING(@Filter, 1, 
        CASE CHARINDEX(',', @Filter) 
        WHEN 0 THEN LEN(@Filter) 
        ELSE CHARINDEX(',', @Filter) - 1 END
    ) AS int) AS FilterId,
    CHARINDEX(',', @Filter) AS Position
    WHERE @Filter IS NOT NULL AND LEN(@Filter) > 0

    UNION ALL

    SELECT 
    CAST(SUBSTRING(@Filter, 
        Position + 1, 
        CASE CHARINDEX(',', @Filter, Position + 1) 
        WHEN 0 THEN LEN(@Filter) - Position 
        ELSE CHARINDEX(',', @Filter, Position + 1) - Position - 1 END
    ) AS int) AS FilterId,
    CHARINDEX(',', @Filter, Position + 1) AS Position
    FROM Filter WHERE Position > 0
)

SELECT * FROM Filter

The recursive query makes use of the last position to "move" to the next id in the string. When it has hit the end of the string the last position is set to zero which terminates the recursion. The results are as follows:

image

You'll also notice that the query that selects from the CTE immediately follows it; this is another requirement for CTE's. Now lets select some employees from the AdventureWorks database:

DECLARE @Filter varchar(1000)

SET @Filter = '4,8,23,56,72';

WITH Filter(FilterId, Position) AS
(
    SELECT 
    CAST(SUBSTRING(@Filter, 
        1, 
        CASE CHARINDEX(',', @Filter) 
        WHEN 0 THEN LEN(@Filter) 
        ELSE CHARINDEX(',', @Filter) - 1 END
    ) AS int) AS FilterId,
    CHARINDEX(',', @Filter) AS Position
    WHERE @Filter IS NOT NULL AND LEN(@Filter) > 0

    UNION ALL

    SELECT 
    CAST(SUBSTRING(@Filter, 
        Position + 1, 
        CASE CHARINDEX(',', @Filter, Position + 1) 
        WHEN 0 THEN LEN(@Filter) - Position 
        ELSE CHARINDEX(',', @Filter, Position + 1) - Position - 1 END
    ) AS int) AS FilterId,
    CHARINDEX(',', @Filter, Position + 1) AS Position
    FROM Filter WHERE Position > 0
)

SELECT EmployeeID, LoginID, Title 
FROM HumanResources.Employee
WHERE EmployeeID IN (SELECT FilterId FROM Filter)

And here are the results:

image

Tuesday, March 04, 2008 4:33:58 PM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  | 
 Monday, February 11, 2008

I cant believe I wasn't aware of this cool little feature but with the release of C# 2.0 came the yield keyword. Basically it allows you to create an enumerator that "yields" when it has the current value ready. It's much simpler and elegant than enumerator code you would normally have to write. As an example we will create an enumerable class that returns numbers in the Fibonacci sequence.

public class FibonacciSeries : IEnumerable
{
    int size;

    internal FibonacciSeries(int size)
    { this.size = size; }

    public IEnumerator GetEnumerator()
    {
        int termA = -1;
        int termB = 1;

        for (int index = 0; index < size; index++)
        {
            int current = termA + termB;
            termA = termB;
            termB = current;
            yield return current;
        }
    }
}

Instead of creating a separate class that implements IEnumerable and keeps track of iterator state, we simply put our enumerator code in the GetEnumerator() method and call yield return ...; when we have a value ready. This allows the iterator to be written as if we were pushing the value out, much cleaner and simpler. Behind the scenes, when our code is compiled, the compiler builds what we would have normally had to write . Below is the compiled version of the above code in Reflector (Albeit cleaned it up a bit):

public class FibonacciSeries : IEnumerable
{
    private int size;

    internal FibonacciSeries(int size)
    {
        this.size = size;
    }

    public IEnumerator GetEnumerator()
    {
        Enumerator enumerator = new Enumerator(0);
        enumerator.parent = this;
        return enumerator;
    }

    private sealed class Enumerator : IEnumerator<object>, IEnumerator, IDisposable
    {
        private int state;
        private object current;
        public FibonacciSeries parent;
        public int currentValue;
        public int index;
        private int termA = -1;
        private int termB = 1;

        public Enumerator(int state)
        {
            this.state = state;
        }

        public bool MoveNext()
        {
            switch (this.state)
            {
                case 0:
                    this.index = 0;
                    break;

                case 1:
                    this.index++;
                    break;
            }

            this.state = -1;

            while (this.index < this.parent.size)
            {
                this.currentValue = this.termA + this.termB;
                this.termA = this.termB;
                this.termB = this.currentValue;
                this.current = this.currentValue;
                this.state = 1;
                return true;
            }

            return false;
        }

        void IEnumerator.Reset()
        { throw new NotSupportedException(); }

        void IDisposable.Dispose() { }

        object IEnumerator<object>.Current
        { get { return this.current; } }

        object IEnumerator.Current
        { get { return this.current; } }
    }
}
C#
Monday, February 11, 2008 1:43:21 AM (GMT Standard Time, UTC+00:00)  #   |  Comments [0]  |