update the asset file so that more attrs are lazily read and memoized

This alters an asset file so that its md5, content, url, and href
are all lazy eval'd and memoized.

This sets the stage for an asset deriving content from its source
file if its output file hasn't been written (ie its source hasn't
been digested yet).
find a source file by its digest path

This adds a utility class method for finding source files by their
digest paths.  This is useful because it will allow asset files
(which already know their digest path) to now know their source
files.

Source files are found by scanning the sources and finding the
last source with a matching digest path.  We choose the last one
to handle the case where their are two source files that produce
the same digest path.  When digested, the last source file would
overwrite any previous sources.  Therefore the last source file
matching that digest path is the intended one.

This also introduces the concept of a `NullSourceFile` to handle
the case where a matching source file cannot be found.
make the asset file aware of its source file

Using the find by digest path logic, an asset file can now know
its corresponding source file.  This allows an asset file to fetch
its md5 and content from the source file in the case its output
file has not yet been created.

This ensures that an asset's content attrs can always be known -
on-demand and regardless of digest order.