Introduced a ComputeNode class.

This refactors out the hash()/compute() machinery from DependencyNode, allowing DependencyNode to be used for tracking dependencies that are not computed in the usual fashion - this will be useful for shader nodes and executable requirements, and anyone who wishes to define their own means of computing results from a node graph.
Implemented dirty propagation for Shader nodes.

Derived Shader from DependencyNode, which makes reasonable sense now that DependencyNode doesn't contain the hash()/compute() mechanism that doesn't make sense for shaders.