Changeset 64547 in webkit


Ignore:
Timestamp:
Aug 3, 2010 6:07:01 AM (14 years ago)
Author:
yurys@chromium.org
Message:

2010-08-03 Yury Semikhatsky <yurys@chromium.org>

Reviewed by Pavel Feldman.

Web Inspector: use InspectorValue to push resource data to the frontend
https://bugs.webkit.org/show_bug.cgi?id=43414

  • inspector/Inspector.idl:
  • inspector/InspectorController.cpp: (WebCore::InspectorController::disconnectFrontend): destroy remote frontend object along with the old inspector frontend (WebCore::InspectorController::populateScriptObjects): (WebCore::InspectorController::didCommitLoad): (WebCore::InspectorController::didLoadResourceFromMemoryCache): (WebCore::InspectorController::identifierForInitialRequest): (WebCore::InspectorController::mainResourceFiredDOMContentEvent): (WebCore::InspectorController::mainResourceFiredLoadEvent): (WebCore::InspectorController::willSendRequest): (WebCore::InspectorController::didReceiveResponse): (WebCore::InspectorController::didReceiveContentLength): (WebCore::InspectorController::didFinishLoading): (WebCore::InspectorController::didFailLoading): (WebCore::InspectorController::resourceRetrievedByXMLHttpRequest): (WebCore::InspectorController::scriptImported):
  • inspector/InspectorFrontend.cpp:
  • inspector/InspectorFrontend.h:
  • inspector/InspectorResource.cpp: (WebCore::buildHeadersObject): (WebCore::buildObjectForTiming): (WebCore::InspectorResource::updateScriptObject):
  • inspector/InspectorResource.h:
  • inspector/front-end/inspector.js: (WebInspector.updateResource):
Location:
trunk/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r64546 r64547  
     12010-08-03  Yury Semikhatsky  <yurys@chromium.org>
     2
     3        Reviewed by Pavel Feldman.
     4
     5        Web Inspector: use InspectorValue to push resource data to the frontend
     6        https://bugs.webkit.org/show_bug.cgi?id=43414
     7
     8        * inspector/Inspector.idl:
     9        * inspector/InspectorController.cpp:
     10        (WebCore::InspectorController::disconnectFrontend): destroy remote frontend object along with the old inspector frontend
     11        (WebCore::InspectorController::populateScriptObjects):
     12        (WebCore::InspectorController::didCommitLoad):
     13        (WebCore::InspectorController::didLoadResourceFromMemoryCache):
     14        (WebCore::InspectorController::identifierForInitialRequest):
     15        (WebCore::InspectorController::mainResourceFiredDOMContentEvent):
     16        (WebCore::InspectorController::mainResourceFiredLoadEvent):
     17        (WebCore::InspectorController::willSendRequest):
     18        (WebCore::InspectorController::didReceiveResponse):
     19        (WebCore::InspectorController::didReceiveContentLength):
     20        (WebCore::InspectorController::didFinishLoading):
     21        (WebCore::InspectorController::didFailLoading):
     22        (WebCore::InspectorController::resourceRetrievedByXMLHttpRequest):
     23        (WebCore::InspectorController::scriptImported):
     24        * inspector/InspectorFrontend.cpp:
     25        * inspector/InspectorFrontend.h:
     26        * inspector/InspectorResource.cpp:
     27        (WebCore::buildHeadersObject):
     28        (WebCore::buildObjectForTiming):
     29        (WebCore::InspectorResource::updateScriptObject):
     30        * inspector/InspectorResource.h:
     31        * inspector/front-end/inspector.js:
     32        (WebInspector.updateResource):
     33
    1342010-08-03  Sheriff Bot  <webkit.review.bot@gmail.com>
    235
  • trunk/WebCore/inspector/Inspector.idl

    r64540 r64547  
    4545        [notify] void updateConsoleMessageExpiredCount(out unsigned long count);
    4646        [notify] void updateConsoleMessageRepeatCount(out unsigned long count);
     47        [notify] void updateResource(out Value resource);
     48        [notify] void removeResource(out unsigned long resourceId);
    4749#if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER
    4850        [notify] void pausedScript(out Value callFrames);
     
    6365        [handler=Controller] void enableResourceTracking(in boolean always);
    6466        [handler=Controller] void disableResourceTracking(in boolean always);
    65         [handler=Controller] void getResourceContent(in long callId, in unsigned long identifier);
     67        [handler=Controller] void getResourceContent(in long callId, in unsigned long identifier, out String content);
    6668        [handler=Controller] void reloadPage();
    6769
  • trunk/WebCore/inspector/InspectorController.cpp

    r64540 r64547  
    596596        return;
    597597    m_frontend.clear();
     598    m_remoteFrontend.clear();
    598599
    599600    connectedFrontendCount--;
     
    662663    ResourcesMap::iterator resourcesEnd = m_resources.end();
    663664    for (ResourcesMap::iterator it = m_resources.begin(); it != resourcesEnd; ++it)
    664         it->second->updateScriptObject(m_frontend.get());
     665        it->second->updateScriptObject(m_remoteFrontend.get());
    665666
    666667    m_domAgent->setDocument(m_inspectedPage->mainFrame()->document());
     
    734735        if (!loaderToKeep || !resource->isSameLoader(loaderToKeep)) {
    735736            removeResource(resource);
    736             if (m_frontend)
    737                 resource->releaseScriptObject(m_frontend.get());
     737            if (m_remoteFrontend)
     738                resource->releaseScriptObject(m_remoteFrontend.get());
    738739        }
    739740    }
     
    796797                // needed to keep the load for a user-entered URL from showing up in the
    797798                // list of resources for the page they are navigating away from.
    798                 m_mainResource->updateScriptObject(m_frontend.get());
     799                m_mainResource->updateScriptObject(m_remoteFrontend.get());
    799800            } else {
    800801                // Pages loaded from the page cache are committed before
     
    907908    addResource(resource.get());
    908909
    909     if (m_frontend)
    910         resource->updateScriptObject(m_frontend.get());
     910    if (m_remoteFrontend)
     911        resource->updateScriptObject(m_remoteFrontend.get());
    911912}
    912913
     
    931932    addResource(resource.get());
    932933
    933     if (m_frontend && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
    934         resource->updateScriptObject(m_frontend.get());
     934    if (m_remoteFrontend && loader->frameLoader()->isLoadingFromCachedPage() && resource == m_mainResource)
     935        resource->updateScriptObject(m_remoteFrontend.get());
    935936}
    936937
     
    944945        if (m_timelineAgent)
    945946            m_timelineAgent->didMarkDOMContentEvent();
    946         if (m_frontend)
    947             m_mainResource->updateScriptObject(m_frontend.get());
     947        if (m_remoteFrontend)
     948            m_mainResource->updateScriptObject(m_remoteFrontend.get());
    948949    }
    949950}
     
    958959        if (m_timelineAgent)
    959960            m_timelineAgent->didMarkLoadEvent();
    960         if (m_frontend)
    961             m_mainResource->updateScriptObject(m_frontend.get());
     961        if (m_remoteFrontend)
     962            m_mainResource->updateScriptObject(m_remoteFrontend.get());
    962963    }
    963964}
     
    10061007    resource->updateRequest(request);
    10071008
    1008     if (resource != m_mainResource && m_frontend)
    1009         resource->updateScriptObject(m_frontend.get());
     1009    if (resource != m_mainResource && m_remoteFrontend)
     1010        resource->updateScriptObject(m_remoteFrontend.get());
    10101011}
    10111012
     
    10181019        resource->updateResponse(response);
    10191020
    1020         if (resource != m_mainResource && m_frontend)
    1021             resource->updateScriptObject(m_frontend.get());
     1021        if (resource != m_mainResource && m_remoteFrontend)
     1022            resource->updateScriptObject(m_remoteFrontend.get());
    10221023    }
    10231024    if (response.httpStatusCode() >= 400) {
     
    10401041    resource->addLength(lengthReceived);
    10411042
    1042     if (resource != m_mainResource && m_frontend)
    1043         resource->updateScriptObject(m_frontend.get());
     1043    if (resource != m_mainResource && m_remoteFrontend)
     1044        resource->updateScriptObject(m_remoteFrontend.get());
    10441045}
    10451046
     
    10591060
    10601061    // No need to mute this event for main resource since it happens after did commit load.
    1061     if (m_frontend)
    1062         resource->updateScriptObject(m_frontend.get());
     1062    if (m_remoteFrontend)
     1063        resource->updateScriptObject(m_remoteFrontend.get());
    10631064}
    10641065
     
    10841085
    10851086    // No need to mute this event for main resource since it happens after did commit load.
    1086     if (m_frontend)
    1087         resource->updateScriptObject(m_frontend.get());
     1087    if (m_remoteFrontend)
     1088        resource->updateScriptObject(m_remoteFrontend.get());
    10881089}
    10891090
     
    11051106    resource->setOverrideContent(sourceString, InspectorResource::XHR);
    11061107
    1107     if (m_frontend)
    1108         resource->updateScriptObject(m_frontend.get());
     1108    if (m_remoteFrontend)
     1109        resource->updateScriptObject(m_remoteFrontend.get());
    11091110}
    11101111
     
    11201121    resource->setOverrideContent(ScriptString(sourceString), InspectorResource::Script);
    11211122
    1122     if (m_frontend)
    1123         resource->updateScriptObject(m_frontend.get());
     1123    if (m_remoteFrontend)
     1124        resource->updateScriptObject(m_remoteFrontend.get());
    11241125}
    11251126
     
    21832184void InspectorController::getResourceContent(long callId, unsigned long identifier)
    21842185{
    2185     if (!m_frontend)
     2186    if (!m_remoteFrontend)
    21862187        return;
    21872188
    21882189    RefPtr<InspectorResource> resource = m_resources.get(identifier);
    2189     if (resource)
    2190         m_frontend->didGetResourceContent(callId, resource->sourceString());
    2191     else
    2192         m_frontend->didGetResourceContent(callId, "");
     2190    String content = resource ? resource->sourceString() : String();
     2191    m_remoteFrontend->didGetResourceContent(callId, content);
    21932192}
    21942193
  • trunk/WebCore/inspector/InspectorFrontend.cpp

    r64540 r64547  
    104104}
    105105
    106 void InspectorFrontend::updateConsoleMessageExpiredCount(unsigned count)
    107 {
    108     ScriptFunctionCall function(m_webInspector, "dispatch");
    109     function.appendArgument("updateConsoleMessageExpiredCount");
    110     function.appendArgument(count);
    111     function.call();
    112 }
    113 
    114 void InspectorFrontend::addConsoleMessage(const ScriptObject& messageObj)
    115 {
    116     ScriptFunctionCall function(m_webInspector, "dispatch");
    117     function.appendArgument("addConsoleMessage");
    118     function.appendArgument(messageObj);
    119     function.call();
    120 }
    121 
    122 void InspectorFrontend::updateConsoleMessageRepeatCount(unsigned count)
    123 {
    124     ScriptFunctionCall function(m_webInspector, "dispatch");
    125     function.appendArgument("updateConsoleMessageRepeatCount");
    126     function.appendArgument(count);
    127     function.call();
    128 }
    129 
    130 void InspectorFrontend::clearConsoleMessages()
    131 {
    132     callSimpleFunction("clearConsoleMessages");
    133 }
    134 
    135 bool InspectorFrontend::updateResource(unsigned long identifier, const ScriptObject& resourceObj)
    136 {
    137     ScriptFunctionCall function(m_webInspector, "dispatch");
    138     function.appendArgument("updateResource");
    139     function.appendArgument(identifier);
    140     function.appendArgument(resourceObj);
    141     bool hadException = false;
    142     function.call(hadException);
    143     return !hadException;
    144 }
    145 
    146 void InspectorFrontend::removeResource(unsigned long identifier)
    147 {
    148     ScriptFunctionCall function(m_webInspector, "dispatch");
    149     function.appendArgument("removeResource");
    150     function.appendArgument(identifier);
    151     function.call();
    152 }
    153 
    154 void InspectorFrontend::didGetResourceContent(long callId, const String& content)
    155 {
    156     ScriptFunctionCall function(m_webInspector, "dispatch");
    157     function.appendArgument("didGetResourceContent");
    158     function.appendArgument(callId);
    159     function.appendArgument(content);
    160     function.call();
    161 }
    162 
    163106void InspectorFrontend::updateFocusedNode(long nodeId)
    164107{
  • trunk/WebCore/inspector/InspectorFrontend.h

    r64540 r64547  
    6767        void populateApplicationSettings(const String& settings);
    6868        void populateSessionSettings(const String& settings);
    69 
    70         void updateConsoleMessageExpiredCount(unsigned count);
    71         void addConsoleMessage(const ScriptObject& messageObj);
    72         void updateConsoleMessageRepeatCount(unsigned count);
    73         void clearConsoleMessages();
    74 
    75         bool updateResource(unsigned long identifier, const ScriptObject& resourceObj);
    76         void removeResource(unsigned long identifier);
    77         void didGetResourceContent(long callId, const String& content);
    7869
    7970        void updateFocusedNode(long nodeId);
  • trunk/WebCore/inspector/InspectorResource.cpp

    r64203 r64547  
    3939#include "DocumentLoader.h"
    4040#include "Frame.h"
    41 #include "InspectorFrontend.h"
     41#include "InspectorValues.h"
     42#include "RemoteInspectorFrontend.h"
    4243#include "ResourceLoadTiming.h"
    4344#include "ResourceRequest.h"
    4445#include "ResourceResponse.h"
    4546#include "TextEncoding.h"
    46 #include "ScriptObject.h"
    4747
    4848namespace WebCore {
     
    147147}
    148148
    149 static void populateHeadersObject(ScriptObject* object, const HTTPHeaderMap& headers)
    150 {
     149static PassRefPtr<InspectorObject> buildHeadersObject(const HTTPHeaderMap& headers)
     150{
     151    RefPtr<InspectorObject> object = InspectorObject::create();
    151152    HTTPHeaderMap::const_iterator end = headers.end();
    152153    for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
    153         object->set(it->first.string(), it->second);
    154     }
    155 }
    156 
    157 void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
     154        object->setString(it->first.string(), it->second);
     155    }
     156    return object;
     157}
     158
     159static PassRefPtr<InspectorObject> buildObjectForTiming(ResourceLoadTiming* timing)
     160{
     161    RefPtr<InspectorObject> jsonObject = InspectorObject::create();
     162    jsonObject->setNumber("requestTime", timing->requestTime);
     163    jsonObject->setNumber("proxyStart", timing->proxyStart);
     164    jsonObject->setNumber("proxyEnd", timing->proxyEnd);
     165    jsonObject->setNumber("dnsStart", timing->dnsStart);
     166    jsonObject->setNumber("dnsEnd", timing->dnsEnd);
     167    jsonObject->setNumber("connectStart", timing->connectStart);
     168    jsonObject->setNumber("connectEnd", timing->connectEnd);
     169    jsonObject->setNumber("sslStart", timing->sslStart);
     170    jsonObject->setNumber("sslEnd", timing->sslEnd);
     171    jsonObject->setNumber("sendStart", timing->sendStart);
     172    jsonObject->setNumber("sendEnd", timing->sendEnd);
     173    jsonObject->setNumber("receiveHeadersEnd", timing->receiveHeadersEnd);
     174    return jsonObject;
     175}
     176
     177
     178void InspectorResource::updateScriptObject(RemoteInspectorFrontend* frontend)
    158179{
    159180    if (m_changes.hasChange(NoChange))
    160181        return;
    161182
    162     ScriptObject jsonObject = frontend->newScriptObject();
     183    RefPtr<InspectorObject> jsonObject = InspectorObject::create();
     184    jsonObject->setNumber("id", m_identifier);
    163185    if (m_changes.hasChange(RequestChange)) {
    164         jsonObject.set("url", m_requestURL.string());
    165         jsonObject.set("documentURL", m_frame->document()->url().string());
    166         jsonObject.set("host", m_requestURL.host());
    167         jsonObject.set("path", m_requestURL.path());
    168         jsonObject.set("lastPathComponent", m_requestURL.lastPathComponent());
    169         ScriptObject requestHeaders = frontend->newScriptObject();
    170         populateHeadersObject(&requestHeaders, m_requestHeaderFields);
    171         jsonObject.set("requestHeaders", requestHeaders);
    172         jsonObject.set("mainResource", m_isMainResource);
    173         jsonObject.set("requestMethod", m_requestMethod);
    174         jsonObject.set("requestFormData", m_requestFormData);
    175         jsonObject.set("didRequestChange", true);
     186        jsonObject->setString("url", m_requestURL.string());
     187        jsonObject->setString("documentURL", m_frame->document()->url().string());
     188        jsonObject->setString("host", m_requestURL.host());
     189        jsonObject->setString("path", m_requestURL.path());
     190        jsonObject->setString("lastPathComponent", m_requestURL.lastPathComponent());
     191        RefPtr<InspectorObject> requestHeaders = buildHeadersObject(m_requestHeaderFields);
     192        jsonObject->set("requestHeaders", requestHeaders);
     193        jsonObject->setBool("mainResource", m_isMainResource);
     194        jsonObject->setString("requestMethod", m_requestMethod);
     195        jsonObject->setString("requestFormData", m_requestFormData);
     196        jsonObject->setBool("didRequestChange", true);
    176197    }
    177198
    178199    if (m_changes.hasChange(ResponseChange)) {
    179         jsonObject.set("mimeType", m_mimeType);
    180         jsonObject.set("suggestedFilename", m_suggestedFilename);
    181         jsonObject.set("expectedContentLength", m_expectedContentLength);
    182         jsonObject.set("statusCode", m_responseStatusCode);
    183         jsonObject.set("statusText", m_responseStatusText);
    184         ScriptObject responseHeaders = frontend->newScriptObject();
    185         populateHeadersObject(&responseHeaders, m_responseHeaderFields);
    186         jsonObject.set("responseHeaders", responseHeaders);
    187         jsonObject.set("connectionID", m_connectionID);
    188         jsonObject.set("connectionReused", m_connectionReused);
    189         jsonObject.set("cached", m_cached);
     200        jsonObject->setString("mimeType", m_mimeType);
     201        jsonObject->setString("suggestedFilename", m_suggestedFilename);
     202        jsonObject->setNumber("expectedContentLength", m_expectedContentLength);
     203        jsonObject->setNumber("statusCode", m_responseStatusCode);
     204        jsonObject->setString("statusText", m_responseStatusText);
     205        RefPtr<InspectorObject> responseHeaders = buildHeadersObject(m_responseHeaderFields);
     206        jsonObject->set("responseHeaders", responseHeaders);
     207        jsonObject->setNumber("connectionID", m_connectionID);
     208        jsonObject->setBool("connectionReused", m_connectionReused);
     209        jsonObject->setBool("cached", m_cached);
    190210        if (m_loadTiming && !m_cached)
    191             jsonObject.set("timing", buildObjectForTiming(frontend, m_loadTiming.get()));
    192         jsonObject.set("didResponseChange", true);
     211            jsonObject->set("timing", buildObjectForTiming(m_loadTiming.get()));
     212        jsonObject->setBool("didResponseChange", true);
    193213    }
    194214
    195215    if (m_changes.hasChange(TypeChange)) {
    196         jsonObject.set("type", static_cast<int>(type()));
    197         jsonObject.set("didTypeChange", true);
     216        jsonObject->setNumber("type", static_cast<int>(type()));
     217        jsonObject->setBool("didTypeChange", true);
    198218    }
    199219
    200220    if (m_changes.hasChange(LengthChange)) {
    201         jsonObject.set("resourceSize", m_length);
    202         jsonObject.set("didLengthChange", true);
     221        jsonObject->setNumber("resourceSize", m_length);
     222        jsonObject->setBool("didLengthChange", true);
    203223    }
    204224
    205225    if (m_changes.hasChange(CompletionChange)) {
    206         jsonObject.set("failed", m_failed);
    207         jsonObject.set("finished", m_finished);
    208         jsonObject.set("didCompletionChange", true);
     226        jsonObject->setBool("failed", m_failed);
     227        jsonObject->setBool("finished", m_finished);
     228        jsonObject->setBool("didCompletionChange", true);
    209229    }
    210230
    211231    if (m_changes.hasChange(TimingChange)) {
    212232        if (m_startTime > 0)
    213             jsonObject.set("startTime", m_startTime);
     233            jsonObject->setNumber("startTime", m_startTime);
    214234        if (m_responseReceivedTime > 0)
    215             jsonObject.set("responseReceivedTime", m_responseReceivedTime);
     235            jsonObject->setNumber("responseReceivedTime", m_responseReceivedTime);
    216236        if (m_endTime > 0)
    217             jsonObject.set("endTime", m_endTime);
     237            jsonObject->setNumber("endTime", m_endTime);
    218238        if (m_loadEventTime > 0)
    219             jsonObject.set("loadEventTime", m_loadEventTime);
     239            jsonObject->setNumber("loadEventTime", m_loadEventTime);
    220240        if (m_domContentEventTime > 0)
    221             jsonObject.set("domContentEventTime", m_domContentEventTime);
    222         jsonObject.set("didTimingChange", true);
     241            jsonObject->setNumber("domContentEventTime", m_domContentEventTime);
     242        jsonObject->setBool("didTimingChange", true);
    223243    }
    224244
     
    228248    }
    229249
    230     if (frontend->updateResource(m_identifier, jsonObject))
    231         m_changes.clearAll();
    232 }
    233 
    234 void InspectorResource::releaseScriptObject(InspectorFrontend* frontend)
     250    frontend->updateResource(jsonObject);
     251    m_changes.clearAll();
     252}
     253
     254void InspectorResource::releaseScriptObject(RemoteInspectorFrontend* frontend)
    235255{
    236256    m_changes.setAll();
     
    391411}
    392412
    393 ScriptObject InspectorResource::buildObjectForTiming(InspectorFrontend* frontend, ResourceLoadTiming* timing)
    394 {
    395     ScriptObject jsonObject = frontend->newScriptObject();
    396     jsonObject.set("requestTime", timing->requestTime);
    397     jsonObject.set("proxyStart", timing->proxyStart);
    398     jsonObject.set("proxyEnd", timing->proxyEnd);
    399     jsonObject.set("dnsStart", timing->dnsStart);
    400     jsonObject.set("dnsEnd", timing->dnsEnd);
    401     jsonObject.set("connectStart", timing->connectStart);
    402     jsonObject.set("connectEnd", timing->connectEnd);
    403     jsonObject.set("sslStart", timing->sslStart);
    404     jsonObject.set("sslEnd", timing->sslEnd);
    405     jsonObject.set("sendStart", timing->sendStart);
    406     jsonObject.set("sendEnd", timing->sendEnd);
    407     jsonObject.set("receiveHeadersEnd", timing->receiveHeadersEnd);
    408     return jsonObject;
    409 }
    410 
    411413} // namespace WebCore
    412414
  • trunk/WebCore/inspector/InspectorResource.h

    r64142 r64547  
    3434#include "HTTPHeaderMap.h"
    3535#include "KURL.h"
    36 #include "ScriptObject.h"
    37 #include "ScriptState.h"
    3836#include "ScriptString.h"
    3937
     
    4846    class CachedResource;
    4947    class DocumentLoader;
    50     class InspectorFrontend;
    5148    class Frame;
     49    class RemoteInspectorFrontend;
    5250    class ResourceLoadTiming;
    5351    class ResourceRequest;
     
    7977
    8078        PassRefPtr<InspectorResource> appendRedirect(unsigned long identifier, const KURL& redirectURL);
    81         void updateScriptObject(InspectorFrontend* frontend);
    82         void releaseScriptObject(InspectorFrontend* frontend);
     79        void updateScriptObject(RemoteInspectorFrontend* frontend);
     80        void releaseScriptObject(RemoteInspectorFrontend* frontend);
    8381
    8482        void updateRequest(const ResourceRequest&);
     
    152150        CachedResource* cachedResource() const;
    153151
    154         ScriptObject buildObjectForTiming(InspectorFrontend*, ResourceLoadTiming*);
    155 
    156152        unsigned long m_identifier;
    157153        RefPtr<DocumentLoader> m_loader;
  • trunk/WebCore/inspector/front-end/inspector.js

    r64458 r64547  
    11451145}
    11461146
    1147 WebInspector.updateResource = function(identifier, payload)
    1148 {
     1147WebInspector.updateResource = function(payload)
     1148{
     1149    var identifier = payload.id;
    11491150    var resource = this.resources[identifier];
    11501151    if (!resource) {
Note: See TracChangeset for help on using the changeset viewer.