digraph URLRequestRoot {
    subgraph cluster_legend {
	label="Legend";

	## The following legend is an attempt to match UML notation,
	## except for template_class and Factory->object, which are
	## invented for this diagram.
	BaseClass;
	SubClass [label="Derived Class"];
	Whole;
	Part;
	A;
	B;
	Interface [label="Interface / ABC", style=dashed];
	template_class [shape=diamond]; # Link will name parameter(s)

	SubClass -> BaseClass [arrowhead="empty"];
	SubClass -> Interface [arrowhead="empty", style=dashed];
	Part -> Whole [arrowhead="diamond", label="ownership"];
	Part -> Whole [arrowhead="odiamond", label="pointer"];
	A -> B [arrowhead="none", headlabel="?..?", taillabel="?..?",
		label="association"];
	// Often a "subgraph { rank=same; .. }" is used to wrap the
	// below to make the generative relationship distinctive
	// from the other class relationships.
	Factory -> object [arrowhead=veevee];
    };

    ## URLRequest, URLRequestJob, and subclasses
    URLRequestContext;
    URLRequest;
    URLRequestJob [style=dashed];
    URLRequestJob_Others [label="...other job types..."];
    URLRequestHttpJob;
    Filter;

    {URLRequestHttpJob, URLRequestJob_Others} -> URLRequestJob
	[arrowhead="empty"];

    URLRequestJob -> URLRequest [arrowhead="diamond"];
    Filter -> URLRequestJob [arrowhead="diamond"];
    Filter -> Filter [arrowhead="diamond", taillabel="0..1"];

    subgraph {
	rank=same;
	URLRequestContext -> URLRequest [arrowhead=veevee];
    }
    subgraph {
	rank=same;
	URLRequestHttpJob -> Filter [arrowhead=veevee];
    }


    ## HttpTransaction, subclasses, and generative classes.
    HttpTransactionFactory [style=dashed];
    HttpCache;
    HttpNetworkLayer;
    HttpTransaction [style=dashed];
    HttpCache_Transaction [label="HttpCache::Transaction"];
    HttpNetworkTransaction;

    { HttpNetworkTransaction, HttpCache_Transaction } -> HttpTransaction
	[style=dashed, arrowhead="empty"];
    { HttpNetworkLayer, HttpCache } -> HttpTransactionFactory
	[arrowhead=empty, style=dashed];

    HttpTransaction -> HttpCache_Transaction  [arrowhead=diamond];
    HttpTransaction -> URLRequestHttpJob [arrowhead="diamond"]

    subgraph {
	rank=same;
	HttpCache -> HttpCache_Transaction [arrowhead=veevee];
    }
    subgraph {
	rank=same;
	HttpTransactionFactory -> HttpTransaction [arrowhead=veevee];
    }
    subgraph {
	rank=same;
	HttpNetworkLayer -> HttpNetworkTransaction [arrowhead=veevee];
    }

    ## HttpStreamFactory and related.
    HttpStreamFactory;
    HttpStreamRequest;
    HttpStream [style=dashed];
    HttpStreamFactory_Job [label="HttpStreamFactory::Job"];
    HttpStreamRequest_Delegate
	[label="HttpStreamRequest::Delegate",style=dashed];
    HttpBasicStream;
    QuicHttpStream;
    SpdyHttpStream;
    HttpBasicState;

    HttpNetworkTransaction -> HttpStreamRequest_Delegate
	[style=dashed, arrowhead="empty"];
    { HttpBasicStream, QuicHttpStream, SpdyHttpStream } -> HttpStream
	[style=dashed, arrowhead="empty"];

    HttpStreamRequest -> HttpNetworkTransaction [arrowhead="diamond"];
    HttpStream -> HttpNetworkTransaction [arrowhead="diamond"];
    HttpBasicState -> HttpBasicStream [arrowhead=diamond];
    HttpStreamFactory_Job -> HttpStreamRequest
	[arrowhead="diamond",taillabel="1..*"];

    HttpStreamRequest_Delegate -> HttpStreamRequest
        [arrowhead=odiamond];
    HttpStreamFactory_Job -> HttpStreamFactory_Job
        [arrowhead=odiamond, label="blocking_job_\nwaiting_job_"];

    subgraph {
	rank=same;
	HttpStreamFactory -> HttpStreamRequest [arrowhead=veevee];
    }
    subgraph {
	rank=same;
	HttpStreamRequest -> HttpStream [arrowhead=veevee];
    }

    ## ClientSocketHandle and socket pools.
    ClientSocketPool [style=dashed];
    TransportClientSocketPool;
    SSLClientSocketPool;
    ClientSocketPool_Others [label="...others..."];
    ClientSocketPoolBase [label="ClientSocketPoolBase", shape=diamond];
    ClientSocketPoolBaseHelper;

    ConnectJobFactory;
    ConnectJob [style=dashed];
    TransportConnectJob;
    SSLConnectJob;
    ConnectJob_Others [label="...other connect job types..."];
    ConnectJob_Delegate [label="ConnectJob::Delegate",style=dashed];

    StreamSocket [style=dashed];
    TransportClientSocket [style=dashed];
    TCPClientSocket;
    StreamSocket_Others [label="...other socket types..."];

    TransportConnectJobHelper;
    SingleRequestHostResolver;

    { SSLClientSocketPool, TransportClientSocketPool,
      ClientSocketPool_Others} -> ClientSocketPool
	[style=dashed, arrowhead=empty];
    ClientSocketPoolBaseHelper -> ConnectJob_Delegate
	[arrowhead=empty, style=dashed];
    StreamSocket -> Socket [arrowhead=empty, style=dashed];
    TCPClientSocket -> TransportClientSocket
        [arrowhead=empty, style=dashed];
    TransportClientSocket -> StreamSocket
        [arrowhead=empty, style=dashed];
    StreamSocket_Others -> StreamSocket
	[arrowhead=empty, style=dashed];
    {SSLConnectJob, TransportConnectJob, ConnectJob_Others} -> ConnectJob
	[style=dashed, arrowhead=empty];

    ClientSocketHandle -> HttpStreamFactory_Job [arrowhead="diamond"];
    ClientSocketHandle -> HttpBasicState [arrowhead="diamond"];
    ClientSocketPoolBaseHelper -> ClientSocketPoolBase [arrowhead=diamond];
    ClientSocketPoolBase -> TransportClientSocketPool
	[arrowhead=diamond, label=TransportSocketParams];
    ClientSocketPoolBase -> SSLClientSocketPool
	[arrowhead=diamond, label=SSLSocketParams];

    StreamSocket -> ClientSocketHandle [arrowhead=diamond];
    ConnectJobFactory -> ClientSocketPoolBase [arrowhead=diamond];
    StreamSocket -> ConnectJob [arrowhead=diamond];
    SingleRequestHostResolver -> TransportConnectJobHelper
	[arrowhead=diamond];
    TransportConnectJobHelper -> TransportConnectJob [arrowhead=diamond];

    ClientSocketPool -> ClientSocketHandle  [arrowhead=odiamond];
    ConnectJob_Delegate -> ConnectJob  [arrowhead=odiamond];

    subgraph {
	rank=same;
	ConnectJobFactory -> ConnectJob [arrowhead=veevee];
    }
    subgraph {
	rank=same;
	HttpStreamFactory_Job -> ClientSocketHandle [arrowhead=veevee];
    }
    subgraph {
        rank=same;
	TransportConnectJob -> StreamSocket [arrowhead=veevee];
    }
}
