diff --git a/README.md b/README.md index 1b438c79..98b78f4c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ Hosting node.js applications in IIS on Windows === +**Branches** + +- master: stable version. +- iisnode-dev: development branch. + **Why would I want to do it?** [Benefits](https://github.com/tjanczuk/iisnode/wiki) @@ -36,22 +41,29 @@ Hosting node.js applications in IIS on Windows - Open WebMatrix, choose “Site from folder”, enter %localappdata%\iisnode\www, start the site, and play with the iisnode samples, or - Use node.js templates to get started quickly with an Express application or a skeleton Hello World -**Howtos** +**Installing for IIS Express 8 on Windows x64** +This can be a head-scratcher since IIS Express 8 gives you both 32-bit and 64-bit versions (http://www.iis.net/learn/extensions/introduction-to-iis-express/iis-80-express-readme). You can either: +- Install the full x64 version, then in Visual Studio go to Tools > Options > Projects and Solutions > Web Projects > Use the 64 bit version of IIS Express. This way you have a single install for both IIS and IIS Express. +- Separately install iisnode express version (https://github.com/azure/iisnode/wiki/iisnode-releases). -[the basics](http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html) -[the basics (Pусский перевод)](http://softdroid.net/hosting-nodejs-applications-ru) -[**NEW: websockets**] (http://tomasz.janczuk.org/2012/11/how-to-use-websockets-with-nodejs-apps.html) -[using with express framework](http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html) -[using with URL rewrite module](http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html) -[using with WebMatrix and IIS Express](http://tomasz.janczuk.org/2011/08/developing-nodejs-applications-in.html) -[site templates for WebMatrix](https://github.com/SteveSanderson/Node.js-Site-Templates-for-WebMatrix) -[using with mongodb](http://www.amazedsaint.com/2011/09/creating-10-minute-todo-listing-app-on.html) -[diagnosing problems with ETW traces](http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html) -[using with MVC](http://weblogs.asp.net/jgalloway/archive/2011/10/26/using-node-js-in-an-asp-net-mvc-application-with-iisnode.aspx) -[portuguese: node.js no windows: instalando o iisnode](http://vivina.com.br/nodejs-windows-parte-2) -[integrated debugging](http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html) -[pub/sub server using faye](http://weblogs.asp.net/cibrax/archive/2011/12/12/transform-your-iis-into-a-real-time-pub-sub-engine-with-faye-node.aspx) -[appharbor uses iisnode](http://blog.appharbor.com/2012/01/19/announcing-node-js-support) + +**Howtos** +======= +- [the basics](http://tomasz.janczuk.org/2011/08/hosting-nodejs-applications-in-iis-on.html) +- [the basics (Pусский перевод)](http://softdroid.net/hosting-nodejs-applications-ru) +- [**NEW: websockets**] (http://tomasz.janczuk.org/2012/11/how-to-use-websockets-with-nodejs-apps.html) +- [using with express framework](http://tomasz.janczuk.org/2011/08/hosting-express-nodejs-applications-in.html) +- [using with URL rewrite module](http://tomasz.janczuk.org/2011/08/using-url-rewriting-with-nodejs.html) +- [using with WebMatrix and IIS Express](http://tomasz.janczuk.org/2011/08/developing-nodejs-applications-in.html) +- [site templates for WebMatrix](https://github.com/SteveSanderson/Node.js-Site-Templates-for-WebMatrix) +- [using with mongodb](http://www.amazedsaint.com/2011/09/creating-10-minute-todo-listing-app-on.html) +- [diagnosing problems with ETW traces](http://tomasz.janczuk.org/2011/09/using-event-tracing-for-windows-to.html) +- [using with MVC](http://weblogs.asp.net/jgalloway/archive/2011/10/26/using-node-js-in-an-asp-net-mvc-application-with-iisnode.aspx) +- [portuguese: node.js no windows: instalando o iisnode](http://vivina.com.br/nodejs-windows-parte-2) +- [integrated debugging](http://tomasz.janczuk.org/2011/11/debug-nodejs-applications-on-windows.html) +- [**NEW: integrated debugging with node-inspector v0.7.3**](http://www.ranjithr.com/?p=98) +- [pub/sub server using faye](http://weblogs.asp.net/cibrax/archive/2011/12/12/transform-your-iis-into-a-real-time-pub-sub-engine-with-faye-node.aspx) +- [appharbor uses iisnode](http://blog.appharbor.com/2012/01/19/announcing-node-js-support) **Prerequisites for building** diff --git a/src/config/iisnode_dev_x64.xml b/src/config/iisnode_dev_x64.xml index 0bb30c18..71f1d133 100644 --- a/src/config/iisnode_dev_x64.xml +++ b/src/config/iisnode_dev_x64.xml @@ -36,13 +36,14 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ - + + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_dev_x86_on_x64.xml b/src/config/iisnode_dev_x86_on_x64.xml index 2c028b7a..0516dbdc 100644 --- a/src/config/iisnode_dev_x86_on_x64.xml +++ b/src/config/iisnode_dev_x86_on_x64.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_dev_x86_on_x86.xml b/src/config/iisnode_dev_x86_on_x86.xml index 6b1c4744..77804a6e 100644 --- a/src/config/iisnode_dev_x86_on_x86.xml +++ b/src/config/iisnode_dev_x86_on_x86.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_express_schema.xml b/src/config/iisnode_express_schema.xml index 7f52546b..e6786b7b 100644 --- a/src/config/iisnode_express_schema.xml +++ b/src/config/iisnode_express_schema.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_express_schema_x64.xml b/src/config/iisnode_express_schema_x64.xml index 7c587a13..084df609 100644 --- a/src/config/iisnode_express_schema_x64.xml +++ b/src/config/iisnode_express_schema_x64.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_schema.xml b/src/config/iisnode_schema.xml index cf06d146..59f4e0d4 100644 --- a/src/config/iisnode_schema.xml +++ b/src/config/iisnode_schema.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/config/iisnode_schema_x64.xml b/src/config/iisnode_schema_x64.xml index bf7eec69..873ba749 100644 --- a/src/config/iisnode_schema_x64.xml +++ b/src/config/iisnode_schema_x64.xml @@ -43,6 +43,7 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + @@ -57,5 +58,6 @@ Details at http://learn.iis.net/page.aspx/241/configuration-extensibility/ + diff --git a/src/iisnode/cfilewatcher.cpp b/src/iisnode/cfilewatcher.cpp index 0cda805e..c21ba160 100644 --- a/src/iisnode/cfilewatcher.cpp +++ b/src/iisnode/cfilewatcher.cpp @@ -1,603 +1,626 @@ #include "precomp.h" CFileWatcher::CFileWatcher() - : completionPort(NULL), worker(NULL), directories(NULL), uncFileSharePollingInterval(0), - configOverridesFileName(NULL), configOverridesFileNameLength(0) + : completionPort(NULL), worker(NULL), directories(NULL), uncFileSharePollingInterval(0), + configOverridesFileName(NULL), configOverridesFileNameLength(0) { - InitializeCriticalSection(&this->syncRoot); + InitializeCriticalSection(&this->syncRoot); } CFileWatcher::~CFileWatcher() { - if (NULL != this->worker) - { - PostQueuedCompletionStatus(this->completionPort, 0, -1L, NULL); - WaitForSingleObject(this->worker, INFINITE); - CloseHandle(this->worker); - this->worker = NULL; - } - - if (NULL != this->completionPort) - { - CloseHandle(this->completionPort); - this->completionPort = NULL; - } - - while (NULL != this->directories) - { - WatchedDirectory* currentDirectory = this->directories; - if(currentDirectory->watchHandle != NULL) - { - CloseHandle(currentDirectory->watchHandle); - currentDirectory->watchHandle = NULL; - } - delete [] currentDirectory->directoryName; - while (NULL != currentDirectory->files) - { - WatchedFile* currentFile = currentDirectory->files; - delete [] currentFile->fileName; - currentDirectory->files = currentFile->next; - delete currentFile; - } - this->directories = currentDirectory->next; - delete currentDirectory; - } - - if (NULL != this->configOverridesFileName) - { - delete [] this->configOverridesFileName; - this->configOverridesFileName = NULL; - } - - DeleteCriticalSection(&this->syncRoot); + if (NULL != this->worker) + { + PostQueuedCompletionStatus(this->completionPort, 0, -1L, NULL); + WaitForSingleObject(this->worker, INFINITE); + CloseHandle(this->worker); + this->worker = NULL; + } + + if (NULL != this->completionPort) + { + CloseHandle(this->completionPort); + this->completionPort = NULL; + } + + while (NULL != this->directories) + { + WatchedDirectory* currentDirectory = this->directories; + if(currentDirectory->watchHandle != NULL) + { + CloseHandle(currentDirectory->watchHandle); + currentDirectory->watchHandle = NULL; + } + delete [] currentDirectory->directoryName; + while (NULL != currentDirectory->files) + { + WatchedFile* currentFile = currentDirectory->files; + delete [] currentFile->fileName; + currentDirectory->files = currentFile->next; + delete currentFile; + } + this->directories = currentDirectory->next; + delete currentDirectory; + } + + if (NULL != this->configOverridesFileName) + { + delete [] this->configOverridesFileName; + this->configOverridesFileName = NULL; + } + + DeleteCriticalSection(&this->syncRoot); } HRESULT CFileWatcher::Initialize(IHttpContext* context) { - HRESULT hr; + HRESULT hr; - ErrorIf(NULL == (this->completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1)), GetLastError()); - this->uncFileSharePollingInterval = CModuleConfiguration::GetUNCFileChangesPollingInterval(context); + ErrorIf(NULL == (this->completionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1)), GetLastError()); + this->uncFileSharePollingInterval = CModuleConfiguration::GetUNCFileChangesPollingInterval(context); - LPWSTR overrides = CModuleConfiguration::GetConfigOverrides(context); - if (overrides && *overrides != L'\0') - { - this->configOverridesFileNameLength = wcslen(overrides); - ErrorIf(NULL == (this->configOverridesFileName = new WCHAR[this->configOverridesFileNameLength + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(this->configOverridesFileName, overrides); - } + LPWSTR overrides = CModuleConfiguration::GetConfigOverrides(context); + if (overrides && *overrides != L'\0') + { + this->configOverridesFileNameLength = wcslen(overrides); + ErrorIf(NULL == (this->configOverridesFileName = new WCHAR[this->configOverridesFileNameLength + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(this->configOverridesFileName, overrides); + } - return S_OK; + return S_OK; Error: - if (NULL != this->completionPort) - { - CloseHandle(this->completionPort); - this->completionPort = NULL; - } + if (NULL != this->completionPort) + { + CloseHandle(this->completionPort); + this->completionPort = NULL; + } - return hr; + return hr; +} + +BOOL CFileWatcher::IsWebConfigFile(PCWSTR pszStart, PCWSTR pszEnd) +{ + DWORD dwEndIndex = pszEnd - pszStart; + + if(dwEndIndex < 10) + { + return FALSE; + } + + return _wcsnicmp((pszStart + ( dwEndIndex - 10 )), L"web.config", 10) == 0; } HRESULT CFileWatcher::WatchFiles(PCWSTR mainFileName, PCWSTR watchedFiles, FileModifiedCallback callback, CNodeApplicationManager* manager, CNodeApplication* application) { - HRESULT hr; - WCHAR fileOnly[_MAX_FNAME]; - WCHAR ext[_MAX_EXT]; - WCHAR* directoryName = NULL; - DWORD fileNameLength; - DWORD fileNameOnlyLength; - DWORD directoryLength; - BOOL unc; - BOOL wildcard; - PWSTR startSubdirectory; - PWSTR startFile; - PWSTR endFile; - WatchedDirectory* directory; - WatchedFile* file; - - CheckNull(mainFileName); - CheckNull(watchedFiles); - - // create and normalize a copy of directory name, determine if it is UNC share - - fileNameLength = wcslen(mainFileName); - ErrorIf(0 != _wsplitpath_s(mainFileName, NULL, 0, NULL, 0, fileOnly, _MAX_FNAME, ext, _MAX_EXT), ERROR_INVALID_PARAMETER); - fileNameOnlyLength = wcslen(fileOnly) + wcslen(ext); - directoryLength = fileNameLength - fileNameOnlyLength; - ErrorIf(NULL == (directoryName = new WCHAR[directoryLength + 8]), ERROR_NOT_ENOUGH_MEMORY); // pessimistic length after normalization with prefix \\?\UNC\ - - if (fileNameLength > 8 && 0 == memcmp(mainFileName, L"\\\\?\\UNC\\", 8 * sizeof WCHAR)) - { - // normalized UNC path - unc = TRUE; - memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR); - directoryName[directoryLength] = L'\0'; - } - else if (fileNameLength > 4 && 0 == memcmp(mainFileName, L"\\\\?\\", 4 * sizeof WCHAR)) - { - // normalized local file - unc = FALSE; - memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR); - directoryName[directoryLength] = L'\0'; - } - else if (fileNameLength > 2 && 0 == memcmp(mainFileName, L"\\\\", 2 * sizeof(WCHAR))) - { - // not normalized UNC path - unc = TRUE; - wcscpy(directoryName, L"\\\\?\\UNC\\"); - memcpy(directoryName + 8, mainFileName + 2, (directoryLength - 2) * sizeof WCHAR); - directoryName[8 + directoryLength - 2] = L'\0'; - } - else - { - // not normalized local file - unc = FALSE; - wcscpy(directoryName, L"\\\\?\\"); - memcpy(directoryName + 4, mainFileName, directoryLength * sizeof WCHAR); - directoryName[4 + directoryLength] = L'\0'; - } - - directoryLength = wcslen(directoryName); - - ENTER_CS(this->syncRoot) - - // parse watchedFiles and create a file listener for each of the files - - startFile = (PWSTR)watchedFiles; - do { - endFile = startSubdirectory = startFile; - wildcard = FALSE; - while (*endFile && *endFile != L';') - { - wildcard |= *endFile == L'*' || *endFile == L'?'; - if (*endFile == L'\\') - { - startFile = endFile + 1; - } - - endFile++; - } - - if (startFile != endFile) - { - hr = this->WatchFile(directoryName, directoryLength, unc, startSubdirectory, startFile, endFile, wildcard); - - // ignore files and directories that do not exist instead of failing - - if (S_OK != hr && ERROR_FILE_NOT_FOUND != hr) - { - // still under lock remove file watch entries that were just created, then do regular cleanup - - this->RemoveWatch(NULL); - CheckError(hr); - } - } - - startFile = endFile + 1; - - } while(*endFile); - - // update temporary entries with application and callback pointers - - directory = this->directories; - while (NULL != directory) - { - file = directory->files; - while (NULL != file) - { - if (NULL == file->application) - { - file->application = application; - file->manager = manager; - file->callback = callback; - } - - file = file->next; - } - - directory = directory->next; - } - - LEAVE_CS(this->syncRoot) - - delete [] directoryName; - - return S_OK; + HRESULT hr; + WCHAR fileOnly[_MAX_FNAME]; + WCHAR ext[_MAX_EXT]; + WCHAR* directoryName = NULL; + DWORD fileNameLength; + DWORD fileNameOnlyLength; + DWORD directoryLength; + BOOL unc; + BOOL wildcard; + PWSTR startSubdirectory; + PWSTR startFile; + PWSTR endFile; + WatchedDirectory* directory; + WatchedFile* file; + + CheckNull(mainFileName); + CheckNull(watchedFiles); + + // create and normalize a copy of directory name, determine if it is UNC share + + fileNameLength = wcslen(mainFileName); + ErrorIf(0 != _wsplitpath_s(mainFileName, NULL, 0, NULL, 0, fileOnly, _MAX_FNAME, ext, _MAX_EXT), ERROR_INVALID_PARAMETER); + fileNameOnlyLength = wcslen(fileOnly) + wcslen(ext); + directoryLength = fileNameLength - fileNameOnlyLength; + ErrorIf(NULL == (directoryName = new WCHAR[directoryLength + 8]), ERROR_NOT_ENOUGH_MEMORY); // pessimistic length after normalization with prefix \\?\UNC\ + + if (fileNameLength > 8 && 0 == memcmp(mainFileName, L"\\\\?\\UNC\\", 8 * sizeof WCHAR)) + { + // normalized UNC path + unc = TRUE; + memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR); + directoryName[directoryLength] = L'\0'; + } + else if (fileNameLength > 4 && 0 == memcmp(mainFileName, L"\\\\?\\", 4 * sizeof WCHAR)) + { + // normalized local file + unc = FALSE; + memcpy(directoryName, mainFileName, directoryLength * sizeof WCHAR); + directoryName[directoryLength] = L'\0'; + } + else if (fileNameLength > 2 && 0 == memcmp(mainFileName, L"\\\\", 2 * sizeof(WCHAR))) + { + // not normalized UNC path + unc = TRUE; + wcscpy(directoryName, L"\\\\?\\UNC\\"); + memcpy(directoryName + 8, mainFileName + 2, (directoryLength - 2) * sizeof WCHAR); + directoryName[8 + directoryLength - 2] = L'\0'; + } + else + { + // not normalized local file + unc = FALSE; + wcscpy(directoryName, L"\\\\?\\"); + memcpy(directoryName + 4, mainFileName, directoryLength * sizeof WCHAR); + directoryName[4 + directoryLength] = L'\0'; + } + + directoryLength = wcslen(directoryName); + + ENTER_CS(this->syncRoot) + + // parse watchedFiles and create a file listener for each of the files + + startFile = (PWSTR)watchedFiles; + do { + endFile = startSubdirectory = startFile; + wildcard = FALSE; + while (*endFile && *endFile != L';') + { + wildcard |= *endFile == L'*' || *endFile == L'?'; + if (*endFile == L'\\') + { + startFile = endFile + 1; + } + + endFile++; + } + + if (startFile != endFile) + { + // + // skip web.config file (GlobalFileChangeNotification will handle web.config). + // + + if(IsWebConfigFile(startFile, endFile)) + { + hr = S_OK; + } + else + { + hr = this->WatchFile(directoryName, directoryLength, unc, startSubdirectory, startFile, endFile, wildcard); + } + + // ignore files and directories that do not exist instead of failing + + if (S_OK != hr && ERROR_FILE_NOT_FOUND != hr) + { + // still under lock remove file watch entries that were just created, then do regular cleanup + + this->RemoveWatch(NULL); + CheckError(hr); + } + } + + startFile = endFile + 1; + + } while(*endFile); + + // update temporary entries with application and callback pointers + + directory = this->directories; + while (NULL != directory) + { + file = directory->files; + while (NULL != file) + { + if (NULL == file->application) + { + file->application = application; + file->manager = manager; + file->callback = callback; + } + + file = file->next; + } + + directory = directory->next; + } + + LEAVE_CS(this->syncRoot) + + delete [] directoryName; + + return S_OK; Error: - if (NULL != directoryName) - { - delete [] directoryName; - directoryName = NULL; - } + if (NULL != directoryName) + { + delete [] directoryName; + directoryName = NULL; + } - return hr; + return hr; } HRESULT CFileWatcher::GetWatchedFileTimestamp(WatchedFile* file, FILETIME* timestamp) { - HRESULT hr; - WIN32_FILE_ATTRIBUTE_DATA attributes; - WIN32_FIND_DATAW findData; - HANDLE foundFile = INVALID_HANDLE_VALUE; - - if (file->wildcard) - { - // a timestamp of a wildcard watched file is the XOR of the timestamps of all matching files and their names and sizes; - // that way if any of the matching files changes, or matching files are added or removed, the timestamp will change as well - - RtlZeroMemory(timestamp, sizeof FILETIME); - foundFile = FindFirstFileW(file->fileName, &findData); - if (INVALID_HANDLE_VALUE != foundFile) - { - do - { - if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) - { - timestamp->dwHighDateTime ^= findData.ftLastWriteTime.dwHighDateTime ^ findData.nFileSizeHigh; - timestamp->dwLowDateTime ^= findData.ftLastWriteTime.dwLowDateTime ^ findData.nFileSizeLow; - WCHAR* current = findData.cFileName; - while (*current) - { - timestamp->dwLowDateTime ^= *current; - current++; - } - } - } while (FindNextFileW(foundFile, &findData)); - - ErrorIf(ERROR_NO_MORE_FILES != (hr = GetLastError()), hr); - FindClose(foundFile); - foundFile = NULL; - } - } - else - { - ErrorIf(!GetFileAttributesExW(file->fileName, GetFileExInfoStandard, &attributes), GetLastError()); - memcpy(timestamp, &attributes.ftLastWriteTime, sizeof attributes.ftLastWriteTime); - } - - return S_OK; + HRESULT hr; + WIN32_FILE_ATTRIBUTE_DATA attributes; + WIN32_FIND_DATAW findData; + HANDLE foundFile = INVALID_HANDLE_VALUE; + + if (file->wildcard) + { + // a timestamp of a wildcard watched file is the XOR of the timestamps of all matching files and their names and sizes; + // that way if any of the matching files changes, or matching files are added or removed, the timestamp will change as well + + RtlZeroMemory(timestamp, sizeof FILETIME); + foundFile = FindFirstFileW(file->fileName, &findData); + if (INVALID_HANDLE_VALUE != foundFile) + { + do + { + if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + timestamp->dwHighDateTime ^= findData.ftLastWriteTime.dwHighDateTime ^ findData.nFileSizeHigh; + timestamp->dwLowDateTime ^= findData.ftLastWriteTime.dwLowDateTime ^ findData.nFileSizeLow; + WCHAR* current = findData.cFileName; + while (*current) + { + timestamp->dwLowDateTime ^= *current; + current++; + } + } + } while (FindNextFileW(foundFile, &findData)); + + ErrorIf(ERROR_NO_MORE_FILES != (hr = GetLastError()), hr); + FindClose(foundFile); + foundFile = NULL; + } + } + else + { + ErrorIf(!GetFileAttributesExW(file->fileName, GetFileExInfoStandard, &attributes), GetLastError()); + memcpy(timestamp, &attributes.ftLastWriteTime, sizeof attributes.ftLastWriteTime); + } + + return S_OK; Error: - if (INVALID_HANDLE_VALUE != foundFile) - { - FindClose(foundFile); - foundFile = INVALID_HANDLE_VALUE; - } + if (INVALID_HANDLE_VALUE != foundFile) + { + FindClose(foundFile); + foundFile = INVALID_HANDLE_VALUE; + } - return hr; + return hr; } HRESULT CFileWatcher::WatchFile(PCWSTR directoryName, DWORD directoryNameLength, BOOL unc, PCWSTR startSubdirectoryName, PCWSTR startFileName, PCWSTR endFileName, BOOL wildcard) { - HRESULT hr; - WatchedFile* file = NULL; - WatchedDirectory* directory; - WatchedDirectory* newDirectory = NULL; - - // allocate new WatchedFile, get snapshot of the last write time - - ErrorIf(NULL == (file = new WatchedFile), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(file, sizeof WatchedFile); - ErrorIf(NULL == (file->fileName = new WCHAR[directoryNameLength + endFileName - startSubdirectoryName + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(file->fileName, directoryName); - memcpy((void*)(file->fileName + directoryNameLength), startSubdirectoryName, (endFileName - startSubdirectoryName) * sizeof WCHAR); - file->fileName[directoryNameLength + endFileName - startSubdirectoryName] = L'\0'; - file->unc = unc; - file->wildcard = wildcard; - this->GetWatchedFileTimestamp(file, &file->lastWrite); - - // determine if this is the yaml config file - - if (this->configOverridesFileNameLength == (endFileName - startFileName)) - { - file->yamlConfig = 0 == memcmp(this->configOverridesFileName, startFileName, this->configOverridesFileNameLength * sizeof WCHAR); - } - - // find matching directory watcher entry - - directory = this->directories; - while (NULL != directory) - { - if (wcslen(directory->directoryName) == directoryNameLength + startFileName - startSubdirectoryName - && 0 == wcsncmp(directory->directoryName, directoryName, directoryNameLength) - && 0 == wcsncmp(directory->directoryName + directoryNameLength, startSubdirectoryName, startFileName - startSubdirectoryName)) - { - break; - } - - directory = directory->next; - } - - // if directory watcher not found, create one - - if (NULL == directory) - { - ErrorIf(NULL == (newDirectory = new WatchedDirectory), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(newDirectory, sizeof WatchedDirectory); - ErrorIf(NULL == (newDirectory->directoryName = new WCHAR[directoryNameLength + startFileName - startSubdirectoryName + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(newDirectory->directoryName, directoryName); - if (startFileName > startSubdirectoryName) - { - wcsncat(newDirectory->directoryName, startSubdirectoryName, startFileName - startSubdirectoryName); - } - - newDirectory->files = file; - - ErrorIf(INVALID_HANDLE_VALUE == (newDirectory->watchHandle = CreateFileW( - newDirectory->directoryName, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, - NULL)), - GetLastError()); - - ErrorIf(NULL == CreateIoCompletionPort(newDirectory->watchHandle, this->completionPort, (ULONG_PTR)newDirectory, 0), - GetLastError()); - - ErrorIf(0 == ReadDirectoryChangesW( - newDirectory->watchHandle, - &newDirectory->info, - sizeof newDirectory->info, - FALSE, - FILE_NOTIFY_CHANGE_LAST_WRITE, - NULL, - &newDirectory->overlapped, - NULL), - GetLastError()); - - if (NULL == this->worker) - { - // no watchers exist yet, start the watcher thread - - ErrorIf(NULL == (this->worker = (HANDLE)_beginthreadex( - NULL, - 4096, - CFileWatcher::Worker, - this, - 0, - NULL)), - ERROR_NOT_ENOUGH_MEMORY); - } - - newDirectory->next = this->directories; - this->directories = newDirectory; - newDirectory = NULL; - } - else - { - file->next = directory->files; - directory->files = file; - file = NULL; - } - - return S_OK; + HRESULT hr; + WatchedFile* file = NULL; + WatchedDirectory* directory; + WatchedDirectory* newDirectory = NULL; + + // allocate new WatchedFile, get snapshot of the last write time + + ErrorIf(NULL == (file = new WatchedFile), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(file, sizeof WatchedFile); + ErrorIf(NULL == (file->fileName = new WCHAR[directoryNameLength + endFileName - startSubdirectoryName + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(file->fileName, directoryName); + memcpy((void*)(file->fileName + directoryNameLength), startSubdirectoryName, (endFileName - startSubdirectoryName) * sizeof WCHAR); + file->fileName[directoryNameLength + endFileName - startSubdirectoryName] = L'\0'; + file->unc = unc; + file->wildcard = wildcard; + this->GetWatchedFileTimestamp(file, &file->lastWrite); + + // determine if this is the yaml config file + + if (this->configOverridesFileNameLength == (endFileName - startFileName)) + { + file->yamlConfig = 0 == memcmp(this->configOverridesFileName, startFileName, this->configOverridesFileNameLength * sizeof WCHAR); + } + + // find matching directory watcher entry + + directory = this->directories; + while (NULL != directory) + { + if (wcslen(directory->directoryName) == directoryNameLength + startFileName - startSubdirectoryName + && 0 == wcsncmp(directory->directoryName, directoryName, directoryNameLength) + && 0 == wcsncmp(directory->directoryName + directoryNameLength, startSubdirectoryName, startFileName - startSubdirectoryName)) + { + break; + } + + directory = directory->next; + } + + // if directory watcher not found, create one + + if (NULL == directory) + { + ErrorIf(NULL == (newDirectory = new WatchedDirectory), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(newDirectory, sizeof WatchedDirectory); + ErrorIf(NULL == (newDirectory->directoryName = new WCHAR[directoryNameLength + startFileName - startSubdirectoryName + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(newDirectory->directoryName, directoryName); + if (startFileName > startSubdirectoryName) + { + wcsncat(newDirectory->directoryName, startSubdirectoryName, startFileName - startSubdirectoryName); + } + + newDirectory->files = file; + + ErrorIf(INVALID_HANDLE_VALUE == (newDirectory->watchHandle = CreateFileW( + newDirectory->directoryName, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL)), + GetLastError()); + + ErrorIf(NULL == CreateIoCompletionPort(newDirectory->watchHandle, this->completionPort, (ULONG_PTR)newDirectory, 0), + GetLastError()); + + ErrorIf(0 == ReadDirectoryChangesW( + newDirectory->watchHandle, + &newDirectory->info, + sizeof newDirectory->info, + FALSE, + FILE_NOTIFY_CHANGE_LAST_WRITE, + NULL, + &newDirectory->overlapped, + NULL), + GetLastError()); + + if (NULL == this->worker) + { + // no watchers exist yet, start the watcher thread + + ErrorIf(NULL == (this->worker = (HANDLE)_beginthreadex( + NULL, + 4096, + CFileWatcher::Worker, + this, + 0, + NULL)), + ERROR_NOT_ENOUGH_MEMORY); + } + + newDirectory->next = this->directories; + this->directories = newDirectory; + newDirectory = NULL; + } + else + { + file->next = directory->files; + directory->files = file; + file = NULL; + } + + return S_OK; Error: - if (NULL != newDirectory) - { - if (NULL != newDirectory->directoryName) - { - delete [] newDirectory->directoryName; - } - - if (NULL != newDirectory->watchHandle) - { - CloseHandle(newDirectory->watchHandle); - newDirectory->watchHandle = NULL; - } - - delete newDirectory; - } - - if (NULL != file) - { - if (NULL != file->fileName) - { - delete [] file->fileName; - } - - delete file; - } - - return hr; + if (NULL != newDirectory) + { + if (NULL != newDirectory->directoryName) + { + delete [] newDirectory->directoryName; + } + + if (NULL != newDirectory->watchHandle) + { + CloseHandle(newDirectory->watchHandle); + newDirectory->watchHandle = NULL; + } + + delete newDirectory; + } + + if (NULL != file) + { + if (NULL != file->fileName) + { + delete [] file->fileName; + } + + delete file; + } + + return hr; } HRESULT CFileWatcher::RemoveWatch(CNodeApplication* application) { - ENTER_CS(this->syncRoot) - - WatchedDirectory* directory = this->directories; - WatchedDirectory* previousDirectory = NULL; - while (directory) - { - WatchedFile* file = directory->files; - WatchedFile* previousFile = NULL; - - while (file) - { - if (file->application == application) - { - WatchedFile* tmpFile = file; - delete [] file->fileName; - if (previousFile) - { - previousFile->next = file->next; - file = file->next; - if (!file) - { - previousDirectory = directory; - directory = directory->next; - } - } - else - { - directory->files = file->next; - file = file->next; - if (!directory->files) - { - delete [] directory->directoryName; - if(directory->watchHandle != NULL) - { - CloseHandle(directory->watchHandle); - directory->watchHandle = NULL; - } - - if (previousDirectory) - { - previousDirectory->next = directory->next; - } - else - { - this->directories = directory->next; - } - - WatchedDirectory* tmpDirectory = directory; - directory = directory->next; - delete tmpDirectory; - } - } - - delete tmpFile; - } - else - { - previousFile = file; - file = file->next; - if (!file) - { - previousDirectory = directory; - directory = directory->next; - } - } - } - } - - LEAVE_CS(this->syncRoot) - - return S_OK; + ENTER_CS(this->syncRoot) + + WatchedDirectory* directory = this->directories; + WatchedDirectory* previousDirectory = NULL; + while (directory) + { + WatchedFile* file = directory->files; + WatchedFile* previousFile = NULL; + + while (file) + { + if (file->application == application) + { + WatchedFile* tmpFile = file; + delete [] file->fileName; + if (previousFile) + { + previousFile->next = file->next; + file = file->next; + if (!file) + { + previousDirectory = directory; + directory = directory->next; + } + } + else + { + directory->files = file->next; + file = file->next; + if (!directory->files) + { + delete [] directory->directoryName; + if(directory->watchHandle != NULL) + { + CloseHandle(directory->watchHandle); + directory->watchHandle = NULL; + } + + if (previousDirectory) + { + previousDirectory->next = directory->next; + } + else + { + this->directories = directory->next; + } + + WatchedDirectory* tmpDirectory = directory; + directory = directory->next; + delete tmpDirectory; + } + } + + delete tmpFile; + } + else + { + previousFile = file; + file = file->next; + if (!file) + { + previousDirectory = directory; + directory = directory->next; + } + } + } + } + + LEAVE_CS(this->syncRoot) + + return S_OK; } unsigned int CFileWatcher::Worker(void* arg) { - CFileWatcher* watcher = (CFileWatcher*)arg; - DWORD error; - DWORD bytes; - ULONG_PTR key; - LPOVERLAPPED overlapped; - - while (TRUE) - { - error = S_OK; - if (!GetQueuedCompletionStatus( - watcher->completionPort, &bytes, &key, &overlapped, watcher->uncFileSharePollingInterval)) - { - error = GetLastError(); - } - - if (-1L == key) // terminate thread - { - break; - } - else if (S_OK == error) // a change in registered directory detected (local file system) - { - WatchedDirectory* directory = (WatchedDirectory*)key; - - ENTER_CS(watcher->syncRoot) - - // make sure the directory is still watched - - WatchedDirectory* current = watcher->directories; - while (current && current != directory) - current = current->next; - - if (current && current->watchHandle != NULL) - { - watcher->ScanDirectory(current, FALSE); - - // make sure the directory is still watched - it could have been removed by a recursive call to RemoveWatch - - current = watcher->directories; - while (current && current != directory) - current = current->next; - - if (current) - { - RtlZeroMemory(¤t->overlapped, sizeof current->overlapped); - ReadDirectoryChangesW( - current->watchHandle, - ¤t->info, - sizeof directory->info, - FALSE, - FILE_NOTIFY_CHANGE_LAST_WRITE, - NULL, - ¤t->overlapped, - NULL); - } - } - - LEAVE_CS(watcher->syncRoot) - } - else // timeout - scan all registered UNC files for changes - { - ENTER_CS(watcher->syncRoot) - - WatchedDirectory* current = watcher->directories; - while (current) - { - // - // watched directory exists, check if handle is valid, if not, create one. - // watchHandle will be NULL if the watched directory was deleted before. - // - if(watcher->DirectoryExists(current->directoryName)) - { - if(current->watchHandle == NULL) - { - current->watchHandle = CreateFileW( - current->directoryName, - FILE_LIST_DIRECTORY, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, - NULL, - OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, - NULL); - } - - // - // scan the directory for file changes - // - if (watcher->ScanDirectory(current, TRUE)) - { - // - // found a change that will recycle the application. - // - break; - } - } - else - { - // - // directory being watched was deleted, close the handle. - // - if(current->watchHandle != NULL) - { - CloseHandle(current->watchHandle); - current->watchHandle = NULL; - } - } - current = current->next; - } - - LEAVE_CS(watcher->syncRoot) - } - } - - return 0; + CFileWatcher* watcher = (CFileWatcher*)arg; + DWORD error; + DWORD bytes; + ULONG_PTR key; + LPOVERLAPPED overlapped; + + while (TRUE) + { + error = S_OK; + if (!GetQueuedCompletionStatus( + watcher->completionPort, &bytes, &key, &overlapped, watcher->uncFileSharePollingInterval)) + { + error = GetLastError(); + } + + if (-1L == key) // terminate thread + { + break; + } + else if (S_OK == error) // a change in registered directory detected (local file system) + { + WatchedDirectory* directory = (WatchedDirectory*)key; + + ENTER_CS(watcher->syncRoot) + + // make sure the directory is still watched + + WatchedDirectory* current = watcher->directories; + while (current && current != directory) + current = current->next; + + if (current && current->watchHandle != NULL) + { + watcher->ScanDirectory(current, FALSE); + + // make sure the directory is still watched - it could have been removed by a recursive call to RemoveWatch + + current = watcher->directories; + while (current && current != directory) + current = current->next; + + if (current) + { + RtlZeroMemory(¤t->overlapped, sizeof current->overlapped); + ReadDirectoryChangesW( + current->watchHandle, + ¤t->info, + sizeof directory->info, + FALSE, + FILE_NOTIFY_CHANGE_LAST_WRITE, + NULL, + ¤t->overlapped, + NULL); + } + } + + LEAVE_CS(watcher->syncRoot) + } + else // timeout - scan all registered UNC files for changes + { + ENTER_CS(watcher->syncRoot) + + WatchedDirectory* current = watcher->directories; + while (current) + { + // + // watched directory exists, check if handle is valid, if not, create one. + // watchHandle will be NULL if the watched directory was deleted before. + // + if(watcher->DirectoryExists(current->directoryName)) + { + if(current->watchHandle == NULL) + { + current->watchHandle = CreateFileW( + current->directoryName, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, + NULL); + } + + // + // scan the directory for file changes + // + if (watcher->ScanDirectory(current, TRUE)) + { + // + // found a change that will recycle the application. + // + break; + } + } + else + { + // + // directory being watched was deleted, close the handle. + // + if(current->watchHandle != NULL) + { + CloseHandle(current->watchHandle); + current->watchHandle = NULL; + } + } + current = current->next; + } + + LEAVE_CS(watcher->syncRoot) + } + } + + return 0; } BOOL CFileWatcher::DirectoryExists(LPCWSTR directoryPath) @@ -612,31 +635,31 @@ BOOL CFileWatcher::DirectoryExists(LPCWSTR directoryPath) BOOL CFileWatcher::ScanDirectory(WatchedDirectory* directory, BOOL unc) { - WatchedFile* file = directory->files; - FILETIME timestamp; - - while (file) - { - if (unc == file->unc) - { - if (S_OK == CFileWatcher::GetWatchedFileTimestamp(file, ×tamp) - && 0 != memcmp(×tamp, &file->lastWrite, sizeof FILETIME)) - { - if (file->yamlConfig) - { - // the iisnode.yml file has changed - // invalidate the configuration such that on next message it will be re-created - - CModuleConfiguration::Invalidate(); - } - - memcpy(&file->lastWrite, ×tamp, sizeof FILETIME); - file->callback(file->manager, file->application); - return TRUE; - } - } - file = file->next; - } - - return FALSE; + WatchedFile* file = directory->files; + FILETIME timestamp; + + while (file) + { + if (unc == file->unc) + { + if (S_OK == CFileWatcher::GetWatchedFileTimestamp(file, ×tamp) + && 0 != memcmp(×tamp, &file->lastWrite, sizeof FILETIME)) + { + if (file->yamlConfig) + { + // the iisnode.yml file has changed + // invalidate the configuration such that on next message it will be re-created + + CModuleConfiguration::Invalidate(); + } + + memcpy(&file->lastWrite, ×tamp, sizeof FILETIME); + file->callback(file->manager, file->application); + return TRUE; + } + } + file = file->next; + } + + return FALSE; } diff --git a/src/iisnode/cfilewatcher.h b/src/iisnode/cfilewatcher.h index cdf9659c..0b401839 100644 --- a/src/iisnode/cfilewatcher.h +++ b/src/iisnode/cfilewatcher.h @@ -10,49 +10,50 @@ class CFileWatcher { private: - typedef struct _WatchedFile { - WCHAR* fileName; - FileModifiedCallback callback; - CNodeApplicationManager* manager; - CNodeApplication* application; - BOOL unc; - BOOL wildcard; - FILETIME lastWrite; - BOOL yamlConfig; - struct _WatchedFile* next; - } WatchedFile; - - typedef struct _WatchedDirectory { - WatchedFile* files; - WCHAR* directoryName; - HANDLE watchHandle; - FILE_NOTIFY_INFORMATION info; - OVERLAPPED overlapped; - struct _WatchedDirectory* next; - } WatchedDirectory; - - HANDLE worker; - HANDLE completionPort; - WatchedDirectory* directories; - DWORD uncFileSharePollingInterval; - CRITICAL_SECTION syncRoot; - LPWSTR configOverridesFileName; - DWORD configOverridesFileNameLength; - - static unsigned int WINAPI Worker(void* arg); - BOOL ScanDirectory(WatchedDirectory* directory, BOOL unc); - HRESULT WatchFile(PCWSTR directoryName, DWORD directoryNameLength, BOOL unc, PCWSTR startSubdirectoryName, PCWSTR startFileName, PCWSTR endFileName, BOOL wildcard); - BOOL DirectoryExists(LPCWSTR directoryPath); - static HRESULT GetWatchedFileTimestamp(WatchedFile* file, FILETIME* timestamp); + typedef struct _WatchedFile { + WCHAR* fileName; + FileModifiedCallback callback; + CNodeApplicationManager* manager; + CNodeApplication* application; + BOOL unc; + BOOL wildcard; + FILETIME lastWrite; + BOOL yamlConfig; + struct _WatchedFile* next; + } WatchedFile; + + typedef struct _WatchedDirectory { + WatchedFile* files; + WCHAR* directoryName; + HANDLE watchHandle; + FILE_NOTIFY_INFORMATION info; + OVERLAPPED overlapped; + struct _WatchedDirectory* next; + } WatchedDirectory; + + HANDLE worker; + HANDLE completionPort; + WatchedDirectory* directories; + DWORD uncFileSharePollingInterval; + CRITICAL_SECTION syncRoot; + LPWSTR configOverridesFileName; + DWORD configOverridesFileNameLength; + + static unsigned int WINAPI Worker(void* arg); + BOOL ScanDirectory(WatchedDirectory* directory, BOOL unc); + HRESULT WatchFile(PCWSTR directoryName, DWORD directoryNameLength, BOOL unc, PCWSTR startSubdirectoryName, PCWSTR startFileName, PCWSTR endFileName, BOOL wildcard); + BOOL DirectoryExists(LPCWSTR directoryPath); + BOOL IsWebConfigFile(PCWSTR pszStart, PCWSTR pszEnd); + static HRESULT GetWatchedFileTimestamp(WatchedFile* file, FILETIME* timestamp); public: - CFileWatcher(); - ~CFileWatcher(); + CFileWatcher(); + ~CFileWatcher(); - HRESULT Initialize(IHttpContext* context); - HRESULT WatchFiles(PCWSTR mainFileName, PCWSTR watchedFiles, FileModifiedCallback callback, CNodeApplicationManager* manager, CNodeApplication* application); - HRESULT RemoveWatch(CNodeApplication* application); + HRESULT Initialize(IHttpContext* context); + HRESULT WatchFiles(PCWSTR mainFileName, PCWSTR watchedFiles, FileModifiedCallback callback, CNodeApplicationManager* manager, CNodeApplication* application); + HRESULT RemoveWatch(CNodeApplication* application); }; #endif \ No newline at end of file diff --git a/src/iisnode/chttpprotocol.cpp b/src/iisnode/chttpprotocol.cpp index 883f3fb1..38fae8a3 100644 --- a/src/iisnode/chttpprotocol.cpp +++ b/src/iisnode/chttpprotocol.cpp @@ -168,6 +168,9 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void PSOCKADDR addr = request->GetRemoteAddress(); DWORD addrSize = addr->sa_family == AF_INET ? sizeof SOCKADDR_IN : sizeof SOCKADDR_IN6; ErrorIf(0 != GetNameInfo(addr, addrSize, remoteHost, remoteHostSize, NULL, 0, NI_NUMERICHOST), GetLastError()); + + // Set remoteHostSize to the size of remoteHost + remoteHostSize = strlen(remoteHost); } for (int i = 0; i < raw->Headers.UnknownHeaderCount; i++) @@ -178,10 +181,14 @@ HRESULT CHttpProtocol::SerializeRequestHeaders(CNodeHttpStoredContext* ctx, void if (addXFF && 15 == raw->Headers.pUnknownHeaders[i].NameLength && 0 == _stricmp("X-Forwarded-For", raw->Headers.pUnknownHeaders[i].pName)) { - // augment existing X-Forwarded-For header - - CheckError(CHttpProtocol::Append(context, ", ", 2, result, &bufferLength, &offset)); - CheckError(CHttpProtocol::Append(context, remoteHost, 0, result, &bufferLength, &offset)); + // augment existing X-Forwarded-For header, but only if the last item isn't the same IP as what we are adding + // (fixes https://github.com/tjanczuk/iisnode/issues/340) + if (raw->Headers.pUnknownHeaders[i].RawValueLength < remoteHostSize || + 0 != _stricmp(remoteHost, (raw->Headers.pUnknownHeaders[i].pRawValue + (raw->Headers.pUnknownHeaders[i].RawValueLength - remoteHostSize)))) + { + CheckError(CHttpProtocol::Append(context, ", ", 2, result, &bufferLength, &offset)); + CheckError(CHttpProtocol::Append(context, remoteHost, 0, result, &bufferLength, &offset)); + } addXFF = FALSE; } diff --git a/src/iisnode/cmoduleconfiguration.cpp b/src/iisnode/cmoduleconfiguration.cpp index d7e833fe..5526cd92 100644 --- a/src/iisnode/cmoduleconfiguration.cpp +++ b/src/iisnode/cmoduleconfiguration.cpp @@ -8,7 +8,7 @@ HTTP_MODULE_ID CModuleConfiguration::moduleId = NULL; BOOL CModuleConfiguration::invalid = FALSE; #define EXTENDED_MAX_PATH 32768 -#define MAX_HASH_CHAR 32 +#define MAX_HASH_CHAR 8 CModuleConfiguration::CModuleConfiguration() : nodeProcessCommandLine(NULL), @@ -21,38 +21,40 @@ CModuleConfiguration::CModuleConfiguration() debugPortEnd(0), node_env(NULL), watchedFiles(NULL), - enableXFF(FALSE), + enableXFF(FALSE), promoteServerVars(NULL), promoteServerVarsRaw(NULL), configOverridesFileName(NULL), - configOverrides(NULL), + configOverrides(NULL), interceptor(NULL), debugHeaderEnabled(FALSE), debuggerVirtualDir(NULL), debuggerVirtualDirLength(0), - debuggerVirtualDirPhysicalPath(NULL) + debuggerVirtualDirPhysicalPath(NULL), + recycleSignalEnabled(FALSE), + debuggerExtensionDll(NULL) { - InitializeSRWLock(&this->srwlock); + InitializeSRWLock(&this->srwlock); } CModuleConfiguration::~CModuleConfiguration() { - if (NULL != this->nodeProcessCommandLine) - { - delete [] this->nodeProcessCommandLine; - this->nodeProcessCommandLine = NULL; - } - - if (NULL != this->interceptor) { - delete [] this->interceptor; - this->interceptor = NULL; - } - - if (NULL != this->logDirectory) - { - delete [] this->logDirectory; - this->logDirectory = NULL; - } + if (NULL != this->nodeProcessCommandLine) + { + delete [] this->nodeProcessCommandLine; + this->nodeProcessCommandLine = NULL; + } + + if (NULL != this->interceptor) { + delete [] this->interceptor; + this->interceptor = NULL; + } + + if (NULL != this->logDirectory) + { + delete [] this->logDirectory; + this->logDirectory = NULL; + } if(NULL != this->debuggerVirtualDir) { @@ -60,6 +62,12 @@ CModuleConfiguration::~CModuleConfiguration() this->debuggerVirtualDir = NULL; } + if(NULL != this->debuggerExtensionDll) + { + delete [] this->debuggerExtensionDll; + this->debuggerExtensionDll = NULL; + } + if(NULL != this->debuggerFilesPathSegment) { delete [] this->debuggerFilesPathSegment; @@ -72,357 +80,363 @@ CModuleConfiguration::~CModuleConfiguration() this->debuggerVirtualDirPhysicalPath = NULL; } - if (NULL != this->debuggerPathSegment) - { - delete [] this->debuggerPathSegment; - this->debuggerPathSegment = NULL; - } - - if (NULL != this->node_env) - { - delete this->node_env; - this->node_env = NULL; - } - - if (NULL != this->watchedFiles) - { - delete this->watchedFiles; - this->watchedFiles = NULL; - } - - if (NULL != this->promoteServerVars) - { - for (int i = 0; i < this->promoteServerVarsCount; i++) - { - if (this->promoteServerVars[i]) - { - delete [] this->promoteServerVars[i]; - } - } - - delete [] this->promoteServerVars; - this->promoteServerVars = NULL; - } - - if (NULL != this->promoteServerVarsRaw) - { - delete [] this->promoteServerVarsRaw; - this->promoteServerVarsRaw = NULL; - } - - if (NULL != this->configOverridesFileName) - { - delete [] this->configOverridesFileName; - this->configOverridesFileName = NULL; - } - - if (NULL != this->configOverrides) - { - delete [] this->configOverrides; - this->configOverrides = NULL; - } + if (NULL != this->debuggerPathSegment) + { + delete [] this->debuggerPathSegment; + this->debuggerPathSegment = NULL; + } + + if (NULL != this->node_env) + { + delete this->node_env; + this->node_env = NULL; + } + + if (NULL != this->watchedFiles) + { + delete this->watchedFiles; + this->watchedFiles = NULL; + } + + if (NULL != this->promoteServerVars) + { + for (int i = 0; i < this->promoteServerVarsCount; i++) + { + if (this->promoteServerVars[i]) + { + delete [] this->promoteServerVars[i]; + } + } + + delete [] this->promoteServerVars; + this->promoteServerVars = NULL; + } + + if (NULL != this->promoteServerVarsRaw) + { + delete [] this->promoteServerVarsRaw; + this->promoteServerVarsRaw = NULL; + } + + if (NULL != this->configOverridesFileName) + { + delete [] this->configOverridesFileName; + this->configOverridesFileName = NULL; + } + + if (NULL != this->configOverrides) + { + delete [] this->configOverrides; + this->configOverrides = NULL; + } } void CModuleConfiguration::Invalidate() { - CModuleConfiguration::invalid = TRUE; + CModuleConfiguration::invalid = TRUE; } HRESULT CModuleConfiguration::Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId) { - HRESULT hr; + HRESULT hr; - CheckNull(server); - CheckNull(moduleId); + CheckNull(server); + CheckNull(moduleId); - CModuleConfiguration::server = server; - CModuleConfiguration::moduleId = moduleId; + CModuleConfiguration::server = server; + CModuleConfiguration::moduleId = moduleId; - return S_OK; + return S_OK; Error: - return hr; + return hr; } -HRESULT CModuleConfiguration::CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH* env) +HRESULT CModuleConfiguration::CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH signalPipeName, PCH* env) { - HRESULT hr; - LPCH currentEnvironment = NULL; - LPCH tmpStart, tmpIndex = NULL; - DWORD tmpSize; - DWORD environmentSize; - IAppHostElement* section = NULL; - IAppHostElementCollection* appSettings = NULL; - IAppHostElement* entry = NULL; - IAppHostPropertyCollection* properties = NULL; - IAppHostProperty* prop = NULL; - BSTR keyPropertyName = NULL; - BSTR valuePropertyName = NULL; - VARIANT vKeyPropertyName; - VARIANT vValuePropertyName; - DWORD count; - BSTR propertyValue = NULL; - int propertySize; - - CheckNull(env); - *env = NULL; - - // this is a zero terminated list of zero terminated strings of the form = - - // calculate size of current environment - - ErrorIf(NULL == (currentEnvironment = GetEnvironmentStrings()), GetLastError()); - environmentSize = 0; - do { - while (*(currentEnvironment + environmentSize++) != 0); - } while (*(currentEnvironment + environmentSize++) != 0); - - // allocate memory for new environment variables - - tmpSize = 32767 - environmentSize; - ErrorIf(NULL == (tmpIndex = tmpStart = new char[tmpSize]), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(tmpIndex, tmpSize); - - // set PORT and IISNODE_VERSION variables - - ErrorIf(tmpSize < (strlen(namedPipe) + strlen(IISNODE_VERSION) + 6 + 17), ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "PORT=%s", namedPipe); - tmpIndex += strlen(namedPipe) + 6; - sprintf(tmpIndex, "IISNODE_VERSION=%s", IISNODE_VERSION); - tmpIndex += strlen(IISNODE_VERSION) + 17; - - // set DEBUGPORT environment variable if requested (used by node-inspector) - - if (debugPort > 0) - { - char debugPortS[64]; - sprintf(debugPortS, "%d", debugPort); - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(debugPortS) + 11), ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "DEBUGPORT=%s", debugPortS); - tmpIndex += strlen(debugPortS) + 11; - } - - // add environment variables from the appSettings section of config - - ErrorIf(NULL == (keyPropertyName = SysAllocString(L"key")), ERROR_NOT_ENOUGH_MEMORY); - vKeyPropertyName.vt = VT_BSTR; - vKeyPropertyName.bstrVal = keyPropertyName; - ErrorIf(NULL == (valuePropertyName = SysAllocString(L"value")), ERROR_NOT_ENOUGH_MEMORY); - vValuePropertyName.vt = VT_BSTR; - vValuePropertyName.bstrVal = valuePropertyName; - CheckError(GetConfigSection(ctx, §ion, L"appSettings")); - CheckError(section->get_Collection(&appSettings)); - CheckError(appSettings->get_Count(&count)); - - for (USHORT i = 0; i < count; i++) - { - VARIANT index; - index.vt = VT_I2; - index.iVal = i; - - CheckError(appSettings->get_Item(index, &entry)); - CheckError(entry->get_Properties(&properties)); - - CheckError(properties->get_Item(vKeyPropertyName, &prop)); - CheckError(prop->get_StringValue(&propertyValue)); - if (L'\0' != *propertyValue) - { - // the name of the setting is non-empty - - ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf((propertySize + 2) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL); - tmpIndex[propertySize] = '='; - tmpIndex += propertySize + 1; - SysFreeString(propertyValue); - propertyValue = NULL; - prop->Release(); - prop = NULL; - - CheckError(properties->get_Item(vValuePropertyName, &prop)); - CheckError(prop->get_StringValue(&propertyValue)); - if (L'\0' != *propertyValue) - { - // the value of the property is non-empty - - ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL); - tmpIndex += propertySize + 1; - } - else - { - // zero-terminate the environment variable of the form "foo=" (i.e. without a value) - - *tmpIndex = L'\0'; - tmpIndex++; - } - } - - SysFreeString(propertyValue); - propertyValue = NULL; - prop->Release(); - prop = NULL; - - properties->Release(); - properties = NULL; - entry->Release(); - entry = NULL; - } - - // set NODE_ENV variable based on the iisnode/@node_env configuration setting, if not empty - - LPWSTR node_env = CModuleConfiguration::GetNodeEnv(ctx); - if (0 != wcscmp(L"", node_env) && 0 != wcscmp(L"%node_env%", node_env)) - { - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 10, ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "NODE_ENV="); - tmpIndex += 9; - ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, node_env, wcslen(node_env), NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, node_env, wcslen(node_env), tmpIndex, propertySize, NULL, NULL), E_FAIL); - tmpIndex += propertySize + 1; - } - - if (CModuleConfiguration::GetLoggingEnabled(ctx)) - { - // set IISNODE_LOGGINGENABLED variable - - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 25, ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "IISNODE_LOGGINGENABLED=1"); - tmpIndex += 25; - - // set IISNODE_LOGDIRECTORY variable based on the iisnode/@logDirectory configuration setting, if not empty - - LPWSTR logDirectory = CModuleConfiguration::GetLogDirectory(ctx); - if (0 != wcscmp(L"", logDirectory)) - { - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 22, ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "IISNODE_LOGDIRECTORY="); - tmpIndex += 21; - ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, logDirectory, wcslen(logDirectory), NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, logDirectory, wcslen(logDirectory), tmpIndex, propertySize, NULL, NULL), E_FAIL); - tmpIndex += propertySize + 1; - } - - // set IISNODE_MAXTOTALLOGFILESIZEINKB, IISNODE_MAXLOGFILESIZEINKB, and IISNODE_MAXLOGFILES variables - - char tmp[64]; - sprintf(tmp, "%d", CModuleConfiguration::GetMaxTotalLogFileSizeInKB(ctx)); - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 33), ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "IISNODE_MAXTOTALLOGFILESIZEINKB=%s", tmp); - tmpIndex += strlen(tmp) + 33; - - sprintf(tmp, "%d", CModuleConfiguration::GetMaxLogFileSizeInKB(ctx)); - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 28), ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "IISNODE_MAXLOGFILESIZEINKB=%s", tmp); - tmpIndex += strlen(tmp) + 28; - - sprintf(tmp, "%d", CModuleConfiguration::GetMaxLogFiles(ctx)); - ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 21), ERROR_NOT_ENOUGH_MEMORY); - sprintf(tmpIndex, "IISNODE_MAXLOGFILES=%s", tmp); - tmpIndex += strlen(tmp) + 21; - - } - - // add a trailing zero to new variables - - ErrorIf(1 > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); - *tmpIndex = 0; - tmpIndex++; - - // concatenate new environment variables with the current environment block - - ErrorIf(NULL == (*env = (LPCH)new char[environmentSize + (tmpIndex - tmpStart)]), ERROR_NOT_ENOUGH_MEMORY); - memcpy(*env, currentEnvironment, environmentSize); - memcpy(*env + environmentSize - 1, tmpStart, (tmpIndex - tmpStart)); - - // cleanup - - FreeEnvironmentStrings(currentEnvironment); - section->Release(); - appSettings->Release(); - SysFreeString(keyPropertyName); - SysFreeString(valuePropertyName); - delete [] tmpStart; - - return S_OK; + HRESULT hr; + LPCH currentEnvironment = NULL; + LPCH tmpStart, tmpIndex = NULL; + DWORD tmpSize; + DWORD environmentSize; + IAppHostElement* section = NULL; + IAppHostElementCollection* appSettings = NULL; + IAppHostElement* entry = NULL; + IAppHostPropertyCollection* properties = NULL; + IAppHostProperty* prop = NULL; + BSTR keyPropertyName = NULL; + BSTR valuePropertyName = NULL; + VARIANT vKeyPropertyName; + VARIANT vValuePropertyName; + DWORD count; + BSTR propertyValue = NULL; + int propertySize; + + CheckNull(env); + *env = NULL; + + // this is a zero terminated list of zero terminated strings of the form = + + // calculate size of current environment + + ErrorIf(NULL == (currentEnvironment = GetEnvironmentStrings()), GetLastError()); + environmentSize = 0; + do { + while (*(currentEnvironment + environmentSize++) != 0); + } while (*(currentEnvironment + environmentSize++) != 0); + + // allocate memory for new environment variables + + tmpSize = 32767 - environmentSize; + ErrorIf(NULL == (tmpIndex = tmpStart = new char[tmpSize]), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(tmpIndex, tmpSize); + + // set PORT and IISNODE_VERSION variables + + ErrorIf(tmpSize < (strlen(namedPipe) + strlen(IISNODE_VERSION) + 6 + 17), ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "PORT=%s", namedPipe); + tmpIndex += strlen(namedPipe) + 6; + sprintf(tmpIndex, "IISNODE_VERSION=%s", IISNODE_VERSION); + tmpIndex += strlen(IISNODE_VERSION) + 17; + + if(CModuleConfiguration::GetRecycleSignalEnabled(ctx) && signalPipeName != NULL) + { + sprintf(tmpIndex, "IISNODE_CONTROL_PIPE=%s", signalPipeName); + tmpIndex += strlen(signalPipeName) + 22; + } + + // set DEBUGPORT environment variable if requested (used by node-inspector) + + if (debugPort > 0) + { + char debugPortS[64]; + sprintf(debugPortS, "%d", debugPort); + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(debugPortS) + 11), ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "DEBUGPORT=%s", debugPortS); + tmpIndex += strlen(debugPortS) + 11; + } + + // add environment variables from the appSettings section of config + + ErrorIf(NULL == (keyPropertyName = SysAllocString(L"key")), ERROR_NOT_ENOUGH_MEMORY); + vKeyPropertyName.vt = VT_BSTR; + vKeyPropertyName.bstrVal = keyPropertyName; + ErrorIf(NULL == (valuePropertyName = SysAllocString(L"value")), ERROR_NOT_ENOUGH_MEMORY); + vValuePropertyName.vt = VT_BSTR; + vValuePropertyName.bstrVal = valuePropertyName; + CheckError(GetConfigSection(ctx, §ion, L"appSettings")); + CheckError(section->get_Collection(&appSettings)); + CheckError(appSettings->get_Count(&count)); + + for (USHORT i = 0; i < count; i++) + { + VARIANT index; + index.vt = VT_I2; + index.iVal = i; + + CheckError(appSettings->get_Item(index, &entry)); + CheckError(entry->get_Properties(&properties)); + + CheckError(properties->get_Item(vKeyPropertyName, &prop)); + CheckError(prop->get_StringValue(&propertyValue)); + if (L'\0' != *propertyValue) + { + // the name of the setting is non-empty + + ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf((propertySize + 2) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL); + tmpIndex[propertySize] = '='; + tmpIndex += propertySize + 1; + SysFreeString(propertyValue); + propertyValue = NULL; + prop->Release(); + prop = NULL; + + CheckError(properties->get_Item(vValuePropertyName, &prop)); + CheckError(prop->get_StringValue(&propertyValue)); + if (L'\0' != *propertyValue) + { + // the value of the property is non-empty + + ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, propertyValue, wcslen(propertyValue), tmpIndex, propertySize, NULL, NULL), E_FAIL); + tmpIndex += propertySize + 1; + } + else + { + // zero-terminate the environment variable of the form "foo=" (i.e. without a value) + + *tmpIndex = L'\0'; + tmpIndex++; + } + } + + SysFreeString(propertyValue); + propertyValue = NULL; + prop->Release(); + prop = NULL; + + properties->Release(); + properties = NULL; + entry->Release(); + entry = NULL; + } + + // set NODE_ENV variable based on the iisnode/@node_env configuration setting, if not empty + + LPWSTR node_env = CModuleConfiguration::GetNodeEnv(ctx); + if (0 != wcscmp(L"", node_env) && 0 != wcscmp(L"%node_env%", node_env)) + { + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 10, ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "NODE_ENV="); + tmpIndex += 9; + ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, node_env, wcslen(node_env), NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, node_env, wcslen(node_env), tmpIndex, propertySize, NULL, NULL), E_FAIL); + tmpIndex += propertySize + 1; + } + + if (CModuleConfiguration::GetLoggingEnabled(ctx)) + { + // set IISNODE_LOGGINGENABLED variable + + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 25, ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "IISNODE_LOGGINGENABLED=1"); + tmpIndex += 25; + + // set IISNODE_LOGDIRECTORY variable based on the iisnode/@logDirectory configuration setting, if not empty + + LPWSTR logDirectory = CModuleConfiguration::GetLogDirectory(ctx); + if (0 != wcscmp(L"", logDirectory)) + { + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < 22, ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "IISNODE_LOGDIRECTORY="); + tmpIndex += 21; + ErrorIf(0 == (propertySize = WideCharToMultiByte(CP_ACP, 0, logDirectory, wcslen(logDirectory), NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf((propertySize + 1) > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(propertySize != WideCharToMultiByte(CP_ACP, 0, logDirectory, wcslen(logDirectory), tmpIndex, propertySize, NULL, NULL), E_FAIL); + tmpIndex += propertySize + 1; + } + + // set IISNODE_MAXTOTALLOGFILESIZEINKB, IISNODE_MAXLOGFILESIZEINKB, and IISNODE_MAXLOGFILES variables + + char tmp[64]; + sprintf(tmp, "%d", CModuleConfiguration::GetMaxTotalLogFileSizeInKB(ctx)); + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 33), ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "IISNODE_MAXTOTALLOGFILESIZEINKB=%s", tmp); + tmpIndex += strlen(tmp) + 33; + + sprintf(tmp, "%d", CModuleConfiguration::GetMaxLogFileSizeInKB(ctx)); + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 28), ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "IISNODE_MAXLOGFILESIZEINKB=%s", tmp); + tmpIndex += strlen(tmp) + 28; + + sprintf(tmp, "%d", CModuleConfiguration::GetMaxLogFiles(ctx)); + ErrorIf((tmpSize - (tmpIndex - tmpStart)) < (strlen(tmp) + 21), ERROR_NOT_ENOUGH_MEMORY); + sprintf(tmpIndex, "IISNODE_MAXLOGFILES=%s", tmp); + tmpIndex += strlen(tmp) + 21; + + } + + // add a trailing zero to new variables + + ErrorIf(1 > (tmpSize - (tmpStart - tmpIndex)), ERROR_NOT_ENOUGH_MEMORY); + *tmpIndex = 0; + tmpIndex++; + + // concatenate new environment variables with the current environment block + + ErrorIf(NULL == (*env = (LPCH)new char[environmentSize + (tmpIndex - tmpStart)]), ERROR_NOT_ENOUGH_MEMORY); + memcpy(*env, currentEnvironment, environmentSize); + memcpy(*env + environmentSize - 1, tmpStart, (tmpIndex - tmpStart)); + + // cleanup + + FreeEnvironmentStrings(currentEnvironment); + section->Release(); + appSettings->Release(); + SysFreeString(keyPropertyName); + SysFreeString(valuePropertyName); + delete [] tmpStart; + + return S_OK; Error: - if (currentEnvironment) - { - FreeEnvironmentStrings(currentEnvironment); - currentEnvironment = NULL; - } - - if (section) - { - section->Release(); - section = NULL; - } - - if (appSettings) - { - appSettings->Release(); - appSettings = NULL; - } - - if (keyPropertyName) - { - SysFreeString(keyPropertyName); - keyPropertyName = NULL; - } - - if (valuePropertyName) - { - SysFreeString(valuePropertyName); - valuePropertyName = NULL; - } - - if (entry) - { - entry->Release(); - entry = NULL; - } - - if (properties) - { - properties->Release(); - properties = NULL; - } - - if (prop) - { - prop->Release(); - prop = NULL; - } - - if (propertyValue) - { - SysFreeString(propertyValue); - propertyValue = NULL; - } - - if (tmpStart) - { - delete [] tmpStart; - tmpStart = NULL; - } - - return hr; + if (currentEnvironment) + { + FreeEnvironmentStrings(currentEnvironment); + currentEnvironment = NULL; + } + + if (section) + { + section->Release(); + section = NULL; + } + + if (appSettings) + { + appSettings->Release(); + appSettings = NULL; + } + + if (keyPropertyName) + { + SysFreeString(keyPropertyName); + keyPropertyName = NULL; + } + + if (valuePropertyName) + { + SysFreeString(valuePropertyName); + valuePropertyName = NULL; + } + + if (entry) + { + entry->Release(); + entry = NULL; + } + + if (properties) + { + properties->Release(); + properties = NULL; + } + + if (prop) + { + prop->Release(); + prop = NULL; + } + + if (propertyValue) + { + SysFreeString(propertyValue); + propertyValue = NULL; + } + + if (tmpStart) + { + delete [] tmpStart; + tmpStart = NULL; + } + + return hr; } HRESULT CModuleConfiguration::GetConfigSection(IHttpContext* context, IAppHostElement** section, OLECHAR* configElement) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; BSTR path = NULL; BSTR elementName = NULL; - CheckNull(section); - *section = NULL; - ErrorIf(NULL == (path = SysAllocString(context->GetMetadata()->GetMetaPath())), ERROR_NOT_ENOUGH_MEMORY); + CheckNull(section); + *section = NULL; + ErrorIf(NULL == (path = SysAllocString(context->GetMetadata()->GetMetaPath())), ERROR_NOT_ENOUGH_MEMORY); ErrorIf(NULL == (elementName = SysAllocString(configElement)), ERROR_NOT_ENOUGH_MEMORY); - CheckError(server->GetAdminManager()->GetAdminSection(elementName, path, section)); + CheckError(server->GetAdminManager()->GetAdminSection(elementName, path, section)); Error: @@ -443,56 +457,56 @@ HRESULT CModuleConfiguration::GetConfigSection(IHttpContext* context, IAppHostEl HRESULT CModuleConfiguration::GetEnvVariable(LPCWSTR propertyName, LPWSTR buffer, DWORD bufferSize, LPWSTR* result) { - HRESULT hr; - WCHAR variableName[124]; - - CheckNull(result); - ErrorIf(124 < (wcslen(propertyName) + 9), IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); - wcscpy(variableName, L"IISNODE_"); - wcscat(variableName, propertyName); - DWORD size = GetEnvironmentVariableW(variableName, buffer, bufferSize); - ErrorIf(size > bufferSize, IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); - if (size == 0) - { - *result = NULL; - ErrorIf(ERROR_ENVVAR_NOT_FOUND != (hr = GetLastError()), hr); - } - else - { - *result = buffer; - } - - return S_OK; + HRESULT hr; + WCHAR variableName[124]; + + CheckNull(result); + ErrorIf(124 < (wcslen(propertyName) + 9), IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); + wcscpy(variableName, L"IISNODE_"); + wcscat(variableName, propertyName); + DWORD size = GetEnvironmentVariableW(variableName, buffer, bufferSize); + ErrorIf(size > bufferSize, IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); + if (size == 0) + { + *result = NULL; + ErrorIf(ERROR_ENVVAR_NOT_FOUND != (hr = GetLastError()), hr); + } + else + { + *result = buffer; + } + + return S_OK; Error: - return hr; + return hr; } HRESULT CModuleConfiguration::GetString(IAppHostElement* section, LPCWSTR propertyName, LPWSTR* value) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; BSTR sysPropertyName = NULL; BSTR sysPropertyValue = NULL; IAppHostProperty* prop = NULL; - WCHAR variableValueBuffer[1024]; - WCHAR* variableValue = NULL; - - CheckNull(value); - *value = NULL; - - CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 1024, &variableValue)); - if (variableValue) - { - ErrorIf(NULL == (*value = new WCHAR[wcslen(variableValue) + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(*value, variableValue); - } - else - { - ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); - CheckError(section->GetPropertyByName(sysPropertyName, &prop)); - CheckError(prop->get_StringValue(&sysPropertyValue)); - ErrorIf(NULL == (*value = new WCHAR[wcslen(sysPropertyValue) + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(*value, sysPropertyValue); - } + WCHAR variableValueBuffer[1024]; + WCHAR* variableValue = NULL; + + CheckNull(value); + *value = NULL; + + CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 1024, &variableValue)); + if (variableValue) + { + ErrorIf(NULL == (*value = new WCHAR[wcslen(variableValue) + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(*value, variableValue); + } + else + { + ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); + CheckError(section->GetPropertyByName(sysPropertyName, &prop)); + CheckError(prop->get_StringValue(&sysPropertyValue)); + ErrorIf(NULL == (*value = new WCHAR[wcslen(sysPropertyValue) + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(*value, sysPropertyValue); + } Error: @@ -519,51 +533,51 @@ HRESULT CModuleConfiguration::GetString(IAppHostElement* section, LPCWSTR proper HRESULT CModuleConfiguration::GetBOOL(IAppHostElement* section, LPCWSTR propertyName, BOOL* value, BOOL defaultValue) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; BSTR sysPropertyName = NULL; IAppHostProperty* prop = NULL; - VARIANT var; - WCHAR variableValueBuffer[8]; - WCHAR* variableValue = NULL; - - CheckNull(value); - *value = FALSE; - VariantInit(&var); - - CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 8, &variableValue)); - if (variableValue) - { - if (0 == _wcsicmp(variableValue, L"true") || 0 == _wcsicmp(variableValue, L"1")) - { - *value = TRUE; - } - else if (0 == _wcsicmp(variableValue, L"false") || 0 == _wcsicmp(variableValue, L"0")) - { - *value = FALSE; - } - else - { - CheckError(IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); - } - } - else - { - ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); - if (S_OK != section->GetPropertyByName(sysPropertyName, &prop)) - { - *value = defaultValue; - } - else - { - CheckError(prop->get_Value(&var)); - CheckError(VariantChangeType(&var, &var, 0, VT_BOOL)); - *value = (V_BOOL(&var) == VARIANT_TRUE); - } - } + VARIANT var; + WCHAR variableValueBuffer[8]; + WCHAR* variableValue = NULL; + + CheckNull(value); + *value = FALSE; + VariantInit(&var); + + CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 8, &variableValue)); + if (variableValue) + { + if (0 == _wcsicmp(variableValue, L"true") || 0 == _wcsicmp(variableValue, L"1")) + { + *value = TRUE; + } + else if (0 == _wcsicmp(variableValue, L"false") || 0 == _wcsicmp(variableValue, L"0")) + { + *value = FALSE; + } + else + { + CheckError(IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); + } + } + else + { + ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); + if (S_OK != section->GetPropertyByName(sysPropertyName, &prop)) + { + *value = defaultValue; + } + else + { + CheckError(prop->get_Value(&var)); + CheckError(VariantChangeType(&var, &var, 0, VT_BOOL)); + *value = (V_BOOL(&var) == VARIANT_TRUE); + } + } Error: - VariantClear(&var); + VariantClear(&var); if ( sysPropertyName ) { @@ -582,37 +596,37 @@ HRESULT CModuleConfiguration::GetBOOL(IAppHostElement* section, LPCWSTR property HRESULT CModuleConfiguration::GetDWORD(IAppHostElement* section, LPCWSTR propertyName, DWORD* value) { - HRESULT hr = S_OK; + HRESULT hr = S_OK; BSTR sysPropertyName = NULL; IAppHostProperty* prop = NULL; - VARIANT var; - WCHAR variableValueBuffer[64]; - WCHAR* variableValue = NULL; - WCHAR* endValue = NULL; - - CheckNull(value); - *value = NULL; - VariantInit(&var); - - CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 64, &variableValue)); - if (variableValue) - { - long parsed = wcstol(variableValue, &endValue, 10); - ErrorIf(ERANGE == errno || parsed < 0 || variableValue == endValue, IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); - *value = parsed; - } - else - { - ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); - CheckError(section->GetPropertyByName(sysPropertyName, &prop)); - CheckError(prop->get_Value(&var)); - CheckError(VariantChangeType(&var, &var, 0, VT_UI4)); - *value = var.ulVal; - } + VARIANT var; + WCHAR variableValueBuffer[64]; + WCHAR* variableValue = NULL; + WCHAR* endValue = NULL; + + CheckNull(value); + *value = NULL; + VariantInit(&var); + + CheckError(CModuleConfiguration::GetEnvVariable(propertyName, variableValueBuffer, 64, &variableValue)); + if (variableValue) + { + long parsed = wcstol(variableValue, &endValue, 10); + ErrorIf(ERANGE == errno || parsed < 0 || variableValue == endValue, IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_FROM_ENVIRONMENT); + *value = parsed; + } + else + { + ErrorIf(NULL == (sysPropertyName = SysAllocString(propertyName)), ERROR_NOT_ENOUGH_MEMORY); + CheckError(section->GetPropertyByName(sysPropertyName, &prop)); + CheckError(prop->get_Value(&var)); + CheckError(VariantChangeType(&var, &var, 0, VT_UI4)); + *value = var.ulVal; + } Error: - VariantClear(&var); + VariantClear(&var); if ( sysPropertyName ) { @@ -631,473 +645,481 @@ HRESULT CModuleConfiguration::GetDWORD(IAppHostElement* section, LPCWSTR propert HRESULT CModuleConfiguration::GetDWORD(char* str, DWORD* value) { - HRESULT hr; + HRESULT hr; - if (str) - { - long v = atol(str); - ErrorIf((v == LONG_MAX || v == LONG_MIN) && errno == ERANGE, E_FAIL); - *value = (DWORD)v; - } + if (str) + { + long v = atol(str); + ErrorIf((v == LONG_MAX || v == LONG_MIN) && errno == ERANGE, E_FAIL); + *value = (DWORD)v; + } - return S_OK; + return S_OK; Error: - return hr; + return hr; } HRESULT CModuleConfiguration::GetBOOL(char* str, BOOL* value) { - if (!str) - { - *value = FALSE; - } - else if (0 == strcmpi(str, "false") || 0 == strcmpi(str, "0") || 0 == strcmpi(str, "no")) - { - *value = FALSE; - } - else if (0 == strcmpi(str, "true") || 0 == strcmpi(str, "1") || 0 == strcmpi(str, "yes")) - { - *value = TRUE; - } - else - { - return E_FAIL; - } - - return S_OK; + if (!str) + { + *value = FALSE; + } + else if (0 == strcmpi(str, "false") || 0 == strcmpi(str, "0") || 0 == strcmpi(str, "no")) + { + *value = FALSE; + } + else if (0 == strcmpi(str, "true") || 0 == strcmpi(str, "1") || 0 == strcmpi(str, "yes")) + { + *value = TRUE; + } + else + { + return E_FAIL; + } + + return S_OK; } HRESULT CModuleConfiguration::GetString(char* str, LPWSTR* value, BOOL expandEnvironmentStrings) { - HRESULT hr; - int wcharSize, bytesConverted; - LPWSTR pszStr = NULL; - - if (*value) - { - delete [] *value; - *value = NULL; - } - - if (!str) - { - str = ""; - } - - if(expandEnvironmentStrings == FALSE) - { - ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); - ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, *value, wcharSize), GetLastError()); - } - else - { - ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); - ErrorIf(NULL == (pszStr = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, pszStr, wcharSize), GetLastError()); - ErrorIf(0 == (wcharSize = ExpandEnvironmentStringsW(pszStr, NULL, 0)), GetLastError()); - ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(wcharSize != ExpandEnvironmentStringsW(pszStr, *value, wcharSize), GetLastError()); - } - - hr = S_OK; // fall through to clean up section. + HRESULT hr; + int wcharSize, bytesConverted; + LPWSTR pszStr = NULL; + + if (*value) + { + delete [] *value; + *value = NULL; + } + + if (!str) + { + str = ""; + } + + if(expandEnvironmentStrings == FALSE) + { + ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); + ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, *value, wcharSize), GetLastError()); + } + else + { + ErrorIf(0 == (wcharSize = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0)), GetLastError()); + ErrorIf(NULL == (pszStr = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != MultiByteToWideChar(CP_ACP, 0, str, -1, pszStr, wcharSize), GetLastError()); + ErrorIf(0 == (wcharSize = ExpandEnvironmentStringsW(pszStr, NULL, 0)), GetLastError()); + ErrorIf(NULL == (*value = new WCHAR[wcharSize]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(wcharSize != ExpandEnvironmentStringsW(pszStr, *value, wcharSize), GetLastError()); + } + + hr = S_OK; // fall through to clean up section. Error: - if(pszStr != NULL) - { - delete[] pszStr; - } + if(pszStr != NULL) + { + delete[] pszStr; + } - return hr; + return hr; } HRESULT CModuleConfiguration::ApplyConfigOverrideKeyValue(IHttpContext* context, CModuleConfiguration* config, char* keyStart, char* keyEnd, char* valueStart, char* valueEnd) { - HRESULT hr; - - keyEnd++; - *keyEnd = 0; - - if (valueEnd) - { - valueEnd++; - *valueEnd = 0; - } - - if (0 == strcmpi(keyStart, "asyncCompletionThreadCount")) - { - CheckError(GetDWORD(valueStart, &config->asyncCompletionThreadCount)); - } - else if (0 == strcmpi(keyStart, "nodeProcessCountPerApplication")) - { - CheckError(GetDWORD(valueStart, &config->nodeProcessCountPerApplication)); - } - else if (0 == strcmpi(keyStart, "maxConcurrentRequestsPerProcess")) - { - CheckError(GetDWORD(valueStart, &config->maxConcurrentRequestsPerProcess)); - } - else if (0 == strcmpi(keyStart, "maxNamedPipeConnectionRetry")) - { - CheckError(GetDWORD(valueStart, &config->maxNamedPipeConnectionRetry)); - } - else if (0 == strcmpi(keyStart, "namedPipeConnectionRetryDelay")) - { - CheckError(GetDWORD(valueStart, &config->namedPipeConnectionRetryDelay)); - } - else if (0 == strcmpi(keyStart, "maxNamedPipeConnectionPoolSize")) - { - CheckError(GetDWORD(valueStart, &config->maxNamedPipeConnectionPoolSize)); - } - else if (0 == strcmpi(keyStart, "maxNamedPipePooledConnectionAge")) - { - CheckError(GetDWORD(valueStart, &config->maxNamedPipePooledConnectionAge)); - } - else if (0 == strcmpi(keyStart, "initialRequestBufferSize")) - { - CheckError(GetDWORD(valueStart, &config->initialRequestBufferSize)); - } - else if (0 == strcmpi(keyStart, "maxRequestBufferSize")) - { - CheckError(GetDWORD(valueStart, &config->maxRequestBufferSize)); - } - else if (0 == strcmpi(keyStart, "uncFileChangesPollingInterval")) - { - CheckError(GetDWORD(valueStart, &config->uncFileChangesPollingInterval)); - } - else if (0 == strcmpi(keyStart, "gracefulShutdownTimeout")) - { - CheckError(GetDWORD(valueStart, &config->gracefulShutdownTimeout)); - } - else if (0 == strcmpi(keyStart, "maxTotalLogFileSizeInKB")) - { - CheckError(GetDWORD(valueStart, &config->maxTotalLogFileSizeInKB)); - } - else if (0 == strcmpi(keyStart, "maxLogFileSizeInKB")) - { - CheckError(GetDWORD(valueStart, &config->maxLogFileSizeInKB)); - } - else if (0 == strcmpi(keyStart, "maxLogFiles")) - { - CheckError(GetDWORD(valueStart, &config->maxLogFiles)); - } - else if (0 == strcmpi(keyStart, "loggingEnabled")) - { - CheckError(GetBOOL(valueStart, &config->loggingEnabled)); - } - else if (0 == strcmpi(keyStart, "devErrorsEnabled")) - { - CheckError(GetBOOL(valueStart, &config->devErrorsEnabled)); - } - else if (0 == strcmpi(keyStart, "flushResponse")) - { - CheckError(GetBOOL(valueStart, &config->flushResponse)); - } - else if (0 == strcmpi(keyStart, "debuggingEnabled")) - { - CheckError(GetBOOL(valueStart, &config->debuggingEnabled)); - } - else if (0 == strcmpi(keyStart, "debugHeaderEnabled")) - { - CheckError(GetBOOL(valueStart, &config->debugHeaderEnabled)); - } + HRESULT hr; + + keyEnd++; + *keyEnd = 0; + + if (valueEnd) + { + valueEnd++; + *valueEnd = 0; + } + + if (0 == strcmpi(keyStart, "asyncCompletionThreadCount")) + { + CheckError(GetDWORD(valueStart, &config->asyncCompletionThreadCount)); + } + else if (0 == strcmpi(keyStart, "nodeProcessCountPerApplication")) + { + CheckError(GetDWORD(valueStart, &config->nodeProcessCountPerApplication)); + } + else if (0 == strcmpi(keyStart, "maxConcurrentRequestsPerProcess")) + { + CheckError(GetDWORD(valueStart, &config->maxConcurrentRequestsPerProcess)); + } + else if (0 == strcmpi(keyStart, "maxNamedPipeConnectionRetry")) + { + CheckError(GetDWORD(valueStart, &config->maxNamedPipeConnectionRetry)); + } + else if (0 == strcmpi(keyStart, "namedPipeConnectionRetryDelay")) + { + CheckError(GetDWORD(valueStart, &config->namedPipeConnectionRetryDelay)); + } + else if (0 == strcmpi(keyStart, "maxNamedPipeConnectionPoolSize")) + { + CheckError(GetDWORD(valueStart, &config->maxNamedPipeConnectionPoolSize)); + } + else if (0 == strcmpi(keyStart, "maxNamedPipePooledConnectionAge")) + { + CheckError(GetDWORD(valueStart, &config->maxNamedPipePooledConnectionAge)); + } + else if (0 == strcmpi(keyStart, "initialRequestBufferSize")) + { + CheckError(GetDWORD(valueStart, &config->initialRequestBufferSize)); + } + else if (0 == strcmpi(keyStart, "maxRequestBufferSize")) + { + CheckError(GetDWORD(valueStart, &config->maxRequestBufferSize)); + } + else if (0 == strcmpi(keyStart, "uncFileChangesPollingInterval")) + { + CheckError(GetDWORD(valueStart, &config->uncFileChangesPollingInterval)); + } + else if (0 == strcmpi(keyStart, "gracefulShutdownTimeout")) + { + CheckError(GetDWORD(valueStart, &config->gracefulShutdownTimeout)); + } + else if (0 == strcmpi(keyStart, "maxTotalLogFileSizeInKB")) + { + CheckError(GetDWORD(valueStart, &config->maxTotalLogFileSizeInKB)); + } + else if (0 == strcmpi(keyStart, "maxLogFileSizeInKB")) + { + CheckError(GetDWORD(valueStart, &config->maxLogFileSizeInKB)); + } + else if (0 == strcmpi(keyStart, "maxLogFiles")) + { + CheckError(GetDWORD(valueStart, &config->maxLogFiles)); + } + else if (0 == strcmpi(keyStart, "loggingEnabled")) + { + CheckError(GetBOOL(valueStart, &config->loggingEnabled)); + } + else if (0 == strcmpi(keyStart, "devErrorsEnabled")) + { + CheckError(GetBOOL(valueStart, &config->devErrorsEnabled)); + } + else if (0 == strcmpi(keyStart, "flushResponse")) + { + CheckError(GetBOOL(valueStart, &config->flushResponse)); + } + else if (0 == strcmpi(keyStart, "debuggingEnabled")) + { + CheckError(GetBOOL(valueStart, &config->debuggingEnabled)); + } + else if (0 == strcmpi(keyStart, "debuggerExtensionDll")) + { + CheckError(GetString(valueStart, &config->debuggerExtensionDll)); + } + else if (0 == strcmpi(keyStart, "debugHeaderEnabled")) + { + CheckError(GetBOOL(valueStart, &config->debugHeaderEnabled)); + } + else if(0 == strcmpi(keyStart, "recycleSignalEnabled")) + { + CheckError(GetBOOL(valueStart, &config->recycleSignalEnabled)); + } else if (0 == strcmpi(keyStart, "debuggerVirtualDir")) - { - CheckError(GetString(valueStart, &config->debuggerVirtualDir)); + { + CheckError(GetString(valueStart, &config->debuggerVirtualDir)); config->debuggerVirtualDirLength = wcslen(config->debuggerVirtualDir); - } - else if (0 == strcmpi(keyStart, "enableXFF")) - { - CheckError(GetBOOL(valueStart, &config->enableXFF)); - } - else if (0 == strcmpi(keyStart, "logDirectory")) - { - CheckError(GetString(valueStart, &config->logDirectory, TRUE)); - } - else if (0 == strcmpi(keyStart, "node_env")) - { - CheckError(GetString(valueStart, &config->node_env, TRUE)); - } - else if (0 == strcmpi(keyStart, "debugPortRange")) - { - CheckError(GetString(valueStart, &config->debugPortRange)); - } - else if (0 == strcmpi(keyStart, "watchedFiles")) - { - CheckError(GetString(valueStart, &config->watchedFiles, TRUE)); - } - else if (0 == strcmpi(keyStart, "promoteServerVars")) - { - CheckError(GetString(valueStart, &config->promoteServerVarsRaw)); - } - else if (0 == strcmpi(keyStart, "debuggerPathSegment")) - { - CheckError(GetString(valueStart, &config->debuggerPathSegment)); - config->debuggerPathSegmentLength = wcslen(config->debuggerPathSegment); - } - else if (0 == strcmpi(keyStart, "nodeProcessCommandLine")) - { - CheckError(GetString(valueStart, &config->nodeProcessCommandLine, TRUE)); - } - else if (0 == strcmpi(keyStart, "interceptor")) - { - CheckError(GetString(valueStart, &config->interceptor, TRUE)); - } - - return S_OK; + } + else if (0 == strcmpi(keyStart, "enableXFF")) + { + CheckError(GetBOOL(valueStart, &config->enableXFF)); + } + else if (0 == strcmpi(keyStart, "logDirectory")) + { + CheckError(GetString(valueStart, &config->logDirectory, TRUE)); + } + else if (0 == strcmpi(keyStart, "node_env")) + { + CheckError(GetString(valueStart, &config->node_env, TRUE)); + } + else if (0 == strcmpi(keyStart, "debugPortRange")) + { + CheckError(GetString(valueStart, &config->debugPortRange)); + } + else if (0 == strcmpi(keyStart, "watchedFiles")) + { + CheckError(GetString(valueStart, &config->watchedFiles, TRUE)); + } + else if (0 == strcmpi(keyStart, "promoteServerVars")) + { + CheckError(GetString(valueStart, &config->promoteServerVarsRaw)); + } + else if (0 == strcmpi(keyStart, "debuggerPathSegment")) + { + CheckError(GetString(valueStart, &config->debuggerPathSegment)); + config->debuggerPathSegmentLength = wcslen(config->debuggerPathSegment); + } + else if (0 == strcmpi(keyStart, "nodeProcessCommandLine")) + { + CheckError(GetString(valueStart, &config->nodeProcessCommandLine, TRUE)); + } + else if (0 == strcmpi(keyStart, "interceptor")) + { + CheckError(GetString(valueStart, &config->interceptor, TRUE)); + } + + return S_OK; Error: - return hr; + return hr; } HRESULT CModuleConfiguration::ApplyYamlConfigOverrides(IHttpContext* context, CModuleConfiguration* config) { - HRESULT hr; - PCWSTR scriptTranslated; - DWORD scriptTranslatedLength; - HANDLE overridesHandle = INVALID_HANDLE_VALUE; - DWORD fileSize; - DWORD bytesRead; - char* content = NULL; - char* lineStart; - char* lineEnd; - char* colon; - char* comment; - char *keyStart, *keyEnd; - char *valueStart, *valueEnd; - - if (config->configOverrides == L'\0') - { - // no file name with config overrides specified, return success - - return S_OK; - } - - // construct absolute file name by replacing the script name in the script translated path with the config override file name - - if (!config->configOverridesFileName) - { - scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); - ErrorIf(NULL == (config->configOverridesFileName = new WCHAR[scriptTranslatedLength + wcslen(config->configOverrides) + 1]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(config->configOverridesFileName, scriptTranslated); - while (scriptTranslatedLength > 0 && config->configOverridesFileName[scriptTranslatedLength] != L'\\') - scriptTranslatedLength--; - wcscpy(config->configOverridesFileName + scriptTranslatedLength + 1, config->configOverrides); - } - - // open configuration override file if it exists - - if (INVALID_HANDLE_VALUE == (overridesHandle = CreateFileW( - config->configOverridesFileName, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - 0, - NULL))) { - hr = GetLastError(); - - // if file does not exist, clean up and return success (i.e. no config overrides specified) - ErrorIf(ERROR_FILE_NOT_FOUND == hr, S_OK); + HRESULT hr; + PCWSTR scriptTranslated; + DWORD scriptTranslatedLength; + HANDLE overridesHandle = INVALID_HANDLE_VALUE; + DWORD fileSize; + DWORD bytesRead; + char* content = NULL; + char* lineStart; + char* lineEnd; + char* colon; + char* comment; + char *keyStart, *keyEnd; + char *valueStart, *valueEnd; + + if (config->configOverrides == L'\0') + { + // no file name with config overrides specified, return success + + return S_OK; + } + + // construct absolute file name by replacing the script name in the script translated path with the config override file name + + if (!config->configOverridesFileName) + { + scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); + ErrorIf(NULL == (config->configOverridesFileName = new WCHAR[scriptTranslatedLength + wcslen(config->configOverrides) + 1]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(config->configOverridesFileName, scriptTranslated); + while (scriptTranslatedLength > 0 && config->configOverridesFileName[scriptTranslatedLength] != L'\\') + scriptTranslatedLength--; + wcscpy(config->configOverridesFileName + scriptTranslatedLength + 1, config->configOverrides); + } + + // open configuration override file if it exists + + if (INVALID_HANDLE_VALUE == (overridesHandle = CreateFileW( + config->configOverridesFileName, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + 0, + NULL))) { + hr = GetLastError(); + + // if file does not exist, clean up and return success (i.e. no config overrides specified) + ErrorIf(ERROR_FILE_NOT_FOUND == hr, S_OK); ErrorIf(ERROR_PATH_NOT_FOUND == hr, S_OK); - - // if other error occurred, return the error - ErrorIf(TRUE, hr); - } - - // read file content - - ErrorIf(INVALID_FILE_SIZE == (fileSize = GetFileSize(overridesHandle, NULL)), GetLastError()); - ErrorIf(0 == fileSize, S_OK); // empty file, clean up and return success - ErrorIf(NULL == (content = new char[fileSize + 1]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(!ReadFile(overridesHandle, content, fileSize, &bytesRead, NULL), GetLastError()); - ErrorIf(fileSize != bytesRead, E_FAIL); - content[bytesRead] = 0; - CloseHandle(overridesHandle); - overridesHandle = INVALID_HANDLE_VALUE; - - // parse file - - lineStart = lineEnd = content; - while (*lineStart) - { - // determine the placement of a comment and colon as well as the end of the line - colon = comment = NULL; - while (*lineEnd && *lineEnd != '\r' && *lineEnd != '\n') - { - if (*lineEnd == ':') - { - if (!colon) - colon = lineEnd; - } - else if (*lineEnd == '#') - { - if (!comment) - comment = lineEnd; - } - - lineEnd++; - } - - // comment will be the sentinel of the end of this line - if (!comment) - comment = lineEnd; - - // skip whitespace at the end of this line and beginning of next - while (*lineEnd == ' ' || *lineEnd == '\r' || *lineEnd == '\n') - lineEnd++; - - // skip whitespace at the beginning of line - while (lineStart < comment && *lineStart == ' ') - lineStart++; - - if (lineStart < comment) - { - // there is a non-whitespace character before the end of the line or comment on that line - // assume : [#] syntax of the line - keyStart = lineStart; - ErrorIf(!colon, E_FAIL); // there is no colon on the line - ErrorIf(keyStart == colon, E_FAIL); // colon is the first non-whitespace character on the line - - // find end of key name - while (lineStart < colon && *lineStart != ' ') - lineStart++; - keyEnd = lineStart - 1; - - // skip whitespace between end of key name and colon - while (lineStart < colon && *lineStart == ' ') - lineStart++; - ErrorIf(lineStart != colon, E_FAIL); // non-whitespace character found - - // skip whitespace before value - lineStart++; - while (lineStart < comment && *lineStart == ' ') - lineStart++; - - if (lineStart == comment) - { - // empty value - valueStart = valueEnd = NULL; - } - else - { - valueStart = lineStart; - - // find end of value as a last non-whitespace character before comment - valueEnd = comment - 1; - while (valueEnd > valueStart && *valueEnd == ' ') - valueEnd--; - - CheckError(CModuleConfiguration::ApplyConfigOverrideKeyValue(context, config, keyStart, keyEnd, valueStart, valueEnd)); - } - - } - - // move on to the next line - lineStart = lineEnd; - } - - hr = S_OK; // fall through to cleanup in the Error section + + // if other error occurred, return the error + ErrorIf(TRUE, hr); + } + + // read file content + + ErrorIf(INVALID_FILE_SIZE == (fileSize = GetFileSize(overridesHandle, NULL)), GetLastError()); + ErrorIf(0 == fileSize, S_OK); // empty file, clean up and return success + ErrorIf(NULL == (content = new char[fileSize + 1]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(!ReadFile(overridesHandle, content, fileSize, &bytesRead, NULL), GetLastError()); + ErrorIf(fileSize != bytesRead, E_FAIL); + content[bytesRead] = 0; + CloseHandle(overridesHandle); + overridesHandle = INVALID_HANDLE_VALUE; + + // parse file + + lineStart = lineEnd = content; + while (*lineStart) + { + // determine the placement of a comment and colon as well as the end of the line + colon = comment = NULL; + while (*lineEnd && *lineEnd != '\r' && *lineEnd != '\n') + { + if (*lineEnd == ':') + { + if (!colon) + colon = lineEnd; + } + else if (*lineEnd == '#') + { + if (!comment) + comment = lineEnd; + } + + lineEnd++; + } + + // comment will be the sentinel of the end of this line + if (!comment) + comment = lineEnd; + + // skip whitespace at the end of this line and beginning of next + while (*lineEnd == ' ' || *lineEnd == '\r' || *lineEnd == '\n') + lineEnd++; + + // skip whitespace at the beginning of line + while (lineStart < comment && *lineStart == ' ') + lineStart++; + + if (lineStart < comment) + { + // there is a non-whitespace character before the end of the line or comment on that line + // assume : [#] syntax of the line + keyStart = lineStart; + ErrorIf(!colon, E_FAIL); // there is no colon on the line + ErrorIf(keyStart == colon, E_FAIL); // colon is the first non-whitespace character on the line + + // find end of key name + while (lineStart < colon && *lineStart != ' ') + lineStart++; + keyEnd = lineStart - 1; + + // skip whitespace between end of key name and colon + while (lineStart < colon && *lineStart == ' ') + lineStart++; + ErrorIf(lineStart != colon, E_FAIL); // non-whitespace character found + + // skip whitespace before value + lineStart++; + while (lineStart < comment && *lineStart == ' ') + lineStart++; + + if (lineStart == comment) + { + // empty value + valueStart = valueEnd = NULL; + } + else + { + valueStart = lineStart; + + // find end of value as a last non-whitespace character before comment + valueEnd = comment - 1; + while (valueEnd > valueStart && *valueEnd == ' ') + valueEnd--; + + CheckError(CModuleConfiguration::ApplyConfigOverrideKeyValue(context, config, keyStart, keyEnd, valueStart, valueEnd)); + } + + } + + // move on to the next line + lineStart = lineEnd; + } + + hr = S_OK; // fall through to cleanup in the Error section Error: - if (overridesHandle != INVALID_HANDLE_VALUE) - { - CloseHandle(overridesHandle); - overridesHandle = INVALID_HANDLE_VALUE; - } + if (overridesHandle != INVALID_HANDLE_VALUE) + { + CloseHandle(overridesHandle); + overridesHandle = INVALID_HANDLE_VALUE; + } - if (content) - { - delete [] content; - content = NULL; - } + if (content) + { + delete [] content; + content = NULL; + } - return S_OK == hr ? S_OK : IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE; + return S_OK == hr ? S_OK : IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE; } HRESULT CModuleConfiguration::TokenizePromoteServerVars(CModuleConfiguration* c) { - HRESULT hr; - size_t i; - size_t varLength; - LPWSTR start, end; - wchar_t terminator; - - if (c->promoteServerVarsRaw) - { - if (NULL != c->promoteServerVars) - { - for (int i = 0; i < c->promoteServerVarsCount; i++) - { - if (c->promoteServerVars[i]) - { - delete [] c->promoteServerVars[i]; - } - } - - delete [] c->promoteServerVars; - c->promoteServerVars = NULL; - } - - if (*c->promoteServerVarsRaw == L'\0') - { - c->promoteServerVarsCount = 0; - } - else - { - // determine number of server variables - - c->promoteServerVarsCount = 1; - start = c->promoteServerVarsRaw; - while (*start) - { - if (L',' == *start) - { - c->promoteServerVarsCount++; - } - - start++; - } - - // tokenize server variable names (comma delimited list) - - ErrorIf(NULL == (c->promoteServerVars = new char*[c->promoteServerVarsCount]), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(c->promoteServerVars, c->promoteServerVarsCount * sizeof(char*)); - - i = 0; - end = c->promoteServerVarsRaw; - while (*end) - { - start = end; - while (*end && L',' != *end) - { - end++; - } - - if (start != end) - { - terminator = *end; - *end = L'\0'; - ErrorIf(0 != wcstombs_s(&varLength, NULL, 0, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); - ErrorIf(NULL == (c->promoteServerVars[i] = new char[varLength]), ERROR_NOT_ENOUGH_MEMORY); - ErrorIf(0 != wcstombs_s(&varLength, c->promoteServerVars[i], varLength, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); - i++; - *end = terminator; - } - - if (*end) - { - end++; - } - } - } - - delete [] c->promoteServerVarsRaw; - c->promoteServerVarsRaw = NULL; - } - - return S_OK; + HRESULT hr; + size_t i; + size_t varLength; + LPWSTR start, end; + wchar_t terminator; + + if (c->promoteServerVarsRaw) + { + if (NULL != c->promoteServerVars) + { + for (int i = 0; i < c->promoteServerVarsCount; i++) + { + if (c->promoteServerVars[i]) + { + delete [] c->promoteServerVars[i]; + } + } + + delete [] c->promoteServerVars; + c->promoteServerVars = NULL; + } + + if (*c->promoteServerVarsRaw == L'\0') + { + c->promoteServerVarsCount = 0; + } + else + { + // determine number of server variables + + c->promoteServerVarsCount = 1; + start = c->promoteServerVarsRaw; + while (*start) + { + if (L',' == *start) + { + c->promoteServerVarsCount++; + } + + start++; + } + + // tokenize server variable names (comma delimited list) + + ErrorIf(NULL == (c->promoteServerVars = new char*[c->promoteServerVarsCount]), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(c->promoteServerVars, c->promoteServerVarsCount * sizeof(char*)); + + i = 0; + end = c->promoteServerVarsRaw; + while (*end) + { + start = end; + while (*end && L',' != *end) + { + end++; + } + + if (start != end) + { + terminator = *end; + *end = L'\0'; + ErrorIf(0 != wcstombs_s(&varLength, NULL, 0, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); + ErrorIf(NULL == (c->promoteServerVars[i] = new char[varLength]), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf(0 != wcstombs_s(&varLength, c->promoteServerVars[i], varLength, start, _TRUNCATE), ERROR_CAN_NOT_COMPLETE); + i++; + *end = terminator; + } + + if (*end) + { + end++; + } + } + } + + delete [] c->promoteServerVarsRaw; + c->promoteServerVarsRaw = NULL; + } + + return S_OK; Error: - return hr; + return hr; } HRESULT CModuleConfiguration::ApplyDefaults(CModuleConfiguration* c) @@ -1112,222 +1134,224 @@ HRESULT CModuleConfiguration::ApplyDefaults(CModuleConfiguration* c) c->asyncCompletionThreadCount = 0 == info.dwNumberOfProcessors ? 4 : info.dwNumberOfProcessors; } - if (0 == c->nodeProcessCountPerApplication) - { - // default number of node.exe processes to create per node.js application + if (0 == c->nodeProcessCountPerApplication) + { + // default number of node.exe processes to create per node.js application SYSTEM_INFO info; GetSystemInfo(&info); c->nodeProcessCountPerApplication = 0 == info.dwNumberOfProcessors ? 1 : info.dwNumberOfProcessors; - } + } - return S_OK; + return S_OK; } HRESULT CModuleConfiguration::EnsureCurrent(IHttpContext* context, CModuleConfiguration* config) { - HRESULT hr; + HRESULT hr; - if (config && CModuleConfiguration::invalid) - { - // yaml config has changed and needs to be re-read; this condition was set by the CFileWatcher + if (config && CModuleConfiguration::invalid) + { + // yaml config has changed and needs to be re-read; this condition was set by the CFileWatcher - ENTER_SRW_EXCLUSIVE(config->srwlock) + ENTER_SRW_EXCLUSIVE(config->srwlock) - if (CModuleConfiguration::invalid) - { - CheckError(CModuleConfiguration::ApplyYamlConfigOverrides(context, config)); + if (CModuleConfiguration::invalid) + { + CheckError(CModuleConfiguration::ApplyYamlConfigOverrides(context, config)); CheckError(CModuleConfiguration::GenerateDebuggerConfig(context, config)); - CheckError(CModuleConfiguration::TokenizePromoteServerVars(config)); - CheckError(CModuleConfiguration::ApplyDefaults(config)); - CModuleConfiguration::invalid = FALSE; - } + CheckError(CModuleConfiguration::TokenizePromoteServerVars(config)); + CheckError(CModuleConfiguration::ApplyDefaults(config)); + CModuleConfiguration::invalid = FALSE; + } - LEAVE_SRW_EXCLUSIVE(config->srwlock) - } + LEAVE_SRW_EXCLUSIVE(config->srwlock) + } - return S_OK; + return S_OK; Error: - return hr; + return hr; } HRESULT CModuleConfiguration::GetConfig(IHttpContext* context, CModuleConfiguration** config) { - HRESULT hr; - CModuleConfiguration* c = NULL; - IAppHostElement* section = NULL; - size_t i; - CheckNull(config); - - *config = (CModuleConfiguration*)context->GetMetadata()->GetModuleContextContainer()->GetModuleContext(moduleId); - - CheckError(CModuleConfiguration::EnsureCurrent(context, *config)); - - if (NULL == *config) - { - ErrorIf(NULL == (c = new CModuleConfiguration()), ERROR_NOT_ENOUGH_MEMORY); - - CheckError(GetConfigSection(context, §ion)); - CheckError(GetDWORD(section, L"asyncCompletionThreadCount", &c->asyncCompletionThreadCount)); - CheckError(GetDWORD(section, L"nodeProcessCountPerApplication", &c->nodeProcessCountPerApplication)); - CheckError(GetDWORD(section, L"maxConcurrentRequestsPerProcess", &c->maxConcurrentRequestsPerProcess)); - CheckError(GetDWORD(section, L"maxNamedPipeConnectionRetry", &c->maxNamedPipeConnectionRetry)); - CheckError(GetDWORD(section, L"namedPipeConnectionRetryDelay", &c->namedPipeConnectionRetryDelay)); - CheckError(GetDWORD(section, L"maxNamedPipeConnectionPoolSize", &c->maxNamedPipeConnectionPoolSize)); - CheckError(GetDWORD(section, L"maxNamedPipePooledConnectionAge", &c->maxNamedPipePooledConnectionAge)); - CheckError(GetDWORD(section, L"initialRequestBufferSize", &c->initialRequestBufferSize)); - CheckError(GetDWORD(section, L"maxRequestBufferSize", &c->maxRequestBufferSize)); - CheckError(GetDWORD(section, L"uncFileChangesPollingInterval", &c->uncFileChangesPollingInterval)); - CheckError(GetDWORD(section, L"gracefulShutdownTimeout", &c->gracefulShutdownTimeout)); - CheckError(GetDWORD(section, L"maxTotalLogFileSizeInKB", &c->maxTotalLogFileSizeInKB)); - CheckError(GetDWORD(section, L"maxLogFileSizeInKB", &c->maxLogFileSizeInKB)); - CheckError(GetDWORD(section, L"maxLogFiles", &c->maxLogFiles)); - CheckError(GetBOOL(section, L"loggingEnabled", &c->loggingEnabled, TRUE)); - CheckError(GetBOOL(section, L"devErrorsEnabled", &c->devErrorsEnabled, TRUE)); - CheckError(GetBOOL(section, L"flushResponse", &c->flushResponse, FALSE)); - CheckError(GetString(section, L"logDirectory", &c->logDirectory)); - CheckError(GetBOOL(section, L"debuggingEnabled", &c->debuggingEnabled, TRUE)); - CheckError(GetBOOL(section, L"debugHeaderEnabled", &c->debugHeaderEnabled, FALSE)); + HRESULT hr; + CModuleConfiguration* c = NULL; + IAppHostElement* section = NULL; + size_t i; + CheckNull(config); + + *config = (CModuleConfiguration*)context->GetMetadata()->GetModuleContextContainer()->GetModuleContext(moduleId); + + CheckError(CModuleConfiguration::EnsureCurrent(context, *config)); + + if (NULL == *config) + { + ErrorIf(NULL == (c = new CModuleConfiguration()), ERROR_NOT_ENOUGH_MEMORY); + + CheckError(GetConfigSection(context, §ion)); + CheckError(GetDWORD(section, L"asyncCompletionThreadCount", &c->asyncCompletionThreadCount)); + CheckError(GetDWORD(section, L"nodeProcessCountPerApplication", &c->nodeProcessCountPerApplication)); + CheckError(GetDWORD(section, L"maxConcurrentRequestsPerProcess", &c->maxConcurrentRequestsPerProcess)); + CheckError(GetDWORD(section, L"maxNamedPipeConnectionRetry", &c->maxNamedPipeConnectionRetry)); + CheckError(GetDWORD(section, L"namedPipeConnectionRetryDelay", &c->namedPipeConnectionRetryDelay)); + CheckError(GetDWORD(section, L"maxNamedPipeConnectionPoolSize", &c->maxNamedPipeConnectionPoolSize)); + CheckError(GetDWORD(section, L"maxNamedPipePooledConnectionAge", &c->maxNamedPipePooledConnectionAge)); + CheckError(GetDWORD(section, L"initialRequestBufferSize", &c->initialRequestBufferSize)); + CheckError(GetDWORD(section, L"maxRequestBufferSize", &c->maxRequestBufferSize)); + CheckError(GetDWORD(section, L"uncFileChangesPollingInterval", &c->uncFileChangesPollingInterval)); + CheckError(GetDWORD(section, L"gracefulShutdownTimeout", &c->gracefulShutdownTimeout)); + CheckError(GetDWORD(section, L"maxTotalLogFileSizeInKB", &c->maxTotalLogFileSizeInKB)); + CheckError(GetDWORD(section, L"maxLogFileSizeInKB", &c->maxLogFileSizeInKB)); + CheckError(GetDWORD(section, L"maxLogFiles", &c->maxLogFiles)); + CheckError(GetBOOL(section, L"loggingEnabled", &c->loggingEnabled, TRUE)); + CheckError(GetBOOL(section, L"devErrorsEnabled", &c->devErrorsEnabled, TRUE)); + CheckError(GetBOOL(section, L"flushResponse", &c->flushResponse, FALSE)); + CheckError(GetString(section, L"logDirectory", &c->logDirectory)); + CheckError(GetBOOL(section, L"debuggingEnabled", &c->debuggingEnabled, TRUE)); + CheckError(GetString(section, L"debuggerExtensionDll", &c->debuggerExtensionDll)); + CheckError(GetBOOL(section, L"debugHeaderEnabled", &c->debugHeaderEnabled, FALSE)); + CheckError(GetBOOL(section, L"recycleSignalEnabled", &c->recycleSignalEnabled, FALSE)); CheckError(GetString(section, L"debuggerVirtualDir", &c->debuggerVirtualDir)); c->debuggerVirtualDirLength = wcslen(c->debuggerVirtualDir); - CheckError(GetString(section, L"node_env", &c->node_env)); - CheckError(GetString(section, L"debuggerPortRange", &c->debugPortRange)); - CheckError(GetString(section, L"watchedFiles", &c->watchedFiles)); - CheckError(GetBOOL(section, L"enableXFF", &c->enableXFF, FALSE)); - CheckError(GetString(section, L"promoteServerVars", &c->promoteServerVarsRaw)); - CheckError(GetString(section, L"configOverrides", &c->configOverrides)); - CheckError(GetString(section, L"nodeProcessCommandLine", &c->nodeProcessCommandLine)); - CheckError(GetString(section, L"interceptor", &c->interceptor)); + CheckError(GetString(section, L"node_env", &c->node_env)); + CheckError(GetString(section, L"debuggerPortRange", &c->debugPortRange)); + CheckError(GetString(section, L"watchedFiles", &c->watchedFiles)); + CheckError(GetBOOL(section, L"enableXFF", &c->enableXFF, FALSE)); + CheckError(GetString(section, L"promoteServerVars", &c->promoteServerVarsRaw)); + CheckError(GetString(section, L"configOverrides", &c->configOverrides)); + CheckError(GetString(section, L"nodeProcessCommandLine", &c->nodeProcessCommandLine)); + CheckError(GetString(section, L"interceptor", &c->interceptor)); - // debuggerPathSegment + // debuggerPathSegment - CheckError(GetString(section, L"debuggerPathSegment", &c->debuggerPathSegment)); - c->debuggerPathSegmentLength = wcslen(c->debuggerPathSegment); + CheckError(GetString(section, L"debuggerPathSegment", &c->debuggerPathSegment)); + c->debuggerPathSegmentLength = wcslen(c->debuggerPathSegment); - // apply config setting overrides from the optional YAML configuration file + // apply config setting overrides from the optional YAML configuration file - CheckError(CModuleConfiguration::ApplyYamlConfigOverrides(context, c)); + CheckError(CModuleConfiguration::ApplyYamlConfigOverrides(context, c)); // generate debugger related config based on debuggerVirtualDir value. CheckError(CModuleConfiguration::GenerateDebuggerConfig(context, c)); - // tokenize promoteServerVars + // tokenize promoteServerVars - CheckError(CModuleConfiguration::TokenizePromoteServerVars(c)); + CheckError(CModuleConfiguration::TokenizePromoteServerVars(c)); - // done with section - - section->Release(); - section = NULL; + // done with section + + section->Release(); + section = NULL; // apply defaults - CheckError(CModuleConfiguration::ApplyDefaults(c)); - - // CR: check for ERROR_ALREADY_ASSIGNED to detect a race in creation of this section - // CR: refcounting may be needed if synchronous code paths proove too long (race with config changes) - context->GetMetadata()->GetModuleContextContainer()->SetModuleContext(c, moduleId); - *config = c; - c = NULL; - } + CheckError(CModuleConfiguration::ApplyDefaults(c)); + + // CR: check for ERROR_ALREADY_ASSIGNED to detect a race in creation of this section + // CR: refcounting may be needed if synchronous code paths proove too long (race with config changes) + context->GetMetadata()->GetModuleContextContainer()->SetModuleContext(c, moduleId); + *config = c; + c = NULL; + } - return S_OK; + return S_OK; Error: - if (NULL != section) - { - section->Release(); - section = NULL; - } + if (NULL != section) + { + section->Release(); + section = NULL; + } - if (NULL != c) - { - delete c; - c = NULL; - } + if (NULL != c) + { + delete c; + c = NULL; + } - return hr; + return hr; } void CModuleConfiguration::CleanupStoredContext() { - delete this; + delete this; } #define GETCONFIG(prop) \ - CModuleConfiguration* c; \ - GetConfig(ctx, &c); \ - return c->prop; + CModuleConfiguration* c; \ + GetConfig(ctx, &c); \ + return c->prop; DWORD CModuleConfiguration::GetAsyncCompletionThreadCount(IHttpContext* ctx) { - GETCONFIG(asyncCompletionThreadCount) + GETCONFIG(asyncCompletionThreadCount) } DWORD CModuleConfiguration::GetNodeProcessCountPerApplication(IHttpContext* ctx) { - GETCONFIG(nodeProcessCountPerApplication) + GETCONFIG(nodeProcessCountPerApplication) } LPWSTR CModuleConfiguration::GetNodeProcessCommandLine(IHttpContext* ctx) { - GETCONFIG(nodeProcessCommandLine) + GETCONFIG(nodeProcessCommandLine) } LPWSTR CModuleConfiguration::GetInterceptor(IHttpContext* ctx) { - GETCONFIG(interceptor) + GETCONFIG(interceptor) } DWORD CModuleConfiguration::GetMaxConcurrentRequestsPerProcess(IHttpContext* ctx) { - GETCONFIG(maxConcurrentRequestsPerProcess) + GETCONFIG(maxConcurrentRequestsPerProcess) } DWORD CModuleConfiguration::GetMaxNamedPipeConnectionRetry(IHttpContext* ctx) { - GETCONFIG(maxNamedPipeConnectionRetry) + GETCONFIG(maxNamedPipeConnectionRetry) } DWORD CModuleConfiguration::GetNamedPipeConnectionRetryDelay(IHttpContext* ctx) { - GETCONFIG(namedPipeConnectionRetryDelay) + GETCONFIG(namedPipeConnectionRetryDelay) } DWORD CModuleConfiguration::GetInitialRequestBufferSize(IHttpContext* ctx) { - GETCONFIG(initialRequestBufferSize) + GETCONFIG(initialRequestBufferSize) } DWORD CModuleConfiguration::GetMaxRequestBufferSize(IHttpContext* ctx) { - GETCONFIG(maxRequestBufferSize) + GETCONFIG(maxRequestBufferSize) } DWORD CModuleConfiguration::GetUNCFileChangesPollingInterval(IHttpContext* ctx) { - GETCONFIG(uncFileChangesPollingInterval) + GETCONFIG(uncFileChangesPollingInterval) } DWORD CModuleConfiguration::GetGracefulShutdownTimeout(IHttpContext* ctx) { - GETCONFIG(gracefulShutdownTimeout) + GETCONFIG(gracefulShutdownTimeout) } LPWSTR CModuleConfiguration::GetLogDirectory(IHttpContext* ctx) { - GETCONFIG(logDirectory) + GETCONFIG(logDirectory) } LPWSTR CModuleConfiguration::GetDebuggerPathSegment(IHttpContext* ctx) { - GETCONFIG(debuggerPathSegment) + GETCONFIG(debuggerPathSegment) } DWORD CModuleConfiguration::GetDebuggerPathSegmentLength(IHttpContext* ctx) { - GETCONFIG(debuggerPathSegmentLength) + GETCONFIG(debuggerPathSegmentLength) } LPWSTR CModuleConfiguration::GetDebuggerVirtualDir(IHttpContext* ctx) @@ -1357,73 +1381,82 @@ DWORD CModuleConfiguration::GetDebuggerFilesPathSegmentLength(IHttpContext* ctx) DWORD CModuleConfiguration::GetMaxTotalLogFileSizeInKB(IHttpContext* ctx) { - GETCONFIG(maxTotalLogFileSizeInKB) + GETCONFIG(maxTotalLogFileSizeInKB) } DWORD CModuleConfiguration::GetMaxLogFileSizeInKB(IHttpContext* ctx) { - GETCONFIG(maxLogFileSizeInKB) + GETCONFIG(maxLogFileSizeInKB) } DWORD CModuleConfiguration::GetMaxLogFiles(IHttpContext* ctx) { - GETCONFIG(maxLogFiles) + GETCONFIG(maxLogFiles) } BOOL CModuleConfiguration::GetLoggingEnabled(IHttpContext* ctx) { - GETCONFIG(loggingEnabled); + GETCONFIG(loggingEnabled); } BOOL CModuleConfiguration::GetDebuggingEnabled(IHttpContext* ctx) { - GETCONFIG(debuggingEnabled) + GETCONFIG(debuggingEnabled) +} + +PWSTR CModuleConfiguration::GetDebuggerExtensionDll(IHttpContext* ctx) +{ + GETCONFIG(debuggerExtensionDll) } BOOL CModuleConfiguration::GetDebugHeaderEnabled(IHttpContext* ctx) { - GETCONFIG(debugHeaderEnabled) + GETCONFIG(debugHeaderEnabled) } +BOOL CModuleConfiguration::GetRecycleSignalEnabled(IHttpContext* ctx) +{ + GETCONFIG(recycleSignalEnabled) +} LPWSTR CModuleConfiguration::GetNodeEnv(IHttpContext* ctx) { - GETCONFIG(node_env) + GETCONFIG(node_env) } BOOL CModuleConfiguration::GetDevErrorsEnabled(IHttpContext* ctx) { - GETCONFIG(devErrorsEnabled) + GETCONFIG(devErrorsEnabled) } BOOL CModuleConfiguration::GetFlushResponse(IHttpContext* ctx) { - GETCONFIG(flushResponse) + GETCONFIG(flushResponse) } LPWSTR CModuleConfiguration::GetWatchedFiles(IHttpContext* ctx) { - GETCONFIG(watchedFiles) + GETCONFIG(watchedFiles) } DWORD CModuleConfiguration::GetMaxNamedPipeConnectionPoolSize(IHttpContext* ctx) { - GETCONFIG(maxNamedPipeConnectionPoolSize) + GETCONFIG(maxNamedPipeConnectionPoolSize) } DWORD CModuleConfiguration::GetMaxNamedPipePooledConnectionAge(IHttpContext* ctx) { - GETCONFIG(maxNamedPipePooledConnectionAge) + GETCONFIG(maxNamedPipePooledConnectionAge) } BOOL CModuleConfiguration::GetEnableXFF(IHttpContext* ctx) { - GETCONFIG(enableXFF) + GETCONFIG(enableXFF) } LPWSTR CModuleConfiguration::GetConfigOverrides(IHttpContext* ctx) { - GETCONFIG(configOverrides) + GETCONFIG(configOverrides) } HRESULT CModuleConfiguration::GenerateDebuggerConfig(IHttpContext* context, CModuleConfiguration *config) @@ -1462,46 +1495,46 @@ HRESULT CModuleConfiguration::GenerateDebuggerConfig(IHttpContext* context, CMod HRESULT CModuleConfiguration::GetDebugPortRange(IHttpContext* ctx, DWORD* start, DWORD* end) { - HRESULT hr; - - CheckNull(start); - CheckNull(end); - - CModuleConfiguration* c = NULL; - CheckError(GetConfig(ctx, &c)); - - if (0 == c->debugPortStart) - { - CheckNull(c->debugPortRange); - LPWSTR dash = c->debugPortRange; - while (*dash != L'\0' && *dash != L'-') - dash++; - ErrorIf(dash == c->debugPortRange, ERROR_INVALID_PARAMETER); - c->debugPortStart = _wtoi(c->debugPortRange); - ErrorIf(c->debugPortStart < 1025, ERROR_INVALID_PARAMETER); - if (*dash != L'\0') - { - c->debugPortEnd = _wtoi(dash + 1); - ErrorIf(c->debugPortEnd < c->debugPortStart || c->debugPortEnd > 65535, ERROR_INVALID_PARAMETER); - } - else - { - c->debugPortEnd = c->debugPortStart; - } - } - - *start = c->debugPortStart; - *end = c->debugPortEnd; - - return S_OK; + HRESULT hr; + + CheckNull(start); + CheckNull(end); + + CModuleConfiguration* c = NULL; + CheckError(GetConfig(ctx, &c)); + + if (0 == c->debugPortStart) + { + CheckNull(c->debugPortRange); + LPWSTR dash = c->debugPortRange; + while (*dash != L'\0' && *dash != L'-') + dash++; + ErrorIf(dash == c->debugPortRange, ERROR_INVALID_PARAMETER); + c->debugPortStart = _wtoi(c->debugPortRange); + ErrorIf(c->debugPortStart < 1025, ERROR_INVALID_PARAMETER); + if (*dash != L'\0') + { + c->debugPortEnd = _wtoi(dash + 1); + ErrorIf(c->debugPortEnd < c->debugPortStart || c->debugPortEnd > 65535, ERROR_INVALID_PARAMETER); + } + else + { + c->debugPortEnd = c->debugPortStart; + } + } + + *start = c->debugPortStart; + *end = c->debugPortEnd; + + return S_OK; Error: - if (c) - { - c->debugPortStart = c->debugPortEnd = 0; - } + if (c) + { + c->debugPortStart = c->debugPortEnd = 0; + } - return hr; + return hr; } // @@ -1518,9 +1551,9 @@ HRESULT CModuleConfiguration::GetDebuggerFilesPathSegmentHelper( HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; CHAR rgbDigits[] = "0123456789abcdef"; - BYTE rgbHash[MAX_HASH_CHAR]; // sha256 ==> 32 bytes. + BYTE rgbHash[32]; // sha256 ==> 32 bytes. DWORD cbHash = 0; - CHAR shaHash[MAX_HASH_CHAR + 1]; // we will only use first 16 bytes of the sha256 hash ==> 32 hex chars. + CHAR shaHash[MAX_HASH_CHAR + 1]; // we will only use first MAX_HASH_CHAR bytes of the sha256 hash ==> 32 hex chars. DWORD dwSHALength = 0; CHAR *pInput = NULL; DWORD dwInputSize = 0; @@ -1548,12 +1581,13 @@ HRESULT CModuleConfiguration::GetDebuggerFilesPathSegmentHelper( ErrorIf(!CryptHashData(hHash, (BYTE*) pInput, strnlen_s(pInput, dwInputSize), 0), HRESULT_FROM_WIN32(GetLastError())); - cbHash = MAX_HASH_CHAR; + // sha256 ==> 32 bytes. + cbHash = 32; ErrorIf(!CryptGetHashParam(hHash, HP_HASHVAL, rgbHash, &cbHash, 0), HRESULT_FROM_WIN32(GetLastError())); dwIndex = 0; - // convert first 16 bytes to hexadecimal form. - for (DWORD i = 0; i < 16; i++, dwIndex=dwIndex+2) + // convert first (MAX_HASH_CHAR / 2) bytes to hexadecimal form. + for (DWORD i = 0; i < (MAX_HASH_CHAR / 2); i++, dwIndex=dwIndex+2) { shaHash[dwIndex] = rgbDigits[rgbHash[i] >> 4]; shaHash[dwIndex+1] = rgbDigits[rgbHash[i] & 0xf]; @@ -1780,18 +1814,18 @@ HRESULT CModuleConfiguration::GetDebuggerVirtualDirPhysicalPathFromConfig( HRESULT CModuleConfiguration::GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count) { - HRESULT hr; + HRESULT hr; - CheckNull(vars); - CheckNull(count); + CheckNull(vars); + CheckNull(count); - CModuleConfiguration* c = NULL; - CheckError(GetConfig(ctx, &c)); + CModuleConfiguration* c = NULL; + CheckError(GetConfig(ctx, &c)); - *vars = c->promoteServerVars; - *count = c->promoteServerVarsCount; + *vars = c->promoteServerVars; + *count = c->promoteServerVarsCount; - return S_OK; + return S_OK; Error: - return hr; + return hr; } \ No newline at end of file diff --git a/src/iisnode/cmoduleconfiguration.h b/src/iisnode/cmoduleconfiguration.h index 5aa2965b..70ea22e7 100644 --- a/src/iisnode/cmoduleconfiguration.h +++ b/src/iisnode/cmoduleconfiguration.h @@ -7,64 +7,66 @@ class CModuleConfiguration : public IHttpStoredContext { private: - DWORD asyncCompletionThreadCount; - DWORD nodeProcessCountPerApplication; - LPWSTR nodeProcessCommandLine; - LPWSTR interceptor; - DWORD maxConcurrentRequestsPerProcess; - DWORD maxNamedPipeConnectionRetry; - DWORD namedPipeConnectionRetryDelay; - DWORD initialRequestBufferSize; - DWORD maxRequestBufferSize; - DWORD uncFileChangesPollingInterval; - DWORD gracefulShutdownTimeout; - LPWSTR logDirectory; - LPWSTR debuggerPathSegment; - DWORD debuggerPathSegmentLength; + DWORD asyncCompletionThreadCount; + DWORD nodeProcessCountPerApplication; + LPWSTR nodeProcessCommandLine; + LPWSTR interceptor; + DWORD maxConcurrentRequestsPerProcess; + DWORD maxNamedPipeConnectionRetry; + DWORD namedPipeConnectionRetryDelay; + DWORD initialRequestBufferSize; + DWORD maxRequestBufferSize; + DWORD uncFileChangesPollingInterval; + DWORD gracefulShutdownTimeout; + LPWSTR logDirectory; + LPWSTR debuggerPathSegment; + DWORD debuggerPathSegmentLength; LPWSTR debuggerFilesPathSegment; DWORD debuggerFilesPathSegmentLength; - DWORD maxLogFileSizeInKB; - DWORD maxTotalLogFileSizeInKB; - DWORD maxLogFiles; - BOOL loggingEnabled; - BOOL debuggingEnabled; - BOOL debugHeaderEnabled; + DWORD maxLogFileSizeInKB; + DWORD maxTotalLogFileSizeInKB; + DWORD maxLogFiles; + BOOL loggingEnabled; + BOOL debuggingEnabled; + PWSTR debuggerExtensionDll; + BOOL debugHeaderEnabled; + BOOL recycleSignalEnabled; LPWSTR debuggerVirtualDir; DWORD debuggerVirtualDirLength; LPWSTR debuggerVirtualDirPhysicalPath; - LPWSTR debugPortRange; - DWORD debugPortStart; - DWORD debugPortEnd; - LPWSTR node_env; - BOOL devErrorsEnabled; - BOOL flushResponse; - LPWSTR watchedFiles; - DWORD maxNamedPipeConnectionPoolSize; - DWORD maxNamedPipePooledConnectionAge; - BOOL enableXFF; - char** promoteServerVars; - int promoteServerVarsCount; - LPWSTR promoteServerVarsRaw; - LPWSTR configOverridesFileName; - static BOOL invalid; - SRWLOCK srwlock; - LPWSTR configOverrides; + LPWSTR debugPortRange; + DWORD debugPortStart; + DWORD debugPortEnd; + LPWSTR node_env; + BOOL devErrorsEnabled; + BOOL flushResponse; + LPWSTR watchedFiles; + DWORD maxNamedPipeConnectionPoolSize; + DWORD maxNamedPipePooledConnectionAge; + BOOL enableXFF; + char** promoteServerVars; + int promoteServerVarsCount; + LPWSTR promoteServerVarsRaw; + LPWSTR configOverridesFileName; + static BOOL invalid; + SRWLOCK srwlock; + LPWSTR configOverrides; - static IHttpServer* server; - static HTTP_MODULE_ID moduleId; - static HRESULT GetConfigSection(IHttpContext* context, IAppHostElement** section, OLECHAR* configElement = L"system.webServer/iisnode"); - static HRESULT GetString(IAppHostElement* section, LPCWSTR propertyName, LPWSTR* value); - static HRESULT GetBOOL(IAppHostElement* section, LPCWSTR propertyName, BOOL* value, BOOL defaultValue); - static HRESULT GetDWORD(char* str, DWORD* value); - static HRESULT GetBOOL(char* str, BOOL* value); - static HRESULT GetString(char* str, LPWSTR* value, BOOL expandEnvironmentStrings = FALSE); - static HRESULT GetDWORD(IAppHostElement* section, LPCWSTR propertyName, DWORD* value); - static HRESULT ApplyConfigOverrideKeyValue(IHttpContext* context, CModuleConfiguration* config, char* keyStart, char* keyEnd, char* valueStart, char* valueEnd); - static HRESULT ApplyYamlConfigOverrides(IHttpContext* context, CModuleConfiguration* config); - static HRESULT TokenizePromoteServerVars(CModuleConfiguration* c); - static HRESULT ApplyDefaults(CModuleConfiguration* c); - static HRESULT EnsureCurrent(IHttpContext* context, CModuleConfiguration* config); - static HRESULT GetEnvVariable(LPCWSTR propertyName, LPWSTR buffer, DWORD bufferSize, LPWSTR* result); + static IHttpServer* server; + static HTTP_MODULE_ID moduleId; + static HRESULT GetConfigSection(IHttpContext* context, IAppHostElement** section, OLECHAR* configElement = L"system.webServer/iisnode"); + static HRESULT GetString(IAppHostElement* section, LPCWSTR propertyName, LPWSTR* value); + static HRESULT GetBOOL(IAppHostElement* section, LPCWSTR propertyName, BOOL* value, BOOL defaultValue); + static HRESULT GetDWORD(char* str, DWORD* value); + static HRESULT GetBOOL(char* str, BOOL* value); + static HRESULT GetString(char* str, LPWSTR* value, BOOL expandEnvironmentStrings = FALSE); + static HRESULT GetDWORD(IAppHostElement* section, LPCWSTR propertyName, DWORD* value); + static HRESULT ApplyConfigOverrideKeyValue(IHttpContext* context, CModuleConfiguration* config, char* keyStart, char* keyEnd, char* valueStart, char* valueEnd); + static HRESULT ApplyYamlConfigOverrides(IHttpContext* context, CModuleConfiguration* config); + static HRESULT TokenizePromoteServerVars(CModuleConfiguration* c); + static HRESULT ApplyDefaults(CModuleConfiguration* c); + static HRESULT EnsureCurrent(IHttpContext* context, CModuleConfiguration* config); + static HRESULT GetEnvVariable(LPCWSTR propertyName, LPWSTR buffer, DWORD bufferSize, LPWSTR* result); static HRESULT GenerateDebuggerConfig(IHttpContext* context, CModuleConfiguration *config); static HRESULT GetDebuggerVirtualDirPhysicalPathFromConfig( DWORD siteId, @@ -79,56 +81,58 @@ class CModuleConfiguration : public IHttpStoredContext DWORD *pdwDebuggerFilesPathSegmentSize ); - CModuleConfiguration(); - ~CModuleConfiguration(); + CModuleConfiguration(); + ~CModuleConfiguration(); public: - static HRESULT Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId); + static HRESULT Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId); - static HRESULT GetConfig(IHttpContext* context, CModuleConfiguration** config); + static HRESULT GetConfig(IHttpContext* context, CModuleConfiguration** config); - static DWORD GetAsyncCompletionThreadCount(IHttpContext* ctx); - static DWORD GetNodeProcessCountPerApplication(IHttpContext* ctx); - static LPWSTR GetNodeProcessCommandLine(IHttpContext* ctx); - static LPWSTR GetInterceptor(IHttpContext* ctx); - static DWORD GetMaxConcurrentRequestsPerProcess(IHttpContext* ctx); - static DWORD GetMaxNamedPipeConnectionRetry(IHttpContext* ctx); - static DWORD GetNamedPipeConnectionRetryDelay(IHttpContext* ctx); - static DWORD GetInitialRequestBufferSize(IHttpContext* ctx); - static DWORD GetMaxRequestBufferSize(IHttpContext* ctx); - static DWORD GetUNCFileChangesPollingInterval(IHttpContext* ctx); - static DWORD GetGracefulShutdownTimeout(IHttpContext* ctx); - static LPWSTR GetLogDirectory(IHttpContext* ctx); - static LPWSTR GetDebuggerPathSegment(IHttpContext* ctx); - static DWORD GetDebuggerPathSegmentLength(IHttpContext* ctx); + static DWORD GetAsyncCompletionThreadCount(IHttpContext* ctx); + static DWORD GetNodeProcessCountPerApplication(IHttpContext* ctx); + static LPWSTR GetNodeProcessCommandLine(IHttpContext* ctx); + static LPWSTR GetInterceptor(IHttpContext* ctx); + static DWORD GetMaxConcurrentRequestsPerProcess(IHttpContext* ctx); + static DWORD GetMaxNamedPipeConnectionRetry(IHttpContext* ctx); + static DWORD GetNamedPipeConnectionRetryDelay(IHttpContext* ctx); + static DWORD GetInitialRequestBufferSize(IHttpContext* ctx); + static DWORD GetMaxRequestBufferSize(IHttpContext* ctx); + static DWORD GetUNCFileChangesPollingInterval(IHttpContext* ctx); + static DWORD GetGracefulShutdownTimeout(IHttpContext* ctx); + static LPWSTR GetLogDirectory(IHttpContext* ctx); + static LPWSTR GetDebuggerPathSegment(IHttpContext* ctx); + static DWORD GetDebuggerPathSegmentLength(IHttpContext* ctx); static LPWSTR GetDebuggerFilesPathSegment(IHttpContext* ctx); static DWORD GetDebuggerFilesPathSegmentLength(IHttpContext* ctx); - static DWORD GetMaxLogFileSizeInKB(IHttpContext* ctx); - static DWORD GetMaxTotalLogFileSizeInKB(IHttpContext* ctx); - static DWORD GetMaxLogFiles(IHttpContext* ctx); - static BOOL GetLoggingEnabled(IHttpContext* ctx); - static BOOL GetDebuggingEnabled(IHttpContext* ctx); - static BOOL GetDebugHeaderEnabled(IHttpContext* ctx); + static DWORD GetMaxLogFileSizeInKB(IHttpContext* ctx); + static DWORD GetMaxTotalLogFileSizeInKB(IHttpContext* ctx); + static DWORD GetMaxLogFiles(IHttpContext* ctx); + static BOOL GetLoggingEnabled(IHttpContext* ctx); + static BOOL GetDebuggingEnabled(IHttpContext* ctx); + static PWSTR GetDebuggerExtensionDll(IHttpContext* ctx); + static BOOL GetDebugHeaderEnabled(IHttpContext* ctx); static LPWSTR GetDebuggerVirtualDir(IHttpContext* ctx); static DWORD GetDebuggerVirtualDirLength(IHttpContext* ctx); static LPWSTR GetDebuggerVirtualDirPhysicalPath(IHttpContext* ctx); - static HRESULT GetDebugPortRange(IHttpContext* ctx, DWORD* start, DWORD* end); - static LPWSTR GetNodeEnv(IHttpContext* ctx); - static BOOL GetDevErrorsEnabled(IHttpContext* ctx); - static BOOL GetFlushResponse(IHttpContext* ctx); - static LPWSTR GetWatchedFiles(IHttpContext* ctx); - static DWORD GetMaxNamedPipeConnectionPoolSize(IHttpContext* ctx); - static DWORD GetMaxNamedPipePooledConnectionAge(IHttpContext* ctx); - static BOOL GetEnableXFF(IHttpContext* ctx); - static HRESULT GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count); - static LPWSTR GetConfigOverrides(IHttpContext* ctx); + static BOOL GetRecycleSignalEnabled(IHttpContext* ctx); + static HRESULT GetDebugPortRange(IHttpContext* ctx, DWORD* start, DWORD* end); + static LPWSTR GetNodeEnv(IHttpContext* ctx); + static BOOL GetDevErrorsEnabled(IHttpContext* ctx); + static BOOL GetFlushResponse(IHttpContext* ctx); + static LPWSTR GetWatchedFiles(IHttpContext* ctx); + static DWORD GetMaxNamedPipeConnectionPoolSize(IHttpContext* ctx); + static DWORD GetMaxNamedPipePooledConnectionAge(IHttpContext* ctx); + static BOOL GetEnableXFF(IHttpContext* ctx); + static HRESULT GetPromoteServerVars(IHttpContext* ctx, char*** vars, int* count); + static LPWSTR GetConfigOverrides(IHttpContext* ctx); - static HRESULT CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH* env); + static HRESULT CreateNodeEnvironment(IHttpContext* ctx, DWORD debugPort, PCH namedPipe, PCH signalPipeName, PCH* env); - static void Invalidate(); + static void Invalidate(); - virtual void CleanupStoredContext(); + virtual void CleanupStoredContext(); }; #endif \ No newline at end of file diff --git a/src/iisnode/cnodeapplication.cpp b/src/iisnode/cnodeapplication.cpp index 6aa4949e..f3fa41ca 100644 --- a/src/iisnode/cnodeapplication.cpp +++ b/src/iisnode/cnodeapplication.cpp @@ -1,161 +1,192 @@ #include "precomp.h" CNodeApplication::CNodeApplication(CNodeApplicationManager* applicationManager, BOOL isDebugger, NodeDebugCommand debugCommand, DWORD debugPort) - : applicationManager(applicationManager), scriptName(NULL), processManager(NULL), - isDebugger(isDebugger), peerApplication(NULL), debugCommand(debugCommand), debugPort(debugPort), needsRecycling(FALSE) + : applicationManager(applicationManager), scriptName(NULL), processManager(NULL), + isDebugger(isDebugger), peerApplication(NULL), debugCommand(debugCommand), + debugPort(debugPort), needsRecycling(FALSE), configPath(NULL) { } CNodeApplication::~CNodeApplication() { - this->Cleanup(); + this->Cleanup(); } void CNodeApplication::Cleanup() { - this->GetApplicationManager()->GetFileWatcher()->RemoveWatch(this); + this->GetApplicationManager()->GetFileWatcher()->RemoveWatch(this); - if (NULL != this->scriptName) - { - delete [] this->scriptName; - this->scriptName = NULL; - } + if (NULL != this->scriptName) + { + delete [] this->scriptName; + this->scriptName = NULL; + } - if (NULL != this->processManager) - { - this->processManager->DecRef(); // incremented in CNodeProcessManager::ctor - this->processManager = NULL; - } + if (NULL != this->configPath) + { + delete [] this->configPath; + this->configPath = NULL; + } + + if (NULL != this->processManager) + { + this->processManager->DecRef(); // incremented in CNodeProcessManager::ctor + this->processManager = NULL; + } } HRESULT CNodeApplication::Initialize(PCWSTR scriptName, IHttpContext* context) { - HRESULT hr; + HRESULT hr; - CheckNull(scriptName); + CheckNull(scriptName); - DWORD len = wcslen(scriptName) + 1; - ErrorIf(NULL == (this->scriptName = new WCHAR[len]), ERROR_NOT_ENOUGH_MEMORY); - wcscpy(this->scriptName, scriptName); + DWORD len = wcslen(scriptName) + 1; + ErrorIf(NULL == (this->scriptName = new WCHAR[len]), ERROR_NOT_ENOUGH_MEMORY); + wcscpy(this->scriptName, scriptName); - ErrorIf(NULL == (this->processManager = new CNodeProcessManager(this, context)), ERROR_NOT_ENOUGH_MEMORY); - CheckError(this->processManager->Initialize(context)); + ErrorIf(NULL == (this->processManager = new CNodeProcessManager(this, context)), ERROR_NOT_ENOUGH_MEMORY); + CheckError(this->processManager->Initialize(context)); + + CheckError(this->SetConfigPath(context)); - CheckError(this->GetApplicationManager()->GetFileWatcher()->WatchFiles( - scriptName, - CModuleConfiguration::GetWatchedFiles(context), - CNodeApplicationManager::OnScriptModified, - this->GetApplicationManager(), - this)); + CheckError(this->GetApplicationManager()->GetFileWatcher()->WatchFiles( + scriptName, + CModuleConfiguration::GetWatchedFiles(context), + CNodeApplicationManager::OnScriptModified, + this->GetApplicationManager(), + this)); - this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode initialized a new node.js application", WINEVENT_LEVEL_INFO); + this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode initialized a new node.js application", WINEVENT_LEVEL_INFO); - return S_OK; + return S_OK; Error: - this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode failed to initialize a new node.js application", WINEVENT_LEVEL_ERROR); + this->GetApplicationManager()->GetEventProvider()->Log(L"iisnode failed to initialize a new node.js application", WINEVENT_LEVEL_ERROR); + + this->Cleanup(); + + return hr; +} + +PCWSTR CNodeApplication::GetConfigPath() +{ + return this->configPath; +} - this->Cleanup(); +HRESULT CNodeApplication::SetConfigPath(IHttpContext * context) +{ + HRESULT hr = S_OK; + DWORD dwConfigPathLen = wcslen(context->GetMetadata()->GetMetaPath()); + if(this->configPath != NULL) + { + delete [] this->configPath; + this->configPath = NULL; + } - return hr; + ErrorIf(NULL == (this->configPath = new WCHAR[dwConfigPathLen + 1]), E_OUTOFMEMORY); + wcscpy(this->configPath, context->GetMetadata()->GetMetaPath()); + +Error: + return hr; } PCWSTR CNodeApplication::GetScriptName() { - return this->scriptName; + return this->scriptName; } CNodeApplicationManager* CNodeApplication::GetApplicationManager() { - return this->applicationManager; + return this->applicationManager; } HRESULT CNodeApplication::Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx) { - HRESULT hr; + HRESULT hr; - CheckNull(ctx); - CheckNull(context); - CheckNull(pProvider); + CheckNull(ctx); + CheckNull(context); + CheckNull(pProvider); - ErrorIf(NULL == (*ctx = new CNodeHttpStoredContext(this, this->GetApplicationManager()->GetEventProvider(), context)), ERROR_NOT_ENOUGH_MEMORY); - IHttpModuleContextContainer* moduleContextContainer = context->GetModuleContextContainer(); - moduleContextContainer->SetModuleContext(*ctx, this->GetApplicationManager()->GetModuleId()); + ErrorIf(NULL == (*ctx = new CNodeHttpStoredContext(this, this->GetApplicationManager()->GetEventProvider(), context)), ERROR_NOT_ENOUGH_MEMORY); + IHttpModuleContextContainer* moduleContextContainer = context->GetModuleContextContainer(); + moduleContextContainer->SetModuleContext(*ctx, this->GetApplicationManager()->GetModuleId()); - // increase the pending async opertation count; corresponding decrease happens in - // CProtocolBridge::FinalizeResponseCore, possibly after several context switches - (*ctx)->IncreasePendingAsyncOperationCount(); + // increase the pending async opertation count; corresponding decrease happens in + // CProtocolBridge::FinalizeResponseCore, possibly after several context switches + (*ctx)->IncreasePendingAsyncOperationCount(); - // At this point ownership of the request is handed over to Dispach below, including error handling. - // Therefore we don't propagate any errors up the stack. - this->processManager->Dispatch(*ctx); + // At this point ownership of the request is handed over to Dispach below, including error handling. + // Therefore we don't propagate any errors up the stack. + this->processManager->Dispatch(*ctx); - return S_OK; + return S_OK; Error: - // on error, nodeContext need not be freed here as it will be deallocated through IHttpStoredContext when the request is finished + // on error, nodeContext need not be freed here as it will be deallocated through IHttpStoredContext when the request is finished - return hr; + return hr; } CNodeApplication* CNodeApplication::GetPeerApplication() { - return this->peerApplication; + return this->peerApplication; } void CNodeApplication::SetPeerApplication(CNodeApplication* peerApplication) { - this->peerApplication = peerApplication; + this->peerApplication = peerApplication; } BOOL CNodeApplication::IsDebugger() { - return this->isDebugger; + return this->isDebugger; } BOOL CNodeApplication::IsDebuggee() { - return !this->IsDebugger() && NULL != this->GetPeerApplication(); + return !this->IsDebugger() && NULL != this->GetPeerApplication(); } BOOL CNodeApplication::IsDebugMode() { - return this->IsDebuggee() || this->IsDebugger(); + return this->IsDebuggee() || this->IsDebugger(); } NodeDebugCommand CNodeApplication::GetDebugCommand() { - return this->debugCommand; + return this->debugCommand; } HRESULT CNodeApplication::Recycle() { - return this->processManager->Recycle(); + return this->processManager->Recycle(); } DWORD CNodeApplication::GetDebugPort() { - return this->debugPort; + return this->debugPort; } DWORD CNodeApplication::GetActiveRequestCount() { - return this->processManager->GetActiveRequestCount(); + return this->processManager->GetActiveRequestCount(); } DWORD CNodeApplication::GetProcessCount() { - return this->processManager->GetProcessCount(); + return this->processManager->GetProcessCount(); } void CNodeApplication::SetNeedsRecycling() { - this->needsRecycling = TRUE; + this->needsRecycling = TRUE; } BOOL CNodeApplication::GetNeedsRecycling() { - return this->needsRecycling; + return this->needsRecycling; } diff --git a/src/iisnode/cnodeapplication.h b/src/iisnode/cnodeapplication.h index 0b8c65c0..8b3190bd 100644 --- a/src/iisnode/cnodeapplication.h +++ b/src/iisnode/cnodeapplication.h @@ -10,38 +10,41 @@ class CNodeApplication { private: - PWSTR scriptName; - CNodeApplicationManager* applicationManager; - CNodeProcessManager* processManager; - CNodeApplication* peerApplication; - BOOL isDebugger; - NodeDebugCommand debugCommand; - DWORD debugPort; - BOOL needsRecycling; - - void Cleanup(); + PWSTR scriptName; + PWSTR configPath; + CNodeApplicationManager* applicationManager; + CNodeProcessManager* processManager; + CNodeApplication* peerApplication; + BOOL isDebugger; + NodeDebugCommand debugCommand; + DWORD debugPort; + BOOL needsRecycling; + + void Cleanup(); public: - CNodeApplication(CNodeApplicationManager* applicationManager, BOOL isDebugger, NodeDebugCommand debugCommand, DWORD debugPort); - ~CNodeApplication(); - - HRESULT Initialize(PCWSTR scriptName, IHttpContext* context); - PCWSTR GetScriptName(); - CNodeApplicationManager* GetApplicationManager(); - HRESULT Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx); - CNodeApplication* GetPeerApplication(); - void SetPeerApplication(CNodeApplication* peerApplication); - BOOL IsDebugger(); - BOOL IsDebuggee(); - BOOL IsDebugMode(); - NodeDebugCommand GetDebugCommand(); - HRESULT Recycle(); - DWORD GetDebugPort(); - DWORD GetActiveRequestCount(); - DWORD GetProcessCount(); - void SetNeedsRecycling(); - BOOL GetNeedsRecycling(); + CNodeApplication(CNodeApplicationManager* applicationManager, BOOL isDebugger, NodeDebugCommand debugCommand, DWORD debugPort); + ~CNodeApplication(); + + HRESULT Initialize(PCWSTR scriptName, IHttpContext* context); + PCWSTR GetScriptName(); + PCWSTR GetConfigPath(); + HRESULT SetConfigPath(IHttpContext* context); + CNodeApplicationManager* GetApplicationManager(); + HRESULT Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx); + CNodeApplication* GetPeerApplication(); + void SetPeerApplication(CNodeApplication* peerApplication); + BOOL IsDebugger(); + BOOL IsDebuggee(); + BOOL IsDebugMode(); + NodeDebugCommand GetDebugCommand(); + HRESULT Recycle(); + DWORD GetDebugPort(); + DWORD GetActiveRequestCount(); + DWORD GetProcessCount(); + void SetNeedsRecycling(); + BOOL GetNeedsRecycling(); }; #endif \ No newline at end of file diff --git a/src/iisnode/cnodeapplicationmanager.cpp b/src/iisnode/cnodeapplicationmanager.cpp index fd009c17..e3ac4f83 100644 --- a/src/iisnode/cnodeapplicationmanager.cpp +++ b/src/iisnode/cnodeapplicationmanager.cpp @@ -1,9 +1,11 @@ #include "precomp.h" +#include CNodeApplicationManager::CNodeApplicationManager(IHttpServer* server, HTTP_MODULE_ID moduleId) : server(server), moduleId(moduleId), applications(NULL), asyncManager(NULL), jobObject(NULL), breakAwayFromJobObject(FALSE), fileWatcher(NULL), initialized(FALSE), eventProvider(NULL), - currentDebugPort(0), inspector(NULL), totalRequests(0) + currentDebugPort(0), inspector(NULL), totalRequests(0), controlSignalHandlerThread(NULL), + signalPipe(NULL), signalPipeName(NULL), pPipeSecAttr(NULL) { InitializeSRWLock(&this->srwlock); } @@ -11,22 +13,22 @@ CNodeApplicationManager::CNodeApplicationManager(IHttpServer* server, HTTP_MODUL HRESULT CNodeApplicationManager::Initialize(IHttpContext* context) { HRESULT hr = S_OK; - CModuleConfiguration *config; + CModuleConfiguration *config; - if (S_OK != (hr = CModuleConfiguration::GetConfig(context, &config))) - { - hr = IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE == hr ? hr : IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION; - } - else if (!this->initialized) + if (S_OK != (hr = CModuleConfiguration::GetConfig(context, &config))) { - ENTER_SRW_EXCLUSIVE(this->srwlock) + hr = IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE == hr ? hr : IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION; + } + else if (!this->initialized) + { + ENTER_SRW_EXCLUSIVE(this->srwlock) - if (!this->initialized) - { - hr = this->InitializeCore(context); - } + if (!this->initialized) + { + hr = this->InitializeCore(context); + } - LEAVE_SRW_EXCLUSIVE(this->srwlock) + LEAVE_SRW_EXCLUSIVE(this->srwlock) } return hr; @@ -34,7 +36,58 @@ HRESULT CNodeApplicationManager::Initialize(IHttpContext* context) LONG CNodeApplicationManager::GetTotalRequests() { - return this->totalRequests; + return this->totalRequests; +} + +LPCWSTR CNodeApplicationManager::GetSignalPipeName() +{ + return this->signalPipeName; +} + +HANDLE CNodeApplicationManager::GetSignalPipe() +{ + return this->signalPipe; +} + +unsigned int CNodeApplicationManager::ControlSignalHandler(void* arg) +{ + CNodeApplicationManager* nodeApplicationManager = (CNodeApplicationManager*)arg; + BYTE buffer[MAX_BUFFER_SIZE] = {0}; + DWORD bytesRead = 0; + + _ASSERT(nodeApplicationManager != NULL); + + // + // wait for a client to connect -- does not support multiple clients yet. + // + if(ConnectNamedPipe(nodeApplicationManager->GetSignalPipe(), NULL) == 0) + { + // failed + nodeApplicationManager->GetEventProvider()->Log(L"iisnode control signal pipe client connection failed", WINEVENT_LEVEL_ERROR); + goto Finished; + } + + // + // Read message from pipe. + // + if(ReadFile(nodeApplicationManager->GetSignalPipe(), buffer, MAX_BUFFER_SIZE, &bytesRead, NULL)) + { + if(strnicmp((char*)buffer, "recycle", MAX_BUFFER_SIZE) == 0) + { + nodeApplicationManager->GetHttpServer()->RecycleProcess(L"Node.exe signalled recycle"); + } + } + +Finished: + return 0; +} + +PSECURITY_ATTRIBUTES +CNodeApplicationManager::GetPipeSecurityAttributes( + VOID +) +{ + return this->pPipeSecAttr; } HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) @@ -42,6 +95,8 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) HRESULT hr; BOOL isInJob, createJob; JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo; + UUID uuid; + RPC_WSTR suuid = NULL; ErrorIf(NULL == (this->eventProvider = new CNodeEventProvider()), ERROR_NOT_ENOUGH_MEMORY); CheckError(this->eventProvider->Initialize()); @@ -51,6 +106,8 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) ErrorIf(NULL == (this->fileWatcher = new CFileWatcher()), ERROR_NOT_ENOUGH_MEMORY); CheckError(this->fileWatcher->Initialize(context)); + CheckError(CUtils::CreatePipeSecurity(&this->pPipeSecAttr)); + // determine whether node processes should be created in a new job object // or whether current job object is adequate; the goal is to kill node processes when // the IIS worker process is killed while preserving current job limits, if any @@ -93,6 +150,48 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) HRESULT_FROM_WIN32(GetLastError())); } + if(CModuleConfiguration::GetRecycleSignalEnabled(context)) + { + // + // generate unique pipe name + // + + ErrorIf(RPC_S_OK != UuidCreate(&uuid), ERROR_CAN_NOT_COMPLETE); + ErrorIf(RPC_S_OK != UuidToStringW(&uuid, &suuid), ERROR_NOT_ENOUGH_MEMORY); + ErrorIf((this->signalPipeName = new WCHAR[1024]) == NULL, ERROR_NOT_ENOUGH_MEMORY); + wcscpy(this->signalPipeName, L"\\\\.\\pipe\\"); + wcscpy(this->signalPipeName + 9, (WCHAR*)suuid); + RpcStringFreeW(&suuid); + suuid = NULL; + + this->signalPipe = CreateNamedPipeW( this->signalPipeName, + PIPE_ACCESS_INBOUND, + PIPE_TYPE_MESSAGE | PIPE_WAIT, + 1, + MAX_BUFFER_SIZE, + MAX_BUFFER_SIZE, + 0, + GetPipeSecurityAttributes() ); + + ErrorIf( this->signalPipe == INVALID_HANDLE_VALUE, + HRESULT_FROM_WIN32(ERROR_INVALID_HANDLE) ); + + // + // start pipe reader thread. + // + + this->controlSignalHandlerThread = (HANDLE) _beginthreadex( NULL, + 0, + CNodeApplicationManager::ControlSignalHandler, + this, + 0, + NULL); + + ErrorIf((HANDLE)-1L == this->controlSignalHandlerThread, ERROR_NOT_ENOUGH_MEMORY); + + this->GetEventProvider()->Log(L"iisnode initialized control pipe", WINEVENT_LEVEL_INFO); + } + this->initialized = TRUE; this->GetEventProvider()->Log(L"iisnode initialized the application manager", WINEVENT_LEVEL_INFO); @@ -102,6 +201,12 @@ HRESULT CNodeApplicationManager::InitializeCore(IHttpContext* context) this->GetEventProvider()->Log(L"iisnode failed to initialize the application manager", WINEVENT_LEVEL_ERROR); + if(suuid != NULL) + { + RpcStringFreeW(&suuid); + suuid = NULL; + } + if (NULL != this->asyncManager) { delete this->asyncManager; @@ -133,6 +238,30 @@ CNodeApplicationManager::~CNodeApplicationManager() delete current; } + if(NULL != this->controlSignalHandlerThread) + { + CloseHandle(this->controlSignalHandlerThread); + this->controlSignalHandlerThread = NULL; + } + + if(NULL != this->signalPipe) + { + CloseHandle(this->signalPipe); + this->signalPipe = NULL; + } + + if(NULL != this->pPipeSecAttr) + { + CUtils::FreePipeSecurity(this->pPipeSecAttr); + this->pPipeSecAttr = NULL; + } + + if(NULL != this->signalPipeName) + { + delete[] this->signalPipeName; + this->signalPipeName = NULL; + } + if (NULL != this->asyncManager) { delete this->asyncManager; @@ -182,48 +311,48 @@ HRESULT CNodeApplicationManager::Dispatch(IHttpContext* context, IHttpEventProvi CheckNull(ctx); *ctx = NULL; - InterlockedIncrement(&this->totalRequests); + InterlockedIncrement(&this->totalRequests); CheckError(CNodeDebugger::GetDebugCommand(context, this->GetEventProvider(), &debugCommand)); - switch (debugCommand) - { - default: + switch (debugCommand) + { + default: ENTER_SRW_SHARED(this->srwlock) CheckError(this->GetOrCreateNodeApplication(context, debugCommand, FALSE, &application)); - if (application && !application->GetNeedsRecycling()) - { - // this is the sweetspot code path: application already exists, shared read lock is sufficient + if (application && !application->GetNeedsRecycling()) + { + // this is the sweetspot code path: application already exists, shared read lock is sufficient - CheckError(application->Dispatch(context, pProvider, ctx)); - } + CheckError(application->Dispatch(context, pProvider, ctx)); + } LEAVE_SRW_SHARED(this->srwlock) - if (!application || application->GetNeedsRecycling()) - { - // this is the initialization code path for activating request: - // application must be created which requires an exclusive lock + if (!application || application->GetNeedsRecycling()) + { + // this is the initialization code path for activating request: + // application must be created which requires an exclusive lock - ENTER_SRW_EXCLUSIVE(this->srwlock) + ENTER_SRW_EXCLUSIVE(this->srwlock) - CheckError(this->GetOrCreateNodeApplication(context, debugCommand, TRUE, &application)); - if (application->GetNeedsRecycling()) - { - this->RecycleApplicationAssumeLock(application); - CheckError(this->GetOrCreateNodeApplication(context, debugCommand, TRUE, &application)); - } + CheckError(this->GetOrCreateNodeApplication(context, debugCommand, TRUE, &application)); + if (application->GetNeedsRecycling()) + { + this->RecycleApplicationAssumeLock(application); + CheckError(this->GetOrCreateNodeApplication(context, debugCommand, TRUE, &application)); + } - CheckError(application->Dispatch(context, pProvider, ctx)); + CheckError(application->Dispatch(context, pProvider, ctx)); - LEAVE_SRW_EXCLUSIVE(this->srwlock) - } + LEAVE_SRW_EXCLUSIVE(this->srwlock) + } - break; + break; - case ND_KILL: + case ND_KILL: ENTER_SRW_EXCLUSIVE(this->srwlock) @@ -231,16 +360,16 @@ HRESULT CNodeApplicationManager::Dispatch(IHttpContext* context, IHttpEventProvi LEAVE_SRW_EXCLUSIVE(this->srwlock) - break; + break; - case ND_REDIRECT: + case ND_REDIRECT: // redirection from e.g. app.js/debug to app.js/debug/ CheckError(this->DebugRedirect(context, ctx)); - break; - }; + break; + }; return S_OK; Error: @@ -297,50 +426,77 @@ HRESULT CNodeApplicationManager::EnsureDebuggedApplicationKilled(IHttpContext* c return hr; } +HRESULT CNodeApplicationManager::RecycleApplicationOnConfigChange(PCWSTR pszConfigPath) +{ + HRESULT hr = ERROR_NOT_FOUND; + + ENTER_SRW_EXCLUSIVE(this->srwlock) + + NodeApplicationEntry* current = this->applications; + while (current) + { + // + // recycle apps if any config along its configPath hierarchy changes. + // + + if (wcsstr(current->nodeApplication->GetConfigPath(), pszConfigPath) != NULL) + { + current->nodeApplication->SetNeedsRecycling(); + hr = S_OK; + } + + current = current->next; + } + + LEAVE_SRW_EXCLUSIVE(this->srwlock) + + return hr; +} + HRESULT CNodeApplicationManager::RecycleApplication(CNodeApplication* app) { - return this->RecycleApplication(app, TRUE); + return this->RecycleApplication(app, TRUE); } HRESULT CNodeApplicationManager::RecycleApplication(CNodeApplication* app, BOOL requiresLock) { - HRESULT hr; + HRESULT hr; - if (requiresLock) - { - ENTER_SRW_EXCLUSIVE(this->srwlock) + if (requiresLock) + { + ENTER_SRW_EXCLUSIVE(this->srwlock) - hr = this->RecycleApplicationAssumeLock(app); + hr = this->RecycleApplicationAssumeLock(app); - LEAVE_SRW_EXCLUSIVE(this->srwlock) - } - else - { - hr = this->RecycleApplicationAssumeLock(app); - } + LEAVE_SRW_EXCLUSIVE(this->srwlock) + } + else + { + hr = this->RecycleApplicationAssumeLock(app); + } - return hr; + return hr; } // this method is always called under exclusive this->srwlock HRESULT CNodeApplicationManager::RecycleApplicationAssumeLock(CNodeApplication* app) { - // ensure the application still exists to avoid race condition with other recycling code paths + // ensure the application still exists to avoid race condition with other recycling code paths - NodeApplicationEntry* current = this->applications; - while (current) - { - if (current->nodeApplication == app) - { - this->RecycleApplicationCore(app->GetPeerApplication()); - this->RecycleApplicationCore(app); - break; - } + NodeApplicationEntry* current = this->applications; + while (current) + { + if (current->nodeApplication == app) + { + this->RecycleApplicationCore(app->GetPeerApplication()); + this->RecycleApplicationCore(app); + break; + } - current = current->next; - } + current = current->next; + } - return S_OK; + return S_OK; } void CNodeApplicationManager::OnScriptModified(CNodeApplicationManager* manager, CNodeApplication* application) @@ -418,26 +574,49 @@ HRESULT CNodeApplicationManager::GetOrCreateNodeApplicationCore(PCWSTR physicalP return hr; } -HRESULT CNodeApplicationManager::EnsureDebuggerFilesInstalled(PWSTR physicalPath, DWORD physicalPathSize) +HRESULT CNodeApplicationManager::EnsureDebuggerFilesInstalled(PWSTR physicalPath, DWORD physicalPathSize, LPWSTR debuggerExtensionDll) { HRESULT hr; HMODULE iisnode; DebuggerFileEnumeratorParams params = { S_OK, physicalPath, wcslen(physicalPath), physicalPathSize }; + BOOL fLoadModule = FALSE; // Process all resources of DEBUGGERFILE type (256) defined in resource.rc and save to disk if necessary - - if (NULL == this->inspector) + ErrorIf(debuggerExtensionDll == NULL, ERROR_INVALID_PARAMETER); + ErrorIf(wcslen(debuggerExtensionDll) >= MAX_PATH, ERROR_INVALID_PARAMETER); + + if(wcsicmp(this->debuggerExtensionDll, debuggerExtensionDll) != 0) + { + fLoadModule = TRUE; + } + + if (NULL == this->inspector || fLoadModule) { // try loading iisnode-inspector.dll from the same location where iisnode.dll is located - char path[MAX_PATH]; + if(this->inspector != NULL) + { + FreeLibrary(this->inspector); + this->inspector = NULL; + } + + WCHAR path[MAX_PATH]; DWORD size; - ErrorIf(NULL == (iisnode = GetModuleHandle("iisnode.dll")), GetLastError()); - ErrorIf(0 == (size = GetModuleFileName(iisnode, path, MAX_PATH)), GetLastError()); + ErrorIf(NULL == (iisnode = GetModuleHandleW(L"iisnode.dll")), GetLastError()); + ErrorIf(0 == (size = GetModuleFileNameW(iisnode, path, MAX_PATH)), GetLastError()); ErrorIf(size == MAX_PATH || S_OK != GetLastError(), E_FAIL); - ErrorIf((size + 10) >= MAX_PATH, E_FAIL); - strcpy(path + size - 4, "-inspector.dll"); - ErrorIf(NULL == (this->inspector = LoadLibraryEx(path, NULL, LOAD_LIBRARY_AS_DATAFILE)), IISNODE_ERROR_INSPECTOR_NOT_FOUND); + + // + // path points to d:\program files\iisnode\iisnode.dll for example. + // need to replace iisnode.dll with the debuggerExtensionDll which is why + // path + size - 11 (11 is length of iisnode.dll) + // + + ErrorIf((size + wcslen(debuggerExtensionDll) - 11) >= MAX_PATH, E_FAIL); + wcscpy(path + size - 11, debuggerExtensionDll); + ErrorIf(NULL == (this->inspector = LoadLibraryExW(path, NULL, LOAD_LIBRARY_AS_DATAFILE)), IISNODE_ERROR_INSPECTOR_NOT_FOUND); + + wcscpy(this->debuggerExtensionDll, debuggerExtensionDll); } ErrorIf(!EnumResourceNames(this->inspector, "DEBUGGERFILE", CNodeApplicationManager::EnsureDebuggerFile, (LONG_PTR)¶ms), GetLastError()); @@ -449,6 +628,12 @@ HRESULT CNodeApplicationManager::EnsureDebuggerFilesInstalled(PWSTR physicalPath return S_OK; Error: + if(this->inspector != NULL) + { + FreeLibrary(this->inspector); + this->inspector = NULL; + } + this->GetEventProvider()->Log( L"iisnode failed to unpack debugger files", WINEVENT_LEVEL_ERROR); @@ -468,16 +653,30 @@ BOOL CALLBACK CNodeApplicationManager::EnsureDebuggerFile(HMODULE hModule, LPCTS DWORD bytesWritten; size_t converted; DWORD lastDirectoryEnd, currentDirectoryEnd; + DWORD dwResourceIndex = 0; + CHAR buffer[MAX_PATH]; ErrorIf(NULL == lpszName, ERROR_INVALID_PARAMETER); + // + // resource file ID cannot start with a number so the format of the ID is F. + // lpszName is of the format F, so just skip the first character and convert the to number + // + + ErrorIf(strlen(lpszName) <= 1, ERROR_INVALID_PARAMETER); + ErrorIf(*lpszName != 'F', ERROR_INVALID_PARAMETER); + + dwResourceIndex = atoi(lpszName + 1); + + ErrorIf(LoadStringA(hModule, dwResourceIndex, buffer, MAX_PATH) == 0, GetLastError()); + // append file name to the base directory name CheckError(mbstowcs_s( &converted, params->physicalFile + params->physicalFileLength, params->physicalFileSize - params->physicalFileLength - 1, - lpszName, + buffer, _TRUNCATE)); // ensure the directory structure is created @@ -489,6 +688,7 @@ BOOL CALLBACK CNodeApplicationManager::EnsureDebuggerFile(HMODULE hModule, LPCTS currentDirectoryEnd = params->physicalFileLength - 1; do { params->physicalFile[currentDirectoryEnd] = L'\0'; + if (!CreateDirectoryW(params->physicalFile, NULL)) { hr = GetLastError(); @@ -503,9 +703,8 @@ BOOL CALLBACK CNodeApplicationManager::EnsureDebuggerFile(HMODULE hModule, LPCTS } while (currentDirectoryEnd <= lastDirectoryEnd); - // check if the file already exists and create it if it does not - - file = CreateFileW(params->physicalFile, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + // check if the file already exists and create it if it does not, if its present, overwrite it. + file = CreateFileW(params->physicalFile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (INVALID_HANDLE_VALUE == file) { @@ -588,9 +787,9 @@ HRESULT CNodeApplicationManager::GetOrCreateDebuggedNodeApplicationCore(PCWSTR p DWORD debuggerFilesPathSegmentLen = CModuleConfiguration::GetDebuggerFilesPathSegmentLength(context); PCWSTR appName = physicalPath + physicalPathLength - 1; - while (appName > physicalPath && *appName != L'\\') - appName--; - appName++; + while (appName > physicalPath && *appName != L'\\') + appName--; + appName++; if( debuggerVirtualDirPhysicalPath[ debuggerVirtualDirPhysicalPathLength - 1 ] == L'\\') { @@ -617,7 +816,7 @@ HRESULT CNodeApplicationManager::GetOrCreateDebuggedNodeApplicationCore(PCWSTR p // which is where EnsureDebuggerFilesInstalled will install all debugger files. } - CheckError(this->EnsureDebuggerFilesInstalled(debuggerPath, debuggerPathSize)); + CheckError(this->EnsureDebuggerFilesInstalled(debuggerPath, debuggerPathSize, CModuleConfiguration::GetDebuggerExtensionDll(context))); // kill any existing instance of the application to debug and the debugger @@ -770,7 +969,7 @@ HRESULT CNodeApplicationManager::GetOrCreateNodeApplication(IHttpContext* contex if (NULL == *application && allowCreate) { - // this code path executes under exclusive this->srwlock + // this code path executes under exclusive this->srwlock ErrorIf(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(physicalPath), GetLastError()); diff --git a/src/iisnode/cnodeapplicationmanager.h b/src/iisnode/cnodeapplicationmanager.h index 2ffbf017..94058e08 100644 --- a/src/iisnode/cnodeapplicationmanager.h +++ b/src/iisnode/cnodeapplicationmanager.h @@ -8,72 +8,88 @@ class CNodeEventProvider; class CNodeHttpStoredContext; enum NodeDebugCommand; +#define MAX_BUFFER_SIZE 64 + class CNodeApplicationManager { private: - typedef struct _NodeApplicationEntry { - CNodeApplication* nodeApplication; - struct _NodeApplicationEntry* next; - } NodeApplicationEntry; - - typedef struct _DebuggerFileEnumeratorParams { - HRESULT hr; - PWSTR physicalFile; - DWORD physicalFileLength; - DWORD physicalFileSize; - } DebuggerFileEnumeratorParams; - - IHttpServer* server; - HTTP_MODULE_ID moduleId; - NodeApplicationEntry* applications; - SRWLOCK srwlock; - CAsyncManager* asyncManager; - HANDLE jobObject; - BOOL breakAwayFromJobObject; - CFileWatcher* fileWatcher; - CNodeEventProvider* eventProvider; - BOOL initialized; - DWORD currentDebugPort; - HMODULE inspector; - LONG totalRequests; + typedef struct _NodeApplicationEntry { + CNodeApplication* nodeApplication; + struct _NodeApplicationEntry* next; + } NodeApplicationEntry; + + typedef struct _DebuggerFileEnumeratorParams { + HRESULT hr; + PWSTR physicalFile; + DWORD physicalFileLength; + DWORD physicalFileSize; + } DebuggerFileEnumeratorParams; + + IHttpServer* server; + HTTP_MODULE_ID moduleId; + NodeApplicationEntry* applications; + SRWLOCK srwlock; + CAsyncManager* asyncManager; + HANDLE jobObject; + BOOL breakAwayFromJobObject; + CFileWatcher* fileWatcher; + CNodeEventProvider* eventProvider; + BOOL initialized; + DWORD currentDebugPort; + HMODULE inspector; + LONG totalRequests; + + HANDLE signalPipe; + HANDLE controlSignalHandlerThread; + LPWSTR signalPipeName; + PSECURITY_ATTRIBUTES pPipeSecAttr; + WCHAR debuggerExtensionDll[MAX_PATH]; + + HANDLE GetSignalPipe(); + HRESULT SetupPipeSecurityAttributes(); BOOL DirectoryExists(LPCWSTR directoryPath); HRESULT EnsureDirectoryStructureExists( LPCWSTR pszSkipPrefix, LPWSTR pszDirectoryPath ); - HRESULT DebugRedirect(IHttpContext* context, CNodeHttpStoredContext** ctx); - HRESULT EnsureDebuggedApplicationKilled(IHttpContext* context, CNodeHttpStoredContext** ctx); - HRESULT GetOrCreateNodeApplication(IHttpContext* context, NodeDebugCommand debugCommand, BOOL allowCreate, CNodeApplication** application); - HRESULT GetOrCreateNodeApplicationCore(PCWSTR physicalPath, DWORD physicalPathLength, IHttpContext* context, CNodeApplication** application); - HRESULT GetOrCreateDebuggedNodeApplicationCore(PCWSTR physicalPath, DWORD physicalPathLength, NodeDebugCommand debugCommand, IHttpContext* context, CNodeApplication** application); - CNodeApplication* TryGetExistingNodeApplication(PCWSTR physicalPath, DWORD physicalPathLength, BOOL debuggerRequest); - HRESULT EnsureDebuggerFilesInstalled(PWSTR physicalPath, DWORD physicalPathSize); - static BOOL CALLBACK EnsureDebuggerFile(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam); - HRESULT RecycleApplicationCore(CNodeApplication* app); - HRESULT RecycleApplicationAssumeLock(CNodeApplication* app); - HRESULT RecycleApplication(CNodeApplication* app, BOOL requiresLock); - HRESULT FindNextDebugPort(IHttpContext* context, DWORD* port); - HRESULT EnsureDebugeeReady(IHttpContext* context, DWORD debugPort); - HRESULT InitializeCore(IHttpContext* context); + HRESULT DebugRedirect(IHttpContext* context, CNodeHttpStoredContext** ctx); + HRESULT EnsureDebuggedApplicationKilled(IHttpContext* context, CNodeHttpStoredContext** ctx); + HRESULT GetOrCreateNodeApplication(IHttpContext* context, NodeDebugCommand debugCommand, BOOL allowCreate, CNodeApplication** application); + HRESULT GetOrCreateNodeApplicationCore(PCWSTR physicalPath, DWORD physicalPathLength, IHttpContext* context, CNodeApplication** application); + HRESULT GetOrCreateDebuggedNodeApplicationCore(PCWSTR physicalPath, DWORD physicalPathLength, NodeDebugCommand debugCommand, IHttpContext* context, CNodeApplication** application); + CNodeApplication* TryGetExistingNodeApplication(PCWSTR physicalPath, DWORD physicalPathLength, BOOL debuggerRequest); + HRESULT EnsureDebuggerFilesInstalled(PWSTR physicalPath, DWORD physicalPathSize, PWSTR debuggerExtensionDll); + static BOOL CALLBACK EnsureDebuggerFile(HMODULE hModule, LPCTSTR lpszType, LPTSTR lpszName, LONG_PTR lParam); + HRESULT RecycleApplicationCore(CNodeApplication* app); + HRESULT RecycleApplicationAssumeLock(CNodeApplication* app); + HRESULT RecycleApplication(CNodeApplication* app, BOOL requiresLock); + HRESULT FindNextDebugPort(IHttpContext* context, DWORD* port); + HRESULT EnsureDebugeeReady(IHttpContext* context, DWORD debugPort); + HRESULT InitializeCore(IHttpContext* context); + + static unsigned int WINAPI ControlSignalHandler(void* arg); public: - CNodeApplicationManager(IHttpServer* server, HTTP_MODULE_ID moduleId); - ~CNodeApplicationManager(); + CNodeApplicationManager(IHttpServer* server, HTTP_MODULE_ID moduleId); + ~CNodeApplicationManager(); - IHttpServer* GetHttpServer(); - HTTP_MODULE_ID GetModuleId(); - CAsyncManager* GetAsyncManager(); - CNodeEventProvider* GetEventProvider(); - CFileWatcher* GetFileWatcher(); - HANDLE GetJobObject(); - BOOL GetBreakAwayFromJobObject(); + IHttpServer* GetHttpServer(); + HTTP_MODULE_ID GetModuleId(); + CAsyncManager* GetAsyncManager(); + CNodeEventProvider* GetEventProvider(); + CFileWatcher* GetFileWatcher(); + HANDLE GetJobObject(); + BOOL GetBreakAwayFromJobObject(); + LPCWSTR GetSignalPipeName(); + PSECURITY_ATTRIBUTES GetPipeSecurityAttributes(); + HRESULT RecycleApplicationOnConfigChange(PCWSTR pszConfigPath); - static void OnScriptModified(CNodeApplicationManager* manager, CNodeApplication* application); + static void OnScriptModified(CNodeApplicationManager* manager, CNodeApplication* application); - HRESULT Initialize(IHttpContext* context); - HRESULT Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx); - HRESULT RecycleApplication(CNodeApplication* app); - LONG GetTotalRequests(); + HRESULT Initialize(IHttpContext* context); + HRESULT Dispatch(IHttpContext* context, IHttpEventProvider* pProvider, CNodeHttpStoredContext** ctx); + HRESULT RecycleApplication(CNodeApplication* app); + LONG GetTotalRequests(); }; #endif \ No newline at end of file diff --git a/src/iisnode/cnodeconstants.h b/src/iisnode/cnodeconstants.h new file mode 100644 index 00000000..5b14a9a9 --- /dev/null +++ b/src/iisnode/cnodeconstants.h @@ -0,0 +1,39 @@ +#ifndef __CNODECONSTATNTS_H__ +#define __CNODECONSTATNTS_H__ + +class CNodeConstants +{ +public: + enum SubStatusCodes500 + { + IISNODE_ERROR_ON_EXECUTE_REQ_HANDLER = 1000, + IISNODE_ERROR_PIPE_CONNECTION = 1001, + IISNODE_ERROR_PIPE_CONNECTION_BEFORE_PROCESS_TERMINATED = 1002, + IISNODE_ERROR_CONFIGURE_PIPE_CONNECTION = 1003, + IISNODE_ERROR_FAILED_INIT_SEND_HTTP_HEADERS = 1004, + IISNODE_ERROR_FAILED_SERIALIZE_HTTP_HEADERS = 1005, + IISNODE_ERROR_FAILED_SEND_HTTP_HEADERS = 1006, + IISNODE_ERROR_FAILED_READ_REQ_BODY = 1007, + IISNODE_ERROR_FAILED_READ_REQ_BODY_COMPLETED = 1008, + IISNODE_ERROR_FAILED_INIT_SEND_REQ_BODY = 1009, + IISNODE_ERROR_FAILED_SEND_REQ_BODY = 1010, + IISNODE_ERROR_FAILED_INIT_READ_RESPONSE = 1011, + IISNODE_ERROR_FAILED_ALLOC_MEM_READ_RESPONSE = 1012, + IISNODE_ERROR_FAILED_PROCESS_HTTP_STATUS_LINE = 1013, + IISNODE_ERROR_FAILED_PROCESS_HTTP_HEADERS = 1014, + IISNODE_ERROR_FAILED_PROCESS_RESPONSE_BODY_CHUNK_HEADER = 1015, + IISNODE_ERROR_FAILED_SEND_RESPONSE_BODY_CHUNK = 1016, + IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY = 1017, + IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY_PARTIAL_FLUSH = 1018 + }; + + enum SubStatusCodes503 + { + IISNODE_ERROR_NOT_ENOUGH_QUOTA = 1000, + IISNODE_ERROR_FAILED_ACCEPT_REQUEST_APP_RECYCLE = 1001, + IISNODE_ERROR_INIT_PROCESS_REQUEST = 1002, + IISNODE_ERROR_PIPE_CONNECTION_TOO_BUSY = 1003 + }; +}; + +#endif \ No newline at end of file diff --git a/src/iisnode/cnodedebugger.cpp b/src/iisnode/cnodedebugger.cpp index 43492afb..5952a6ab 100644 --- a/src/iisnode/cnodedebugger.cpp +++ b/src/iisnode/cnodedebugger.cpp @@ -2,193 +2,219 @@ HRESULT CNodeDebugger::GetDebugCommand(IHttpContext* context, CNodeEventProvider* log, NodeDebugCommand* debugCommand) { - HRESULT hr; - DWORD physicalPathLength; - PCWSTR physicalPath; - DWORD scriptTranslatedLength; - PCWSTR scriptTranslated; - DWORD debuggerPathSegmentLength; - - *debugCommand = ND_NONE; - - if (!CModuleConfiguration::GetDebuggingEnabled(context)) - { - return S_OK; - } - - scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); - physicalPath = context->GetPhysicalPath(&physicalPathLength); - debuggerPathSegmentLength = CModuleConfiguration::GetDebuggerPathSegmentLength(context); - - ErrorIf(0 == physicalPathLength, ERROR_INVALID_PARAMETER); - ErrorIf(0 == scriptTranslatedLength, ERROR_INVALID_PARAMETER); - ErrorIf(0 == debuggerPathSegmentLength, ERROR_INVALID_PARAMETER); - - if ((physicalPathLength - scriptTranslatedLength) <= debuggerPathSegmentLength) - { - return S_OK; - } - else if (physicalPath[scriptTranslatedLength] != L'\\') - { - return S_OK; - } - else if (0 != wcsnicmp(physicalPath + scriptTranslatedLength + 1, CModuleConfiguration::GetDebuggerPathSegment(context), debuggerPathSegmentLength)) - { - return S_OK; - } - else - { - WCHAR postDebugSegment = physicalPath[scriptTranslatedLength + debuggerPathSegmentLength + 1]; - if (L'\0' == postDebugSegment) - { - *debugCommand = ND_REDIRECT; - return S_OK; - } - else if (L'\\' != postDebugSegment) - { - return S_OK; - } - else - { - *debugCommand = ND_DEBUG; - - HTTP_REQUEST* request = context->GetRequest()->GetRawHttpRequest(); - if (request->CookedUrl.pQueryString) - { - if (0 == wcsicmp(request->CookedUrl.pQueryString, L"?brk")) - { - *debugCommand = ND_DEBUG_BRK; - } - else if (0 == wcsicmp(request->CookedUrl.pQueryString, L"?kill")) - { - *debugCommand = ND_KILL; - } - else if (0 != wcsicmp(request->CookedUrl.pQueryString, L"?debug") - && 0 != wcsncmp(physicalPath + scriptTranslatedLength + debuggerPathSegmentLength + 1, L"\\socket.io\\", 11)) - { - // unsupported debugger command - - log->Log(L"iisnode received an unrecognized debugger command", WINEVENT_LEVEL_ERROR); - - // TODO, tjanczuk, return a descriptive error to the browser client - CheckError(IISNODE_ERROR_UNRECOGNIZED_DEBUG_COMMAND); - } - } - } - } - - return S_OK; + HRESULT hr; + DWORD physicalPathLength; + PCWSTR physicalPath; + DWORD scriptTranslatedLength; + PCWSTR scriptTranslated; + DWORD debuggerPathSegmentLength; + + *debugCommand = ND_NONE; + + if (!CModuleConfiguration::GetDebuggingEnabled(context)) + { + return S_OK; + } + + scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); + physicalPath = context->GetPhysicalPath(&physicalPathLength); + debuggerPathSegmentLength = CModuleConfiguration::GetDebuggerPathSegmentLength(context); + + ErrorIf(0 == physicalPathLength, ERROR_INVALID_PARAMETER); + ErrorIf(0 == scriptTranslatedLength, ERROR_INVALID_PARAMETER); + ErrorIf(0 == debuggerPathSegmentLength, ERROR_INVALID_PARAMETER); + + if ((physicalPathLength - scriptTranslatedLength) <= debuggerPathSegmentLength) + { + return S_OK; + } + else if (physicalPath[scriptTranslatedLength] != L'\\') + { + return S_OK; + } + else if (0 != wcsnicmp(physicalPath + scriptTranslatedLength + 1, CModuleConfiguration::GetDebuggerPathSegment(context), debuggerPathSegmentLength)) + { + return S_OK; + } + else + { + WCHAR postDebugSegment = physicalPath[scriptTranslatedLength + debuggerPathSegmentLength + 1]; + if (L'\0' == postDebugSegment) + { + *debugCommand = ND_REDIRECT; + return S_OK; + } + else if (L'\\' != postDebugSegment) + { + return S_OK; + } + else + { + *debugCommand = ND_DEBUG; + + HTTP_REQUEST* request = context->GetRequest()->GetRawHttpRequest(); + if (request->CookedUrl.pQueryString) + { + if (0 == wcsicmp(request->CookedUrl.pQueryString, L"?brk")) + { + *debugCommand = ND_DEBUG_BRK; + } + else if (0 == wcsicmp(request->CookedUrl.pQueryString, L"?kill")) + { + *debugCommand = ND_KILL; + } + } + } + } + + return S_OK; Error: - return hr; + return hr; } HRESULT CNodeDebugger::DispatchDebuggingRequest(CNodeHttpStoredContext* ctx, BOOL* requireChildContext, BOOL* mainDebuggerPage) { - HRESULT hr = S_OK; - PCWSTR actualPath; + HRESULT hr = S_OK; + PCWSTR actualPath; - CheckNull(ctx); - CheckNull(requireChildContext); - CheckNull(mainDebuggerPage); + CheckNull(ctx); + CheckNull(requireChildContext); + CheckNull(mainDebuggerPage); - IHttpContext* context = ctx->GetHttpContext(); - IHttpRequest* request = context->GetRequest(); - HTTP_REQUEST* rawRequest = request->GetRawHttpRequest(); + IHttpContext* context = ctx->GetHttpContext(); + IHttpRequest* request = context->GetRequest(); + HTTP_REQUEST* rawRequest = request->GetRawHttpRequest(); BOOL debuggerRequest = FALSE; - // Debugger requests for static content are to be dispatched to a static file handler via a child IIS context. - // Debugger requests for the debugging protocol will be processed by the node-inspector app. - // All requests in general need re-writing: - // - // /foo/app.js/debug/socket.io/...?abc=def -> /socket.io/...?abc=def - // /foo/app.js/debug/bar/baz.jpg -> /foo/app.js.debug/node_modules/node-inspector/front-end/bar/baz.jpg + // Debugger requests for static content are to be dispatched to a static file handler via a child IIS context. + // Debugger requests for the debugging protocol will be processed by the node-inspector app. + // All requests in general need re-writing: + // + // /foo/app.js/debug/socket.io/...?abc=def -> /socket.io/...?abc=def + // /foo/app.js/debug/bar/baz.jpg -> /foo/app.js.debug/node_modules/node-inspector/front-end/bar/baz.jpg // if debuggerVirtualDir is specified, request will be rewritten to reflect the actual location of the debugger files // which will be under VDirPhysicalPath\SHA256(scriptPath)\app.js.debug // /foo/app.js/debug/bar/baz.jpg -> /VDir/SHA256(app.js physical path)/app.js.debug/node_modules/node-inspector/front-end/bar/baz.jpg - - // Determine the minimal absolute url path that maps to the same physical path as the translated script; - // that minimal absolute url path will be the prefix of the full rewritten url path. - - // determine application name from script translated, e.g. 'app.js' - - DWORD scriptTranslatedLength; - PCWSTR scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); - PCWSTR appName = scriptTranslated + scriptTranslatedLength - 1; - while (appName > scriptTranslated && *appName != L'\\') - appName--; - appName++; - ErrorIf(appName == scriptTranslated, ERROR_INVALID_PARAMETER); - - // determine the url fragment preceding the part of the URL to be rewritten, e.g. 'app.js/debug' - - PWSTR newPath; - // allocate enough memory to hold all cases of the rewritten URL - ErrorIf(NULL == (newPath = (PWSTR)context->AllocateRequestMemory(rawRequest->CookedUrl.AbsPathLength + rawRequest->CookedUrl.QueryStringLength + sizeof WCHAR * 64)), ERROR_NOT_ENOUGH_MEMORY); - wsprintfW(newPath, L"/%s/%s", appName, CModuleConfiguration::GetDebuggerPathSegment(context)); - - // determine the prefix of the absolute path that ends with the url fragment preceeding the part of the URL to be rewritten, e.g. '/foo/bar/app.js/debug' - - DWORD urlFragmentLength = wcslen(newPath); - int indexFound = -1, currentIndex = 0; - while (currentIndex <= ((rawRequest->CookedUrl.AbsPathLength >> 1) - urlFragmentLength)) - { - if (0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + currentIndex, newPath, urlFragmentLength)) - { - indexFound = currentIndex; - break; - } - currentIndex++; - } - ErrorIf(-1 == indexFound, ERROR_INVALID_PARAMETER); - - // determine if the request is for the main debugger page - - *mainDebuggerPage = rawRequest->CookedUrl.AbsPathLength == sizeof WCHAR * (indexFound + urlFragmentLength + 1); - - // construct the re-written URL - - if (10 < ((rawRequest->CookedUrl.AbsPathLength >> 1) - indexFound - urlFragmentLength) - && 0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength, L"/socket.io", 10)) - { - // this is a debugger request - wcscpy(newPath, rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength); // this includes query string if present - *requireChildContext = FALSE; + + // Determine the minimal absolute url path that maps to the same physical path as the translated script; + // that minimal absolute url path will be the prefix of the full rewritten url path. + + // determine application name from script translated, e.g. 'app.js' + + DWORD scriptTranslatedLength; + PCWSTR scriptTranslated = context->GetScriptTranslated(&scriptTranslatedLength); + PCWSTR appName = scriptTranslated + scriptTranslatedLength - 1; + while (appName > scriptTranslated && *appName != L'\\') + appName--; + appName++; + ErrorIf(appName == scriptTranslated, ERROR_INVALID_PARAMETER); + + // determine the url fragment preceding the part of the URL to be rewritten, e.g. 'app.js/debug' + + PWSTR newPath; + // allocate enough memory to hold all cases of the rewritten URL + ErrorIf(NULL == (newPath = (PWSTR)context->AllocateRequestMemory(rawRequest->CookedUrl.AbsPathLength + rawRequest->CookedUrl.QueryStringLength + sizeof WCHAR * 64)), ERROR_NOT_ENOUGH_MEMORY); + wsprintfW(newPath, L"/%s/%s", appName, CModuleConfiguration::GetDebuggerPathSegment(context)); + + // determine the prefix of the absolute path that ends with the url fragment preceeding the part of the URL to be rewritten, e.g. '/foo/bar/app.js/debug' + + DWORD urlFragmentLength = wcslen(newPath); + int indexFound = -1, currentIndex = 0; + while (currentIndex <= ((rawRequest->CookedUrl.AbsPathLength >> 1) - urlFragmentLength)) + { + if (0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + currentIndex, newPath, urlFragmentLength)) + { + indexFound = currentIndex; + break; + } + currentIndex++; + } + ErrorIf(-1 == indexFound, ERROR_INVALID_PARAMETER); + + // determine if the request is for the main debugger page + + *mainDebuggerPage = rawRequest->CookedUrl.AbsPathLength == sizeof WCHAR * (indexFound + urlFragmentLength + 1); + + // construct the re-written URL + if (10 < ((rawRequest->CookedUrl.AbsPathLength >> 1) - indexFound - urlFragmentLength) + && 0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength, L"/socket.io", 10)) + { + // this is a debugger request + wcscpy(newPath, rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength); // this includes query string if present + *requireChildContext = FALSE; + debuggerRequest = TRUE; + } + else + if (2 < ((rawRequest->CookedUrl.AbsPathLength >> 1) - indexFound - urlFragmentLength) + && 0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength, L"/ws", 3)) + { + // this is a debugger websocket request. + // the request comes in for http://site/server.js/debug/ws? which needs to translated into http://site/ws?port=debugPort + wcscpy(newPath, rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength); + WCHAR debugPortStr[10]; + _itow(ctx->GetNodeApplication()->GetDebugPort(), (PWSTR)debugPortStr, 10); + wcscat(newPath, L"port="); + wcscat(newPath, debugPortStr); + *requireChildContext = FALSE; debuggerRequest = TRUE; - } - else - { - // this is static content request - wcscpy(newPath, rawRequest->CookedUrl.pAbsPath); - // replace the segment separator in 'app.js/debug' with a dot to get to 'app.js.debug' - newPath[indexFound + wcslen(appName) + 1] = L'.'; - // inject the '/node_modules/node-inspector/front-end' component - wcscpy(newPath + indexFound + urlFragmentLength, L"/node_modules/node-inspector/front-end/"); - if (*mainDebuggerPage) - { - // requests for the main debugger page must explicitly specity the HTML file name without - // relying on IIS'es default document handler since we must be able to set - // Cache-Control: no-cache header on that response and the default document handler - // prevents it - - wcscpy(newPath + indexFound + urlFragmentLength + 39, L"index.html"); - } - else - { - // append the rest of the relative path (including query string if present) - wcscpy(newPath + indexFound + urlFragmentLength + 39, rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength + 1); - } - - *requireChildContext = TRUE; - } - - // convert to PSTR + } + else + if (17 < ((rawRequest->CookedUrl.AbsPathLength >> 1) - indexFound - urlFragmentLength) + && 0 == wcsnicmp(rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength, L"/node/Overrides.js", 18) + && wcsnicmp(CModuleConfiguration::GetDebuggerExtensionDll(context), L"iisnode-inspector-", 18) == 0) + { + // this only applies to newer versions of node-inspector. + // this is static content request, special case for Overrides.js because its location was modified in node-inspector. + wcscpy(newPath, rawRequest->CookedUrl.pAbsPath); + // replace the segment separator in 'app.js/debug' with a dot to get to 'app.js.debug' + newPath[indexFound + wcslen(appName) + 1] = L'.'; + wcscpy(newPath + indexFound + urlFragmentLength, L"/node_modules/node-inspector/front-end-node/Overrides.js"); + *requireChildContext = TRUE; + } + else + { + // this is static content request + wcscpy(newPath, rawRequest->CookedUrl.pAbsPath); + // replace the segment separator in 'app.js/debug' with a dot to get to 'app.js.debug' + newPath[indexFound + wcslen(appName) + 1] = L'.'; + // inject the '/node_modules/node-inspector/front-end' component + wcscpy(newPath + indexFound + urlFragmentLength, L"/node_modules/node-inspector/front-end/"); + if (*mainDebuggerPage) + { + // requests for the main debugger page must explicitly specity the HTML file name without + // relying on IIS'es default document handler since we must be able to set + // Cache-Control: no-cache header on that response and the default document handler + // prevents it + if(wcsnicmp(CModuleConfiguration::GetDebuggerExtensionDll(context), L"iisnode-inspector-", 18) == 0 ) + { + // newer versions of node-inspector have inspector.html as the starting page instead of index.html. + wcscpy(newPath + indexFound + urlFragmentLength + 39, L"inspector.html?port="); + WCHAR debugPortStr[10]; + _itow(ctx->GetNodeApplication()->GetDebugPort(), (PWSTR)debugPortStr, 10); + wcscat(newPath, debugPortStr); + } + else + { + wcscpy(newPath + indexFound + urlFragmentLength + 39, L"index.html"); + } + } + else + { + // append the rest of the relative path (including query string if present) + wcscpy(newPath + indexFound + urlFragmentLength + 39, rawRequest->CookedUrl.pAbsPath + indexFound + urlFragmentLength + 1); + } + + *requireChildContext = TRUE; + } + + // convert to PSTR LPWSTR vDir = CModuleConfiguration::GetDebuggerVirtualDir(context); DWORD vDirLength = CModuleConfiguration::GetDebuggerVirtualDirLength(context); - PSTR path; - int pathSizeA; + PSTR path; + int pathSizeA; LPWSTR finalPath = NULL; if(debuggerRequest == FALSE && vDirLength > 0) @@ -198,25 +224,25 @@ HRESULT CNodeDebugger::DispatchDebuggingRequest(CNodeHttpStoredContext* ctx, BOO newPath = wcsstr(newPath, appName); wsprintfW(finalPath, L"/%s/%s/%s", vDir, CModuleConfiguration::GetDebuggerFilesPathSegment(context), newPath); - int pathSizeW = wcslen(finalPath); + int pathSizeW = wcslen(finalPath); ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, finalPath, pathSizeW, NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf(NULL == (path = (TCHAR*)context->AllocateRequestMemory(pathSizeA + 1)), E_OUTOFMEMORY); - ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, finalPath, pathSizeW, path, pathSizeA, NULL, NULL), E_FAIL); - path[pathSizeA] = 0; + ErrorIf(NULL == (path = (TCHAR*)context->AllocateRequestMemory(pathSizeA + 1)), E_OUTOFMEMORY); + ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, finalPath, pathSizeW, path, pathSizeA, NULL, NULL), E_FAIL); + path[pathSizeA] = 0; } else { int pathSizeW = wcslen(newPath); - ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, newPath, pathSizeW, NULL, 0, NULL, NULL)), E_FAIL); - ErrorIf(NULL == (path = (TCHAR*)context->AllocateRequestMemory(pathSizeA + 1)), E_OUTOFMEMORY); - ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, newPath, pathSizeW, path, pathSizeA, NULL, NULL), E_FAIL); - path[pathSizeA] = 0; + ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, newPath, pathSizeW, NULL, 0, NULL, NULL)), E_FAIL); + ErrorIf(NULL == (path = (TCHAR*)context->AllocateRequestMemory(pathSizeA + 1)), E_OUTOFMEMORY); + ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, newPath, pathSizeW, path, pathSizeA, NULL, NULL), E_FAIL); + path[pathSizeA] = 0; } - ctx->SetTargetUrl(path, pathSizeA); + ctx->SetTargetUrl(path, pathSizeA); - hr = S_OK; // go do cleanup + hr = S_OK; // go do cleanup Error: if( finalPath != NULL ) @@ -225,6 +251,6 @@ HRESULT CNodeDebugger::DispatchDebuggingRequest(CNodeHttpStoredContext* ctx, BOO finalPath = NULL; } - return hr; + return hr; } diff --git a/src/iisnode/cnodeglobalmodule.cpp b/src/iisnode/cnodeglobalmodule.cpp new file mode 100644 index 00000000..1caa79df --- /dev/null +++ b/src/iisnode/cnodeglobalmodule.cpp @@ -0,0 +1,23 @@ +#include "precomp.h" + +GLOBAL_NOTIFICATION_STATUS +CNodeGlobalModule::OnGlobalConfigurationChange( + IN IGlobalConfigurationChangeProvider * pProvider + ) +{ + UNREFERENCED_PARAMETER( pProvider ); + + // Retrieve the path that has changed. + PCWSTR pwszChangePath = pProvider->GetChangePath(); + + // Test for an error. + if (NULL != pwszChangePath && + wcsicmp(pwszChangePath, L"MACHINE") != 0 && + wcsicmp(pwszChangePath, L"MACHINE/WEBROOT") != 0) + { + this->pNodeApplicationManager->RecycleApplicationOnConfigChange(pwszChangePath); + } + + // Return processing to the pipeline. + return GL_NOTIFICATION_CONTINUE; +} \ No newline at end of file diff --git a/src/iisnode/cnodeglobalmodule.h b/src/iisnode/cnodeglobalmodule.h new file mode 100644 index 00000000..8201e70f --- /dev/null +++ b/src/iisnode/cnodeglobalmodule.h @@ -0,0 +1,34 @@ +#ifndef __CNODEGLOBALMODULE_H__ +#define __CNODEGLOBALMODULE_H__ + +class CNodeApplicationManager; + +class CNodeGlobalModule : public CGlobalModule +{ +private: + CNodeApplicationManager* pNodeApplicationManager; + +public: + + CNodeGlobalModule(CNodeApplicationManager* pNodeApplicationManager) + { + this->pNodeApplicationManager = pNodeApplicationManager; + } + + ~CNodeGlobalModule() + { + } + + VOID Terminate() + { + // Remove the class from memory. + delete this; + } + + GLOBAL_NOTIFICATION_STATUS + OnGlobalConfigurationChange( + IN IGlobalConfigurationChangeProvider * pProvider + ); +}; + +#endif \ No newline at end of file diff --git a/src/iisnode/cnodehttpmodule.cpp b/src/iisnode/cnodehttpmodule.cpp index a976a841..4be68f89 100644 --- a/src/iisnode/cnodehttpmodule.cpp +++ b/src/iisnode/cnodehttpmodule.cpp @@ -1,123 +1,127 @@ #include "precomp.h" CNodeHttpModule::CNodeHttpModule(CNodeApplicationManager* applicationManager) - : applicationManager(applicationManager) + : applicationManager(applicationManager) { } REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnSendResponse(IN IHttpContext* pHttpContext, IN ISendResponseProvider* pProvider) { - if (NULL != pHttpContext && NULL != pProvider) - { - CNodeHttpStoredContext* ctx = (CNodeHttpStoredContext*)pHttpContext->GetModuleContextContainer()->GetModuleContext(this->applicationManager->GetModuleId()); - DWORD flags = pProvider->GetFlags(); - if (NULL != ctx && ctx->GetIsUpgrade() && !ctx->GetOpaqueFlagSet()) - { - // Set opaque mode in HTTP.SYS to enable exchanging raw bytes. - - pProvider->SetFlags(flags | HTTP_SEND_RESPONSE_FLAG_OPAQUE); - ctx->SetOpaqueFlag(); - } - } - - return RQ_NOTIFICATION_CONTINUE; + if (NULL != pHttpContext && NULL != pProvider) + { + CNodeHttpStoredContext* ctx = (CNodeHttpStoredContext*)pHttpContext->GetModuleContextContainer()->GetModuleContext(this->applicationManager->GetModuleId()); + DWORD flags = pProvider->GetFlags(); + if (NULL != ctx && ctx->GetIsUpgrade() && !ctx->GetOpaqueFlagSet()) + { + // Set opaque mode in HTTP.SYS to enable exchanging raw bytes. + + pProvider->SetFlags(flags | HTTP_SEND_RESPONSE_FLAG_OPAQUE); + ctx->SetOpaqueFlag(); + } + } + + return RQ_NOTIFICATION_CONTINUE; } #if TRUE REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( - IN IHttpContext* pHttpContext, - IN IHttpEventProvider* pProvider) + IN IHttpContext* pHttpContext, + IN IHttpEventProvider* pProvider) { - HRESULT hr; - CNodeHttpStoredContext* ctx = NULL; - - CheckError(this->applicationManager->Initialize(pHttpContext)); - - this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO); - - CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx)); - this->applicationManager->GetEventProvider()->Log(L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId()); - ASYNC_CONTEXT* async = ctx->GetAsyncContext(); - async->RunSynchronousContinuations(); - - REQUEST_NOTIFICATION_STATUS result; - if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext - { - result = ctx->GetRequestNotificationStatus(); - } - else - { - result = RQ_NOTIFICATION_PENDING; - } - - switch (result) - { - default: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_CONTINUE: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_CONTINUE", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_FINISH_REQUEST: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_FINISH_REQUEST", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_PENDING: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_PENDING", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - }; - - return result; + HRESULT hr; + CNodeHttpStoredContext* ctx = NULL; + + CheckError(this->applicationManager->Initialize(pHttpContext)); + + this->applicationManager->GetEventProvider()->Log(L"iisnode received a new http request", WINEVENT_LEVEL_INFO); + + CheckError(this->applicationManager->Dispatch(pHttpContext, pProvider, &ctx)); + this->applicationManager->GetEventProvider()->Log(L"iisnode dispatched new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId()); + ASYNC_CONTEXT* async = ctx->GetAsyncContext(); + async->RunSynchronousContinuations(); + + REQUEST_NOTIFICATION_STATUS result; + if (0 == ctx->DecreasePendingAsyncOperationCount()) // decreases ref count set to 1 in the ctor of CNodeHttpStoredContext + { + result = ctx->GetRequestNotificationStatus(); + } + else + { + result = RQ_NOTIFICATION_PENDING; + } + + switch (result) + { + default: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_CONTINUE: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_CONTINUE", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_FINISH_REQUEST: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_FINISH_REQUEST", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_PENDING: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnExecuteRequestHandler with RQ_NOTIFICATION_PENDING", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + }; + + return result; Error: - CNodeEventProvider* log = this->applicationManager->GetEventProvider(); - - if (log) - { - if (ctx) - { - log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId()); - } - else - { - log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO); - } - } - - if (ERROR_NOT_ENOUGH_QUOTA == hr) - { - CProtocolBridge::SendEmptyResponse(pHttpContext, 503, _T("Service Unavailable"), hr); - } - else if (ERROR_FILE_NOT_FOUND == hr) - { - CProtocolBridge::SendEmptyResponse(pHttpContext, 404, _T("Not Found"), hr); - } - else if (ERROR_NOT_SUPPORTED == hr) - { - if (log) - { - log->Log(L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO); - } - CProtocolBridge::SendEmptyResponse(pHttpContext, 501, _T("Not Implemented"), hr); - } - else if (!CProtocolBridge::SendIisnodeError(pHttpContext, hr)) - { - CProtocolBridge::SendEmptyResponse(pHttpContext, 500, _T("Internal Server Error"), hr); - } - - return RQ_NOTIFICATION_FINISH_REQUEST; + CNodeEventProvider* log = this->applicationManager->GetEventProvider(); + + if (log) + { + if (ctx) + { + log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO, ctx->GetActivityId()); + } + else + { + log->Log(L"iisnode failed to process a new http request", WINEVENT_LEVEL_INFO); + } + } + + if (ERROR_NOT_ENOUGH_QUOTA == hr) + { + CProtocolBridge::SendEmptyResponse(pHttpContext, 503, CNodeConstants::IISNODE_ERROR_NOT_ENOUGH_QUOTA, _T("Service Unavailable"), hr); + } + else if (ERROR_FILE_NOT_FOUND == hr) + { + CProtocolBridge::SendEmptyResponse(pHttpContext, 404, 0, _T("Not Found"), hr); + } + else if (ERROR_NOT_SUPPORTED == hr) + { + if (log) + { + log->Log(L"iisnode rejected websocket connection request", WINEVENT_LEVEL_INFO); + } + CProtocolBridge::SendEmptyResponse(pHttpContext, 501, 0, _T("Not Implemented"), hr); + } + else if (!CProtocolBridge::SendIisnodeError(pHttpContext, hr)) + { + CProtocolBridge::SendEmptyResponse( pHttpContext, + 500, + CNodeConstants::IISNODE_ERROR_ON_EXECUTE_REQ_HANDLER, + _T("Internal Server Error"), + hr ); + } + + return RQ_NOTIFICATION_FINISH_REQUEST; } #else @@ -125,8 +129,8 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( // This simple handler returns an HTTP 200 with a Hello, world! in the body REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( - IN IHttpContext* pHttpContext, - IN IHttpEventProvider* pProvider) + IN IHttpContext* pHttpContext, + IN IHttpEventProvider* pProvider) { UNREFERENCED_PARAMETER( pProvider ); @@ -182,46 +186,46 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnExecuteRequestHandler( #endif REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion( - IHttpContext* pHttpContext, DWORD dwNotification, BOOL fPostNotification, IHttpEventProvider* pProvider, IHttpCompletionInfo* pCompletionInfo) + IHttpContext* pHttpContext, DWORD dwNotification, BOOL fPostNotification, IHttpEventProvider* pProvider, IHttpCompletionInfo* pCompletionInfo) { - if (NULL != pCompletionInfo && NULL != pHttpContext) - { - CNodeHttpStoredContext* ctx = (CNodeHttpStoredContext*)pHttpContext->GetModuleContextContainer()->GetModuleContext(this->applicationManager->GetModuleId()); - - if (ctx->GetIsUpgrade()) - { - IHttpCompletionInfo2* pCompletionInfo2 = (IHttpCompletionInfo2*)pCompletionInfo; - if (1 == pCompletionInfo2->GetCompletedOperation()) - { - // This is completion of the read request for incoming bytes of an opaque byte stream after 101 Switching protocol response was sent - - ctx = ctx->GetUpgradeContext(); - } - } - - ctx->IncreasePendingAsyncOperationCount(); - - this->applicationManager->GetEventProvider()->Log( - L"iisnode enters CNodeHttpModule::OnAsyncCompletion callback", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - - ASYNC_CONTEXT* async = ctx->GetAsyncContext(); - if (NULL != async->completionProcessor) - { - DWORD bytesCompleted = pCompletionInfo->GetCompletionBytes(); - if (async->completionProcessor == CProtocolBridge::SendResponseBodyCompleted) - { - bytesCompleted = async->bytesCompleteted; - async->bytesCompleteted = 0; - } - async->completionProcessor(pCompletionInfo->GetCompletionStatus(), bytesCompleted, ctx->GetOverlapped()); - async->RunSynchronousContinuations(); - } - - long value = ctx->DecreasePendingAsyncOperationCount(); - - REQUEST_NOTIFICATION_STATUS result = ctx->GetRequestNotificationStatus(); + if (NULL != pCompletionInfo && NULL != pHttpContext) + { + CNodeHttpStoredContext* ctx = (CNodeHttpStoredContext*)pHttpContext->GetModuleContextContainer()->GetModuleContext(this->applicationManager->GetModuleId()); + + if (ctx->GetIsUpgrade()) + { + IHttpCompletionInfo2* pCompletionInfo2 = (IHttpCompletionInfo2*)pCompletionInfo; + if (1 == pCompletionInfo2->GetCompletedOperation()) + { + // This is completion of the read request for incoming bytes of an opaque byte stream after 101 Switching protocol response was sent + + ctx = ctx->GetUpgradeContext(); + } + } + + ctx->IncreasePendingAsyncOperationCount(); + + this->applicationManager->GetEventProvider()->Log( + L"iisnode enters CNodeHttpModule::OnAsyncCompletion callback", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + + ASYNC_CONTEXT* async = ctx->GetAsyncContext(); + if (NULL != async->completionProcessor) + { + DWORD bytesCompleted = pCompletionInfo->GetCompletionBytes(); + if (async->completionProcessor == CProtocolBridge::SendResponseBodyCompleted) + { + bytesCompleted = async->bytesCompleteted; + async->bytesCompleteted = 0; + } + async->completionProcessor(pCompletionInfo->GetCompletionStatus(), bytesCompleted, ctx->GetOverlapped()); + async->RunSynchronousContinuations(); + } + + long value = ctx->DecreasePendingAsyncOperationCount(); + + REQUEST_NOTIFICATION_STATUS result = ctx->GetRequestNotificationStatus(); if(ctx->GetIsUpgrade() && value == 0) { @@ -233,36 +237,36 @@ REQUEST_NOTIFICATION_STATUS CNodeHttpModule::OnAsyncCompletion( result = RQ_NOTIFICATION_CONTINUE; } - switch (result) - { - default: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnAsyncCompletion", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_CONTINUE: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_CONTINUE", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_FINISH_REQUEST: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_FINISH_REQUEST", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - case RQ_NOTIFICATION_PENDING: - this->applicationManager->GetEventProvider()->Log( - L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_PENDING", - WINEVENT_LEVEL_VERBOSE, - ctx->GetActivityId()); - break; - }; - - return result; - } - - return RQ_NOTIFICATION_CONTINUE; + switch (result) + { + default: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnAsyncCompletion", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_CONTINUE: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_CONTINUE", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_FINISH_REQUEST: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_FINISH_REQUEST", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + case RQ_NOTIFICATION_PENDING: + this->applicationManager->GetEventProvider()->Log( + L"iisnode leaves CNodeHttpModule::OnAsyncCompletion with RQ_NOTIFICATION_PENDING", + WINEVENT_LEVEL_VERBOSE, + ctx->GetActivityId()); + break; + }; + + return result; + } + + return RQ_NOTIFICATION_CONTINUE; } diff --git a/src/iisnode/cnodehttpmodulefactory.cpp b/src/iisnode/cnodehttpmodulefactory.cpp index f154a4e5..b6ee9521 100644 --- a/src/iisnode/cnodehttpmodulefactory.cpp +++ b/src/iisnode/cnodehttpmodulefactory.cpp @@ -1,37 +1,42 @@ #include "precomp.h" CNodeHttpModuleFactory::CNodeHttpModuleFactory() - : applicationManager(NULL) + : applicationManager(NULL) { } CNodeHttpModuleFactory::~CNodeHttpModuleFactory() { - if (NULL != this->applicationManager) - { - delete this->applicationManager; - this->applicationManager = NULL; - } + if (NULL != this->applicationManager) + { + delete this->applicationManager; + this->applicationManager = NULL; + } - WSACleanup(); + WSACleanup(); } HRESULT CNodeHttpModuleFactory::Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId) { - HRESULT hr; - WSADATA wsaData; + HRESULT hr; + WSADATA wsaData; - ErrorIf(NULL == server, ERROR_INVALID_PARAMETER); - ErrorIf(NULL == moduleId, ERROR_INVALID_PARAMETER); + ErrorIf(NULL == server, ERROR_INVALID_PARAMETER); + ErrorIf(NULL == moduleId, ERROR_INVALID_PARAMETER); - CModuleConfiguration::Initialize(server, moduleId); + CModuleConfiguration::Initialize(server, moduleId); - CheckError(WSAStartup(MAKEWORD(2,2), &wsaData)); - ErrorIf(NULL == (this->applicationManager = new CNodeApplicationManager(server, moduleId)), ERROR_NOT_ENOUGH_MEMORY); + CheckError(WSAStartup(MAKEWORD(2,2), &wsaData)); + ErrorIf(NULL == (this->applicationManager = new CNodeApplicationManager(server, moduleId)), ERROR_NOT_ENOUGH_MEMORY); - return S_OK; + return S_OK; Error: - return hr; + return hr; +} + +CNodeApplicationManager* CNodeHttpModuleFactory::GetNodeApplicationManager() +{ + return this->applicationManager; } HRESULT CNodeHttpModuleFactory::GetHttpModule( @@ -39,13 +44,13 @@ HRESULT CNodeHttpModuleFactory::GetHttpModule( IN IModuleAllocator * ) { - HRESULT hr; + HRESULT hr; ErrorIf(NULL == (*ppModule = new CNodeHttpModule(this->applicationManager)), ERROR_NOT_ENOUGH_MEMORY); return S_OK; Error: - return hr; + return hr; } void CNodeHttpModuleFactory::Terminate() diff --git a/src/iisnode/cnodehttpmodulefactory.h b/src/iisnode/cnodehttpmodulefactory.h index de5c7568..2a00554e 100644 --- a/src/iisnode/cnodehttpmodulefactory.h +++ b/src/iisnode/cnodehttpmodulefactory.h @@ -3,15 +3,16 @@ class CNodeHttpModuleFactory : public IHttpModuleFactory { - CNodeApplicationManager* applicationManager; + CNodeApplicationManager* applicationManager; public: - CNodeHttpModuleFactory(); - ~CNodeHttpModuleFactory(); - HRESULT Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId); + CNodeHttpModuleFactory(); + ~CNodeHttpModuleFactory(); + HRESULT Initialize(IHttpServer* server, HTTP_MODULE_ID moduleId); HRESULT GetHttpModule(OUT CHttpModule **ppModule, IN IModuleAllocator *); + CNodeApplicationManager* GetNodeApplicationManager(); void Terminate(); }; diff --git a/src/iisnode/cnodeprocess.cpp b/src/iisnode/cnodeprocess.cpp index 078aae57..dfcf579a 100644 --- a/src/iisnode/cnodeprocess.cpp +++ b/src/iisnode/cnodeprocess.cpp @@ -58,6 +58,7 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context) PWSTR scriptTranslated = NULL; DWORD currentDirectorySize = 0; CNodeApplication* app = this->GetProcessManager()->GetApplication(); + PCH pSignalPipeName = NULL; RtlZeroMemory(&processInformation, sizeof processInformation); RtlZeroMemory(&startupInfo, sizeof startupInfo); @@ -117,12 +118,23 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context) wcscat(fullCommandLine, scriptName); wcscat(fullCommandLine, L"\""); + if(CModuleConfiguration::GetRecycleSignalEnabled(context)) + { + LPCWSTR pszSignalPipeName = app->GetApplicationManager()->GetSignalPipeName(); + DWORD dwSignalPipeNameLen = wcslen(pszSignalPipeName); + + ErrorIf(NULL == (pSignalPipeName = new CHAR[dwSignalPipeNameLen+1]), E_OUTOFMEMORY); + ErrorIf(dwSignalPipeNameLen != WideCharToMultiByte(CP_ACP, 0, pszSignalPipeName, dwSignalPipeNameLen, pSignalPipeName, dwSignalPipeNameLen, NULL, NULL), E_FAIL); + pSignalPipeName[dwSignalPipeNameLen] = '\0'; + } + // create the environment block for the node.js process CheckError(CModuleConfiguration::CreateNodeEnvironment( context, app->IsDebugger() ? app->GetDebugPort() : 0, this->namedPipe, + CModuleConfiguration::GetRecycleSignalEnabled(context) ? pSignalPipeName : NULL, &newEnvironment)); // establish the current directory for node.exe process to be the same as the location of the application *.js file @@ -206,7 +218,12 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context) delete [] fullCommandLine; fullCommandLine = NULL; CloseHandle(processInformation.hThread); - processInformation.hThread = NULL; + processInformation.hThread = NULL; + if(pSignalPipeName != NULL) + { + delete[] pSignalPipeName; + pSignalPipeName = NULL; + } if (this->GetProcessManager()->GetApplication()->IsDebugger()) { @@ -239,6 +256,12 @@ HRESULT CNodeProcess::Initialize(IHttpContext* context) currentDirectory = NULL; } + if(pSignalPipeName) + { + delete[] pSignalPipeName; + pSignalPipeName = NULL; + } + if (suuid != NULL) { RpcStringFree(&suuid); diff --git a/src/iisnode/cnodeprocessmanager.cpp b/src/iisnode/cnodeprocessmanager.cpp index 2343a709..cafb63c0 100644 --- a/src/iisnode/cnodeprocessmanager.cpp +++ b/src/iisnode/cnodeprocessmanager.cpp @@ -1,437 +1,437 @@ #include "precomp.h" CNodeProcessManager::CNodeProcessManager(CNodeApplication* application, IHttpContext* context) - : application(application), processes(NULL), currentProcess(0), isClosing(FALSE), - refCount(1), gracefulShutdownProcessCount(0) + : application(application), processes(NULL), currentProcess(0), isClosing(FALSE), + refCount(1), gracefulShutdownProcessCount(0) { - if (this->GetApplication()->IsDebugMode()) - { - this->processCount = 1; - } - else - { - this->processCount = CModuleConfiguration::GetNodeProcessCountPerApplication(context); - } - - // cache event provider since the application can be disposed prior to CNodeProcessManager - this->eventProvider = this->GetApplication()->GetApplicationManager()->GetEventProvider(); - - this->gracefulShutdownTimeout = CModuleConfiguration::GetGracefulShutdownTimeout(context); - InitializeSRWLock(&this->srwlock); - this->gracefulShutdownDrainHandle = CreateEvent(NULL, TRUE, TRUE, NULL); + if (this->GetApplication()->IsDebugMode()) + { + this->processCount = 1; + } + else + { + this->processCount = CModuleConfiguration::GetNodeProcessCountPerApplication(context); + } + + // cache event provider since the application can be disposed prior to CNodeProcessManager + this->eventProvider = this->GetApplication()->GetApplicationManager()->GetEventProvider(); + + this->gracefulShutdownTimeout = CModuleConfiguration::GetGracefulShutdownTimeout(context); + InitializeSRWLock(&this->srwlock); + this->gracefulShutdownDrainHandle = CreateEvent(NULL, TRUE, TRUE, NULL); } CNodeProcessManager::~CNodeProcessManager() { - this->Cleanup(); + this->Cleanup(); } void CNodeProcessManager::Cleanup() { - if (NULL != this->processes) - { - for (int i = 0; i < this->processCount; i++) - { - if (this->processes[i]) - { - delete this->processes[i]; - } - } - - delete[] this->processes; - this->processes = NULL; - } - - CloseHandle(this->gracefulShutdownDrainHandle); - this->gracefulShutdownDrainHandle = NULL; + if (NULL != this->processes) + { + for (int i = 0; i < this->processCount; i++) + { + if (this->processes[i]) + { + delete this->processes[i]; + } + } + + delete[] this->processes; + this->processes = NULL; + } + + CloseHandle(this->gracefulShutdownDrainHandle); + this->gracefulShutdownDrainHandle = NULL; } CNodeApplication* CNodeProcessManager::GetApplication() { - return this->application; + return this->application; } HRESULT CNodeProcessManager::Initialize(IHttpContext* context) { - HRESULT hr; + HRESULT hr; - ErrorIf(NULL == (this->processes = new CNodeProcess* [this->processCount]), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(this->processes, this->processCount * sizeof(CNodeProcess*)); - for (int i = 0; i < this->processCount; i++) - { - CheckError(this->AddProcess(i, context)); - } + ErrorIf(NULL == (this->processes = new CNodeProcess* [this->processCount]), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(this->processes, this->processCount * sizeof(CNodeProcess*)); + for (int i = 0; i < this->processCount; i++) + { + CheckError(this->AddProcess(i, context)); + } - return S_OK; + return S_OK; Error: - this->Cleanup(); + this->Cleanup(); - return hr; + return hr; } HRESULT CNodeProcessManager::AddProcess(int ordinal, IHttpContext* context) { - HRESULT hr; + HRESULT hr; - ErrorIf(NULL != this->processes[ordinal], ERROR_INVALID_PARAMETER); - ErrorIf(NULL == (this->processes[ordinal] = new CNodeProcess(this, context)), ERROR_NOT_ENOUGH_MEMORY); - CheckError(this->processes[ordinal]->Initialize(context)); + ErrorIf(NULL != this->processes[ordinal], ERROR_INVALID_PARAMETER); + ErrorIf(NULL == (this->processes[ordinal] = new CNodeProcess(this, context)), ERROR_NOT_ENOUGH_MEMORY); + CheckError(this->processes[ordinal]->Initialize(context)); - return S_OK; + return S_OK; Error: - if (NULL != this->processes[ordinal]) - { - delete this->processes[ordinal]; - this->processes[ordinal] = NULL; - } + if (NULL != this->processes[ordinal]) + { + delete this->processes[ordinal]; + this->processes[ordinal] = NULL; + } - return hr; + return hr; } HRESULT CNodeProcessManager::Dispatch(CNodeHttpStoredContext* request) { - HRESULT hr; - unsigned int tmpProcess, processToUse; - - CheckNull(request); - - this->AddRef(); // decremented at the bottom of this method - - if (!this->isClosing) - { - ENTER_SRW_SHARED(this->srwlock) - - if (!this->isClosing) - { - // employ a round robin routing logic to get a "ticket" to use a process with a specific ordinal number - - if (1 == this->processCount) - { - processToUse = 0; - } - else - { - do - { - tmpProcess = this->currentProcess; - processToUse = (tmpProcess + 1) % this->processCount; - } while (tmpProcess != InterlockedCompareExchange(&this->currentProcess, processToUse, tmpProcess)); - } - - // try dispatch to that process - - if (NULL != this->processes[processToUse]) - { - CheckError(this->processes[processToUse]->AcceptRequest(request)); - request = NULL; - } - } - - LEAVE_SRW_SHARED(this->srwlock) - - if (NULL != request) - { - // the process to dispatch to does not exist and must be recreated - - ENTER_SRW_EXCLUSIVE(this->srwlock) - - if (!this->isClosing) - { - if (NULL == this->processes[processToUse]) - { - CheckError(this->AddProcess(processToUse, request->GetHttpContext())); - } - - CheckError(this->processes[processToUse]->AcceptRequest(request)); - request = NULL; - } - - LEAVE_SRW_EXCLUSIVE(this->srwlock) - } - } - - if (request) - { - this->GetEventProvider()->Log(L"iisnode failed to accept a request beacuse the application is recycling", WINEVENT_LEVEL_ERROR, request->GetActivityId()); - CProtocolBridge::SendEmptyResponse(request, 503, _T("Service Unavailable"), IISNODE_ERROR_APPLICATION_IS_RECYCLING); - } - - this->DecRef(); // incremented at the beginning of this method - - return S_OK; + HRESULT hr; + unsigned int tmpProcess, processToUse; + + CheckNull(request); + + this->AddRef(); // decremented at the bottom of this method + + if (!this->isClosing) + { + ENTER_SRW_SHARED(this->srwlock) + + if (!this->isClosing) + { + // employ a round robin routing logic to get a "ticket" to use a process with a specific ordinal number + + if (1 == this->processCount) + { + processToUse = 0; + } + else + { + do + { + tmpProcess = this->currentProcess; + processToUse = (tmpProcess + 1) % this->processCount; + } while (tmpProcess != InterlockedCompareExchange(&this->currentProcess, processToUse, tmpProcess)); + } + + // try dispatch to that process + + if (NULL != this->processes[processToUse]) + { + CheckError(this->processes[processToUse]->AcceptRequest(request)); + request = NULL; + } + } + + LEAVE_SRW_SHARED(this->srwlock) + + if (NULL != request) + { + // the process to dispatch to does not exist and must be recreated + + ENTER_SRW_EXCLUSIVE(this->srwlock) + + if (!this->isClosing) + { + if (NULL == this->processes[processToUse]) + { + CheckError(this->AddProcess(processToUse, request->GetHttpContext())); + } + + CheckError(this->processes[processToUse]->AcceptRequest(request)); + request = NULL; + } + + LEAVE_SRW_EXCLUSIVE(this->srwlock) + } + } + + if (request) + { + this->GetEventProvider()->Log(L"iisnode failed to accept a request beacuse the application is recycling", WINEVENT_LEVEL_ERROR, request->GetActivityId()); + CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_FAILED_ACCEPT_REQUEST_APP_RECYCLE, _T("Service Unavailable"), IISNODE_ERROR_APPLICATION_IS_RECYCLING); + } + + this->DecRef(); // incremented at the beginning of this method + + return S_OK; Error: - this->GetEventProvider()->Log( - L"iisnode failed to initiate processing of a request", WINEVENT_LEVEL_ERROR); + this->GetEventProvider()->Log( + L"iisnode failed to initiate processing of a request", WINEVENT_LEVEL_ERROR); - if (!CProtocolBridge::SendIisnodeError(request, hr)) - { - CProtocolBridge::SendEmptyResponse(request, 503, _T("Service Unavailable"), hr); - } + if (!CProtocolBridge::SendIisnodeError(request, hr)) + { + CProtocolBridge::SendEmptyResponse(request, 503, CNodeConstants::IISNODE_ERROR_INIT_PROCESS_REQUEST, _T("Service Unavailable"), hr); + } - this->DecRef(); // incremented at the beginning of this method + this->DecRef(); // incremented at the beginning of this method - return hr; + return hr; } HRESULT CNodeProcessManager::RecycleProcess(CNodeProcess* process) { - HRESULT hr; - HANDLE recycler; - ProcessRecycleArgs* args = NULL; - BOOL gracefulRecycle = FALSE; - CNodeApplication* appToRecycle = NULL; - - // remove the process from the process pool - - ENTER_SRW_EXCLUSIVE(this->srwlock) - - if (!this->isClosing) - { - appToRecycle = this->GetApplication(); - - if (!appToRecycle->IsDebugMode()) - { - appToRecycle = NULL; - - int i; - for (i = 0; i < this->processCount; i++) - { - if (this->processes[i] == process) - { - break; - } - } - - if (i == this->processCount) - { - // process not found in the active process list - - return S_OK; - } - - this->processes[i] = NULL; - - // prevent the CNodeProcessManager from recycling until all CNodeProcesses that died finished graceful shutdown - if (1L == InterlockedIncrement(&this->gracefulShutdownProcessCount)) - { - ResetEvent(this->gracefulShutdownDrainHandle); - } - - gracefulRecycle = TRUE; - } - } - - LEAVE_SRW_EXCLUSIVE(this->srwlock) - - // graceful recycle - - if (gracefulRecycle) - { - ErrorIf(NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY); - args->count = 1; - args->process = process; - args->processes = &args->process; - args->processManager = this; - args->disposeApplication = FALSE; - args->disposeProcess = TRUE; - ErrorIf((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex(NULL, 0, CNodeProcessManager::GracefulShutdown, args, 0, NULL)), ERROR_NOT_ENOUGH_MEMORY); - CloseHandle(recycler); - } - - if (appToRecycle) - { - appToRecycle->GetApplicationManager()->RecycleApplication(appToRecycle); - } - - return S_OK; + HRESULT hr; + HANDLE recycler; + ProcessRecycleArgs* args = NULL; + BOOL gracefulRecycle = FALSE; + CNodeApplication* appToRecycle = NULL; + + // remove the process from the process pool + + ENTER_SRW_EXCLUSIVE(this->srwlock) + + if (!this->isClosing) + { + appToRecycle = this->GetApplication(); + + if (!appToRecycle->IsDebugMode()) + { + appToRecycle = NULL; + + int i; + for (i = 0; i < this->processCount; i++) + { + if (this->processes[i] == process) + { + break; + } + } + + if (i == this->processCount) + { + // process not found in the active process list + + return S_OK; + } + + this->processes[i] = NULL; + + // prevent the CNodeProcessManager from recycling until all CNodeProcesses that died finished graceful shutdown + if (1L == InterlockedIncrement(&this->gracefulShutdownProcessCount)) + { + ResetEvent(this->gracefulShutdownDrainHandle); + } + + gracefulRecycle = TRUE; + } + } + + LEAVE_SRW_EXCLUSIVE(this->srwlock) + + // graceful recycle + + if (gracefulRecycle) + { + ErrorIf(NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY); + args->count = 1; + args->process = process; + args->processes = &args->process; + args->processManager = this; + args->disposeApplication = FALSE; + args->disposeProcess = TRUE; + ErrorIf((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex(NULL, 0, CNodeProcessManager::GracefulShutdown, args, 0, NULL)), ERROR_NOT_ENOUGH_MEMORY); + CloseHandle(recycler); + } + + if (appToRecycle) + { + appToRecycle->GetApplicationManager()->RecycleApplication(appToRecycle); + } + + return S_OK; Error: - if (args) - { - delete args; - } + if (args) + { + delete args; + } - if (0L == InterlockedDecrement(&this->gracefulShutdownProcessCount)) - { - SetEvent(this->gracefulShutdownDrainHandle); - } + if (0L == InterlockedDecrement(&this->gracefulShutdownProcessCount)) + { + SetEvent(this->gracefulShutdownDrainHandle); + } - return hr; + return hr; } HRESULT CNodeProcessManager::Recycle() { - HRESULT hr; - HANDLE recycler; - ProcessRecycleArgs* args = NULL; + HRESULT hr; + HANDLE recycler; + ProcessRecycleArgs* args = NULL; - ENTER_SRW_EXCLUSIVE(this->srwlock) + ENTER_SRW_EXCLUSIVE(this->srwlock) - this->isClosing = TRUE; + this->isClosing = TRUE; - // perform actual recycling on a diffrent thread to free up the file watcher thread + // perform actual recycling on a diffrent thread to free up the file watcher thread - ErrorIf(NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY); - args->count = this->processCount; - args->process = NULL; - args->processes = this->processes; - args->processManager = this; - args->disposeApplication = TRUE; - args->disposeProcess = FALSE; - ErrorIf((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex(NULL, 0, CNodeProcessManager::GracefulShutdown, args, 0, NULL)), ERROR_NOT_ENOUGH_MEMORY); - CloseHandle(recycler); + ErrorIf(NULL == (args = new ProcessRecycleArgs), ERROR_NOT_ENOUGH_MEMORY); + args->count = this->processCount; + args->process = NULL; + args->processes = this->processes; + args->processManager = this; + args->disposeApplication = TRUE; + args->disposeProcess = FALSE; + ErrorIf((HANDLE)-1L == (recycler = (HANDLE) _beginthreadex(NULL, 0, CNodeProcessManager::GracefulShutdown, args, 0, NULL)), ERROR_NOT_ENOUGH_MEMORY); + CloseHandle(recycler); - LEAVE_SRW_EXCLUSIVE(this->srwlock) + LEAVE_SRW_EXCLUSIVE(this->srwlock) - return S_OK; + return S_OK; Error: - if (args) - { - delete args; - } + if (args) + { + delete args; + } - // if lack of memory is preventing us from initiating shutdown, we will just not provide auto update + // if lack of memory is preventing us from initiating shutdown, we will just not provide auto update - return hr; + return hr; } unsigned int CNodeProcessManager::GracefulShutdown(void* arg) { - ProcessRecycleArgs* args = (ProcessRecycleArgs*)arg; - HRESULT hr; - HANDLE* drainHandles = NULL; - DWORD drainHandleCount = 0; - - // drain active requests - - ErrorIf(NULL == (drainHandles = new HANDLE[args->count + 1]), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(drainHandles, args->count * sizeof HANDLE); - for (int i = 0; i < args->count; i++) - { - if (args->processes[i]) - { - drainHandles[drainHandleCount] = CreateEvent(NULL, TRUE, FALSE, NULL); - args->processes[i]->SignalWhenDrained(drainHandles[drainHandleCount]); - drainHandleCount++; - } - } - - if (args->disposeApplication) - { - // prevent the application from exiting until pending graceful shutdown of died CNodeProcesses has finished - drainHandles[drainHandleCount++] = args->processManager->gracefulShutdownDrainHandle; - } - - if (args->processManager->gracefulShutdownTimeout > 0) - { - WaitForMultipleObjects(drainHandleCount, drainHandles, TRUE, args->processManager->gracefulShutdownTimeout); - } - - if (args->disposeApplication) - { - // do not close the gracefulShutdownDrainHandle as it is owned by CNodeProcessManager - drainHandleCount--; - } - - for (int i = 0; i < drainHandleCount; i++) - { - CloseHandle(drainHandles[i]); - } - delete[] drainHandles; - drainHandles = NULL; - - if (args->disposeApplication) - { - // delete the application if requested (this will also delete process manager and all processes) - // this is the application recycling code path - - delete args->processManager->GetApplication(); - } - else if (args->disposeProcess) - { - // delete a single process if requested - // this is the single process recycling code path (e.g. node.exe died) - - delete args->processes[0]; - if (0L == InterlockedDecrement(&args->processManager->gracefulShutdownProcessCount)) - { - // release recycle of CNodeApplication that may be running concurrently - SetEvent(args->processManager->gracefulShutdownDrainHandle); - } - } - - delete args; - args = NULL; - - return S_OK; + ProcessRecycleArgs* args = (ProcessRecycleArgs*)arg; + HRESULT hr; + HANDLE* drainHandles = NULL; + DWORD drainHandleCount = 0; + + // drain active requests + + ErrorIf(NULL == (drainHandles = new HANDLE[args->count + 1]), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(drainHandles, args->count * sizeof HANDLE); + for (int i = 0; i < args->count; i++) + { + if (args->processes[i]) + { + drainHandles[drainHandleCount] = CreateEvent(NULL, TRUE, FALSE, NULL); + args->processes[i]->SignalWhenDrained(drainHandles[drainHandleCount]); + drainHandleCount++; + } + } + + if (args->disposeApplication) + { + // prevent the application from exiting until pending graceful shutdown of died CNodeProcesses has finished + drainHandles[drainHandleCount++] = args->processManager->gracefulShutdownDrainHandle; + } + + if (args->processManager->gracefulShutdownTimeout > 0) + { + WaitForMultipleObjects(drainHandleCount, drainHandles, TRUE, args->processManager->gracefulShutdownTimeout); + } + + if (args->disposeApplication) + { + // do not close the gracefulShutdownDrainHandle as it is owned by CNodeProcessManager + drainHandleCount--; + } + + for (int i = 0; i < drainHandleCount; i++) + { + CloseHandle(drainHandles[i]); + } + delete[] drainHandles; + drainHandles = NULL; + + if (args->disposeApplication) + { + // delete the application if requested (this will also delete process manager and all processes) + // this is the application recycling code path + + delete args->processManager->GetApplication(); + } + else if (args->disposeProcess) + { + // delete a single process if requested + // this is the single process recycling code path (e.g. node.exe died) + + delete args->processes[0]; + if (0L == InterlockedDecrement(&args->processManager->gracefulShutdownProcessCount)) + { + // release recycle of CNodeApplication that may be running concurrently + SetEvent(args->processManager->gracefulShutdownDrainHandle); + } + } + + delete args; + args = NULL; + + return S_OK; Error: - if (args) - { - if (args->disposeProcess) - { - if (0L == InterlockedDecrement(&args->processManager->gracefulShutdownProcessCount)) - { - // release recycle of CNodeApplication that may be running concurrently - SetEvent(args->processManager->gracefulShutdownDrainHandle); - } - } - - delete args; - args = NULL; - } - - if (drainHandles) - { - delete [] drainHandles; - drainHandles = NULL; - } - - return hr; + if (args) + { + if (args->disposeProcess) + { + if (0L == InterlockedDecrement(&args->processManager->gracefulShutdownProcessCount)) + { + // release recycle of CNodeApplication that may be running concurrently + SetEvent(args->processManager->gracefulShutdownDrainHandle); + } + } + + delete args; + args = NULL; + } + + if (drainHandles) + { + delete [] drainHandles; + drainHandles = NULL; + } + + return hr; } long CNodeProcessManager::AddRef() { - return InterlockedIncrement(&this->refCount); + return InterlockedIncrement(&this->refCount); } long CNodeProcessManager::DecRef() { - long result = InterlockedDecrement(&this->refCount); + long result = InterlockedDecrement(&this->refCount); - if (0 == result) - { - delete this; - } + if (0 == result) + { + delete this; + } - return result; + return result; } CNodeEventProvider* CNodeProcessManager::GetEventProvider() { - return this->eventProvider; + return this->eventProvider; } DWORD CNodeProcessManager::GetActiveRequestCount() { - DWORD result = 0; + DWORD result = 0; - for (DWORD i = 0; i < this->processCount; i++) - { - if (this->processes[i]) - { - result += this->processes[i]->GetActiveRequestCount(); - } - } + for (DWORD i = 0; i < this->processCount; i++) + { + if (this->processes[i]) + { + result += this->processes[i]->GetActiveRequestCount(); + } + } - return result; + return result; } DWORD CNodeProcessManager::GetProcessCount() { - return this->processCount; + return this->processCount; } \ No newline at end of file diff --git a/src/iisnode/cprotocolbridge.cpp b/src/iisnode/cprotocolbridge.cpp index 6c9b9a41..8db68e47 100644 --- a/src/iisnode/cprotocolbridge.cpp +++ b/src/iisnode/cprotocolbridge.cpp @@ -2,1869 +2,1947 @@ HRESULT CProtocolBridge::PostponeProcessing(CNodeHttpStoredContext* context, DWORD dueTime) { - CAsyncManager* async = context->GetNodeApplication()->GetApplicationManager()->GetAsyncManager(); - LARGE_INTEGER delay; - delay.QuadPart = dueTime; - delay.QuadPart *= -10000; // convert from ms to 100ns units + CAsyncManager* async = context->GetNodeApplication()->GetApplicationManager()->GetAsyncManager(); + LARGE_INTEGER delay; + delay.QuadPart = dueTime; + delay.QuadPart *= -10000; // convert from ms to 100ns units - return async->SetTimer(context->GetAsyncContext(), &delay); + return async->SetTimer(context->GetAsyncContext(), &delay); } #define LOCAL127 0x0100007F // 127.0.0.1 BOOL CProtocolBridge::IsLocalCall(IHttpContext* ctx) { - PSOCKADDR src = ctx->GetRequest()->GetRemoteAddress(); - PSOCKADDR dest = ctx->GetRequest()->GetLocalAddress(); + PSOCKADDR src = ctx->GetRequest()->GetRemoteAddress(); + PSOCKADDR dest = ctx->GetRequest()->GetLocalAddress(); - if (AF_INET == src->sa_family && AF_INET == dest->sa_family) - { + if (AF_INET == src->sa_family && AF_INET == dest->sa_family) + { DWORD srcAddress = ntohl(((PSOCKADDR_IN)src)->sin_addr.s_addr); - DWORD destAddress = ntohl(((PSOCKADDR_IN)dest)->sin_addr.s_addr); + DWORD destAddress = ntohl(((PSOCKADDR_IN)dest)->sin_addr.s_addr); - return srcAddress == destAddress || LOCAL127 == srcAddress || LOCAL127 == destAddress; - } - else if (AF_INET6 == src->sa_family && AF_INET6 == dest->sa_family) - { + return srcAddress == destAddress || LOCAL127 == srcAddress || LOCAL127 == destAddress; + } + else if (AF_INET6 == src->sa_family && AF_INET6 == dest->sa_family) + { IN6_ADDR* srcAddress = &((PSOCKADDR_IN6)src)->sin6_addr; - IN6_ADDR* destAddress = &((PSOCKADDR_IN6)dest)->sin6_addr; + IN6_ADDR* destAddress = &((PSOCKADDR_IN6)dest)->sin6_addr; - if (0 == memcmp(srcAddress, destAddress, sizeof IN6_ADDR)) - { - return TRUE; - } + if (0 == memcmp(srcAddress, destAddress, sizeof IN6_ADDR)) + { + return TRUE; + } - if (IN6_IS_ADDR_LOOPBACK(srcAddress) || IN6_IS_ADDR_LOOPBACK(destAddress)) - { - return TRUE; - } - } + if (IN6_IS_ADDR_LOOPBACK(srcAddress) || IN6_IS_ADDR_LOOPBACK(destAddress)) + { + return TRUE; + } + } - return FALSE; + return FALSE; } BOOL CProtocolBridge::SendIisnodeError(IHttpContext* httpCtx, HRESULT hr) { - if (IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION == hr || IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE == hr) - { - if (CProtocolBridge::IsLocalCall(httpCtx)) - { - switch (hr) { - - default: - return FALSE; - - case IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "iisnode was unable to read the configuration file. Make sure the web.config file syntax is correct. In particular, verify the " - " " - "iisnode configuration section matches the expected schema. The schema of the iisnode section that your version of iisnode requires is stored in the " - "%systemroot%\\system32\\inetsrv\\config\\schema\\iisnode_schema.xml file."); - break; - - case IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "iisnode was unable to read the configuration file iisnode.yml. Make sure the iisnode.yml file syntax is correct. For reference, check " - " " - "the sample iisnode.yml file. The property names recognized in the iisnode.yml file of your version of iisnode are stored in the " - "%systemroot%\\system32\\inetsrv\\config\\schema\\iisnode_schema.xml file."); - break; - }; - - return TRUE; - } - else - { - return FALSE; - } - } - - if (!CModuleConfiguration::GetDevErrorsEnabled(httpCtx)) - { - return FALSE; - } - - switch (hr) { - - default: - return FALSE; - - case IISNODE_ERROR_UNRECOGNIZED_DEBUG_COMMAND: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "Unrecognized debugging command. Supported commands are ?debug (default), ?brk, and ?kill."); - break; - - case IISNODE_ERROR_UNABLE_TO_FIND_DEBUGGING_PORT: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "The debugger was unable to acquire a TCP port to establish communication with the debugee. " - "This may be due to lack of free TCP ports in the range specified in the " - "system.webServer/iisnode/@debuggerPortRange configuration " - "section, or due to lack of permissions to create TCP listeners by the identity of the IIS worker process."); - break; - - case IISNODE_ERROR_UNABLE_TO_CONNECT_TO_DEBUGEE: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "The debugger was unable to connect to the the debugee. " - "This may be due to the debugee process terminating during startup (e.g. due to an unhandled exception) or " - "failing to establish a TCP listener on the debugging port. "); - break; - - case IISNODE_ERROR_INSPECTOR_NOT_FOUND: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "The version of iisnode installed on the server does not support remote debugging. " - "To use remote debugging, please update your iisnode installation on the server to one available from " - "http://github.com/tjanczuk/iisnode/downloads. " - "We apologize for inconvenience."); - break; - - case IISNODE_ERROR_UNABLE_TO_CREATE_DEBUGGER_FILES: - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - "The iisnode module is unable to deploy supporting files necessary to initialize the debugger. " - "Please check that the identity of the IIS application pool running the node.js application has read and write access " - "permissions to the directory on the server where the node.js application is located."); - break; - - case IISNODE_ERROR_UNABLE_TO_START_NODE_EXE: - char* errorMessage = - "The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available " - "at the location specified in the " - "system.webServer/iisnode/@nodeProcessCommandLine element of web.config. " - "By default node.exe is expected in one of the directories listed in the PATH environment variable."; - - CProtocolBridge::SendSyncResponse( - httpCtx, - 200, - "OK", - hr, - TRUE, - errorMessage); - break; - - }; - - return TRUE; + if (IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION == hr || IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE == hr) + { + if (CProtocolBridge::IsLocalCall(httpCtx)) + { + switch (hr) { + + default: + return FALSE; + + case IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "iisnode was unable to read the configuration file. Make sure the web.config file syntax is correct. In particular, verify the " + " " + "iisnode configuration section matches the expected schema. The schema of the iisnode section that your version of iisnode requires is stored in the " + "%systemroot%\\system32\\inetsrv\\config\\schema\\iisnode_schema.xml file."); + break; + + case IISNODE_ERROR_UNABLE_TO_READ_CONFIGURATION_OVERRIDE: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "iisnode was unable to read the configuration file iisnode.yml. Make sure the iisnode.yml file syntax is correct. For reference, check " + " " + "the sample iisnode.yml file. The property names recognized in the iisnode.yml file of your version of iisnode are stored in the " + "%systemroot%\\system32\\inetsrv\\config\\schema\\iisnode_schema.xml file."); + break; + }; + + return TRUE; + } + else + { + return FALSE; + } + } + + if (!CModuleConfiguration::GetDevErrorsEnabled(httpCtx)) + { + return FALSE; + } + + switch (hr) { + + default: + return FALSE; + + case IISNODE_ERROR_UNRECOGNIZED_DEBUG_COMMAND: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "Unrecognized debugging command. Supported commands are ?debug (default), ?brk, and ?kill."); + break; + + case IISNODE_ERROR_UNABLE_TO_FIND_DEBUGGING_PORT: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "The debugger was unable to acquire a TCP port to establish communication with the debugee. " + "This may be due to lack of free TCP ports in the range specified in the " + "system.webServer/iisnode/@debuggerPortRange configuration " + "section, or due to lack of permissions to create TCP listeners by the identity of the IIS worker process."); + break; + + case IISNODE_ERROR_UNABLE_TO_CONNECT_TO_DEBUGEE: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "The debugger was unable to connect to the the debugee. " + "This may be due to the debugee process terminating during startup (e.g. due to an unhandled exception) or " + "failing to establish a TCP listener on the debugging port. "); + break; + + case IISNODE_ERROR_INSPECTOR_NOT_FOUND: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "The version of iisnode installed on the server does not support remote debugging. " + "To use remote debugging, please update your iisnode installation on the server to one available from " + "http://github.com/tjanczuk/iisnode/downloads. " + "We apologize for inconvenience."); + break; + + case IISNODE_ERROR_UNABLE_TO_CREATE_DEBUGGER_FILES: + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + "The iisnode module is unable to deploy supporting files necessary to initialize the debugger. " + "Please check that the identity of the IIS application pool running the node.js application has read and write access " + "permissions to the directory on the server where the node.js application is located."); + break; + + case IISNODE_ERROR_UNABLE_TO_START_NODE_EXE: + char* errorMessage = + "The iisnode module is unable to start the node.exe process. Make sure the node.exe executable is available " + "at the location specified in the " + "system.webServer/iisnode/@nodeProcessCommandLine element of web.config. " + "By default node.exe is expected in one of the directories listed in the PATH environment variable."; + + CProtocolBridge::SendSyncResponse( + httpCtx, + 200, + "OK", + hr, + TRUE, + errorMessage); + break; + + }; + + return TRUE; } BOOL CProtocolBridge::SendIisnodeError(CNodeHttpStoredContext* ctx, HRESULT hr) { - if (CProtocolBridge::SendIisnodeError(ctx->GetHttpContext(), hr)) - { - ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log( - L"iisnode request processing failed for reasons recognized by iisnode", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); - - if (INVALID_HANDLE_VALUE != ctx->GetPipe()) - { - CloseHandle(ctx->GetPipe()); - ctx->SetPipe(INVALID_HANDLE_VALUE); - } - - CProtocolBridge::FinalizeResponseCore( - ctx, - RQ_NOTIFICATION_FINISH_REQUEST, - hr, - ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), - L"iisnode posts completion from SendIisnodeError", - WINEVENT_LEVEL_VERBOSE); - - return TRUE; - } - - return FALSE; + if (CProtocolBridge::SendIisnodeError(ctx->GetHttpContext(), hr)) + { + ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log( + L"iisnode request processing failed for reasons recognized by iisnode", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId()); + + if (INVALID_HANDLE_VALUE != ctx->GetPipe()) + { + CloseHandle(ctx->GetPipe()); + ctx->SetPipe(INVALID_HANDLE_VALUE); + } + + CProtocolBridge::FinalizeResponseCore( + ctx, + RQ_NOTIFICATION_FINISH_REQUEST, + hr, + ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), + L"iisnode posts completion from SendIisnodeError", + WINEVENT_LEVEL_VERBOSE); + + return TRUE; + } + + return FALSE; } -BOOL CProtocolBridge::SendDevError(CNodeHttpStoredContext* context, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache) +BOOL CProtocolBridge::SendDevError(CNodeHttpStoredContext* context, + USHORT status, + USHORT subStatus, + PCTSTR reason, + HRESULT hresult, + BOOL disableCache) { - HRESULT hr; - DWORD rawLogSize, htmlLogSize, htmlTotalSize; - IHttpContext* ctx; - char* rawLog; - char* templ1; - char* templ2; - char* templ3; - char* html; - char* current; - - if (500 <= status && CModuleConfiguration::GetDevErrorsEnabled(context->GetHttpContext()) && NULL != context->GetNodeProcess()) - { - // return a friendly HTTP 200 response with HTML entity body that contains error details - // and the content of node.exe stdout/err, if available - - ctx = context->GetHttpContext(); - rawLog = context->GetNodeProcess()->TryGetLog(ctx, &rawLogSize); - templ1 = - "

iisnode encountered an error when processing the request.

"
-			"HRESULT: 0x%x\n"
-			"HTTP status: %d\n"
-			"HTTP reason: %s
" - "

You are receiving this HTTP 200 response because " - "system.webServer/iisnode/@devErrorsEnabled configuration setting is 'true'.

" - "

In addition to the log of stdout and stderr of the node.exe process, consider using " - "debugging " - "and ETW traces to further diagnose the problem.

"; - templ2 = "

The node.exe process has not written any information to stderr or iisnode was unable to capture this information. " - "Frequent reason is that the iisnode module is unable to create a log file to capture stdout and stderr output from node.exe. " - "Please check that the identity of the IIS application pool running the node.js application has read and write access " - "permissions to the directory on the server where the node.js application is located. Alternatively you can disable logging " - "by setting " - "system.webServer/iisnode/@loggingEnabled element of web.config to 'false'."; - templ3="

You may get additional information about this error condition by logging stdout and stderr of the node.exe process." - "To enable logging, set the " - "system.webServer/iisnode/@loggingEnabled configuration setting to 'true' (current value is 'false').

"; - - // calculate HTML encoded size of the log - - htmlLogSize = 0; - for (int i = 0; i < rawLogSize; i++) - { - if (rawLog[i] >= 0 && rawLog[i] <= 0x8 - || rawLog[i] >= 0xb && rawLog[i] <= 0xc - || rawLog[i] >= 0xe && rawLog[i] <= 0x1f - || rawLog[i] >= 0x80 && rawLog[i] <= 0x9f) - { - // characters disallowed in HTML will be converted to [xAB] notation, thus taking 5 bytes - htmlLogSize += 5; - } - else - { - switch (rawLog[i]) - { - default: - htmlLogSize++; - break; - case '&': - htmlLogSize += 5; // & - break; - case '<': - case '>': - htmlLogSize += 4; // < > - break; - case '"': - case '\'': - htmlLogSize += 6; // " ' - break; - }; - } - } - - // calculate total size of HTML and allocate memory - - htmlTotalSize = strlen(templ1) + 20 /* hresult */ + 20 /* status code */ + strlen(reason) + strlen(templ2) /* log content heading */ + htmlLogSize; - ErrorIf(NULL == (html = (char*)ctx->AllocateRequestMemory(htmlTotalSize)), ERROR_NOT_ENOUGH_MEMORY); - RtlZeroMemory(html, htmlTotalSize); - - // construct the HTML - - sprintf(html, templ1, hresult, status, reason); - - if (0 == rawLogSize) - { - if (CModuleConfiguration::GetLoggingEnabled(ctx)) - { - strcat(html, templ2); - } - else - { - strcat(html, templ3); - } - } - else - { - strcat(html, "

The last 64k of the output generated by the node.exe process to stderr is shown below:

");
-
-			current = html + strlen(html);
-
-			if (htmlLogSize == rawLogSize)
-			{
-				// no HTML encoding is necessary
-				
-				memcpy(current, rawLog, rawLogSize);
-			}
-			else
-			{
-				// HTML encode the log
-
-				for (int i = 0; i < rawLogSize; i++)
-				{
-					if (rawLog[i] >= 0 && rawLog[i] <= 0x8
-						|| rawLog[i] >= 0xb && rawLog[i] <= 0xc
-						|| rawLog[i] >= 0xe && rawLog[i] <= 0x1f
-						|| rawLog[i] >= 0x80 && rawLog[i] <= 0x9f)
-					{
-						// characters disallowed in HTML are converted to [xAB] notation
-						*current++ = '[';
-						*current++ = 'x';
-						*current = rawLog[i] >> 4;
-						*current++ += *current > 9 ? 'A' - 10 : '0';
-						*current = rawLog[i] & 15;
-						*current++ += *current > 9 ? 'A' - 10 : '0';
-						*current++ = ']';
-					}
-					else
-					{
-						switch (rawLog[i]) 
-						{
-						default:
-							*current++ = rawLog[i];
-							break;
-						case '&':
-							*current++ = '&';
-							*current++ = 'a';
-							*current++ = 'm';
-							*current++ = 'p';
-							*current++ = ';';
-							break;
-						case '<':
-							*current++ = '&';
-							*current++ = 'l';
-							*current++ = 't';
-							*current++ = ';';
-							break;
-						case '>':
-							*current++ = '&';
-							*current++ = 'g';
-							*current++ = 't';
-							*current++ = ';';
-							break;
-						case '"':
-							*current++ = '&';
-							*current++ = 'q';
-							*current++ = 'u';
-							*current++ = 'o';
-							*current++ = 't';
-							*current++ = ';';
-							break;
-						case '\'':
-							*current++ = '&';
-							*current++ = 'a';
-							*current++ = 'p';
-							*current++ = 'o';
-							*current++ = 's';
-							*current++ = ';';
-							break;
-						};
-					}
-				}
-			}
-		}
-
-		// send the response
-
-		CheckError(CProtocolBridge::SendSyncResponse(
-			ctx,
-			200,
-			"OK",
-			hresult,
-			TRUE,
-			html));
-
-		return true;
-	}
+    HRESULT hr;
+    DWORD rawLogSize, htmlLogSize, htmlTotalSize;
+    IHttpContext* ctx;
+    char* rawLog;
+    char* templ1;
+    char* templ2;
+    char* templ3;
+    char* html;
+    char* current;
+
+    if (500 <= status && CModuleConfiguration::GetDevErrorsEnabled(context->GetHttpContext()) && NULL != context->GetNodeProcess())
+    {
+        // return a friendly HTTP 200 response with HTML entity body that contains error details 
+        // and the content of node.exe stdout/err, if available
+
+        ctx = context->GetHttpContext();		
+        rawLog = context->GetNodeProcess()->TryGetLog(ctx, &rawLogSize);
+        templ1 = 
+            "

iisnode encountered an error when processing the request.

"
+            "HRESULT: 0x%x\n"
+            "HTTP status: %d\n"
+            "HTTP subStatus: %d\n"
+            "HTTP reason: %s
" + "

You are receiving this HTTP 200 response because " + "system.webServer/iisnode/@devErrorsEnabled configuration setting is 'true'.

" + "

In addition to the log of stdout and stderr of the node.exe process, consider using " + "debugging " + "and ETW traces to further diagnose the problem.

"; + templ2 = "

The node.exe process has not written any information to stderr or iisnode was unable to capture this information. " + "Frequent reason is that the iisnode module is unable to create a log file to capture stdout and stderr output from node.exe. " + "Please check that the identity of the IIS application pool running the node.js application has read and write access " + "permissions to the directory on the server where the node.js application is located. Alternatively you can disable logging " + "by setting " + "system.webServer/iisnode/@loggingEnabled element of web.config to 'false'."; + templ3="

You may get additional information about this error condition by logging stdout and stderr of the node.exe process." + "To enable logging, set the " + "system.webServer/iisnode/@loggingEnabled configuration setting to 'true' (current value is 'false').

"; + + // calculate HTML encoded size of the log + + htmlLogSize = 0; + for (int i = 0; i < rawLogSize; i++) + { + if (rawLog[i] >= 0 && rawLog[i] <= 0x8 + || rawLog[i] >= 0xb && rawLog[i] <= 0xc + || rawLog[i] >= 0xe && rawLog[i] <= 0x1f + || rawLog[i] >= 0x80 && rawLog[i] <= 0x9f) + { + // characters disallowed in HTML will be converted to [xAB] notation, thus taking 5 bytes + htmlLogSize += 5; + } + else + { + switch (rawLog[i]) + { + default: + htmlLogSize++; + break; + case '&': + htmlLogSize += 5; // & + break; + case '<': + case '>': + htmlLogSize += 4; // < > + break; + case '"': + case '\'': + htmlLogSize += 6; // " ' + break; + }; + } + } + + // calculate total size of HTML and allocate memory + + htmlTotalSize = strlen(templ1) + 20 /* hresult */ + 20 /* status code */ + strlen(reason) + strlen(templ2) /* log content heading */ + htmlLogSize; + ErrorIf(NULL == (html = (char*)ctx->AllocateRequestMemory(htmlTotalSize)), ERROR_NOT_ENOUGH_MEMORY); + RtlZeroMemory(html, htmlTotalSize); + + // construct the HTML + + sprintf(html, templ1, hresult, status, subStatus, reason); + + if (0 == rawLogSize) + { + if (CModuleConfiguration::GetLoggingEnabled(ctx)) + { + strcat(html, templ2); + } + else + { + strcat(html, templ3); + } + } + else + { + strcat(html, "

The last 64k of the output generated by the node.exe process to stderr is shown below:

");
+
+            current = html + strlen(html);
+
+            if (htmlLogSize == rawLogSize)
+            {
+                // no HTML encoding is necessary
+                
+                memcpy(current, rawLog, rawLogSize);
+            }
+            else
+            {
+                // HTML encode the log
+
+                for (int i = 0; i < rawLogSize; i++)
+                {
+                    if (rawLog[i] >= 0 && rawLog[i] <= 0x8
+                        || rawLog[i] >= 0xb && rawLog[i] <= 0xc
+                        || rawLog[i] >= 0xe && rawLog[i] <= 0x1f
+                        || rawLog[i] >= 0x80 && rawLog[i] <= 0x9f)
+                    {
+                        // characters disallowed in HTML are converted to [xAB] notation
+                        *current++ = '[';
+                        *current++ = 'x';
+                        *current = rawLog[i] >> 4;
+                        *current++ += *current > 9 ? 'A' - 10 : '0';
+                        *current = rawLog[i] & 15;
+                        *current++ += *current > 9 ? 'A' - 10 : '0';
+                        *current++ = ']';
+                    }
+                    else
+                    {
+                        switch (rawLog[i]) 
+                        {
+                        default:
+                            *current++ = rawLog[i];
+                            break;
+                        case '&':
+                            *current++ = '&';
+                            *current++ = 'a';
+                            *current++ = 'm';
+                            *current++ = 'p';
+                            *current++ = ';';
+                            break;
+                        case '<':
+                            *current++ = '&';
+                            *current++ = 'l';
+                            *current++ = 't';
+                            *current++ = ';';
+                            break;
+                        case '>':
+                            *current++ = '&';
+                            *current++ = 'g';
+                            *current++ = 't';
+                            *current++ = ';';
+                            break;
+                        case '"':
+                            *current++ = '&';
+                            *current++ = 'q';
+                            *current++ = 'u';
+                            *current++ = 'o';
+                            *current++ = 't';
+                            *current++ = ';';
+                            break;
+                        case '\'':
+                            *current++ = '&';
+                            *current++ = 'a';
+                            *current++ = 'p';
+                            *current++ = 'o';
+                            *current++ = 's';
+                            *current++ = ';';
+                            break;
+                        };
+                    }
+                }
+            }
+        }
+
+        // send the response
+
+        CheckError(CProtocolBridge::SendSyncResponse(
+            ctx,
+            200,
+            "OK",
+            hresult,
+            TRUE,
+            html));
+
+        return true;
+    }
 
 Error:
-	return false;
+    return false;
 }
 
-HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache)
+HRESULT CProtocolBridge::SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache)
 {
-	context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode request processing failed for reasons unrecognized by iisnode", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-	if (INVALID_HANDLE_VALUE != context->GetPipe())
-	{
-		CloseHandle(context->GetPipe());
-		context->SetPipe(INVALID_HANDLE_VALUE);
-	}
-
-	if (!CProtocolBridge::SendDevError(context, status, reason, hresult, disableCache))
-	{
-		// return default IIS response
-
-		CProtocolBridge::SendEmptyResponse(context->GetHttpContext(), status, reason, hresult, disableCache);	
-	}
-
-	CProtocolBridge::FinalizeResponseCore(
-		context, 
-		RQ_NOTIFICATION_FINISH_REQUEST, 
-		hresult, 
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(),
-		L"iisnode posts completion from SendEmtpyResponse", 
-		WINEVENT_LEVEL_VERBOSE);
-
-	return S_OK;
+    context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode request processing failed for reasons unrecognized by iisnode", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+    if (INVALID_HANDLE_VALUE != context->GetPipe())
+    {
+        CloseHandle(context->GetPipe());
+        context->SetPipe(INVALID_HANDLE_VALUE);
+    }
+
+    if (!CProtocolBridge::SendDevError(context, status, subStatus, reason, hresult, disableCache))
+    {
+        // return default IIS response
+
+        CProtocolBridge::SendEmptyResponse(context->GetHttpContext(), status, subStatus, reason, hresult, disableCache);
+    }
+
+    CProtocolBridge::FinalizeResponseCore(
+        context, 
+        RQ_NOTIFICATION_FINISH_REQUEST, 
+        hresult, 
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(),
+        L"iisnode posts completion from SendEmtpyResponse", 
+        WINEVENT_LEVEL_VERBOSE);
+
+    return S_OK;
 }
 
 HRESULT CProtocolBridge::SendSyncResponse(IHttpContext* httpCtx, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache, PCSTR htmlBody)
 {
-	HRESULT hr;
-	DWORD bytesSent;
-	HTTP_DATA_CHUNK body;
+    HRESULT hr;
+    DWORD bytesSent;
+    HTTP_DATA_CHUNK body;
 
-	CProtocolBridge::SendEmptyResponse(httpCtx, status, reason, hresult, disableCache);
+    CProtocolBridge::SendEmptyResponse(httpCtx, status, 0, reason, hresult, disableCache);
 
-	IHttpResponse* response = httpCtx->GetResponse();
-	response->SetHeader(HttpHeaderContentType, "text/html", 9, TRUE);
-	body.DataChunkType = HttpDataChunkFromMemory;
-	body.FromMemory.pBuffer = (PVOID)htmlBody;
-	body.FromMemory.BufferLength = strlen(htmlBody);
-	CheckError(response->WriteEntityChunks(&body, 1, FALSE, FALSE, &bytesSent));
+    IHttpResponse* response = httpCtx->GetResponse();
+    response->SetHeader(HttpHeaderContentType, "text/html", 9, TRUE);
+    body.DataChunkType = HttpDataChunkFromMemory;
+    body.FromMemory.pBuffer = (PVOID)htmlBody;
+    body.FromMemory.BufferLength = strlen(htmlBody);
+    CheckError(response->WriteEntityChunks(&body, 1, FALSE, FALSE, &bytesSent));
 
-	return S_OK;
+    return S_OK;
 Error:
-	return hr;
+    return hr;
 }
 
-void CProtocolBridge::SendEmptyResponse(IHttpContext* httpCtx, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache)
+void CProtocolBridge::SendEmptyResponse(IHttpContext* httpCtx, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache)
 {
-	if (!httpCtx->GetResponseHeadersSent())
-	{
-		httpCtx->GetResponse()->Clear();
-		httpCtx->GetResponse()->SetStatus(status, reason, 0, hresult);
-		if (disableCache)
-		{
-			httpCtx->GetResponse()->SetHeader(HttpHeaderCacheControl, "no-cache", 8, TRUE);
-		}
-	}
+    if (!httpCtx->GetResponseHeadersSent())
+    {
+        httpCtx->GetResponse()->Clear();
+        httpCtx->GetResponse()->SetStatus(status, reason, subStatus, hresult);
+        if (disableCache)
+        {
+            httpCtx->GetResponse()->SetHeader(HttpHeaderCacheControl, "no-cache", 8, TRUE);
+        }
+    }
 }
 
 HRESULT CProtocolBridge::InitiateRequest(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;
-	BOOL requireChildContext = FALSE;	
-	BOOL mainDebuggerPage = FALSE;
-	IHttpContext* child = NULL;
-	BOOL completionExpected;
-
-	// determine what the target path of the request is
-
-	if (context->GetNodeApplication()->IsDebugger())
-	{
-		// All debugger URLs require rewriting. Requests for static content will be processed using a child http context and served
-		// by a static file handler. Debugging protocol requests will continue executing in the current context and be processed 
-		// by the node-inspector application.
-
-		CheckError(CNodeDebugger::DispatchDebuggingRequest(context, &requireChildContext, &mainDebuggerPage));
-	}
-	else
-	{
-		// For application requests, if the URL rewrite module had been used to rewrite the URL, 
-		// present the original URL to the node.js application instead of the re-written one.
-
-		PCSTR url;
-		USHORT urlLength;
-		IHttpRequest* request = context->GetHttpContext()->GetRequest();
-
-		if (NULL == (url = request->GetHeader("X-Original-URL", &urlLength)))
-		{
-			HTTP_REQUEST* raw = request->GetRawHttpRequest();
-			
-			// Fix for https://github.com/tjanczuk/iisnode/issues/296
-			PSTR path = NULL;
-			int pathSizeA = 0;
-			int cchAbsPathLength = (raw->CookedUrl.AbsPathLength + raw->CookedUrl.QueryStringLength) >> 1;
-			ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, NULL, 0, NULL, NULL)), E_FAIL);
-			ErrorIf(NULL == (path = (TCHAR*)context->GetHttpContext()->AllocateRequestMemory(pathSizeA + 1)), ERROR_NOT_ENOUGH_MEMORY);
-			ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, path, pathSizeA, NULL, NULL), E_FAIL);
-			path[pathSizeA] = 0;
-
-			context->SetTargetUrl(path, pathSizeA);
-		}
-		else
-		{
-			context->SetTargetUrl(url, urlLength);
-		}
-	}
-
-	// determine how to process the request
-
-	if (requireChildContext)
-	{
-		CheckError(context->GetHttpContext()->CloneContext(CLONE_FLAG_BASICS | CLONE_FLAG_ENTITY | CLONE_FLAG_HEADERS, &child));
-		if (mainDebuggerPage)
-		{
-			// Prevent client caching of responses to requests for debugger entry points e.g. app.js/debug or app.js/debug?brk
-			// This is to allow us to run initialization logic on the server if necessary every time user refreshes the page
-			// Static content subordinate to the main debugger page is eligible for client side caching
-
-			child->GetResponse()->SetHeader(HttpHeaderCacheControl, "no-cache", 8, TRUE);
-		}
-
-		CheckError(child->GetRequest()->SetUrl(context->GetTargetUrl(), context->GetTargetUrlLength(), FALSE));
-		context->SetChildContext(child);
-		context->SetNextProcessor(CProtocolBridge::ChildContextCompleted);
-		
-		CheckError(context->GetHttpContext()->ExecuteRequest(TRUE, child, 0, NULL, &completionExpected));
-		if (!completionExpected)
-		{
-			CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped());
-		}
-	}
-	else
-	{
-		context->SetNextProcessor(CProtocolBridge::CreateNamedPipeConnection);
-		CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->InitializeOverlapped());
-	}
-
-	return S_OK; 
+    HRESULT hr;
+    BOOL requireChildContext = FALSE;	
+    BOOL mainDebuggerPage = FALSE;
+    IHttpContext* child = NULL;
+    BOOL completionExpected;
+
+    // determine what the target path of the request is
+
+    if (context->GetNodeApplication()->IsDebugger())
+    {
+        // All debugger URLs require rewriting. Requests for static content will be processed using a child http context and served
+        // by a static file handler. Debugging protocol requests will continue executing in the current context and be processed 
+        // by the node-inspector application.
+
+        CheckError(CNodeDebugger::DispatchDebuggingRequest(context, &requireChildContext, &mainDebuggerPage));
+    }
+    else
+    {
+        // For application requests, if the URL rewrite module had been used to rewrite the URL, 
+        // present the original URL to the node.js application instead of the re-written one.
+
+        PCSTR url;
+        USHORT urlLength;
+        IHttpRequest* request = context->GetHttpContext()->GetRequest();
+
+        if (NULL == (url = request->GetHeader("X-Original-URL", &urlLength)))
+        {
+            HTTP_REQUEST* raw = request->GetRawHttpRequest();
+            
+            // Fix for https://github.com/tjanczuk/iisnode/issues/296
+            PSTR path = NULL;
+            int pathSizeA = 0;
+            int cchAbsPathLength = (raw->CookedUrl.AbsPathLength + raw->CookedUrl.QueryStringLength) >> 1;
+            ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, NULL, 0, NULL, NULL)), E_FAIL);
+            ErrorIf(NULL == (path = (TCHAR*)context->GetHttpContext()->AllocateRequestMemory(pathSizeA + 1)), ERROR_NOT_ENOUGH_MEMORY);
+            ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, cchAbsPathLength, path, pathSizeA, NULL, NULL), E_FAIL);
+            path[pathSizeA] = 0;
+
+            context->SetTargetUrl(path, pathSizeA);
+        }
+        else
+        {
+            context->SetTargetUrl(url, urlLength);
+        }
+    }
+
+    // determine how to process the request
+
+    if (requireChildContext)
+    {
+        CheckError(context->GetHttpContext()->CloneContext(CLONE_FLAG_BASICS | CLONE_FLAG_ENTITY | CLONE_FLAG_HEADERS, &child));
+        if (mainDebuggerPage)
+        {
+            // Prevent client caching of responses to requests for debugger entry points e.g. app.js/debug or app.js/debug?brk
+            // This is to allow us to run initialization logic on the server if necessary every time user refreshes the page
+            // Static content subordinate to the main debugger page is eligible for client side caching
+
+            child->GetResponse()->SetHeader(HttpHeaderCacheControl, "no-cache", 8, TRUE);
+        }
+
+        CheckError(child->GetRequest()->SetUrl(context->GetTargetUrl(), context->GetTargetUrlLength(), FALSE));
+        context->SetChildContext(child);
+        context->SetNextProcessor(CProtocolBridge::ChildContextCompleted);
+        
+        CheckError(context->GetHttpContext()->ExecuteRequest(TRUE, child, 0, NULL, &completionExpected));
+        if (!completionExpected)
+        {
+            CProtocolBridge::ChildContextCompleted(S_OK, 0, context->GetOverlapped());
+        }
+    }
+    else
+    {
+        context->SetNextProcessor(CProtocolBridge::CreateNamedPipeConnection);
+        CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->InitializeOverlapped());
+    }
+
+    return S_OK; 
 Error:
 
-	if (child)
-	{		
-		child->ReleaseClonedContext();
-		child = NULL;
-		context->SetChildContext(NULL);
-	}
+    if (child)
+    {		
+        child->ReleaseClonedContext();
+        child = NULL;
+        context->SetChildContext(NULL);
+    }
 
-	return hr;
+    return hr;
 }
 
 void WINAPI CProtocolBridge::ChildContextCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-
-	ctx->GetChildContext()->ReleaseClonedContext();
-	ctx->SetChildContext(NULL);
-
-	if (S_OK == error)
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode finished processing child http request", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to process child http request", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-	}
-
-	ctx->SetHresult(error);
-	ctx->SetRequestNotificationStatus(RQ_NOTIFICATION_CONTINUE);	
-	ctx->SetNextProcessor(NULL);
-	
-	CProtocolBridge::FinalizeResponseCore(
-		ctx, 
-		RQ_NOTIFICATION_CONTINUE, 
-		error, 
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), 
-		L"iisnode posts completion from ChildContextCompleted", 
-		WINEVENT_LEVEL_VERBOSE);
-	
-	return;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+
+    ctx->GetChildContext()->ReleaseClonedContext();
+    ctx->SetChildContext(NULL);
+
+    if (S_OK == error)
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode finished processing child http request", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to process child http request", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+    }
+
+    ctx->SetHresult(error);
+    ctx->SetRequestNotificationStatus(RQ_NOTIFICATION_CONTINUE);	
+    ctx->SetNextProcessor(NULL);
+    
+    CProtocolBridge::FinalizeResponseCore(
+        ctx, 
+        RQ_NOTIFICATION_CONTINUE, 
+        error, 
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider(), 
+        L"iisnode posts completion from ChildContextCompleted", 
+        WINEVENT_LEVEL_VERBOSE);
+    
+    return;
 }
 
 void WINAPI CProtocolBridge::CreateNamedPipeConnection(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-	HANDLE pipe = INVALID_HANDLE_VALUE;
-	DWORD retry = ctx->GetConnectionRetryCount();
-
-	if (0 == retry)
-	{
-		// only the first connection attempt uses connections from the pool
-
-		pipe = ctx->GetNodeProcess()->GetConnectionPool()->Take();
-	}
-
-	if (INVALID_HANDLE_VALUE == pipe)
-	{
-		ErrorIf(INVALID_HANDLE_VALUE == (pipe = CreateFile(
-			ctx->GetNodeProcess()->GetNamedPipeName(),
-			GENERIC_READ | GENERIC_WRITE,
-			0,
-			NULL,
-			OPEN_EXISTING,
-			FILE_FLAG_OVERLAPPED,
-			NULL)), 
-			GetLastError());
-
-		ErrorIf(!SetFileCompletionNotificationModes(
-			pipe, 
-			FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE), 
-			GetLastError());
-
-		ctx->SetIsConnectionFromPool(FALSE);
-		ctx->GetNodeApplication()->GetApplicationManager()->GetAsyncManager()->AddAsyncCompletionHandle(pipe);
-	}
-	else
-	{
-		ctx->SetIsConnectionFromPool(TRUE);
-	}
-
-	ctx->SetPipe(pipe);	
-
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode created named pipe connection to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-	
-	CProtocolBridge::SendHttpRequestHeaders(ctx);
-
-	return;
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HANDLE pipe = INVALID_HANDLE_VALUE;
+    DWORD retry = ctx->GetConnectionRetryCount();
+
+    if (0 == retry)
+    {
+        // only the first connection attempt uses connections from the pool
+
+        pipe = ctx->GetNodeProcess()->GetConnectionPool()->Take();
+    }
+
+    if (INVALID_HANDLE_VALUE == pipe)
+    {
+        ErrorIf(INVALID_HANDLE_VALUE == (pipe = CreateFile(
+            ctx->GetNodeProcess()->GetNamedPipeName(),
+            GENERIC_READ | GENERIC_WRITE,
+            0,
+            NULL,
+            OPEN_EXISTING,
+            FILE_FLAG_OVERLAPPED,
+            NULL)), 
+            GetLastError());
+
+        ErrorIf(!SetFileCompletionNotificationModes(
+            pipe, 
+            FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE), 
+            GetLastError());
+
+        ctx->SetIsConnectionFromPool(FALSE);
+        ctx->GetNodeApplication()->GetApplicationManager()->GetAsyncManager()->AddAsyncCompletionHandle(pipe);
+    }
+    else
+    {
+        ctx->SetIsConnectionFromPool(TRUE);
+    }
+
+    ctx->SetPipe(pipe);	
+
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode created named pipe connection to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    
+    CProtocolBridge::SendHttpRequestHeaders(ctx);
+
+    return;
 
 Error:
 
-	if (INVALID_HANDLE_VALUE == pipe) 
-	{
-		if (retry >= CModuleConfiguration::GetMaxNamedPipeConnectionRetry(ctx->GetHttpContext()))
-		{
-			if (hr == ERROR_PIPE_BUSY)
-			{
-				ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-					L"iisnode was unable to establish named pipe connection to the node.exe process because the named pipe server is too busy", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-				CProtocolBridge::SendEmptyResponse(ctx, 503, _T("Service Unavailable"), hr);
-			}
-			else
-			{
-				ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-					L"iisnode was unable to establish named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-				CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-			}
-		}
-		else if (ctx->GetNodeProcess()->HasProcessExited()) 
-		{
-			// the process has exited, likely due to initialization error
-			// stop trying to establish the named pipe connection to minimize the failure latency
-
-			ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-				L"iisnode was unable to establish named pipe connection to the node.exe process before the process terminated", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-			CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-		}
-		else 
-		{
-			ctx->SetConnectionRetryCount(retry + 1);
-			ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-				L"iisnode scheduled a retry of a named pipe connection to the node.exe process ", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
-			CProtocolBridge::PostponeProcessing(ctx, CModuleConfiguration::GetNamedPipeConnectionRetryDelay(ctx->GetHttpContext()));
-		}
-	}
-	else
-	{
-		CloseHandle(pipe);
-		pipe = INVALID_HANDLE_VALUE;
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode was unable to configure the named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    if (INVALID_HANDLE_VALUE == pipe) 
+    {
+        if (retry >= CModuleConfiguration::GetMaxNamedPipeConnectionRetry(ctx->GetHttpContext()))
+        {
+            if (hr == ERROR_PIPE_BUSY)
+            {
+                ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                    L"iisnode was unable to establish named pipe connection to the node.exe process because the named pipe server is too busy", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+                CProtocolBridge::SendEmptyResponse(ctx, 503, CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION_TOO_BUSY, _T("Service Unavailable"), hr);
+            }
+            else
+            {
+                ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                    L"iisnode was unable to establish named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+                CProtocolBridge::SendEmptyResponse( ctx, 
+                                                    500, 
+                                                    CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION, 
+                                                    _T("Internal Server Error"), 
+                                                    hr );
+            }
+        }
+        else if (ctx->GetNodeProcess()->HasProcessExited()) 
+        {
+            // the process has exited, likely due to initialization error
+            // stop trying to establish the named pipe connection to minimize the failure latency
+
+            ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                L"iisnode was unable to establish named pipe connection to the node.exe process before the process terminated", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+            CProtocolBridge::SendEmptyResponse( ctx, 
+                                                500, 
+                                                CNodeConstants::IISNODE_ERROR_PIPE_CONNECTION_BEFORE_PROCESS_TERMINATED, 
+                                                _T("Internal Server Error"), 
+                                                hr );
+        }
+        else 
+        {
+            ctx->SetConnectionRetryCount(retry + 1);
+            ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                L"iisnode scheduled a retry of a named pipe connection to the node.exe process ", WINEVENT_LEVEL_INFO, ctx->GetActivityId());
+            CProtocolBridge::PostponeProcessing(ctx, CModuleConfiguration::GetNamedPipeConnectionRetryDelay(ctx->GetHttpContext()));
+        }
+    }
+    else
+    {
+        CloseHandle(pipe);
+        pipe = INVALID_HANDLE_VALUE;
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode was unable to configure the named pipe connection to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_CONFIGURE_PIPE_CONNECTION, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 void CProtocolBridge::SendHttpRequestHeaders(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;
-	DWORD length;
-	IHttpRequest *request;
-
-	// set the start time of the request
-
-	GetSystemTimeAsFileTime(context->GetStartTime());
-
-	// capture ETW provider since after a successful call to WriteFile the context may be asynchronously deleted
-
-	CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
-	GUID activityId;
-	memcpy(&activityId, context->GetActivityId(), sizeof GUID);
-
-	// request the named pipe to be kept alive by the server after the response is sent
-	// to enable named pipe connection pooling
-
-	request = context->GetHttpContext()->GetRequest();
-	CheckError(request->SetHeader(HttpHeaderConnection, "keep-alive", 10, TRUE));
-
-	// Expect: 100-continue has been processed by IIS - do not propagate it up to node.js since node will
-	// attempt to process it again
-
-	USHORT expectLength;
-	PCSTR expect = request->GetHeader(HttpHeaderExpect, &expectLength);
-	if (NULL != expect && 0 == strnicmp(expect, "100-continue", expectLength))
-	{
-		CheckError(request->DeleteHeader(HttpHeaderExpect));
-	}
-
-	// determine if the request body had been chunked; IIS decodes chunked encoding, so it
-	// must be re-applied when sending the request entity body
-
-	USHORT encodingLength;
-	PCSTR encoding = request->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
-	if (NULL != encoding && 0 == strnicmp(encoding, "chunked;", encodingLength > 8 ? 8 : encodingLength))
-	{
-		context->SetIsChunked(TRUE);
-		context->SetIsLastChunk(FALSE);
-	}
-
-	// serialize and send request headers
-
-	CheckError(CHttpProtocol::SerializeRequestHeaders(context, context->GetBufferRef(), context->GetBufferSizeRef(), &length));
-
-	context->SetNextProcessor(CProtocolBridge::SendHttpRequestHeadersCompleted);
-	
-	if (WriteFile(context->GetPipe(), context->GetBuffer(), length, NULL, context->InitializeOverlapped()))
-	{
-		// completed synchronously
-
-		etw->Log(L"iisnode initiated sending http request headers to the node.exe process and completed synchronously", 
-			WINEVENT_LEVEL_VERBOSE, 
-			&activityId);
-
-		// despite IO completion ports are used, asynchronous callback will not be invoked because in 
-		// CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
-		// - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
-		// and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
-
-		CProtocolBridge::SendHttpRequestHeadersCompleted(S_OK, 0, context->GetOverlapped());
-	}
-	else 
-	{
-		hr = GetLastError();
-		if (ERROR_IO_PENDING == hr)
-		{
-			// will complete asynchronously
-
-			etw->Log(L"iisnode initiated sending http request headers to the node.exe process and will complete asynchronously", 
-				WINEVENT_LEVEL_VERBOSE, 
-				&activityId);
-		}
-		else 
-		{
-			// error
-
-			if (context->GetIsConnectionFromPool())
-			{
-				// communication over a connection from the connection pool failed
-				// try to create a brand new connection instead
-
-				context->SetConnectionRetryCount(1);
-				CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->GetOverlapped());
-			}
-			else
-			{
-				etw->Log(L"iisnode failed to initiate sending http request headers to the node.exe process", 
-					WINEVENT_LEVEL_ERROR, 
-					&activityId);
-
-				CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), hr);		
-			}
-		}
-	}
-
-	return;
+    HRESULT hr;
+    DWORD length;
+    IHttpRequest *request;
+
+    // set the start time of the request
+
+    GetSystemTimeAsFileTime(context->GetStartTime());
+
+    // capture ETW provider since after a successful call to WriteFile the context may be asynchronously deleted
+
+    CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
+    GUID activityId;
+    memcpy(&activityId, context->GetActivityId(), sizeof GUID);
+
+    // request the named pipe to be kept alive by the server after the response is sent
+    // to enable named pipe connection pooling
+
+    request = context->GetHttpContext()->GetRequest();
+    CheckError(request->SetHeader(HttpHeaderConnection, "keep-alive", 10, TRUE));
+
+    // Expect: 100-continue has been processed by IIS - do not propagate it up to node.js since node will
+    // attempt to process it again
+
+    USHORT expectLength;
+    PCSTR expect = request->GetHeader(HttpHeaderExpect, &expectLength);
+    if (NULL != expect && 0 == strnicmp(expect, "100-continue", expectLength))
+    {
+        CheckError(request->DeleteHeader(HttpHeaderExpect));
+    }
+
+    // determine if the request body had been chunked; IIS decodes chunked encoding, so it
+    // must be re-applied when sending the request entity body
+
+    USHORT encodingLength;
+    PCSTR encoding = request->GetHeader(HttpHeaderTransferEncoding, &encodingLength);
+    if (NULL != encoding && 0 == strnicmp(encoding, "chunked;", encodingLength > 8 ? 8 : encodingLength))
+    {
+        context->SetIsChunked(TRUE);
+        context->SetIsLastChunk(FALSE);
+    }
+
+    // serialize and send request headers
+
+    CheckError(CHttpProtocol::SerializeRequestHeaders(context, context->GetBufferRef(), context->GetBufferSizeRef(), &length));
+
+    context->SetNextProcessor(CProtocolBridge::SendHttpRequestHeadersCompleted);
+    
+    if (WriteFile(context->GetPipe(), context->GetBuffer(), length, NULL, context->InitializeOverlapped()))
+    {
+        // completed synchronously
+
+        etw->Log(L"iisnode initiated sending http request headers to the node.exe process and completed synchronously", 
+            WINEVENT_LEVEL_VERBOSE, 
+            &activityId);
+
+        // despite IO completion ports are used, asynchronous callback will not be invoked because in 
+        // CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
+        // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
+        // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
+
+        CProtocolBridge::SendHttpRequestHeadersCompleted(S_OK, 0, context->GetOverlapped());
+    }
+    else 
+    {
+        hr = GetLastError();
+        if (ERROR_IO_PENDING == hr)
+        {
+            // will complete asynchronously
+
+            etw->Log(L"iisnode initiated sending http request headers to the node.exe process and will complete asynchronously", 
+                WINEVENT_LEVEL_VERBOSE, 
+                &activityId);
+        }
+        else 
+        {
+            // error
+
+            if (context->GetIsConnectionFromPool())
+            {
+                // communication over a connection from the connection pool failed
+                // try to create a brand new connection instead
+
+                context->SetConnectionRetryCount(1);
+                CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, context->GetOverlapped());
+            }
+            else
+            {
+                etw->Log(L"iisnode failed to initiate sending http request headers to the node.exe process", 
+                    WINEVENT_LEVEL_ERROR, 
+                    &activityId);
+
+                CProtocolBridge::SendEmptyResponse( context, 
+                                                    500, 
+                                                    CNodeConstants::IISNODE_ERROR_FAILED_INIT_SEND_HTTP_HEADERS, 
+                                                    _T("Internal Server Error"), 
+                                                    hr );
+            }
+        }
+    }
+
+    return;
 
 Error:
 
-	etw->Log(L"iisnode failed to serialize http request headers", 
-		WINEVENT_LEVEL_ERROR, 
-		&activityId);
+    etw->Log(L"iisnode failed to serialize http request headers", 
+        WINEVENT_LEVEL_ERROR, 
+        &activityId);
 
-	CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), hr);		
+    CProtocolBridge::SendEmptyResponse( context, 
+                                        500, 
+                                        CNodeConstants::IISNODE_ERROR_FAILED_SERIALIZE_HTTP_HEADERS, 
+                                        _T("Internal Server Error"), 
+                                        hr );
 
-	return;
+    return;
 }
 
 void WINAPI CProtocolBridge::SendHttpRequestHeadersCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
 
-	CheckError(error);
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode finished sending http request headers to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-	CProtocolBridge::ReadRequestBody(ctx);
+    CheckError(error);
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode finished sending http request headers to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    CProtocolBridge::ReadRequestBody(ctx);
 
-	return;
+    return;
 Error:
 
-	if (ctx->GetIsConnectionFromPool())
-	{
-		// communication over a connection from the connection pool failed
-		// try to create a brand new connection instead
-
-		ctx->SetConnectionRetryCount(1);
-		CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, ctx->GetOverlapped());
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to send http request headers to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    if (ctx->GetIsConnectionFromPool())
+    {
+        // communication over a connection from the connection pool failed
+        // try to create a brand new connection instead
+
+        ctx->SetConnectionRetryCount(1);
+        CProtocolBridge::CreateNamedPipeConnection(S_OK, 0, ctx->GetOverlapped());
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to send http request headers to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_SEND_HTTP_HEADERS, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 void CProtocolBridge::ReadRequestBody(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;	
-	DWORD bytesReceived = 0;
-	BOOL completionPending = FALSE;
-	BOOL continueSynchronouslyNow = TRUE;
-
-	if (0 < context->GetHttpContext()->GetRequest()->GetRemainingEntityBytes() || context->GetIsUpgrade())
-	{
-		context->SetNextProcessor(CProtocolBridge::ReadRequestBodyCompleted);
-		
-		if (context->GetIsChunked())
-		{
-			CheckError(context->GetHttpContext()->GetRequest()->ReadEntityBody(context->GetChunkBuffer(), context->GetChunkBufferSize(), TRUE, &bytesReceived, &completionPending));
-		}
-		else
-		{
-			CheckError(context->GetHttpContext()->GetRequest()->ReadEntityBody(context->GetBuffer(), context->GetBufferSize(), TRUE, &bytesReceived, &completionPending));
-		}
-
-		if (!completionPending)
-		{
-			context->SetContinueSynchronously(TRUE);
-			continueSynchronouslyNow = FALSE;
-			context->SetBytesCompleted(bytesReceived);
-		}
-	}
-
-	if (!completionPending)
-	{
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode initiated reading http request body chunk and completed synchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-		context->SetBytesCompleted(bytesReceived);
-		if (continueSynchronouslyNow)
-		{
-			CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
-		}
-	}
-	else
-	{
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode initiated reading http request body chunk and will complete asynchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-	}
-
-	return;
+    HRESULT hr;	
+    DWORD bytesReceived = 0;
+    BOOL completionPending = FALSE;
+    BOOL continueSynchronouslyNow = TRUE;
+
+    if (0 < context->GetHttpContext()->GetRequest()->GetRemainingEntityBytes() || context->GetIsUpgrade())
+    {
+        context->SetNextProcessor(CProtocolBridge::ReadRequestBodyCompleted);
+        
+        if (context->GetIsChunked())
+        {
+            CheckError(context->GetHttpContext()->GetRequest()->ReadEntityBody(context->GetChunkBuffer(), context->GetChunkBufferSize(), TRUE, &bytesReceived, &completionPending));
+        }
+        else
+        {
+            CheckError(context->GetHttpContext()->GetRequest()->ReadEntityBody(context->GetBuffer(), context->GetBufferSize(), TRUE, &bytesReceived, &completionPending));
+        }
+
+        if (!completionPending)
+        {
+            context->SetContinueSynchronously(TRUE);
+            continueSynchronouslyNow = FALSE;
+            context->SetBytesCompleted(bytesReceived);
+        }
+    }
+
+    if (!completionPending)
+    {
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode initiated reading http request body chunk and completed synchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+        context->SetBytesCompleted(bytesReceived);
+        if (continueSynchronouslyNow)
+        {
+            CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
+        }
+    }
+    else
+    {
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode initiated reading http request body chunk and will complete asynchronously", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+    }
+
+    return;
 Error:
 
-	if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
-	{
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-		if (context->GetIsUpgrade())
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(context, S_OK);
-		}
-		else if (context->GetIsChunked() && !context->GetIsLastChunk())
-		{
-			// send the terminating zero-length chunk
-
-			CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
-		}
-		else
-		{
-			CProtocolBridge::StartReadResponse(context);
-		}
-	}
-	else
-	{
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, context->GetActivityId());
-
-		if (context->GetIsUpgrade()) 
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(context, HRESULT_FROM_WIN32(hr));
-		}
-		else
-		{
-			CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), HRESULT_FROM_WIN32(hr));
-		}
-	}
-
-	return;
+    if (HRESULT_FROM_WIN32(ERROR_HANDLE_EOF) == hr)
+    {
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+        if (context->GetIsUpgrade())
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(context, S_OK);
+        }
+        else if (context->GetIsChunked() && !context->GetIsLastChunk())
+        {
+            // send the terminating zero-length chunk
+
+            CProtocolBridge::ReadRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
+        }
+        else
+        {
+            CProtocolBridge::StartReadResponse(context);
+        }
+    }
+    else
+    {
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, context->GetActivityId());
+
+        if (context->GetIsUpgrade()) 
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(context, HRESULT_FROM_WIN32(hr));
+        }
+        else
+        {
+            CProtocolBridge::SendEmptyResponse( context, 
+                                                500, 
+                                                CNodeConstants::IISNODE_ERROR_FAILED_READ_REQ_BODY, 
+                                                _T("Internal Server Error"), 
+                                                HRESULT_FROM_WIN32(hr) );
+        }
+    }
+
+    return;
 }
 
 void WINAPI CProtocolBridge::ReadRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {	
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-
-	if (S_OK == error && bytesTransfered > 0)
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode read a chunk of http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-		CProtocolBridge::SendRequestBody(ctx, bytesTransfered);
-	}
-	else if (ERROR_HANDLE_EOF == error || 0 == bytesTransfered)
-	{	
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-
-		if (ctx->GetIsUpgrade()) 
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
-		}
-		else if (ctx->GetIsChunked() && !ctx->GetIsLastChunk()) 
-		{
-			// send the zero-length last chunk to indicate the end of a chunked entity body
-
-			CProtocolBridge::SendRequestBody(ctx, 0);
-		}
-		else
-		{
-			CProtocolBridge::StartReadResponse(ctx);
-		}
-	}
-	else 
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-
-		if (ctx->GetIsUpgrade())
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(ctx, error);
-		}
-		else
-		{
-			CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), error);
-		}
-	}
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+
+    if (S_OK == error && bytesTransfered > 0)
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode read a chunk of http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+        CProtocolBridge::SendRequestBody(ctx, bytesTransfered);
+    }
+    else if (ERROR_HANDLE_EOF == error || 0 == bytesTransfered)
+    {	
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode detected the end of the http request body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+
+        if (ctx->GetIsUpgrade()) 
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
+        }
+        else if (ctx->GetIsChunked() && !ctx->GetIsLastChunk()) 
+        {
+            // send the zero-length last chunk to indicate the end of a chunked entity body
+
+            CProtocolBridge::SendRequestBody(ctx, 0);
+        }
+        else
+        {
+            CProtocolBridge::StartReadResponse(ctx);
+        }
+    }
+    else 
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed reading http request body", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+
+        if (ctx->GetIsUpgrade())
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(ctx, error);
+        }
+        else
+        {
+            CProtocolBridge::SendEmptyResponse( ctx, 
+                                                500, 
+                                                CNodeConstants::IISNODE_ERROR_FAILED_READ_REQ_BODY_COMPLETED, 
+                                                _T("Internal Server Error"), 
+                                                error );
+        }
+    }
 }
 
 void CProtocolBridge::SendRequestBody(CNodeHttpStoredContext* context, DWORD chunkLength)
 {
-	// capture ETW provider since after a successful call to WriteFile the context may be asynchronously deleted
-
-	CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
-	GUID activityId;
-	memcpy(&activityId, context->GetActivityId(), sizeof GUID);
-
-	DWORD length;
-	char* buffer;
-
-	if (context->GetIsChunked())
-	{
-		// IIS decodes chunked transfer encoding of request entity body. Chunked encoding must be 
-		// re-applied here around the request body data IIS provided in the buffer before it is sent to node.exe.
-		// This is done by calculating and pre-pending the chunk header to the data in the buffer 
-		// and appending a chunk terminating CRLF to the data in the buffer. 
-
-		// http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6
-
-		// Generate the chunk header (from last byte to first)
-
-		buffer = (char*)context->GetChunkBuffer(); // first byte of entity body chunk data
-		*(--buffer) = 0x0A; // LF
-		*(--buffer) = 0x0D; // CR
-
-		if (0 == chunkLength) 
-		{
-			// this is the end of the request entity body - generate last, zero-length chunk
-			*(--buffer) = '0';
-			context->SetIsLastChunk(TRUE);
-		}
-		else 
-		{
-			length = chunkLength;
-			while (length > 0)
-			{
-				DWORD digit = length % 16;
-				*(--buffer) = (digit < 10) ? ('0' + digit) : ('a' + digit - 10);
-				length >>= 4;
-			}
-		}
-
-		// Append CRLF to the entity body chunk
-
-		char* end = (char*)context->GetChunkBuffer() + chunkLength; // first byte after the chunk data
-		*end = 0x0D; // CR
-		*(++end) = 0x0A; // LF
-
-		// Calculate total length of the chunk including framing
-
-		length = end - buffer + 1;
-	}
-	else
-	{
-		length = chunkLength;
-		buffer = (char*)context->GetBuffer();
-	}
-
-	// send the entity body data to the node.exe process
-
-	context->SetNextProcessor(CProtocolBridge::SendRequestBodyCompleted);
-
-	if (WriteFile(context->GetPipe(), (void*)buffer, length, NULL, context->InitializeOverlapped()))
-	{
-		// completed synchronously
-
-		etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and completed synchronously", 
-			WINEVENT_LEVEL_VERBOSE, 
-			&activityId);
-
-		// despite IO completion ports are used, asynchronous callback will not be invoked because in 
-		// CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
-		// - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
-		// and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
-
-		CProtocolBridge::SendRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
-	}
-	else 
-	{
-		HRESULT hr = GetLastError();
-
-		if (ERROR_IO_PENDING == hr)
-		{
-			// will complete asynchronously
-
-			etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and will complete asynchronously", 
-				WINEVENT_LEVEL_VERBOSE, 
-				&activityId);
-		}
-		else if (ERROR_NO_DATA == hr)
-		{
-			// Node.exe has closed the named pipe. This means it does not expect any more request data, but it does not mean there is no response.
-			// This may happen even for POST requests if the node.js application does not register event handlers for the 'data' or 'end' request events.
-			// Ignore the write error and attempt to read the response instead (which might have been written by node.exe before the named pipe connection 
-			// was closed). This may also happen for WebSocket traffic. 
-
-			etw->Log(L"iisnode detected the node.exe process closed the named pipe connection", 
-				WINEVENT_LEVEL_VERBOSE, 
-				&activityId);
-
-			if (context->GetIsUpgrade()) 
-			{
-				CProtocolBridge::FinalizeUpgradeResponse(context, S_OK);
-			}
-			else
-			{
-				CProtocolBridge::StartReadResponse(context);
-			}
-		}
-		else
-		{
-			// error
-
-			etw->Log(L"iisnode failed to initiate sending http request body chunk to the node.exe process", 
-				WINEVENT_LEVEL_ERROR, 
-				&activityId);
-
-			if (context->GetIsUpgrade())
-			{
-				CProtocolBridge::FinalizeUpgradeResponse(context, hr);
-			}
-			else
-			{
-				CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), hr);
-			}
-		}
-	}
-
-	return;
+    // capture ETW provider since after a successful call to WriteFile the context may be asynchronously deleted
+
+    CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
+    GUID activityId;
+    memcpy(&activityId, context->GetActivityId(), sizeof GUID);
+
+    DWORD length;
+    char* buffer;
+
+    if (context->GetIsChunked())
+    {
+        // IIS decodes chunked transfer encoding of request entity body. Chunked encoding must be 
+        // re-applied here around the request body data IIS provided in the buffer before it is sent to node.exe.
+        // This is done by calculating and pre-pending the chunk header to the data in the buffer 
+        // and appending a chunk terminating CRLF to the data in the buffer. 
+
+        // http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6
+
+        // Generate the chunk header (from last byte to first)
+
+        buffer = (char*)context->GetChunkBuffer(); // first byte of entity body chunk data
+        *(--buffer) = 0x0A; // LF
+        *(--buffer) = 0x0D; // CR
+
+        if (0 == chunkLength) 
+        {
+            // this is the end of the request entity body - generate last, zero-length chunk
+            *(--buffer) = '0';
+            context->SetIsLastChunk(TRUE);
+        }
+        else 
+        {
+            length = chunkLength;
+            while (length > 0)
+            {
+                DWORD digit = length % 16;
+                *(--buffer) = (digit < 10) ? ('0' + digit) : ('a' + digit - 10);
+                length >>= 4;
+            }
+        }
+
+        // Append CRLF to the entity body chunk
+
+        char* end = (char*)context->GetChunkBuffer() + chunkLength; // first byte after the chunk data
+        *end = 0x0D; // CR
+        *(++end) = 0x0A; // LF
+
+        // Calculate total length of the chunk including framing
+
+        length = end - buffer + 1;
+    }
+    else
+    {
+        length = chunkLength;
+        buffer = (char*)context->GetBuffer();
+    }
+
+    // send the entity body data to the node.exe process
+
+    context->SetNextProcessor(CProtocolBridge::SendRequestBodyCompleted);
+
+    if (WriteFile(context->GetPipe(), (void*)buffer, length, NULL, context->InitializeOverlapped()))
+    {
+        // completed synchronously
+
+        etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and completed synchronously", 
+            WINEVENT_LEVEL_VERBOSE, 
+            &activityId);
+
+        // despite IO completion ports are used, asynchronous callback will not be invoked because in 
+        // CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
+        // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
+        // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
+
+        CProtocolBridge::SendRequestBodyCompleted(S_OK, 0, context->GetOverlapped());
+    }
+    else 
+    {
+        HRESULT hr = GetLastError();
+
+        if (ERROR_IO_PENDING == hr)
+        {
+            // will complete asynchronously
+
+            etw->Log(L"iisnode initiated sending http request body chunk to the node.exe process and will complete asynchronously", 
+                WINEVENT_LEVEL_VERBOSE, 
+                &activityId);
+        }
+        else if (ERROR_NO_DATA == hr)
+        {
+            // Node.exe has closed the named pipe. This means it does not expect any more request data, but it does not mean there is no response.
+            // This may happen even for POST requests if the node.js application does not register event handlers for the 'data' or 'end' request events.
+            // Ignore the write error and attempt to read the response instead (which might have been written by node.exe before the named pipe connection 
+            // was closed). This may also happen for WebSocket traffic. 
+
+            etw->Log(L"iisnode detected the node.exe process closed the named pipe connection", 
+                WINEVENT_LEVEL_VERBOSE, 
+                &activityId);
+
+            if (context->GetIsUpgrade()) 
+            {
+                CProtocolBridge::FinalizeUpgradeResponse(context, S_OK);
+            }
+            else
+            {
+                CProtocolBridge::StartReadResponse(context);
+            }
+        }
+        else
+        {
+            // error
+
+            etw->Log(L"iisnode failed to initiate sending http request body chunk to the node.exe process", 
+                WINEVENT_LEVEL_ERROR, 
+                &activityId);
+
+            if (context->GetIsUpgrade())
+            {
+                CProtocolBridge::FinalizeUpgradeResponse(context, hr);
+            }
+            else
+            {
+                CProtocolBridge::SendEmptyResponse( context, 
+                                                    500, 
+                                                    CNodeConstants::IISNODE_ERROR_FAILED_INIT_SEND_REQ_BODY, 
+                                                    _T("Internal Server Error"), 
+                                                    hr );
+            }
+        }
+    }
+
+    return;
 }
 
 void WINAPI CProtocolBridge::SendRequestBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-
-	if (S_OK == error)
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode finished sending http request body chunk to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-		CProtocolBridge::ReadRequestBody(ctx);
-	}
-	else 
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to send http request body chunk to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-
-		if (ctx->GetIsUpgrade())
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(ctx, error);
-		}
-		else
-		{
-			CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), error);
-		}
-	}
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+
+    if (S_OK == error)
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode finished sending http request body chunk to the node.exe process", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+        CProtocolBridge::ReadRequestBody(ctx);
+    }
+    else 
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to send http request body chunk to the node.exe process", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+
+        if (ctx->GetIsUpgrade())
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(ctx, error);
+        }
+        else
+        {
+            CProtocolBridge::SendEmptyResponse( ctx, 
+                                                500, 
+                                                CNodeConstants::IISNODE_ERROR_FAILED_SEND_REQ_BODY, 
+                                                _T("Internal Server Error"), 
+                                                error );
+        }
+    }
 }
 
 void CProtocolBridge::StartReadResponse(CNodeHttpStoredContext* context)
 {
-	context->SetDataSize(0);
-	context->SetParsingOffset(0);
-	context->SetNextProcessor(CProtocolBridge::ProcessResponseStatusLine);
-	context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode starting to read http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-	CProtocolBridge::ContinueReadResponse(context);
+    context->SetDataSize(0);
+    context->SetParsingOffset(0);
+    context->SetNextProcessor(CProtocolBridge::ProcessResponseStatusLine);
+    context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode starting to read http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+    CProtocolBridge::ContinueReadResponse(context);
 }
 
 HRESULT CProtocolBridge::EnsureBuffer(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;
-
-	if (context->GetBufferSize() == context->GetDataSize())
-	{
-		// buffer is full
-
-		if (context->GetParsingOffset() > 0)
-		{
-			// remove already parsed data from buffer by moving unprocessed data to the front; this will free up space at the end
-
-			char* b = (char*)context->GetBuffer();
-			memcpy(b, b + context->GetParsingOffset(), context->GetDataSize() - context->GetParsingOffset());
-		}
-		else 
-		{
-			// allocate more buffer memory
-
-			context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-				L"iisnode allocating more buffer memory to handle http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-			DWORD* bufferLength = context->GetBufferSizeRef();
-			void** buffer = context->GetBufferRef();
-
-			DWORD quota = CModuleConfiguration::GetMaxRequestBufferSize(context->GetHttpContext());
-			ErrorIf(*bufferLength >= quota, ERROR_NOT_ENOUGH_QUOTA);
-
-			void* newBuffer;
-			DWORD newBufferLength = *bufferLength * 2;
-			if (newBufferLength > quota)
-			{
-				newBufferLength = quota;
-			}
-
-			ErrorIf(NULL == (newBuffer = context->GetHttpContext()->AllocateRequestMemory(newBufferLength)), ERROR_NOT_ENOUGH_MEMORY);
-			memcpy(newBuffer, (char*)(*buffer) + context->GetParsingOffset(), context->GetDataSize() - context->GetParsingOffset());
-			*buffer = newBuffer;
-			*bufferLength = newBufferLength;
-		}
-
-		context->SetDataSize(context->GetDataSize() - context->GetParsingOffset());
-		context->SetParsingOffset(0);
-	}
-
-	return S_OK;
+    HRESULT hr;
+
+    if (context->GetBufferSize() == context->GetDataSize())
+    {
+        // buffer is full
+
+        if (context->GetParsingOffset() > 0)
+        {
+            // remove already parsed data from buffer by moving unprocessed data to the front; this will free up space at the end
+
+            char* b = (char*)context->GetBuffer();
+            memcpy(b, b + context->GetParsingOffset(), context->GetDataSize() - context->GetParsingOffset());
+        }
+        else 
+        {
+            // allocate more buffer memory
+
+            context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                L"iisnode allocating more buffer memory to handle http response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+            DWORD* bufferLength = context->GetBufferSizeRef();
+            void** buffer = context->GetBufferRef();
+
+            DWORD quota = CModuleConfiguration::GetMaxRequestBufferSize(context->GetHttpContext());
+            ErrorIf(*bufferLength >= quota, ERROR_NOT_ENOUGH_QUOTA);
+
+            void* newBuffer;
+            DWORD newBufferLength = *bufferLength * 2;
+            if (newBufferLength > quota)
+            {
+                newBufferLength = quota;
+            }
+
+            ErrorIf(NULL == (newBuffer = context->GetHttpContext()->AllocateRequestMemory(newBufferLength)), ERROR_NOT_ENOUGH_MEMORY);
+            memcpy(newBuffer, (char*)(*buffer) + context->GetParsingOffset(), context->GetDataSize() - context->GetParsingOffset());
+            *buffer = newBuffer;
+            *bufferLength = newBufferLength;
+        }
+
+        context->SetDataSize(context->GetDataSize() - context->GetParsingOffset());
+        context->SetParsingOffset(0);
+    }
+
+    return S_OK;
 Error:
-	return hr;
+    return hr;
 
 }
 
 void CProtocolBridge::ContinueReadResponse(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;
-	DWORD bytesRead = 0;
-
-	// capture ETW provider since after a successful call to ReadFile the context may be asynchronously deleted
-
-	CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
-	GUID activityId;
-	memcpy(&activityId, context->GetActivityId(), sizeof GUID);
-
-	CheckError(CProtocolBridge::EnsureBuffer(context));
-
-	if (ReadFile(
-			context->GetPipe(), 
-			(char*)context->GetBuffer() + context->GetDataSize(), 
-			context->GetBufferSize() - context->GetDataSize(),
-			&bytesRead,
-			context->InitializeOverlapped()))
-	{
-		// read completed synchronously 
-
-		etw->Log(L"iisnode initiated reading http response chunk and completed synchronously", 
-			WINEVENT_LEVEL_VERBOSE, 
-			&activityId);
-
-		// despite IO completion ports are used, asynchronous callback will not be invoked because in 
-		// CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
-		// - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
-		// and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
-
-		context->GetAsyncContext()->completionProcessor(S_OK, bytesRead, context->GetOverlapped());
-	}
-	else if (ERROR_IO_PENDING == (hr = GetLastError()))
-	{
-		// read will complete asynchronously
-
-		etw->Log(L"iisnode initiated reading http response chunk and will complete asynchronously", 
-			WINEVENT_LEVEL_VERBOSE, 
-			&activityId);
-	}
-	else if (ERROR_BROKEN_PIPE == hr && context->GetCloseConnection())
-	{
-		// Termination of a connection indicates the end of the response body if Connection: close response header was present
-
-		CProtocolBridge::FinalizeResponse(context);
-	}
-	else
-	{
-		// error
-
-		etw->Log(L"iisnode failed to initialize reading of http response chunk", 
-			WINEVENT_LEVEL_ERROR, 
-			&activityId);
-
-		CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    HRESULT hr;
+    DWORD bytesRead = 0;
+
+    // capture ETW provider since after a successful call to ReadFile the context may be asynchronously deleted
+
+    CNodeEventProvider* etw = context->GetNodeApplication()->GetApplicationManager()->GetEventProvider();
+    GUID activityId;
+    memcpy(&activityId, context->GetActivityId(), sizeof GUID);
+
+    CheckError(CProtocolBridge::EnsureBuffer(context));
+
+    if (ReadFile(
+            context->GetPipe(), 
+            (char*)context->GetBuffer() + context->GetDataSize(), 
+            context->GetBufferSize() - context->GetDataSize(),
+            &bytesRead,
+            context->InitializeOverlapped()))
+    {
+        // read completed synchronously 
+
+        etw->Log(L"iisnode initiated reading http response chunk and completed synchronously", 
+            WINEVENT_LEVEL_VERBOSE, 
+            &activityId);
+
+        // despite IO completion ports are used, asynchronous callback will not be invoked because in 
+        // CProtocolBridge:CreateNamedPipeConnection the SetFileCompletionNotificationModes function was called
+        // - see http://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
+        // and http://msdn.microsoft.com/en-us/library/windows/desktop/aa365538(v=vs.85).aspx
+
+        context->GetAsyncContext()->completionProcessor(S_OK, bytesRead, context->GetOverlapped());
+    }
+    else if (ERROR_IO_PENDING == (hr = GetLastError()))
+    {
+        // read will complete asynchronously
+
+        etw->Log(L"iisnode initiated reading http response chunk and will complete asynchronously", 
+            WINEVENT_LEVEL_VERBOSE, 
+            &activityId);
+    }
+    else if (ERROR_BROKEN_PIPE == hr && context->GetCloseConnection())
+    {
+        // Termination of a connection indicates the end of the response body if Connection: close response header was present
+
+        CProtocolBridge::FinalizeResponse(context);
+    }
+    else
+    {
+        // error
+
+        etw->Log(L"iisnode failed to initialize reading of http response chunk", 
+            WINEVENT_LEVEL_ERROR, 
+            &activityId);
+
+        CProtocolBridge::SendEmptyResponse( context, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_INIT_READ_RESPONSE, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 Error:
 
-	context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode failed to allocate memory buffer to read http response chunk", WINEVENT_LEVEL_ERROR, &activityId);
+    context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode failed to allocate memory buffer to read http response chunk", WINEVENT_LEVEL_ERROR, &activityId);
 
-	CProtocolBridge::SendEmptyResponse(context, 500, _T("Internal Server Error"), hr);
+    CProtocolBridge::SendEmptyResponse( context, 
+                                        500, 
+                                        CNodeConstants::IISNODE_ERROR_FAILED_ALLOC_MEM_READ_RESPONSE, 
+                                        _T("Internal Server Error"), 
+                                        hr );
 
-	return;
+    return;
 }
 
 void WINAPI CProtocolBridge::ProcessResponseStatusLine(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode starting to process http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode starting to process http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
 
-	CheckError(error);
-	ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
-	CheckError(CHttpProtocol::ParseResponseStatusLine(ctx));
+    CheckError(error);
+    ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
+    CheckError(CHttpProtocol::ParseResponseStatusLine(ctx));
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode finished processing http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode finished processing http response status line", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
 
-	ctx->SetNextProcessor(CProtocolBridge::ProcessResponseHeaders);
-	CProtocolBridge::ProcessResponseHeaders(S_OK, 0, ctx->GetOverlapped());
+    ctx->SetNextProcessor(CProtocolBridge::ProcessResponseHeaders);
+    CProtocolBridge::ProcessResponseHeaders(S_OK, 0, ctx->GetOverlapped());
 
-	return;
+    return;
 Error:
 
-	if (ERROR_MORE_DATA == hr)
-	{
-		CProtocolBridge::ContinueReadResponse(ctx);
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to process http response status line", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    if (ERROR_MORE_DATA == hr)
+    {
+        CProtocolBridge::ContinueReadResponse(ctx);
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to process http response status line", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_HTTP_STATUS_LINE, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 HRESULT CProtocolBridge::AddDebugHeader(CNodeHttpStoredContext* context)
 {
-	HRESULT hr;
-	char* header;
-	char buffer[256];
+    HRESULT hr;
+    char* header;
+    char buffer[256];
 
-	ErrorIf(NULL == (header = (char*)context->GetHttpContext()->AllocateRequestMemory(512)), ERROR_NOT_ENOUGH_MEMORY);
-	*header = 0;
+    ErrorIf(NULL == (header = (char*)context->GetHttpContext()->AllocateRequestMemory(512)), ERROR_NOT_ENOUGH_MEMORY);
+    *header = 0;
 
-	// iisnode version
+    // iisnode version
 
-	strcat(header, "http://bit.ly/NsU2nd#iisnode_ver=");
-	strcat(header, IISNODE_VERSION);
+    strcat(header, "http://bit.ly/NsU2nd#iisnode_ver=");
+    strcat(header, IISNODE_VERSION);
 
-	// node process command line
+    // node process command line
 
-	WCHAR* npcl = CModuleConfiguration::GetNodeProcessCommandLine(context->GetHttpContext());	
+    WCHAR* npcl = CModuleConfiguration::GetNodeProcessCommandLine(context->GetHttpContext());	
     size_t npcl_length = wcslen(npcl) + 1;
-	char* npcl_c;
-	ErrorIf(NULL == (npcl_c = (char*)context->GetHttpContext()->AllocateRequestMemory(npcl_length)), ERROR_NOT_ENOUGH_MEMORY);
+    char* npcl_c;
+    ErrorIf(NULL == (npcl_c = (char*)context->GetHttpContext()->AllocateRequestMemory(npcl_length)), ERROR_NOT_ENOUGH_MEMORY);
     size_t converted;
     wcstombs_s(&converted, 	npcl_c, npcl_length, npcl, _TRUNCATE);
-	strcat(header, "&node=");
-	strcat(header, npcl_c);
+    strcat(header, "&node=");
+    strcat(header, npcl_c);
 
-	// dns name
+    // dns name
 
-	DWORD length = sizeof buffer;
-	if (GetComputerNameEx(ComputerNameDnsFullyQualified, buffer, &length))
-	{
-		strcat(header, "&dns=");
-		strcat(header, buffer);
-	}
+    DWORD length = sizeof buffer;
+    if (GetComputerNameEx(ComputerNameDnsFullyQualified, buffer, &length))
+    {
+        strcat(header, "&dns=");
+        strcat(header, buffer);
+    }
 
-	// worker PID
+    // worker PID
 
-	sprintf(buffer, "&worker_pid=%d", GetCurrentProcessId());
-	strcat(header, buffer);
+    sprintf(buffer, "&worker_pid=%d", GetCurrentProcessId());
+    strcat(header, buffer);
 
-	// node PID
+    // node PID
 
-	sprintf(buffer, "&node_pid=%d", context->GetNodeProcess()->GetPID());
-	strcat(header, buffer);
+    sprintf(buffer, "&node_pid=%d", context->GetNodeProcess()->GetPID());
+    strcat(header, buffer);
 
-	// worker working set and private bytes
+    // worker working set and private bytes
 
-	PROCESS_MEMORY_COUNTERS_EX memory;
-	ErrorIf(!GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&memory, sizeof memory), GetLastError());
-	sprintf(buffer, "&worker_mem_ws=%u&worker_mem_pagefile=%u", memory.WorkingSetSize / 1024, memory.PagefileUsage / 1024);
-	strcat(header, buffer);
+    PROCESS_MEMORY_COUNTERS_EX memory;
+    ErrorIf(!GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*)&memory, sizeof memory), GetLastError());
+    sprintf(buffer, "&worker_mem_ws=%u&worker_mem_pagefile=%u", memory.WorkingSetSize / 1024, memory.PagefileUsage / 1024);
+    strcat(header, buffer);
 
-	// node working set and private bytes
+    // node working set and private bytes
 
-	ErrorIf(!GetProcessMemoryInfo(context->GetNodeProcess()->GetProcess(), (PROCESS_MEMORY_COUNTERS*)&memory, sizeof memory), GetLastError());
-	sprintf(buffer, "&node_mem_ws=%u&node_mem_pagefile=%u", memory.WorkingSetSize / 1024, memory.PagefileUsage / 1024);
-	strcat(header, buffer);
+    ErrorIf(!GetProcessMemoryInfo(context->GetNodeProcess()->GetProcess(), (PROCESS_MEMORY_COUNTERS*)&memory, sizeof memory), GetLastError());
+    sprintf(buffer, "&node_mem_ws=%u&node_mem_pagefile=%u", memory.WorkingSetSize / 1024, memory.PagefileUsage / 1024);
+    strcat(header, buffer);
 
-	// number of processes
+    // number of processes
 
-	sprintf(buffer, "&app_processes=%d", context->GetNodeApplication()->GetProcessCount());
-	strcat(header, buffer);
+    sprintf(buffer, "&app_processes=%d", context->GetNodeApplication()->GetProcessCount());
+    strcat(header, buffer);
 
-	// process active requests
+    // process active requests
 
-	sprintf(buffer, "&process_active_req=%d", context->GetNodeProcess()->GetActiveRequestCount());
-	strcat(header, buffer);
+    sprintf(buffer, "&process_active_req=%d", context->GetNodeProcess()->GetActiveRequestCount());
+    strcat(header, buffer);
 
-	// application active requests
+    // application active requests
 
-	sprintf(buffer, "&app_active_req=%d", context->GetNodeApplication()->GetActiveRequestCount());
-	strcat(header, buffer);
+    sprintf(buffer, "&app_active_req=%d", context->GetNodeApplication()->GetActiveRequestCount());
+    strcat(header, buffer);
 
-	// worker total requests
+    // worker total requests
 
-	sprintf(buffer, "&worker_total_req=%d", context->GetNodeApplication()->GetApplicationManager()->GetTotalRequests());
-	strcat(header, buffer);
+    sprintf(buffer, "&worker_total_req=%d", context->GetNodeApplication()->GetApplicationManager()->GetTotalRequests());
+    strcat(header, buffer);
 
-	// named pipe reconnect attempts
+    // named pipe reconnect attempts
 
-	sprintf(buffer, "&np_retry=%d", context->GetConnectionRetryCount());
-	strcat(header, buffer);
+    sprintf(buffer, "&np_retry=%d", context->GetConnectionRetryCount());
+    strcat(header, buffer);
 
-	// request time
+    // request time
 
-	FILETIME endTime;
-	GetSystemTimeAsFileTime(&endTime);
-	ULARGE_INTEGER start, end;
-	start.HighPart = context->GetStartTime()->dwHighDateTime;
-	start.LowPart = context->GetStartTime()->dwLowDateTime;
-	end.HighPart = endTime.dwHighDateTime;
-	end.LowPart = endTime.dwLowDateTime;
-	end.QuadPart -= start.QuadPart;
-	end.QuadPart /= 10000; // convert to milliseconds
-	sprintf(buffer, "&req_time=%u", end.LowPart);
-	strcat(header, buffer);
+    FILETIME endTime;
+    GetSystemTimeAsFileTime(&endTime);
+    ULARGE_INTEGER start, end;
+    start.HighPart = context->GetStartTime()->dwHighDateTime;
+    start.LowPart = context->GetStartTime()->dwLowDateTime;
+    end.HighPart = endTime.dwHighDateTime;
+    end.LowPart = endTime.dwLowDateTime;
+    end.QuadPart -= start.QuadPart;
+    end.QuadPart /= 10000; // convert to milliseconds
+    sprintf(buffer, "&req_time=%u", end.LowPart);
+    strcat(header, buffer);
 
-	// hresult
+    // hresult
 
-	sprintf(buffer, "&hresult=%d", context->GetHresult());
-	strcat(header, buffer);
+    sprintf(buffer, "&hresult=%d", context->GetHresult());
+    strcat(header, buffer);
 
-	// add header
+    // add header
 
-	CheckError(context->GetHttpContext()->GetResponse()->SetHeader("iisnode-debug", header, strlen(header), TRUE));
+    CheckError(context->GetHttpContext()->GetResponse()->SetHeader("iisnode-debug", header, strlen(header), TRUE));
 
-	return S_OK;
+    return S_OK;
 
 Error:
 
-	return hr;
+    return hr;
 }
 
 void WINAPI CProtocolBridge::ProcessResponseHeaders(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-	PCSTR contentLength;
-	USHORT contentLengthLength;
-
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode starting to process http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-
-	CheckError(error);
-	ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
-	CheckError(CHttpProtocol::ParseResponseHeaders(ctx));
-
-	if (CModuleConfiguration::GetDebugHeaderEnabled(ctx->GetHttpContext()))
-	{
-		CheckError(CProtocolBridge::AddDebugHeader(ctx));
-	}
-
-	if (!ctx->GetExpectResponseBody())
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode determined the HTTP response does not have entity body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-
-		CProtocolBridge::FinalizeResponse(ctx);
-	}
-	else
-	{
-		if (ctx->GetIsUpgrade())
-		{
-			ctx->SetIsChunked(FALSE);
-			ctx->SetChunkLength(MAXLONGLONG);
-			ctx->SetIsLastChunk(TRUE);
-			ctx->SetNextProcessor(CProtocolBridge::ProcessUpgradeResponse);
-		}
-		else if (ctx->GetCloseConnection())
-		{
-			ctx->SetIsChunked(FALSE);
-			ctx->SetChunkLength(MAXLONGLONG);
-			ctx->SetIsLastChunk(TRUE);
-			ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
-		}
-		else 
-		{
-			contentLength = ctx->GetHttpContext()->GetResponse()->GetHeader(HttpHeaderContentLength, &contentLengthLength);
-			if (0 == contentLengthLength)
-			{
-				ctx->SetIsChunked(TRUE);
-				ctx->SetIsLastChunk(FALSE);
-				ctx->SetNextProcessor(CProtocolBridge::ProcessChunkHeader);
-			}
-			else
-			{
-				LONGLONG length = 0;
-				int i = 0;
-
-				// skip leading white space
-				while (i < contentLengthLength && (contentLength[i] < '0' || contentLength[i] > '9')) 
-					i++;
-
-				while (i < contentLengthLength && contentLength[i] >= '0' && contentLength[i] <= '9') 
-					length = length * 10 + contentLength[i++] - '0';
-
-				ctx->SetIsChunked(FALSE);
-				ctx->SetIsLastChunk(TRUE);
-				ctx->SetChunkLength(length);
-				ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
-			}
-		}
-
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode finished processing http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-
-		ctx->GetAsyncContext()->completionProcessor(S_OK, 0, ctx->GetOverlapped());
-	}
-
-	return;
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    PCSTR contentLength;
+    USHORT contentLengthLength;
+
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode starting to process http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+
+    CheckError(error);
+    ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
+    CheckError(CHttpProtocol::ParseResponseHeaders(ctx));
+
+    if (CModuleConfiguration::GetDebugHeaderEnabled(ctx->GetHttpContext()))
+    {
+        CheckError(CProtocolBridge::AddDebugHeader(ctx));
+    }
+
+    if (!ctx->GetExpectResponseBody())
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode determined the HTTP response does not have entity body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+
+        CProtocolBridge::FinalizeResponse(ctx);
+    }
+    else
+    {
+        if (ctx->GetIsUpgrade())
+        {
+            ctx->SetIsChunked(FALSE);
+            ctx->SetChunkLength(MAXLONGLONG);
+            ctx->SetIsLastChunk(TRUE);
+            ctx->SetNextProcessor(CProtocolBridge::ProcessUpgradeResponse);
+        }
+        else if (ctx->GetCloseConnection())
+        {
+            ctx->SetIsChunked(FALSE);
+            ctx->SetChunkLength(MAXLONGLONG);
+            ctx->SetIsLastChunk(TRUE);
+            ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
+        }
+        else 
+        {
+            contentLength = ctx->GetHttpContext()->GetResponse()->GetHeader(HttpHeaderContentLength, &contentLengthLength);
+            if (0 == contentLengthLength)
+            {
+                ctx->SetIsChunked(TRUE);
+                ctx->SetIsLastChunk(FALSE);
+                ctx->SetNextProcessor(CProtocolBridge::ProcessChunkHeader);
+            }
+            else
+            {
+                LONGLONG length = 0;
+                int i = 0;
+
+                // skip leading white space
+                while (i < contentLengthLength && (contentLength[i] < '0' || contentLength[i] > '9')) 
+                    i++;
+
+                while (i < contentLengthLength && contentLength[i] >= '0' && contentLength[i] <= '9') 
+                    length = length * 10 + contentLength[i++] - '0';
+
+                ctx->SetIsChunked(FALSE);
+                ctx->SetIsLastChunk(TRUE);
+                ctx->SetChunkLength(length);
+                ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
+            }
+        }
+
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode finished processing http response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+
+        ctx->GetAsyncContext()->completionProcessor(S_OK, 0, ctx->GetOverlapped());
+    }
+
+    return;
 Error:
 
-	if (ERROR_MORE_DATA == hr)
-	{
-		CProtocolBridge::ContinueReadResponse(ctx);
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to process http response headers", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    if (ERROR_MORE_DATA == hr)
+    {
+        CProtocolBridge::ContinueReadResponse(ctx);
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to process http response headers", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_HTTP_HEADERS, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 void WINAPI CProtocolBridge::ProcessChunkHeader(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode starting to process http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode starting to process http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
 
-	CheckError(error);
+    CheckError(error);
 
-	ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
-	CheckError(CHttpProtocol::ParseChunkHeader(ctx));
+    ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
+    CheckError(CHttpProtocol::ParseChunkHeader(ctx));
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode finished processing http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode finished processing http response body chunk header", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
 
-	ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
-	CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped());
+    ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
+    CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped());
 
-	return;
+    return;
 
 Error:
 
-	if (ERROR_MORE_DATA == hr)
-	{
-		CProtocolBridge::ContinueReadResponse(ctx);
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to process response body chunk header", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    if (ERROR_MORE_DATA == hr)
+    {
+        CProtocolBridge::ContinueReadResponse(ctx);
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to process response body chunk header", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_PROCESS_RESPONSE_BODY_CHUNK_HEADER, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 void CProtocolBridge::EnsureRequestPumpStarted(CNodeHttpStoredContext* context) 
 {
-	if (context->GetOpaqueFlagSet() && !context->GetRequestPumpStarted())
-	{
-		// Ensure that we start reading the request of an HTTP Upgraded request 
-		// only after the 101 Switching Protocols response had been sent. 
-
-		context->SetRequestPumpStarted();
-		CProtocolBridge::ReadRequestBody(context->GetUpgradeContext());
-		ASYNC_CONTEXT* async = context->GetUpgradeContext()->GetAsyncContext();
-		async->RunSynchronousContinuations();
-	}
+    if (context->GetOpaqueFlagSet() && !context->GetRequestPumpStarted())
+    {
+        // Ensure that we start reading the request of an HTTP Upgraded request 
+        // only after the 101 Switching Protocols response had been sent. 
+
+        context->SetRequestPumpStarted();
+        CProtocolBridge::ReadRequestBody(context->GetUpgradeContext());
+        ASYNC_CONTEXT* async = context->GetUpgradeContext()->GetAsyncContext();
+        async->RunSynchronousContinuations();
+    }
 }
 
 void WINAPI CProtocolBridge::ProcessResponseBody(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-	HTTP_DATA_CHUNK* chunk;
-	DWORD bytesSent;
-	BOOL completionExpected;
-
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode starting to process http response body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-
-	CheckError(error);
-
-	ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
-
-	if (ctx->GetDataSize() > ctx->GetParsingOffset())
-	{
-		// there is response body data in the buffer
-
-		if (ctx->GetChunkLength() > ctx->GetChunkTransmitted())
-		{
-			// send the smaller of the rest of the current chunk or the data available in the buffer to the client
-
-			DWORD dataInBuffer = ctx->GetDataSize() - ctx->GetParsingOffset();
-			DWORD remainingChunkSize = ctx->GetChunkLength() - ctx->GetChunkTransmitted();
-			DWORD bytesToSend = dataInBuffer < remainingChunkSize ? dataInBuffer : remainingChunkSize;
-
-			CheckError(ctx->EnsureResponseChunk(bytesToSend, &chunk));
-			chunk->FromMemory.BufferLength = bytesToSend;
-			memcpy(chunk->FromMemory.pBuffer, (char*)ctx->GetBuffer() + ctx->GetParsingOffset(), chunk->FromMemory.BufferLength);
-
-			if (bytesToSend == dataInBuffer)
-			{
-				ctx->SetDataSize(0);
-				ctx->SetParsingOffset(0);
-			}
-			else
-			{
-				ctx->SetParsingOffset(ctx->GetParsingOffset() + bytesToSend);
-			}
-
-			ctx->SetNextProcessor(CProtocolBridge::SendResponseBodyCompleted);
-			ctx->SetBytesCompleted(bytesToSend);
-
-			CheckError(ctx->GetHttpContext()->GetResponse()->WriteEntityChunks(
-				chunk,
-				1,
-				TRUE,
-				!ctx->GetIsLastChunk() || remainingChunkSize > bytesToSend,
-				&bytesSent,
-				&completionExpected));
-
-			ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-				L"iisnode started sending http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-		
-			if (!completionExpected)
-			{
-				ctx->SetContinueSynchronously(TRUE);
-			}
-		}
-		else if (ctx->GetIsChunked())
-		{
-			// process next chunk of the chunked encoding
-
-			ctx->SetNextProcessor(CProtocolBridge::ProcessChunkHeader);
-			CProtocolBridge::ProcessChunkHeader(S_OK, 0, ctx->GetOverlapped());
-		}
-		else
-		{
-			// response data detected beyond the body length declared with Content-Length
-
-			CheckError(ERROR_BAD_FORMAT);
-		}
-	}
-	else if (ctx->GetIsChunked() || ctx->GetChunkLength() > ctx->GetChunkTransmitted())
-	{
-		// read more body data
-
-		CProtocolBridge::ContinueReadResponse(ctx);
-	}
-	else
-	{
-		// finish request
-
-		if (ctx->GetIsUpgrade())
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
-		}
-		else
-		{
-			CProtocolBridge::FinalizeResponse(ctx);
-		}
-	}
-
-	return;
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HTTP_DATA_CHUNK* chunk;
+    DWORD bytesSent;
+    BOOL completionExpected;
+
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode starting to process http response body", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+
+    CheckError(error);
+
+    ctx->SetDataSize(ctx->GetDataSize() + bytesTransfered);
+
+    if (ctx->GetDataSize() > ctx->GetParsingOffset())
+    {
+        // there is response body data in the buffer
+
+        if (ctx->GetChunkLength() > ctx->GetChunkTransmitted())
+        {
+            // send the smaller of the rest of the current chunk or the data available in the buffer to the client
+
+            DWORD dataInBuffer = ctx->GetDataSize() - ctx->GetParsingOffset();
+            DWORD remainingChunkSize = ctx->GetChunkLength() - ctx->GetChunkTransmitted();
+            DWORD bytesToSend = dataInBuffer < remainingChunkSize ? dataInBuffer : remainingChunkSize;
+
+            CheckError(ctx->EnsureResponseChunk(bytesToSend, &chunk));
+            chunk->FromMemory.BufferLength = bytesToSend;
+            memcpy(chunk->FromMemory.pBuffer, (char*)ctx->GetBuffer() + ctx->GetParsingOffset(), chunk->FromMemory.BufferLength);
+
+            if (bytesToSend == dataInBuffer)
+            {
+                ctx->SetDataSize(0);
+                ctx->SetParsingOffset(0);
+            }
+            else
+            {
+                ctx->SetParsingOffset(ctx->GetParsingOffset() + bytesToSend);
+            }
+
+            ctx->SetNextProcessor(CProtocolBridge::SendResponseBodyCompleted);
+            ctx->SetBytesCompleted(bytesToSend);
+
+            CheckError(ctx->GetHttpContext()->GetResponse()->WriteEntityChunks(
+                chunk,
+                1,
+                TRUE,
+                !ctx->GetIsLastChunk() || remainingChunkSize > bytesToSend,
+                &bytesSent,
+                &completionExpected));
+
+            ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                L"iisnode started sending http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+        
+            if (!completionExpected)
+            {
+                ctx->SetContinueSynchronously(TRUE);
+            }
+        }
+        else if (ctx->GetIsChunked())
+        {
+            // process next chunk of the chunked encoding
+
+            ctx->SetNextProcessor(CProtocolBridge::ProcessChunkHeader);
+            CProtocolBridge::ProcessChunkHeader(S_OK, 0, ctx->GetOverlapped());
+        }
+        else
+        {
+            // response data detected beyond the body length declared with Content-Length
+
+            CheckError(ERROR_BAD_FORMAT);
+        }
+    }
+    else if (ctx->GetIsChunked() || ctx->GetChunkLength() > ctx->GetChunkTransmitted())
+    {
+        // read more body data
+
+        CProtocolBridge::ContinueReadResponse(ctx);
+    }
+    else
+    {
+        // finish request
+
+        if (ctx->GetIsUpgrade())
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
+        }
+        else
+        {
+            CProtocolBridge::FinalizeResponse(ctx);
+        }
+    }
+
+    return;
 Error:
 
-	if (ERROR_BROKEN_PIPE == hr && ctx->GetIsUpgrade())
-	{
-		// Termination of a connection indicates the end of the upgraded request 
-
-		CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
-	}
-	else if (ERROR_BROKEN_PIPE == hr && ctx->GetCloseConnection())
-	{
-		// Termination of a connection indicates the end of the response body if Connection: close response header was present
-
-		CProtocolBridge::FinalizeResponse(ctx);
-	}
-	else
-	{
-		ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode failed to send http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-
-		if (ctx->GetIsUpgrade())
-		{
-			CProtocolBridge::FinalizeUpgradeResponse(ctx, hr);
-		}
-		else
-		{
-			CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-		}
-	}
-
-	return;
+    if (ERROR_BROKEN_PIPE == hr && ctx->GetIsUpgrade())
+    {
+        // Termination of a connection indicates the end of the upgraded request 
+
+        CProtocolBridge::FinalizeUpgradeResponse(ctx, S_OK);
+    }
+    else if (ERROR_BROKEN_PIPE == hr && ctx->GetCloseConnection())
+    {
+        // Termination of a connection indicates the end of the response body if Connection: close response header was present
+
+        CProtocolBridge::FinalizeResponse(ctx);
+    }
+    else
+    {
+        ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode failed to send http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+
+        if (ctx->GetIsUpgrade())
+        {
+            CProtocolBridge::FinalizeUpgradeResponse(ctx, hr);
+        }
+        else
+        {
+            CProtocolBridge::SendEmptyResponse( ctx, 
+                                                500, 
+                                                CNodeConstants::IISNODE_ERROR_FAILED_SEND_RESPONSE_BODY_CHUNK, 
+                                                _T("Internal Server Error"), 
+                                                hr );
+        }
+    }
+
+    return;
 }
 
 void WINAPI CProtocolBridge::SendResponseBodyCompleted(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-	DWORD bytesSent;
-	BOOL completionExpected = FALSE;
-
-	CheckError(error);
-
-	if (!ctx->GetIsUpgrade())
-	{		
-		ctx->SetChunkTransmitted(ctx->GetChunkTransmitted() + bytesTransfered);
-		if (ctx->GetChunkLength() == ctx->GetChunkTransmitted())
-		{
-			ctx->SetChunkTransmitted(0);
-			ctx->SetChunkLength(0);
-		}
-	}
-
-	if (ctx->GetIsLastChunk() && ctx->GetChunkLength() == ctx->GetChunkTransmitted())
-	{
-		CProtocolBridge::FinalizeResponse(ctx);
-	}
-	else
-	{
-		if (ctx->GetIsChunked() && CModuleConfiguration::GetFlushResponse(ctx->GetHttpContext()))
-		{
-			// Flushing of chunked responses is enabled
-
-			ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
-			ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-				L"iisnode initiated flushing http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-			ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
-		}
-
-		if (!completionExpected)
-		{
-			CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped());
-		}
-	}
-
-	return;
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    DWORD bytesSent;
+    BOOL completionExpected = FALSE;
+
+    CheckError(error);
+
+    if (!ctx->GetIsUpgrade())
+    {		
+        ctx->SetChunkTransmitted(ctx->GetChunkTransmitted() + bytesTransfered);
+        if (ctx->GetChunkLength() == ctx->GetChunkTransmitted())
+        {
+            ctx->SetChunkTransmitted(0);
+            ctx->SetChunkLength(0);
+        }
+    }
+
+    if (ctx->GetIsLastChunk() && ctx->GetChunkLength() == ctx->GetChunkTransmitted())
+    {
+        CProtocolBridge::FinalizeResponse(ctx);
+    }
+    else
+    {
+        if (ctx->GetIsChunked() && CModuleConfiguration::GetFlushResponse(ctx->GetHttpContext()))
+        {
+            // Flushing of chunked responses is enabled
+
+            ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
+            ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+                L"iisnode initiated flushing http response body chunk", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+            ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
+        }
+
+        if (!completionExpected)
+        {
+            CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped());
+        }
+    }
+
+    return;
 Error:
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-
-	if (ctx->GetIsUpgrade())
-	{
-		CProtocolBridge::FinalizeUpgradeResponse(ctx, hr);
-	}
-	else 
-	{
-		CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	}
-
-	return;
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+
+    if (ctx->GetIsUpgrade())
+    {
+        CProtocolBridge::FinalizeUpgradeResponse(ctx, hr);
+    }
+    else 
+    {
+        CProtocolBridge::SendEmptyResponse( ctx, 
+                                            500, 
+                                            CNodeConstants::IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY, 
+                                            _T("Internal Server Error"), 
+                                            hr );
+    }
+
+    return;
 }
 
 void WINAPI CProtocolBridge::ProcessUpgradeResponse(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	BOOL completionExpected;
-	DWORD bytesSent;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
-
-	ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode initiated flushing http upgrade response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
-	ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
-
-	if (!completionExpected)
-	{
-		CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped());
-	}
+    BOOL completionExpected;
+    DWORD bytesSent;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+
+    ctx->SetNextProcessor(CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush);
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode initiated flushing http upgrade response headers", WINEVENT_LEVEL_VERBOSE, ctx->GetActivityId());
+    ctx->GetHttpContext()->GetResponse()->Flush(TRUE, TRUE, &bytesSent, &completionExpected);
+
+    if (!completionExpected)
+    {
+        CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(S_OK, 0, ctx->GetOverlapped());
+    }
 }
 
 
 void WINAPI CProtocolBridge::ContinueProcessResponseBodyAfterPartialFlush(DWORD error, DWORD bytesTransfered, LPOVERLAPPED overlapped)
 {
-	HRESULT hr;
-	CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
+    HRESULT hr;
+    CNodeHttpStoredContext* ctx = CNodeHttpStoredContext::Get(overlapped);
 
-	CheckError(error);	
+    CheckError(error);	
 
-	// Start reading the request bytes if the request was an accepted HTTP Upgrade
-	CProtocolBridge::EnsureRequestPumpStarted(ctx);
+    // Start reading the request bytes if the request was an accepted HTTP Upgrade
+    CProtocolBridge::EnsureRequestPumpStarted(ctx);
 
-	// Continue on to reading the response body
-	ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
-	CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped());
+    // Continue on to reading the response body
+    ctx->SetNextProcessor(CProtocolBridge::ProcessResponseBody);
+    CProtocolBridge::ProcessResponseBody(S_OK, 0, ctx->GetOverlapped());
 
-	return;
+    return;
 Error:
 
-	ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
-	CProtocolBridge::SendEmptyResponse(ctx, 500, _T("Internal Server Error"), hr);
-	
-	return;
+    ctx->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode failed to flush http response body chunk", WINEVENT_LEVEL_ERROR, ctx->GetActivityId());
+    CProtocolBridge::SendEmptyResponse( ctx, 
+                                        500, 
+                                        CNodeConstants::IISNODE_ERROR_FAILED_FLUSH_RESPONSE_BODY_PARTIAL_FLUSH, 
+                                        _T("Internal Server Error"), 
+                                        hr );
+
+    return;
 }
 
 void CProtocolBridge::FinalizeUpgradeResponse(CNodeHttpStoredContext* context, HRESULT hresult)
 {
-	context->SetNextProcessor(NULL);
-	context->SetHresult(hresult);	
-
-	if (0 == context->DecreasePendingAsyncOperationCount())
-	{
-		context->GetNodeProcess()->OnRequestCompleted(context);
-
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode finished processing both directions of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-		context->SetRequestNotificationStatus(RQ_NOTIFICATION_CONTINUE);
-		CloseHandle(context->GetPipe());
-		context->SetPipe(INVALID_HANDLE_VALUE);
-		context->GetHttpContext()->GetResponse()->SetNeedDisconnect();
-		context->GetHttpContext()->PostCompletion(0);
-	}
-	else
-	{
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-			L"iisnode finished processing one direction of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-		context->SetRequestNotificationStatus(RQ_NOTIFICATION_PENDING);
-	}
+    context->SetNextProcessor(NULL);
+    context->SetHresult(hresult);	
+
+    if (0 == context->DecreasePendingAsyncOperationCount())
+    {
+        context->GetNodeProcess()->OnRequestCompleted(context);
+
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode finished processing both directions of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+        context->SetRequestNotificationStatus(RQ_NOTIFICATION_CONTINUE);
+        CloseHandle(context->GetPipe());
+        context->SetPipe(INVALID_HANDLE_VALUE);
+        context->GetHttpContext()->GetResponse()->SetNeedDisconnect();
+        context->GetHttpContext()->PostCompletion(0);
+    }
+    else
+    {
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+            L"iisnode finished processing one direction of upgraded http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+        context->SetRequestNotificationStatus(RQ_NOTIFICATION_PENDING);
+    }
 }
 
 void CProtocolBridge::FinalizeResponse(CNodeHttpStoredContext* context)
 {
-	context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
-		L"iisnode finished processing http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
-
-	if (context->GetCloseConnection())
-	{
-		CloseHandle(context->GetPipe());
-	}
-	else
-	{
-		context->GetNodeProcess()->GetConnectionPool()->Return(context->GetPipe());
-	}
-
-	context->SetPipe(INVALID_HANDLE_VALUE);
-	CProtocolBridge::FinalizeResponseCore(
-		context, 
-		RQ_NOTIFICATION_CONTINUE, 
-		S_OK, 
-		context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(),
-		L"iisnode posts completion from FinalizeResponse", 
-		WINEVENT_LEVEL_VERBOSE);
+    context->GetNodeApplication()->GetApplicationManager()->GetEventProvider()->Log(
+        L"iisnode finished processing http request/response", WINEVENT_LEVEL_VERBOSE, context->GetActivityId());
+
+    if (context->GetCloseConnection())
+    {
+        CloseHandle(context->GetPipe());
+    }
+    else
+    {
+        context->GetNodeProcess()->GetConnectionPool()->Return(context->GetPipe());
+    }
+
+    context->SetPipe(INVALID_HANDLE_VALUE);
+    CProtocolBridge::FinalizeResponseCore(
+        context, 
+        RQ_NOTIFICATION_CONTINUE, 
+        S_OK, 
+        context->GetNodeApplication()->GetApplicationManager()->GetEventProvider(),
+        L"iisnode posts completion from FinalizeResponse", 
+        WINEVENT_LEVEL_VERBOSE);
 }
 
 HRESULT CProtocolBridge::FinalizeResponseCore(CNodeHttpStoredContext* context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, CNodeEventProvider* log, PCWSTR etw, UCHAR level)
 {
-	context->SetRequestNotificationStatus(status);
-	context->SetNextProcessor(NULL);
-	context->SetHresult(error);
+    context->SetRequestNotificationStatus(status);
+    context->SetNextProcessor(NULL);
+    context->SetHresult(error);
 
-	if (NULL != context->GetNodeProcess())
-	{
-		// there is no CNodeProcess assigned to the request yet - something failed before it was moved from the pending queue
-		// to an active request queue of a specific process
+    if (NULL != context->GetNodeProcess())
+    {
+        // there is no CNodeProcess assigned to the request yet - something failed before it was moved from the pending queue
+        // to an active request queue of a specific process
 
-		context->GetNodeProcess()->OnRequestCompleted(context);
-	}
+        context->GetNodeProcess()->OnRequestCompleted(context);
+    }
 
-	if (0 == context->DecreasePendingAsyncOperationCount()) // decreases ref count increased in the ctor of CNodeApplication::Dispatch
-	{
-		log->Log(etw, level, context->GetActivityId());	
-		context->GetHttpContext()->PostCompletion(0);
-	}
+    if (0 == context->DecreasePendingAsyncOperationCount()) // decreases ref count increased in the ctor of CNodeApplication::Dispatch
+    {
+        log->Log(etw, level, context->GetActivityId());	
+        context->GetHttpContext()->PostCompletion(0);
+    }
 
-	return S_OK;
+    return S_OK;
 }
 
 HRESULT CProtocolBridge::SendDebugRedirect(CNodeHttpStoredContext* context, CNodeEventProvider* log)
 {
-	HRESULT hr;
-
-	IHttpContext* ctx = context->GetHttpContext();
-	IHttpResponse* response = ctx->GetResponse();
-	HTTP_REQUEST* raw = ctx->GetRequest()->GetRawHttpRequest();
-
-	// redirect app.js/debug to app.js/debug/ by appending '/' at the end of the path
-
-	PSTR path;
-	int pathSizeA;
-	ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, raw->CookedUrl.AbsPathLength >> 1, NULL, 0, NULL, NULL)), E_FAIL);
-	ErrorIf(NULL == (path = (TCHAR*)ctx->AllocateRequestMemory(pathSizeA + 2)), ERROR_NOT_ENOUGH_MEMORY);
-	ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, raw->CookedUrl.AbsPathLength >> 1, path, pathSizeA, NULL, NULL), E_FAIL);
-	path[pathSizeA] = '/';
-	path[pathSizeA + 1] = 0;
-
-	response->SetStatus(301, "Moved Permanently"); 
-	CheckError(context->GetHttpContext()->GetResponse()->Redirect(path, FALSE, TRUE));
-	CProtocolBridge::FinalizeResponseCore(
-		context, 
-		RQ_NOTIFICATION_FINISH_REQUEST, 
-		S_OK, 
-		log,
-		L"iisnode redirected debugging request", 
-		WINEVENT_LEVEL_VERBOSE);
-
-	return S_OK;
+    HRESULT hr;
+
+    IHttpContext* ctx = context->GetHttpContext();
+    IHttpResponse* response = ctx->GetResponse();
+    HTTP_REQUEST* raw = ctx->GetRequest()->GetRawHttpRequest();
+
+    // redirect app.js/debug to app.js/debug/ by appending '/' at the end of the path
+
+    PSTR path;
+    int pathSizeA;
+    ErrorIf(0 == (pathSizeA = WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, raw->CookedUrl.AbsPathLength >> 1, NULL, 0, NULL, NULL)), E_FAIL);
+    ErrorIf(NULL == (path = (TCHAR*)ctx->AllocateRequestMemory(pathSizeA + 2)), ERROR_NOT_ENOUGH_MEMORY);
+    ErrorIf(pathSizeA != WideCharToMultiByte(CP_ACP, 0, raw->CookedUrl.pAbsPath, raw->CookedUrl.AbsPathLength >> 1, path, pathSizeA, NULL, NULL), E_FAIL);
+    path[pathSizeA] = '/';
+    path[pathSizeA + 1] = 0;
+
+    response->SetStatus(301, "Moved Permanently"); 
+    CheckError(context->GetHttpContext()->GetResponse()->Redirect(path, FALSE, TRUE));
+    CProtocolBridge::FinalizeResponseCore(
+        context, 
+        RQ_NOTIFICATION_FINISH_REQUEST, 
+        S_OK, 
+        log,
+        L"iisnode redirected debugging request", 
+        WINEVENT_LEVEL_VERBOSE);
+
+    return S_OK;
 Error:
-	return hr;
+    return hr;
 }
\ No newline at end of file
diff --git a/src/iisnode/cprotocolbridge.h b/src/iisnode/cprotocolbridge.h
index 68f085c7..5ce4ab80 100644
--- a/src/iisnode/cprotocolbridge.h
+++ b/src/iisnode/cprotocolbridge.h
@@ -13,7 +13,7 @@ class CProtocolBridge
 	static HRESULT EnsureBuffer(CNodeHttpStoredContext* context);
 	static HRESULT FinalizeResponseCore(CNodeHttpStoredContext * context, REQUEST_NOTIFICATION_STATUS status, HRESULT error, CNodeEventProvider* log, PCWSTR etw, UCHAR level);
 	static BOOL IsLocalCall(IHttpContext* ctx);
-	static BOOL SendDevError(CNodeHttpStoredContext* context, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
+	static BOOL SendDevError(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
 	static HRESULT AddDebugHeader(CNodeHttpStoredContext* context);
 
 	// processing stages
@@ -52,9 +52,9 @@ class CProtocolBridge
 	static HRESULT InitiateRequest(CNodeHttpStoredContext* context);
 	static BOOL SendIisnodeError(IHttpContext* httpCtx, HRESULT hr);
 	static BOOL SendIisnodeError(CNodeHttpStoredContext* ctx, HRESULT hr);
-	static HRESULT SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
+	static HRESULT SendEmptyResponse(CNodeHttpStoredContext* context, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
 	static HRESULT SendSyncResponse(IHttpContext* httpCtx, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache, PCSTR htmlBody);
-	static void SendEmptyResponse(IHttpContext* httpCtx, USHORT status, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
+	static void SendEmptyResponse(IHttpContext* httpCtx, USHORT status, USHORT subStatus, PCTSTR reason, HRESULT hresult, BOOL disableCache = FALSE);
 	static HRESULT SendDebugRedirect(CNodeHttpStoredContext* context, CNodeEventProvider* log);
 
 };
diff --git a/src/iisnode/debugger_0.7.3.rc b/src/iisnode/debugger_0.7.3.rc
new file mode 100644
index 00000000..6909d315
Binary files /dev/null and b/src/iisnode/debugger_0.7.3.rc differ
diff --git a/src/iisnode/debugger_autogenerated_0.7.3.rc b/src/iisnode/debugger_autogenerated_0.7.3.rc
new file mode 100644
index 00000000..babc1448
--- /dev/null
+++ b/src/iisnode/debugger_autogenerated_0.7.3.rc
@@ -0,0 +1,3492 @@
+//
+// This file was autogenerated in a pre-build step of iisnode by ..\scripts\genDebugRc.bat
+//
+#define IDS_1 1
+#define IDS_2 2
+#define IDS_3 3
+#define IDS_4 4
+#define IDS_5 5
+#define IDS_6 6
+#define IDS_7 7
+#define IDS_8 8
+#define IDS_9 9
+#define IDS_10 10
+#define IDS_11 11
+#define IDS_12 12
+#define IDS_13 13
+#define IDS_14 14
+#define IDS_15 15
+#define IDS_16 16
+#define IDS_17 17
+#define IDS_18 18
+#define IDS_19 19
+#define IDS_20 20
+#define IDS_21 21
+#define IDS_22 22
+#define IDS_23 23
+#define IDS_24 24
+#define IDS_25 25
+#define IDS_26 26
+#define IDS_27 27
+#define IDS_28 28
+#define IDS_29 29
+#define IDS_30 30
+#define IDS_31 31
+#define IDS_32 32
+#define IDS_33 33
+#define IDS_34 34
+#define IDS_35 35
+#define IDS_36 36
+#define IDS_37 37
+#define IDS_38 38
+#define IDS_39 39
+#define IDS_40 40
+#define IDS_41 41
+#define IDS_42 42
+#define IDS_43 43
+#define IDS_44 44
+#define IDS_45 45
+#define IDS_46 46
+#define IDS_47 47
+#define IDS_48 48
+#define IDS_49 49
+#define IDS_50 50
+#define IDS_51 51
+#define IDS_52 52
+#define IDS_53 53
+#define IDS_54 54
+#define IDS_55 55
+#define IDS_56 56
+#define IDS_57 57
+#define IDS_58 58
+#define IDS_59 59
+#define IDS_60 60
+#define IDS_61 61
+#define IDS_62 62
+#define IDS_63 63
+#define IDS_64 64
+#define IDS_65 65
+#define IDS_66 66
+#define IDS_67 67
+#define IDS_68 68
+#define IDS_69 69
+#define IDS_70 70
+#define IDS_71 71
+#define IDS_72 72
+#define IDS_73 73
+#define IDS_74 74
+#define IDS_75 75
+#define IDS_76 76
+#define IDS_77 77
+#define IDS_78 78
+#define IDS_79 79
+#define IDS_80 80
+#define IDS_81 81
+#define IDS_82 82
+#define IDS_83 83
+#define IDS_84 84
+#define IDS_85 85
+#define IDS_86 86
+#define IDS_87 87
+#define IDS_88 88
+#define IDS_89 89
+#define IDS_90 90
+#define IDS_91 91
+#define IDS_92 92
+#define IDS_93 93
+#define IDS_94 94
+#define IDS_95 95
+#define IDS_96 96
+#define IDS_97 97
+#define IDS_98 98
+#define IDS_99 99
+#define IDS_100 100
+#define IDS_101 101
+#define IDS_102 102
+#define IDS_103 103
+#define IDS_104 104
+#define IDS_105 105
+#define IDS_106 106
+#define IDS_107 107
+#define IDS_108 108
+#define IDS_109 109
+#define IDS_110 110
+#define IDS_111 111
+#define IDS_112 112
+#define IDS_113 113
+#define IDS_114 114
+#define IDS_115 115
+#define IDS_116 116
+#define IDS_117 117
+#define IDS_118 118
+#define IDS_119 119
+#define IDS_120 120
+#define IDS_121 121
+#define IDS_122 122
+#define IDS_123 123
+#define IDS_124 124
+#define IDS_125 125
+#define IDS_126 126
+#define IDS_127 127
+#define IDS_128 128
+#define IDS_129 129
+#define IDS_130 130
+#define IDS_131 131
+#define IDS_132 132
+#define IDS_133 133
+#define IDS_134 134
+#define IDS_135 135
+#define IDS_136 136
+#define IDS_137 137
+#define IDS_138 138
+#define IDS_139 139
+#define IDS_140 140
+#define IDS_141 141
+#define IDS_142 142
+#define IDS_143 143
+#define IDS_144 144
+#define IDS_145 145
+#define IDS_146 146
+#define IDS_147 147
+#define IDS_148 148
+#define IDS_149 149
+#define IDS_150 150
+#define IDS_151 151
+#define IDS_152 152
+#define IDS_153 153
+#define IDS_154 154
+#define IDS_155 155
+#define IDS_156 156
+#define IDS_157 157
+#define IDS_158 158
+#define IDS_159 159
+#define IDS_160 160
+#define IDS_161 161
+#define IDS_162 162
+#define IDS_163 163
+#define IDS_164 164
+#define IDS_165 165
+#define IDS_166 166
+#define IDS_167 167
+#define IDS_168 168
+#define IDS_169 169
+#define IDS_170 170
+#define IDS_171 171
+#define IDS_172 172
+#define IDS_173 173
+#define IDS_174 174
+#define IDS_175 175
+#define IDS_176 176
+#define IDS_177 177
+#define IDS_178 178
+#define IDS_179 179
+#define IDS_180 180
+#define IDS_181 181
+#define IDS_182 182
+#define IDS_183 183
+#define IDS_184 184
+#define IDS_185 185
+#define IDS_186 186
+#define IDS_187 187
+#define IDS_188 188
+#define IDS_189 189
+#define IDS_190 190
+#define IDS_191 191
+#define IDS_192 192
+#define IDS_193 193
+#define IDS_194 194
+#define IDS_195 195
+#define IDS_196 196
+#define IDS_197 197
+#define IDS_198 198
+#define IDS_199 199
+#define IDS_200 200
+#define IDS_201 201
+#define IDS_202 202
+#define IDS_203 203
+#define IDS_204 204
+#define IDS_205 205
+#define IDS_206 206
+#define IDS_207 207
+#define IDS_208 208
+#define IDS_209 209
+#define IDS_210 210
+#define IDS_211 211
+#define IDS_212 212
+#define IDS_213 213
+#define IDS_214 214
+#define IDS_215 215
+#define IDS_216 216
+#define IDS_217 217
+#define IDS_218 218
+#define IDS_219 219
+#define IDS_220 220
+#define IDS_221 221
+#define IDS_222 222
+#define IDS_223 223
+#define IDS_224 224
+#define IDS_225 225
+#define IDS_226 226
+#define IDS_227 227
+#define IDS_228 228
+#define IDS_229 229
+#define IDS_230 230
+#define IDS_231 231
+#define IDS_232 232
+#define IDS_233 233
+#define IDS_234 234
+#define IDS_235 235
+#define IDS_236 236
+#define IDS_237 237
+#define IDS_238 238
+#define IDS_239 239
+#define IDS_240 240
+#define IDS_241 241
+#define IDS_242 242
+#define IDS_243 243
+#define IDS_244 244
+#define IDS_245 245
+#define IDS_246 246
+#define IDS_247 247
+#define IDS_248 248
+#define IDS_249 249
+#define IDS_250 250
+#define IDS_251 251
+#define IDS_252 252
+#define IDS_253 253
+#define IDS_254 254
+#define IDS_255 255
+#define IDS_256 256
+#define IDS_257 257
+#define IDS_258 258
+#define IDS_259 259
+#define IDS_260 260
+#define IDS_261 261
+#define IDS_262 262
+#define IDS_263 263
+#define IDS_264 264
+#define IDS_265 265
+#define IDS_266 266
+#define IDS_267 267
+#define IDS_268 268
+#define IDS_269 269
+#define IDS_270 270
+#define IDS_271 271
+#define IDS_272 272
+#define IDS_273 273
+#define IDS_274 274
+#define IDS_275 275
+#define IDS_276 276
+#define IDS_277 277
+#define IDS_278 278
+#define IDS_279 279
+#define IDS_280 280
+#define IDS_281 281
+#define IDS_282 282
+#define IDS_283 283
+#define IDS_284 284
+#define IDS_285 285
+#define IDS_286 286
+#define IDS_287 287
+#define IDS_288 288
+#define IDS_289 289
+#define IDS_290 290
+#define IDS_291 291
+#define IDS_292 292
+#define IDS_293 293
+#define IDS_294 294
+#define IDS_295 295
+#define IDS_296 296
+#define IDS_297 297
+#define IDS_298 298
+#define IDS_299 299
+#define IDS_300 300
+#define IDS_301 301
+#define IDS_302 302
+#define IDS_303 303
+#define IDS_304 304
+#define IDS_305 305
+#define IDS_306 306
+#define IDS_307 307
+#define IDS_308 308
+#define IDS_309 309
+#define IDS_310 310
+#define IDS_311 311
+#define IDS_312 312
+#define IDS_313 313
+#define IDS_314 314
+#define IDS_315 315
+#define IDS_316 316
+#define IDS_317 317
+#define IDS_318 318
+#define IDS_319 319
+#define IDS_320 320
+#define IDS_321 321
+#define IDS_322 322
+#define IDS_323 323
+#define IDS_324 324
+#define IDS_325 325
+#define IDS_326 326
+#define IDS_327 327
+#define IDS_328 328
+#define IDS_329 329
+#define IDS_330 330
+#define IDS_331 331
+#define IDS_332 332
+#define IDS_333 333
+#define IDS_334 334
+#define IDS_335 335
+#define IDS_336 336
+#define IDS_337 337
+#define IDS_338 338
+#define IDS_339 339
+#define IDS_340 340
+#define IDS_341 341
+#define IDS_342 342
+#define IDS_343 343
+#define IDS_344 344
+#define IDS_345 345
+#define IDS_346 346
+#define IDS_347 347
+#define IDS_348 348
+#define IDS_349 349
+#define IDS_350 350
+#define IDS_351 351
+#define IDS_352 352
+#define IDS_353 353
+#define IDS_354 354
+#define IDS_355 355
+#define IDS_356 356
+#define IDS_357 357
+#define IDS_358 358
+#define IDS_359 359
+#define IDS_360 360
+#define IDS_361 361
+#define IDS_362 362
+#define IDS_363 363
+#define IDS_364 364
+#define IDS_365 365
+#define IDS_366 366
+#define IDS_367 367
+#define IDS_368 368
+#define IDS_369 369
+#define IDS_370 370
+#define IDS_371 371
+#define IDS_372 372
+#define IDS_373 373
+#define IDS_374 374
+#define IDS_375 375
+#define IDS_376 376
+#define IDS_377 377
+#define IDS_378 378
+#define IDS_379 379
+#define IDS_380 380
+#define IDS_381 381
+#define IDS_382 382
+#define IDS_383 383
+#define IDS_384 384
+#define IDS_385 385
+#define IDS_386 386
+#define IDS_387 387
+#define IDS_388 388
+#define IDS_389 389
+#define IDS_390 390
+#define IDS_391 391
+#define IDS_392 392
+#define IDS_393 393
+#define IDS_394 394
+#define IDS_395 395
+#define IDS_396 396
+#define IDS_397 397
+#define IDS_398 398
+#define IDS_399 399
+#define IDS_400 400
+#define IDS_401 401
+#define IDS_402 402
+#define IDS_403 403
+#define IDS_404 404
+#define IDS_405 405
+#define IDS_406 406
+#define IDS_407 407
+#define IDS_408 408
+#define IDS_409 409
+#define IDS_410 410
+#define IDS_411 411
+#define IDS_412 412
+#define IDS_413 413
+#define IDS_414 414
+#define IDS_415 415
+#define IDS_416 416
+#define IDS_417 417
+#define IDS_418 418
+#define IDS_419 419
+#define IDS_420 420
+#define IDS_421 421
+#define IDS_422 422
+#define IDS_423 423
+#define IDS_424 424
+#define IDS_425 425
+#define IDS_426 426
+#define IDS_427 427
+#define IDS_428 428
+#define IDS_429 429
+#define IDS_430 430
+#define IDS_431 431
+#define IDS_432 432
+#define IDS_433 433
+#define IDS_434 434
+#define IDS_435 435
+#define IDS_436 436
+#define IDS_437 437
+#define IDS_438 438
+#define IDS_439 439
+#define IDS_440 440
+#define IDS_441 441
+#define IDS_442 442
+#define IDS_443 443
+#define IDS_444 444
+#define IDS_445 445
+#define IDS_446 446
+#define IDS_447 447
+#define IDS_448 448
+#define IDS_449 449
+#define IDS_450 450
+#define IDS_451 451
+#define IDS_452 452
+#define IDS_453 453
+#define IDS_454 454
+#define IDS_455 455
+#define IDS_456 456
+#define IDS_457 457
+#define IDS_458 458
+#define IDS_459 459
+#define IDS_460 460
+#define IDS_461 461
+#define IDS_462 462
+#define IDS_463 463
+#define IDS_464 464
+#define IDS_465 465
+#define IDS_466 466
+#define IDS_467 467
+#define IDS_468 468
+#define IDS_469 469
+#define IDS_470 470
+#define IDS_471 471
+#define IDS_472 472
+#define IDS_473 473
+#define IDS_474 474
+#define IDS_475 475
+#define IDS_476 476
+#define IDS_477 477
+#define IDS_478 478
+#define IDS_479 479
+#define IDS_480 480
+#define IDS_481 481
+#define IDS_482 482
+#define IDS_483 483
+#define IDS_484 484
+#define IDS_485 485
+#define IDS_486 486
+#define IDS_487 487
+#define IDS_488 488
+#define IDS_489 489
+#define IDS_490 490
+#define IDS_491 491
+#define IDS_492 492
+#define IDS_493 493
+#define IDS_494 494
+#define IDS_495 495
+#define IDS_496 496
+#define IDS_497 497
+#define IDS_498 498
+#define IDS_499 499
+#define IDS_500 500
+#define IDS_501 501
+#define IDS_502 502
+#define IDS_503 503
+#define IDS_504 504
+#define IDS_505 505
+#define IDS_506 506
+#define IDS_507 507
+#define IDS_508 508
+#define IDS_509 509
+#define IDS_510 510
+#define IDS_511 511
+#define IDS_512 512
+#define IDS_513 513
+#define IDS_514 514
+#define IDS_515 515
+#define IDS_516 516
+#define IDS_517 517
+#define IDS_518 518
+#define IDS_519 519
+#define IDS_520 520
+#define IDS_521 521
+#define IDS_522 522
+#define IDS_523 523
+#define IDS_524 524
+#define IDS_525 525
+#define IDS_526 526
+#define IDS_527 527
+#define IDS_528 528
+#define IDS_529 529
+#define IDS_530 530
+#define IDS_531 531
+#define IDS_532 532
+#define IDS_533 533
+#define IDS_534 534
+#define IDS_535 535
+#define IDS_536 536
+#define IDS_537 537
+#define IDS_538 538
+#define IDS_539 539
+#define IDS_540 540
+#define IDS_541 541
+#define IDS_542 542
+#define IDS_543 543
+#define IDS_544 544
+#define IDS_545 545
+#define IDS_546 546
+#define IDS_547 547
+#define IDS_548 548
+#define IDS_549 549
+#define IDS_550 550
+#define IDS_551 551
+#define IDS_552 552
+#define IDS_553 553
+#define IDS_554 554
+#define IDS_555 555
+#define IDS_556 556
+#define IDS_557 557
+#define IDS_558 558
+#define IDS_559 559
+#define IDS_560 560
+#define IDS_561 561
+#define IDS_562 562
+#define IDS_563 563
+#define IDS_564 564
+#define IDS_565 565
+#define IDS_566 566
+#define IDS_567 567
+#define IDS_568 568
+#define IDS_569 569
+#define IDS_570 570
+#define IDS_571 571
+#define IDS_572 572
+#define IDS_573 573
+#define IDS_574 574
+#define IDS_575 575
+#define IDS_576 576
+#define IDS_577 577
+#define IDS_578 578
+#define IDS_579 579
+#define IDS_580 580
+#define IDS_581 581
+#define IDS_582 582
+#define IDS_583 583
+#define IDS_584 584
+#define IDS_585 585
+#define IDS_586 586
+#define IDS_587 587
+#define IDS_588 588
+#define IDS_589 589
+#define IDS_590 590
+#define IDS_591 591
+#define IDS_592 592
+#define IDS_593 593
+#define IDS_594 594
+#define IDS_595 595
+#define IDS_596 596
+#define IDS_597 597
+#define IDS_598 598
+#define IDS_599 599
+#define IDS_600 600
+#define IDS_601 601
+#define IDS_602 602
+#define IDS_603 603
+#define IDS_604 604
+#define IDS_605 605
+#define IDS_606 606
+#define IDS_607 607
+#define IDS_608 608
+#define IDS_609 609
+#define IDS_610 610
+#define IDS_611 611
+#define IDS_612 612
+#define IDS_613 613
+#define IDS_614 614
+#define IDS_615 615
+#define IDS_616 616
+#define IDS_617 617
+#define IDS_618 618
+#define IDS_619 619
+#define IDS_620 620
+#define IDS_621 621
+#define IDS_622 622
+#define IDS_623 623
+#define IDS_624 624
+#define IDS_625 625
+#define IDS_626 626
+#define IDS_627 627
+#define IDS_628 628
+#define IDS_629 629
+#define IDS_630 630
+#define IDS_631 631
+#define IDS_632 632
+#define IDS_633 633
+#define IDS_634 634
+#define IDS_635 635
+#define IDS_636 636
+#define IDS_637 637
+#define IDS_638 638
+#define IDS_639 639
+#define IDS_640 640
+#define IDS_641 641
+#define IDS_642 642
+#define IDS_643 643
+#define IDS_644 644
+#define IDS_645 645
+#define IDS_646 646
+#define IDS_647 647
+#define IDS_648 648
+#define IDS_649 649
+#define IDS_650 650
+#define IDS_651 651
+#define IDS_652 652
+#define IDS_653 653
+#define IDS_654 654
+#define IDS_655 655
+#define IDS_656 656
+#define IDS_657 657
+#define IDS_658 658
+#define IDS_659 659
+#define IDS_660 660
+#define IDS_661 661
+#define IDS_662 662
+#define IDS_663 663
+#define IDS_664 664
+#define IDS_665 665
+#define IDS_666 666
+#define IDS_667 667
+#define IDS_668 668
+#define IDS_669 669
+#define IDS_670 670
+#define IDS_671 671
+#define IDS_672 672
+#define IDS_673 673
+#define IDS_674 674
+#define IDS_675 675
+#define IDS_676 676
+#define IDS_677 677
+#define IDS_678 678
+#define IDS_679 679
+#define IDS_680 680
+#define IDS_681 681
+#define IDS_682 682
+#define IDS_683 683
+#define IDS_684 684
+#define IDS_685 685
+#define IDS_686 686
+#define IDS_687 687
+#define IDS_688 688
+#define IDS_689 689
+#define IDS_690 690
+#define IDS_691 691
+#define IDS_692 692
+#define IDS_693 693
+#define IDS_694 694
+#define IDS_695 695
+#define IDS_696 696
+#define IDS_697 697
+#define IDS_698 698
+#define IDS_699 699
+#define IDS_700 700
+#define IDS_701 701
+#define IDS_702 702
+#define IDS_703 703
+#define IDS_704 704
+#define IDS_705 705
+#define IDS_706 706
+#define IDS_707 707
+#define IDS_708 708
+#define IDS_709 709
+#define IDS_710 710
+#define IDS_711 711
+#define IDS_712 712
+#define IDS_713 713
+#define IDS_714 714
+#define IDS_715 715
+#define IDS_716 716
+#define IDS_717 717
+#define IDS_718 718
+#define IDS_719 719
+#define IDS_720 720
+#define IDS_721 721
+#define IDS_722 722
+#define IDS_723 723
+#define IDS_724 724
+#define IDS_725 725
+#define IDS_726 726
+#define IDS_727 727
+#define IDS_728 728
+#define IDS_729 729
+#define IDS_730 730
+#define IDS_731 731
+#define IDS_732 732
+#define IDS_733 733
+#define IDS_734 734
+#define IDS_735 735
+#define IDS_736 736
+#define IDS_737 737
+#define IDS_738 738
+#define IDS_739 739
+#define IDS_740 740
+#define IDS_741 741
+#define IDS_742 742
+#define IDS_743 743
+#define IDS_744 744
+#define IDS_745 745
+#define IDS_746 746
+#define IDS_747 747
+#define IDS_748 748
+#define IDS_749 749
+#define IDS_750 750
+#define IDS_751 751
+#define IDS_752 752
+#define IDS_753 753
+#define IDS_754 754
+#define IDS_755 755
+#define IDS_756 756
+#define IDS_757 757
+#define IDS_758 758
+#define IDS_759 759
+#define IDS_760 760
+#define IDS_761 761
+#define IDS_762 762
+#define IDS_763 763
+#define IDS_764 764
+#define IDS_765 765
+#define IDS_766 766
+#define IDS_767 767
+#define IDS_768 768
+#define IDS_769 769
+#define IDS_770 770
+#define IDS_771 771
+#define IDS_772 772
+#define IDS_773 773
+#define IDS_774 774
+#define IDS_775 775
+#define IDS_776 776
+#define IDS_777 777
+#define IDS_778 778
+#define IDS_779 779
+#define IDS_780 780
+#define IDS_781 781
+#define IDS_782 782
+#define IDS_783 783
+#define IDS_784 784
+#define IDS_785 785
+#define IDS_786 786
+#define IDS_787 787
+#define IDS_788 788
+#define IDS_789 789
+#define IDS_790 790
+#define IDS_791 791
+#define IDS_792 792
+#define IDS_793 793
+#define IDS_794 794
+#define IDS_795 795
+#define IDS_796 796
+#define IDS_797 797
+#define IDS_798 798
+#define IDS_799 799
+#define IDS_800 800
+#define IDS_801 801
+#define IDS_802 802
+#define IDS_803 803
+#define IDS_804 804
+#define IDS_805 805
+#define IDS_806 806
+#define IDS_807 807
+#define IDS_808 808
+#define IDS_809 809
+#define IDS_810 810
+#define IDS_811 811
+#define IDS_812 812
+#define IDS_813 813
+#define IDS_814 814
+#define IDS_815 815
+#define IDS_816 816
+#define IDS_817 817
+#define IDS_818 818
+#define IDS_819 819
+#define IDS_820 820
+#define IDS_821 821
+#define IDS_822 822
+#define IDS_823 823
+#define IDS_824 824
+#define IDS_825 825
+#define IDS_826 826
+#define IDS_827 827
+#define IDS_828 828
+#define IDS_829 829
+#define IDS_830 830
+#define IDS_831 831
+#define IDS_832 832
+#define IDS_833 833
+#define IDS_834 834
+#define IDS_835 835
+#define IDS_836 836
+#define IDS_837 837
+#define IDS_838 838
+#define IDS_839 839
+#define IDS_840 840
+#define IDS_841 841
+#define IDS_842 842
+#define IDS_843 843
+#define IDS_844 844
+#define IDS_845 845
+#define IDS_846 846
+#define IDS_847 847
+#define IDS_848 848
+#define IDS_849 849
+#define IDS_850 850
+#define IDS_851 851
+#define IDS_852 852
+#define IDS_853 853
+#define IDS_854 854
+#define IDS_855 855
+#define IDS_856 856
+#define IDS_857 857
+#define IDS_858 858
+#define IDS_859 859
+#define IDS_860 860
+#define IDS_861 861
+#define IDS_862 862
+#define IDS_863 863
+#define IDS_864 864
+#define IDS_865 865
+#define IDS_866 866
+#define IDS_867 867
+#define IDS_868 868
+#define IDS_869 869
+#define IDS_870 870
+#define IDS_871 871
+#define IDS_872 872
+#define IDS_873 873
+#define IDS_874 874
+#define IDS_875 875
+#define IDS_876 876
+#define IDS_877 877
+#define IDS_878 878
+#define IDS_879 879
+#define IDS_880 880
+#define IDS_881 881
+#define IDS_882 882
+#define IDS_883 883
+#define IDS_884 884
+#define IDS_885 885
+#define IDS_886 886
+#define IDS_887 887
+#define IDS_888 888
+#define IDS_889 889
+#define IDS_890 890
+#define IDS_891 891
+#define IDS_892 892
+#define IDS_893 893
+#define IDS_894 894
+#define IDS_895 895
+#define IDS_896 896
+#define IDS_897 897
+#define IDS_898 898
+#define IDS_899 899
+#define IDS_900 900
+#define IDS_901 901
+#define IDS_902 902
+#define IDS_903 903
+#define IDS_904 904
+#define IDS_905 905
+#define IDS_906 906
+#define IDS_907 907
+#define IDS_908 908
+#define IDS_909 909
+#define IDS_910 910
+#define IDS_911 911
+#define IDS_912 912
+#define IDS_913 913
+#define IDS_914 914
+#define IDS_915 915
+#define IDS_916 916
+#define IDS_917 917
+#define IDS_918 918
+#define IDS_919 919
+#define IDS_920 920
+#define IDS_921 921
+#define IDS_922 922
+#define IDS_923 923
+#define IDS_924 924
+#define IDS_925 925
+#define IDS_926 926
+#define IDS_927 927
+#define IDS_928 928
+#define IDS_929 929
+#define IDS_930 930
+#define IDS_931 931
+#define IDS_932 932
+#define IDS_933 933
+#define IDS_934 934
+#define IDS_935 935
+#define IDS_936 936
+#define IDS_937 937
+#define IDS_938 938
+#define IDS_939 939
+#define IDS_940 940
+#define IDS_941 941
+#define IDS_942 942
+#define IDS_943 943
+#define IDS_944 944
+#define IDS_945 945
+#define IDS_946 946
+#define IDS_947 947
+#define IDS_948 948
+#define IDS_949 949
+#define IDS_950 950
+#define IDS_951 951
+#define IDS_952 952
+#define IDS_953 953
+#define IDS_954 954
+#define IDS_955 955
+#define IDS_956 956
+#define IDS_957 957
+#define IDS_958 958
+#define IDS_959 959
+#define IDS_960 960
+#define IDS_961 961
+#define IDS_962 962
+#define IDS_963 963
+#define IDS_964 964
+#define IDS_965 965
+#define IDS_966 966
+#define IDS_967 967
+#define IDS_968 968
+#define IDS_969 969
+#define IDS_970 970
+#define IDS_971 971
+#define IDS_972 972
+#define IDS_973 973
+#define IDS_974 974
+#define IDS_975 975
+#define IDS_976 976
+#define IDS_977 977
+#define IDS_978 978
+#define IDS_979 979
+#define IDS_980 980
+#define IDS_981 981
+#define IDS_982 982
+#define IDS_983 983
+#define IDS_984 984
+#define IDS_985 985
+#define IDS_986 986
+#define IDS_987 987
+#define IDS_988 988
+#define IDS_989 989
+#define IDS_990 990
+#define IDS_991 991
+#define IDS_992 992
+#define IDS_993 993
+#define IDS_994 994
+#define IDS_995 995
+#define IDS_996 996
+#define IDS_997 997
+#define IDS_998 998
+#define IDS_999 999
+#define IDS_1000 1000
+#define IDS_1001 1001
+#define IDS_1002 1002
+#define IDS_1003 1003
+#define IDS_1004 1004
+#define IDS_1005 1005
+#define IDS_1006 1006
+#define IDS_1007 1007
+#define IDS_1008 1008
+#define IDS_1009 1009
+#define IDS_1010 1010
+#define IDS_1011 1011
+#define IDS_1012 1012
+#define IDS_1013 1013
+#define IDS_1014 1014
+#define IDS_1015 1015
+#define IDS_1016 1016
+#define IDS_1017 1017
+#define IDS_1018 1018
+#define IDS_1019 1019
+#define IDS_1020 1020
+#define IDS_1021 1021
+#define IDS_1022 1022
+#define IDS_1023 1023
+#define IDS_1024 1024
+#define IDS_1025 1025
+#define IDS_1026 1026
+#define IDS_1027 1027
+#define IDS_1028 1028
+#define IDS_1029 1029
+#define IDS_1030 1030
+#define IDS_1031 1031
+#define IDS_1032 1032
+#define IDS_1033 1033
+#define IDS_1034 1034
+#define IDS_1035 1035
+#define IDS_1036 1036
+#define IDS_1037 1037
+#define IDS_1038 1038
+#define IDS_1039 1039
+#define IDS_1040 1040
+#define IDS_1041 1041
+#define IDS_1042 1042
+#define IDS_1043 1043
+#define IDS_1044 1044
+#define IDS_1045 1045
+#define IDS_1046 1046
+#define IDS_1047 1047
+#define IDS_1048 1048
+#define IDS_1049 1049
+#define IDS_1050 1050
+#define IDS_1051 1051
+#define IDS_1052 1052
+#define IDS_1053 1053
+#define IDS_1054 1054
+#define IDS_1055 1055
+#define IDS_1056 1056
+#define IDS_1057 1057
+#define IDS_1058 1058
+#define IDS_1059 1059
+#define IDS_1060 1060
+#define IDS_1061 1061
+#define IDS_1062 1062
+#define IDS_1063 1063
+#define IDS_1064 1064
+#define IDS_1065 1065
+#define IDS_1066 1066
+#define IDS_1067 1067
+#define IDS_1068 1068
+#define IDS_1069 1069
+#define IDS_1070 1070
+#define IDS_1071 1071
+#define IDS_1072 1072
+#define IDS_1073 1073
+#define IDS_1074 1074
+#define IDS_1075 1075
+#define IDS_1076 1076
+#define IDS_1077 1077
+#define IDS_1078 1078
+#define IDS_1079 1079
+#define IDS_1080 1080
+#define IDS_1081 1081
+#define IDS_1082 1082
+#define IDS_1083 1083
+#define IDS_1084 1084
+#define IDS_1085 1085
+#define IDS_1086 1086
+#define IDS_1087 1087
+#define IDS_1088 1088
+#define IDS_1089 1089
+#define IDS_1090 1090
+#define IDS_1091 1091
+#define IDS_1092 1092
+#define IDS_1093 1093
+#define IDS_1094 1094
+#define IDS_1095 1095
+#define IDS_1096 1096
+#define IDS_1097 1097
+#define IDS_1098 1098
+#define IDS_1099 1099
+#define IDS_1100 1100
+#define IDS_1101 1101
+#define IDS_1102 1102
+#define IDS_1103 1103
+#define IDS_1104 1104
+#define IDS_1105 1105
+#define IDS_1106 1106
+#define IDS_1107 1107
+#define IDS_1108 1108
+#define IDS_1109 1109
+#define IDS_1110 1110
+#define IDS_1111 1111
+#define IDS_1112 1112
+#define IDS_1113 1113
+#define IDS_1114 1114
+#define IDS_1115 1115
+#define IDS_1116 1116
+#define IDS_1117 1117
+#define IDS_1118 1118
+#define IDS_1119 1119
+#define IDS_1120 1120
+#define IDS_1121 1121
+#define IDS_1122 1122
+#define IDS_1123 1123
+#define IDS_1124 1124
+#define IDS_1125 1125
+#define IDS_1126 1126
+#define IDS_1127 1127
+#define IDS_1128 1128
+#define IDS_1129 1129
+#define IDS_1130 1130
+#define IDS_1131 1131
+#define IDS_1132 1132
+#define IDS_1133 1133
+#define IDS_1134 1134
+#define IDS_1135 1135
+#define IDS_1136 1136
+#define IDS_1137 1137
+#define IDS_1138 1138
+#define IDS_1139 1139
+#define IDS_1140 1140
+#define IDS_1141 1141
+#define IDS_1142 1142
+#define IDS_1143 1143
+#define IDS_1144 1144
+#define IDS_1145 1145
+#define IDS_1146 1146
+#define IDS_1147 1147
+#define IDS_1148 1148
+#define IDS_1149 1149
+#define IDS_1150 1150
+#define IDS_1151 1151
+#define IDS_1152 1152
+#define IDS_1153 1153
+#define IDS_1154 1154
+#define IDS_1155 1155
+#define IDS_1156 1156
+#define IDS_1157 1157
+#define IDS_1158 1158
+#define IDS_1159 1159
+#define IDS_1160 1160
+#define IDS_1161 1161
+#define IDS_1162 1162
+STRINGTABLE
+BEGIN
+IDS_1 "node_modules\\node-inspector\\.jshintignore"
+IDS_2 "node_modules\\node-inspector\\.jshintrc"
+IDS_3 "node_modules\\node-inspector\\AUTHORS"
+IDS_4 "node_modules\\node-inspector\\config.json"
+IDS_5 "node_modules\\node-inspector\\index.js"
+IDS_6 "node_modules\\node-inspector\\LICENSE"
+IDS_7 "node_modules\\node-inspector\\package.json"
+IDS_8 "node_modules\\node-inspector\\bin\\inspector.js"
+IDS_9 "node_modules\\node-inspector\\bin\\node-debug.js"
+IDS_10 "node_modules\\node-inspector\\bin\\run-repl.js"
+IDS_11 "node_modules\\node-inspector\\build\\config.gypi"
+IDS_12 "node_modules\\node-inspector\\docs\\embedding.md"
+IDS_13 "node_modules\\node-inspector\\front-end\\AdvancedSearchController.js"
+IDS_14 "node_modules\\node-inspector\\front-end\\ApplicationCacheItemsView.js"
+IDS_15 "node_modules\\node-inspector\\front-end\\ApplicationCacheModel.js"
+IDS_16 "node_modules\\node-inspector\\front-end\\AuditCategories.js"
+IDS_17 "node_modules\\node-inspector\\front-end\\AuditController.js"
+IDS_18 "node_modules\\node-inspector\\front-end\\AuditFormatters.js"
+IDS_19 "node_modules\\node-inspector\\front-end\\AuditLauncherView.js"
+IDS_20 "node_modules\\node-inspector\\front-end\\AuditResultView.js"
+IDS_21 "node_modules\\node-inspector\\front-end\\AuditRules.js"
+IDS_22 "node_modules\\node-inspector\\front-end\\auditsPanel.css"
+IDS_23 "node_modules\\node-inspector\\front-end\\AuditsPanel.js"
+IDS_24 "node_modules\\node-inspector\\front-end\\BottomUpProfileDataGridTree.js"
+IDS_25 "node_modules\\node-inspector\\front-end\\breadcrumbList.css"
+IDS_26 "node_modules\\node-inspector\\front-end\\BreakpointManager.js"
+IDS_27 "node_modules\\node-inspector\\front-end\\breakpointsList.css"
+IDS_28 "node_modules\\node-inspector\\front-end\\BreakpointsSidebarPane.js"
+IDS_29 "node_modules\\node-inspector\\front-end\\buildSystemOnly.js"
+IDS_30 "node_modules\\node-inspector\\front-end\\CallStackSidebarPane.js"
+IDS_31 "node_modules\\node-inspector\\front-end\\canvasProfiler.css"
+IDS_32 "node_modules\\node-inspector\\front-end\\CanvasProfileView.js"
+IDS_33 "node_modules\\node-inspector\\front-end\\CanvasReplayStateView.js"
+IDS_34 "node_modules\\node-inspector\\front-end\\Checkbox.js"
+IDS_35 "node_modules\\node-inspector\\front-end\\CodeMirrorTextEditor.js"
+IDS_36 "node_modules\\node-inspector\\front-end\\CodeMirrorUtils.js"
+IDS_37 "node_modules\\node-inspector\\front-end\\Color.js"
+IDS_38 "node_modules\\node-inspector\\front-end\\CompilerScriptMapping.js"
+IDS_39 "node_modules\\node-inspector\\front-end\\CompletionDictionary.js"
+IDS_40 "node_modules\\node-inspector\\front-end\\ConsoleMessage.js"
+IDS_41 "node_modules\\node-inspector\\front-end\\ConsoleModel.js"
+IDS_42 "node_modules\\node-inspector\\front-end\\ConsolePanel.js"
+IDS_43 "node_modules\\node-inspector\\front-end\\ConsoleView.js"
+IDS_44 "node_modules\\node-inspector\\front-end\\ContentProvider.js"
+IDS_45 "node_modules\\node-inspector\\front-end\\ContentProviderBasedProjectDelegate.js"
+IDS_46 "node_modules\\node-inspector\\front-end\\ContentProviders.js"
+IDS_47 "node_modules\\node-inspector\\front-end\\ContextMenu.js"
+IDS_48 "node_modules\\node-inspector\\front-end\\CookieItemsView.js"
+IDS_49 "node_modules\\node-inspector\\front-end\\CookieParser.js"
+IDS_50 "node_modules\\node-inspector\\front-end\\CookiesTable.js"
+IDS_51 "node_modules\\node-inspector\\front-end\\CPUProfileView.js"
+IDS_52 "node_modules\\node-inspector\\front-end\\CSSMetadata.js"
+IDS_53 "node_modules\\node-inspector\\front-end\\CSSNamedFlowCollectionsView.js"
+IDS_54 "node_modules\\node-inspector\\front-end\\cssNamedFlows.css"
+IDS_55 "node_modules\\node-inspector\\front-end\\CSSNamedFlowView.js"
+IDS_56 "node_modules\\node-inspector\\front-end\\CSSStyleModel.js"
+IDS_57 "node_modules\\node-inspector\\front-end\\CSSStyleSheetMapping.js"
+IDS_58 "node_modules\\node-inspector\\front-end\\Database.js"
+IDS_59 "node_modules\\node-inspector\\front-end\\DatabaseQueryView.js"
+IDS_60 "node_modules\\node-inspector\\front-end\\DatabaseTableView.js"
+IDS_61 "node_modules\\node-inspector\\front-end\\dataGrid.css"
+IDS_62 "node_modules\\node-inspector\\front-end\\DataGrid.js"
+IDS_63 "node_modules\\node-inspector\\front-end\\DebuggerModel.js"
+IDS_64 "node_modules\\node-inspector\\front-end\\DebuggerScriptMapping.js"
+IDS_65 "node_modules\\node-inspector\\front-end\\DefaultScriptMapping.js"
+IDS_66 "node_modules\\node-inspector\\front-end\\DevToolsExtensionAPI.js"
+IDS_67 "node_modules\\node-inspector\\front-end\\dialog.css"
+IDS_68 "node_modules\\node-inspector\\front-end\\Dialog.js"
+IDS_69 "node_modules\\node-inspector\\front-end\\DirectoryContentView.js"
+IDS_70 "node_modules\\node-inspector\\front-end\\DockController.js"
+IDS_71 "node_modules\\node-inspector\\front-end\\DOMAgent.js"
+IDS_72 "node_modules\\node-inspector\\front-end\\DOMBreakpointsSidebarPane.js"
+IDS_73 "node_modules\\node-inspector\\front-end\\DOMCountersGraph.js"
+IDS_74 "node_modules\\node-inspector\\front-end\\DOMExtension.js"
+IDS_75 "node_modules\\node-inspector\\front-end\\DOMPresentationUtils.js"
+IDS_76 "node_modules\\node-inspector\\front-end\\DOMStorage.js"
+IDS_77 "node_modules\\node-inspector\\front-end\\DOMStorageItemsView.js"
+IDS_78 "node_modules\\node-inspector\\front-end\\DOMSyntaxHighlighter.js"
+IDS_79 "node_modules\\node-inspector\\front-end\\Drawer.js"
+IDS_80 "node_modules\\node-inspector\\front-end\\EditFileSystemDialog.js"
+IDS_81 "node_modules\\node-inspector\\front-end\\elementsPanel.css"
+IDS_82 "node_modules\\node-inspector\\front-end\\ElementsPanel.js"
+IDS_83 "node_modules\\node-inspector\\front-end\\ElementsPanelDescriptor.js"
+IDS_84 "node_modules\\node-inspector\\front-end\\ElementsTreeOutline.js"
+IDS_85 "node_modules\\node-inspector\\front-end\\EmptyView.js"
+IDS_86 "node_modules\\node-inspector\\front-end\\EventListenersSidebarPane.js"
+IDS_87 "node_modules\\node-inspector\\front-end\\ExtensionAPI.js"
+IDS_88 "node_modules\\node-inspector\\front-end\\ExtensionAuditCategory.js"
+IDS_89 "node_modules\\node-inspector\\front-end\\ExtensionPanel.js"
+IDS_90 "node_modules\\node-inspector\\front-end\\ExtensionRegistryStub.js"
+IDS_91 "node_modules\\node-inspector\\front-end\\ExtensionServer.js"
+IDS_92 "node_modules\\node-inspector\\front-end\\ExtensionView.js"
+IDS_93 "node_modules\\node-inspector\\front-end\\externs.js"
+IDS_94 "node_modules\\node-inspector\\front-end\\FileContentView.js"
+IDS_95 "node_modules\\node-inspector\\front-end\\FileManager.js"
+IDS_96 "node_modules\\node-inspector\\front-end\\FilePathScoreFunction.js"
+IDS_97 "node_modules\\node-inspector\\front-end\\FileSystemMapping.js"
+IDS_98 "node_modules\\node-inspector\\front-end\\FileSystemModel.js"
+IDS_99 "node_modules\\node-inspector\\front-end\\FileSystemProjectDelegate.js"
+IDS_100 "node_modules\\node-inspector\\front-end\\FileSystemView.js"
+IDS_101 "node_modules\\node-inspector\\front-end\\FileUtils.js"
+IDS_102 "node_modules\\node-inspector\\front-end\\filteredItemSelectionDialog.css"
+IDS_103 "node_modules\\node-inspector\\front-end\\FilteredItemSelectionDialog.js"
+IDS_104 "node_modules\\node-inspector\\front-end\\flameChart.css"
+IDS_105 "node_modules\\node-inspector\\front-end\\FlameChart.js"
+IDS_106 "node_modules\\node-inspector\\front-end\\FontView.js"
+IDS_107 "node_modules\\node-inspector\\front-end\\GoToLineDialog.js"
+IDS_108 "node_modules\\node-inspector\\front-end\\HandlerRegistry.js"
+IDS_109 "node_modules\\node-inspector\\front-end\\HAREntry.js"
+IDS_110 "node_modules\\node-inspector\\front-end\\heapProfiler.css"
+IDS_111 "node_modules\\node-inspector\\front-end\\HeapSnapshot.js"
+IDS_112 "node_modules\\node-inspector\\front-end\\HeapSnapshotDataGrids.js"
+IDS_113 "node_modules\\node-inspector\\front-end\\HeapSnapshotGridNodes.js"
+IDS_114 "node_modules\\node-inspector\\front-end\\HeapSnapshotLoader.js"
+IDS_115 "node_modules\\node-inspector\\front-end\\HeapSnapshotProxy.js"
+IDS_116 "node_modules\\node-inspector\\front-end\\HeapSnapshotView.js"
+IDS_117 "node_modules\\node-inspector\\front-end\\HeapSnapshotWorker.js"
+IDS_118 "node_modules\\node-inspector\\front-end\\HeapSnapshotWorkerDispatcher.js"
+IDS_119 "node_modules\\node-inspector\\front-end\\helpScreen.css"
+IDS_120 "node_modules\\node-inspector\\front-end\\HelpScreen.js"
+IDS_121 "node_modules\\node-inspector\\front-end\\ImageView.js"
+IDS_122 "node_modules\\node-inspector\\front-end\\IndexedDBModel.js"
+IDS_123 "node_modules\\node-inspector\\front-end\\indexedDBViews.css"
+IDS_124 "node_modules\\node-inspector\\front-end\\IndexedDBViews.js"
+IDS_125 "node_modules\\node-inspector\\front-end\\InspectElementModeController.js"
+IDS_126 "node_modules\\node-inspector\\front-end\\inspector.css"
+IDS_127 "node_modules\\node-inspector\\front-end\\inspector.html"
+IDS_128 "node_modules\\node-inspector\\front-end\\inspector.js"
+IDS_129 "node_modules\\node-inspector\\front-end\\InspectorBackend.js"
+IDS_130 "node_modules\\node-inspector\\front-end\\InspectorBackendCommands.js"
+IDS_131 "node_modules\\node-inspector\\front-end\\inspectorCommon.css"
+IDS_132 "node_modules\\node-inspector\\front-end\\InspectorFrontendAPI.js"
+IDS_133 "node_modules\\node-inspector\\front-end\\InspectorFrontendHostStub.js"
+IDS_134 "node_modules\\node-inspector\\front-end\\inspectorSyntaxHighlight.css"
+IDS_135 "node_modules\\node-inspector\\front-end\\InspectorView.js"
+IDS_136 "node_modules\\node-inspector\\front-end\\IsolatedFileSystem.js"
+IDS_137 "node_modules\\node-inspector\\front-end\\IsolatedFileSystemManager.js"
+IDS_138 "node_modules\\node-inspector\\front-end\\JavaScriptFormatter.js"
+IDS_139 "node_modules\\node-inspector\\front-end\\JavaScriptSourceFrame.js"
+IDS_140 "node_modules\\node-inspector\\front-end\\jsdifflib.js"
+IDS_141 "node_modules\\node-inspector\\front-end\\JSHeapSnapshot.js"
+IDS_142 "node_modules\\node-inspector\\front-end\\KeyboardShortcut.js"
+IDS_143 "node_modules\\node-inspector\\front-end\\LayerDetailsView.js"
+IDS_144 "node_modules\\node-inspector\\front-end\\Layers3DView.js"
+IDS_145 "node_modules\\node-inspector\\front-end\\layersPanel.css"
+IDS_146 "node_modules\\node-inspector\\front-end\\LayersPanel.js"
+IDS_147 "node_modules\\node-inspector\\front-end\\LayersPanelDescriptor.js"
+IDS_148 "node_modules\\node-inspector\\front-end\\LayerTree.js"
+IDS_149 "node_modules\\node-inspector\\front-end\\LayerTreeModel.js"
+IDS_150 "node_modules\\node-inspector\\front-end\\Linkifier.js"
+IDS_151 "node_modules\\node-inspector\\front-end\\LiveEditSupport.js"
+IDS_152 "node_modules\\node-inspector\\front-end\\MemoryStatistics.js"
+IDS_153 "node_modules\\node-inspector\\front-end\\MetricsSidebarPane.js"
+IDS_154 "node_modules\\node-inspector\\front-end\\NativeBreakpointsSidebarPane.js"
+IDS_155 "node_modules\\node-inspector\\front-end\\NavigatorOverlayController.js"
+IDS_156 "node_modules\\node-inspector\\front-end\\navigatorView.css"
+IDS_157 "node_modules\\node-inspector\\front-end\\NavigatorView.js"
+IDS_158 "node_modules\\node-inspector\\front-end\\NetworkItemView.js"
+IDS_159 "node_modules\\node-inspector\\front-end\\NetworkLog.js"
+IDS_160 "node_modules\\node-inspector\\front-end\\networkLogView.css"
+IDS_161 "node_modules\\node-inspector\\front-end\\NetworkManager.js"
+IDS_162 "node_modules\\node-inspector\\front-end\\networkPanel.css"
+IDS_163 "node_modules\\node-inspector\\front-end\\NetworkPanel.js"
+IDS_164 "node_modules\\node-inspector\\front-end\\NetworkPanelDescriptor.js"
+IDS_165 "node_modules\\node-inspector\\front-end\\NetworkRequest.js"
+IDS_166 "node_modules\\node-inspector\\front-end\\NetworkUISourceCodeProvider.js"
+IDS_167 "node_modules\\node-inspector\\front-end\\Object.js"
+IDS_168 "node_modules\\node-inspector\\front-end\\ObjectPopoverHelper.js"
+IDS_169 "node_modules\\node-inspector\\front-end\\ObjectPropertiesSection.js"
+IDS_170 "node_modules\\node-inspector\\front-end\\OverridesSupport.js"
+IDS_171 "node_modules\\node-inspector\\front-end\\OverridesView.js"
+IDS_172 "node_modules\\node-inspector\\front-end\\OverviewGrid.js"
+IDS_173 "node_modules\\node-inspector\\front-end\\OWNERS"
+IDS_174 "node_modules\\node-inspector\\front-end\\Panel.js"
+IDS_175 "node_modules\\node-inspector\\front-end\\panelEnablerView.css"
+IDS_176 "node_modules\\node-inspector\\front-end\\ParsedURL.js"
+IDS_177 "node_modules\\node-inspector\\front-end\\Placard.js"
+IDS_178 "node_modules\\node-inspector\\front-end\\PlatformFontsSidebarPane.js"
+IDS_179 "node_modules\\node-inspector\\front-end\\popover.css"
+IDS_180 "node_modules\\node-inspector\\front-end\\Popover.js"
+IDS_181 "node_modules\\node-inspector\\front-end\\PresentationConsoleMessageHelper.js"
+IDS_182 "node_modules\\node-inspector\\front-end\\ProfileDataGridTree.js"
+IDS_183 "node_modules\\node-inspector\\front-end\\ProfileLauncherView.js"
+IDS_184 "node_modules\\node-inspector\\front-end\\profilesPanel.css"
+IDS_185 "node_modules\\node-inspector\\front-end\\ProfilesPanel.js"
+IDS_186 "node_modules\\node-inspector\\front-end\\ProfilesPanelDescriptor.js"
+IDS_187 "node_modules\\node-inspector\\front-end\\Progress.js"
+IDS_188 "node_modules\\node-inspector\\front-end\\ProgressIndicator.js"
+IDS_189 "node_modules\\node-inspector\\front-end\\PropertiesSection.js"
+IDS_190 "node_modules\\node-inspector\\front-end\\PropertiesSidebarPane.js"
+IDS_191 "node_modules\\node-inspector\\front-end\\RawSourceCode.js"
+IDS_192 "node_modules\\node-inspector\\front-end\\RemoteObject.js"
+IDS_193 "node_modules\\node-inspector\\front-end\\RequestCookiesView.js"
+IDS_194 "node_modules\\node-inspector\\front-end\\RequestHeadersView.js"
+IDS_195 "node_modules\\node-inspector\\front-end\\RequestHTMLView.js"
+IDS_196 "node_modules\\node-inspector\\front-end\\RequestJSONView.js"
+IDS_197 "node_modules\\node-inspector\\front-end\\RequestPreviewView.js"
+IDS_198 "node_modules\\node-inspector\\front-end\\RequestResponseView.js"
+IDS_199 "node_modules\\node-inspector\\front-end\\RequestTimingView.js"
+IDS_200 "node_modules\\node-inspector\\front-end\\RequestView.js"
+IDS_201 "node_modules\\node-inspector\\front-end\\Resource.js"
+IDS_202 "node_modules\\node-inspector\\front-end\\ResourceScriptMapping.js"
+IDS_203 "node_modules\\node-inspector\\front-end\\resourcesPanel.css"
+IDS_204 "node_modules\\node-inspector\\front-end\\ResourcesPanel.js"
+IDS_205 "node_modules\\node-inspector\\front-end\\ResourceTreeModel.js"
+IDS_206 "node_modules\\node-inspector\\front-end\\ResourceType.js"
+IDS_207 "node_modules\\node-inspector\\front-end\\ResourceUtils.js"
+IDS_208 "node_modules\\node-inspector\\front-end\\resourceView.css"
+IDS_209 "node_modules\\node-inspector\\front-end\\ResourceView.js"
+IDS_210 "node_modules\\node-inspector\\front-end\\ResourceWebSocketFrameView.js"
+IDS_211 "node_modules\\node-inspector\\front-end\\revisionHistory.css"
+IDS_212 "node_modules\\node-inspector\\front-end\\RevisionHistoryView.js"
+IDS_213 "node_modules\\node-inspector\\front-end\\RuntimeModel.js"
+IDS_214 "node_modules\\node-inspector\\front-end\\SASSSourceMapping.js"
+IDS_215 "node_modules\\node-inspector\\front-end\\ScopeChainSidebarPane.js"
+IDS_216 "node_modules\\node-inspector\\front-end\\screencastView.css"
+IDS_217 "node_modules\\node-inspector\\front-end\\ScreencastView.js"
+IDS_218 "node_modules\\node-inspector\\front-end\\Script.js"
+IDS_219 "node_modules\\node-inspector\\front-end\\ScriptFormatter.js"
+IDS_220 "node_modules\\node-inspector\\front-end\\ScriptFormatterWorker.js"
+IDS_221 "node_modules\\node-inspector\\front-end\\ScriptsNavigator.js"
+IDS_222 "node_modules\\node-inspector\\front-end\\ScriptSnippetModel.js"
+IDS_223 "node_modules\\node-inspector\\front-end\\scriptsPanel.css"
+IDS_224 "node_modules\\node-inspector\\front-end\\ScriptsPanel.js"
+IDS_225 "node_modules\\node-inspector\\front-end\\ScriptsPanelDescriptor.js"
+IDS_226 "node_modules\\node-inspector\\front-end\\ScriptsSearchScope.js"
+IDS_227 "node_modules\\node-inspector\\front-end\\SearchController.js"
+IDS_228 "node_modules\\node-inspector\\front-end\\Section.js"
+IDS_229 "node_modules\\node-inspector\\front-end\\Settings.js"
+IDS_230 "node_modules\\node-inspector\\front-end\\SettingsScreen.js"
+IDS_231 "node_modules\\node-inspector\\front-end\\ShortcutsScreen.js"
+IDS_232 "node_modules\\node-inspector\\front-end\\ShowMoreDataGridNode.js"
+IDS_233 "node_modules\\node-inspector\\front-end\\SidebarOverlay.js"
+IDS_234 "node_modules\\node-inspector\\front-end\\sidebarPane.css"
+IDS_235 "node_modules\\node-inspector\\front-end\\SidebarPane.js"
+IDS_236 "node_modules\\node-inspector\\front-end\\SidebarTreeElement.js"
+IDS_237 "node_modules\\node-inspector\\front-end\\SidebarView.js"
+IDS_238 "node_modules\\node-inspector\\front-end\\SimpleWorkspaceProvider.js"
+IDS_239 "node_modules\\node-inspector\\front-end\\SnippetStorage.js"
+IDS_240 "node_modules\\node-inspector\\front-end\\SoftContextMenu.js"
+IDS_241 "node_modules\\node-inspector\\front-end\\SourceFrame.js"
+IDS_242 "node_modules\\node-inspector\\front-end\\SourceMap.js"
+IDS_243 "node_modules\\node-inspector\\front-end\\SourceMapping.js"
+IDS_244 "node_modules\\node-inspector\\front-end\\spectrum.css"
+IDS_245 "node_modules\\node-inspector\\front-end\\Spectrum.js"
+IDS_246 "node_modules\\node-inspector\\front-end\\splitView.css"
+IDS_247 "node_modules\\node-inspector\\front-end\\SplitView.js"
+IDS_248 "node_modules\\node-inspector\\front-end\\StatusBarButton.js"
+IDS_249 "node_modules\\node-inspector\\front-end\\StyleSheetOutlineDialog.js"
+IDS_250 "node_modules\\node-inspector\\front-end\\StylesSidebarPane.js"
+IDS_251 "node_modules\\node-inspector\\front-end\\StylesSourceMapping.js"
+IDS_252 "node_modules\\node-inspector\\front-end\\SuggestBox.js"
+IDS_253 "node_modules\\node-inspector\\front-end\\TabbedEditorContainer.js"
+IDS_254 "node_modules\\node-inspector\\front-end\\tabbedPane.css"
+IDS_255 "node_modules\\node-inspector\\front-end\\TabbedPane.js"
+IDS_256 "node_modules\\node-inspector\\front-end\\test-runner.html"
+IDS_257 "node_modules\\node-inspector\\front-end\\TestController.js"
+IDS_258 "node_modules\\node-inspector\\front-end\\Tests.js"
+IDS_259 "node_modules\\node-inspector\\front-end\\TextEditor.js"
+IDS_260 "node_modules\\node-inspector\\front-end\\textPrompt.css"
+IDS_261 "node_modules\\node-inspector\\front-end\\TextPrompt.js"
+IDS_262 "node_modules\\node-inspector\\front-end\\TextRange.js"
+IDS_263 "node_modules\\node-inspector\\front-end\\TextUtils.js"
+IDS_264 "node_modules\\node-inspector\\front-end\\TimelineFrameController.js"
+IDS_265 "node_modules\\node-inspector\\front-end\\TimelineGrid.js"
+IDS_266 "node_modules\\node-inspector\\front-end\\TimelineManager.js"
+IDS_267 "node_modules\\node-inspector\\front-end\\TimelineModel.js"
+IDS_268 "node_modules\\node-inspector\\front-end\\TimelineOverviewPane.js"
+IDS_269 "node_modules\\node-inspector\\front-end\\timelinePanel.css"
+IDS_270 "node_modules\\node-inspector\\front-end\\TimelinePanel.js"
+IDS_271 "node_modules\\node-inspector\\front-end\\TimelinePanelDescriptor.js"
+IDS_272 "node_modules\\node-inspector\\front-end\\TimelinePresentationModel.js"
+IDS_273 "node_modules\\node-inspector\\front-end\\Toolbar.js"
+IDS_274 "node_modules\\node-inspector\\front-end\\TopDownProfileDataGridTree.js"
+IDS_275 "node_modules\\node-inspector\\front-end\\TracingAgent.js"
+IDS_276 "node_modules\\node-inspector\\front-end\\treeoutline.js"
+IDS_277 "node_modules\\node-inspector\\front-end\\UISourceCode.js"
+IDS_278 "node_modules\\node-inspector\\front-end\\UISourceCodeFrame.js"
+IDS_279 "node_modules\\node-inspector\\front-end\\UIString.js"
+IDS_280 "node_modules\\node-inspector\\front-end\\UIUtils.js"
+IDS_281 "node_modules\\node-inspector\\front-end\\UserMetrics.js"
+IDS_282 "node_modules\\node-inspector\\front-end\\utilities.js"
+IDS_283 "node_modules\\node-inspector\\front-end\\View.js"
+IDS_284 "node_modules\\node-inspector\\front-end\\ViewportControl.js"
+IDS_285 "node_modules\\node-inspector\\front-end\\WatchExpressionsSidebarPane.js"
+IDS_286 "node_modules\\node-inspector\\front-end\\WorkerManager.js"
+IDS_287 "node_modules\\node-inspector\\front-end\\WorkersSidebarPane.js"
+IDS_288 "node_modules\\node-inspector\\front-end\\Workspace.js"
+IDS_289 "node_modules\\node-inspector\\front-end\\WorkspaceController.js"
+IDS_290 "node_modules\\node-inspector\\front-end\\cm\\clike.js"
+IDS_291 "node_modules\\node-inspector\\front-end\\cm\\closebrackets.js"
+IDS_292 "node_modules\\node-inspector\\front-end\\cm\\cmdevtools.css"
+IDS_293 "node_modules\\node-inspector\\front-end\\cm\\codemirror.css"
+IDS_294 "node_modules\\node-inspector\\front-end\\cm\\codemirror.js"
+IDS_295 "node_modules\\node-inspector\\front-end\\cm\\coffeescript.js"
+IDS_296 "node_modules\\node-inspector\\front-end\\cm\\comment.js"
+IDS_297 "node_modules\\node-inspector\\front-end\\cm\\css.js"
+IDS_298 "node_modules\\node-inspector\\front-end\\cm\\headlesscodemirror.js"
+IDS_299 "node_modules\\node-inspector\\front-end\\cm\\htmlembedded.js"
+IDS_300 "node_modules\\node-inspector\\front-end\\cm\\htmlmixed.js"
+IDS_301 "node_modules\\node-inspector\\front-end\\cm\\javascript.js"
+IDS_302 "node_modules\\node-inspector\\front-end\\cm\\LICENSE"
+IDS_303 "node_modules\\node-inspector\\front-end\\cm\\LICENSE_python"
+IDS_304 "node_modules\\node-inspector\\front-end\\cm\\markselection.js"
+IDS_305 "node_modules\\node-inspector\\front-end\\cm\\matchbrackets.js"
+IDS_306 "node_modules\\node-inspector\\front-end\\cm\\overlay.js"
+IDS_307 "node_modules\\node-inspector\\front-end\\cm\\php.js"
+IDS_308 "node_modules\\node-inspector\\front-end\\cm\\python.js"
+IDS_309 "node_modules\\node-inspector\\front-end\\cm\\shell.js"
+IDS_310 "node_modules\\node-inspector\\front-end\\cm\\xml.js"
+IDS_311 "node_modules\\node-inspector\\front-end\\Images\\addIcon.png"
+IDS_312 "node_modules\\node-inspector\\front-end\\Images\\applicationCache.png"
+IDS_313 "node_modules\\node-inspector\\front-end\\Images\\back.png"
+IDS_314 "node_modules\\node-inspector\\front-end\\Images\\breakpoint2.png"
+IDS_315 "node_modules\\node-inspector\\front-end\\Images\\breakpoint2_2x.png"
+IDS_316 "node_modules\\node-inspector\\front-end\\Images\\breakpointBorder.png"
+IDS_317 "node_modules\\node-inspector\\front-end\\Images\\breakpointConditional2.png"
+IDS_318 "node_modules\\node-inspector\\front-end\\Images\\breakpointConditional2_2x.png"
+IDS_319 "node_modules\\node-inspector\\front-end\\Images\\breakpointConditionalBorder.png"
+IDS_320 "node_modules\\node-inspector\\front-end\\Images\\breakpointConditionalCounterBorder.png"
+IDS_321 "node_modules\\node-inspector\\front-end\\Images\\breakpointCounterBorder.png"
+IDS_322 "node_modules\\node-inspector\\front-end\\Images\\checker.png"
+IDS_323 "node_modules\\node-inspector\\front-end\\Images\\cookie.png"
+IDS_324 "node_modules\\node-inspector\\front-end\\Images\\database.png"
+IDS_325 "node_modules\\node-inspector\\front-end\\Images\\databaseTable.png"
+IDS_326 "node_modules\\node-inspector\\front-end\\Images\\deleteIcon.png"
+IDS_327 "node_modules\\node-inspector\\front-end\\Images\\domain.png"
+IDS_328 "node_modules\\node-inspector\\front-end\\Images\\fileSystem.png"
+IDS_329 "node_modules\\node-inspector\\front-end\\Images\\forward.png"
+IDS_330 "node_modules\\node-inspector\\front-end\\Images\\frame.png"
+IDS_331 "node_modules\\node-inspector\\front-end\\Images\\glossyHeader.png"
+IDS_332 "node_modules\\node-inspector\\front-end\\Images\\glossyHeaderPressed.png"
+IDS_333 "node_modules\\node-inspector\\front-end\\Images\\glossyHeaderSelected.png"
+IDS_334 "node_modules\\node-inspector\\front-end\\Images\\glossyHeaderSelectedPressed.png"
+IDS_335 "node_modules\\node-inspector\\front-end\\Images\\graphLabelCalloutLeft.png"
+IDS_336 "node_modules\\node-inspector\\front-end\\Images\\graphLabelCalloutRight.png"
+IDS_337 "node_modules\\node-inspector\\front-end\\Images\\indexedDB.png"
+IDS_338 "node_modules\\node-inspector\\front-end\\Images\\indexedDBIndex.png"
+IDS_339 "node_modules\\node-inspector\\front-end\\Images\\indexedDBObjectStore.png"
+IDS_340 "node_modules\\node-inspector\\front-end\\Images\\localStorage.png"
+IDS_341 "node_modules\\node-inspector\\front-end\\Images\\namedFlowOverflow.png"
+IDS_342 "node_modules\\node-inspector\\front-end\\Images\\paneAddButtons.png"
+IDS_343 "node_modules\\node-inspector\\front-end\\Images\\paneElementStateButtons.png"
+IDS_344 "node_modules\\node-inspector\\front-end\\Images\\paneFilterButtons.png"
+IDS_345 "node_modules\\node-inspector\\front-end\\Images\\paneRefreshButtons.png"
+IDS_346 "node_modules\\node-inspector\\front-end\\Images\\paneSettingsButtons.png"
+IDS_347 "node_modules\\node-inspector\\front-end\\Images\\popoverArrows.png"
+IDS_348 "node_modules\\node-inspector\\front-end\\Images\\popoverBackground.png"
+IDS_349 "node_modules\\node-inspector\\front-end\\Images\\profileGroupIcon.png"
+IDS_350 "node_modules\\node-inspector\\front-end\\Images\\profileIcon.png"
+IDS_351 "node_modules\\node-inspector\\front-end\\Images\\profileSmallIcon.png"
+IDS_352 "node_modules\\node-inspector\\front-end\\Images\\programCounterBorder.png"
+IDS_353 "node_modules\\node-inspector\\front-end\\Images\\radioDot.png"
+IDS_354 "node_modules\\node-inspector\\front-end\\Images\\regionEmpty.png"
+IDS_355 "node_modules\\node-inspector\\front-end\\Images\\regionFit.png"
+IDS_356 "node_modules\\node-inspector\\front-end\\Images\\regionOverset.png"
+IDS_357 "node_modules\\node-inspector\\front-end\\Images\\resourceCSSIcon.png"
+IDS_358 "node_modules\\node-inspector\\front-end\\Images\\resourceDocumentIcon.png"
+IDS_359 "node_modules\\node-inspector\\front-end\\Images\\resourceDocumentIconSmall.png"
+IDS_360 "node_modules\\node-inspector\\front-end\\Images\\resourceJSIcon.png"
+IDS_361 "node_modules\\node-inspector\\front-end\\Images\\resourcePlainIcon.png"
+IDS_362 "node_modules\\node-inspector\\front-end\\Images\\resourcePlainIconSmall.png"
+IDS_363 "node_modules\\node-inspector\\front-end\\Images\\resourcesTimeGraphIcon.png"
+IDS_364 "node_modules\\node-inspector\\front-end\\Images\\searchNext.png"
+IDS_365 "node_modules\\node-inspector\\front-end\\Images\\searchPrev.png"
+IDS_366 "node_modules\\node-inspector\\front-end\\Images\\searchSmallBlue.png"
+IDS_367 "node_modules\\node-inspector\\front-end\\Images\\searchSmallBrightBlue.png"
+IDS_368 "node_modules\\node-inspector\\front-end\\Images\\searchSmallGray.png"
+IDS_369 "node_modules\\node-inspector\\front-end\\Images\\searchSmallWhite.png"
+IDS_370 "node_modules\\node-inspector\\front-end\\Images\\segment.png"
+IDS_371 "node_modules\\node-inspector\\front-end\\Images\\segmentEnd.png"
+IDS_372 "node_modules\\node-inspector\\front-end\\Images\\segmentHover.png"
+IDS_373 "node_modules\\node-inspector\\front-end\\Images\\segmentHoverEnd.png"
+IDS_374 "node_modules\\node-inspector\\front-end\\Images\\segmentSelected.png"
+IDS_375 "node_modules\\node-inspector\\front-end\\Images\\segmentSelectedEnd.png"
+IDS_376 "node_modules\\node-inspector\\front-end\\Images\\sessionStorage.png"
+IDS_377 "node_modules\\node-inspector\\front-end\\Images\\settingsListRemove.png"
+IDS_378 "node_modules\\node-inspector\\front-end\\Images\\settingsListRemove_2x.png"
+IDS_379 "node_modules\\node-inspector\\front-end\\Images\\spinner.gif"
+IDS_380 "node_modules\\node-inspector\\front-end\\Images\\spinnerActive.gif"
+IDS_381 "node_modules\\node-inspector\\front-end\\Images\\spinnerActiveSelected.gif"
+IDS_382 "node_modules\\node-inspector\\front-end\\Images\\spinnerInactive.gif"
+IDS_383 "node_modules\\node-inspector\\front-end\\Images\\spinnerInactiveSelected.gif"
+IDS_384 "node_modules\\node-inspector\\front-end\\Images\\statusbarButtonGlyphs.png"
+IDS_385 "node_modules\\node-inspector\\front-end\\Images\\statusbarButtonGlyphs2x.png"
+IDS_386 "node_modules\\node-inspector\\front-end\\Images\\statusbarResizerHorizontal.png"
+IDS_387 "node_modules\\node-inspector\\front-end\\Images\\statusbarResizerVertical.png"
+IDS_388 "node_modules\\node-inspector\\front-end\\Images\\thumbActiveHoriz.png"
+IDS_389 "node_modules\\node-inspector\\front-end\\Images\\thumbActiveVert.png"
+IDS_390 "node_modules\\node-inspector\\front-end\\Images\\thumbHoriz.png"
+IDS_391 "node_modules\\node-inspector\\front-end\\Images\\thumbHoverHoriz.png"
+IDS_392 "node_modules\\node-inspector\\front-end\\Images\\thumbHoverVert.png"
+IDS_393 "node_modules\\node-inspector\\front-end\\Images\\thumbVert.png"
+IDS_394 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillBlue.png"
+IDS_395 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillGray.png"
+IDS_396 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillGreen.png"
+IDS_397 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillOrange.png"
+IDS_398 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillPurple.png"
+IDS_399 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillRed.png"
+IDS_400 "node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillYellow.png"
+IDS_401 "node_modules\\node-inspector\\front-end\\Images\\timelinePillBlue.png"
+IDS_402 "node_modules\\node-inspector\\front-end\\Images\\timelinePillGray.png"
+IDS_403 "node_modules\\node-inspector\\front-end\\Images\\timelinePillGreen.png"
+IDS_404 "node_modules\\node-inspector\\front-end\\Images\\timelinePillOrange.png"
+IDS_405 "node_modules\\node-inspector\\front-end\\Images\\timelinePillPurple.png"
+IDS_406 "node_modules\\node-inspector\\front-end\\Images\\timelinePillRed.png"
+IDS_407 "node_modules\\node-inspector\\front-end\\Images\\timelinePillYellow.png"
+IDS_408 "node_modules\\node-inspector\\front-end\\Images\\toolbarItemSelected.png"
+IDS_409 "node_modules\\node-inspector\\front-end\\Images\\trackHoriz.png"
+IDS_410 "node_modules\\node-inspector\\front-end\\Images\\trackVert.png"
+IDS_411 "node_modules\\node-inspector\\front-end\\Images\\src\\breakpoints2.svg"
+IDS_412 "node_modules\\node-inspector\\front-end\\Images\\src\\settingListRemove.svg"
+IDS_413 "node_modules\\node-inspector\\front-end\\Images\\src\\statusbarButtonGlyphs.svg"
+IDS_414 "node_modules\\node-inspector\\front-end\\UglifyJS\\parse-js.js"
+IDS_415 "node_modules\\node-inspector\\front-end-node\\Overrides.js"
+IDS_416 "node_modules\\node-inspector\\lib\\BreakEventHandler.js"
+IDS_417 "node_modules\\node-inspector\\lib\\callback.js"
+IDS_418 "node_modules\\node-inspector\\lib\\CallFramesProvider.js"
+IDS_419 "node_modules\\node-inspector\\lib\\config.js"
+IDS_420 "node_modules\\node-inspector\\lib\\convert.js"
+IDS_421 "node_modules\\node-inspector\\lib\\debug-server.js"
+IDS_422 "node_modules\\node-inspector\\lib\\debugger.js"
+IDS_423 "node_modules\\node-inspector\\lib\\DebuggerAgent.js"
+IDS_424 "node_modules\\node-inspector\\lib\\DebuggerClient.js"
+IDS_425 "node_modules\\node-inspector\\lib\\FrontendClient.js"
+IDS_426 "node_modules\\node-inspector\\lib\\FrontendCommandHandler.js"
+IDS_427 "node_modules\\node-inspector\\lib\\NetworkAgent.js"
+IDS_428 "node_modules\\node-inspector\\lib\\PageAgent.js"
+IDS_429 "node_modules\\node-inspector\\lib\\RuntimeAgent.js"
+IDS_430 "node_modules\\node-inspector\\lib\\ScriptFileStorage.js"
+IDS_431 "node_modules\\node-inspector\\lib\\ScriptManager.js"
+IDS_432 "node_modules\\node-inspector\\lib\\session.js"
+IDS_433 "node_modules\\node-inspector\\node_modules\\.bin\\express"
+IDS_434 "node_modules\\node-inspector\\node_modules\\.bin\\express.cmd"
+IDS_435 "node_modules\\node-inspector\\node_modules\\.bin\\opener"
+IDS_436 "node_modules\\node-inspector\\node_modules\\.bin\\opener.cmd"
+IDS_437 "node_modules\\node-inspector\\node_modules\\.bin\\rc"
+IDS_438 "node_modules\\node-inspector\\node_modules\\.bin\\rc.cmd"
+IDS_439 "node_modules\\node-inspector\\node_modules\\.bin\\which"
+IDS_440 "node_modules\\node-inspector\\node_modules\\.bin\\which.cmd"
+IDS_441 "node_modules\\node-inspector\\node_modules\\.bin\\wscat"
+IDS_442 "node_modules\\node-inspector\\node_modules\\.bin\\wscat.cmd"
+IDS_443 "node_modules\\node-inspector\\node_modules\\async\\.travis.yml"
+IDS_444 "node_modules\\node-inspector\\node_modules\\async\\component.json"
+IDS_445 "node_modules\\node-inspector\\node_modules\\async\\LICENSE"
+IDS_446 "node_modules\\node-inspector\\node_modules\\async\\package.json"
+IDS_447 "node_modules\\node-inspector\\node_modules\\async\\lib\\async.js"
+IDS_448 "node_modules\\node-inspector\\node_modules\\debug\\debug.js"
+IDS_449 "node_modules\\node-inspector\\node_modules\\debug\\package.json"
+IDS_450 "node_modules\\node-inspector\\node_modules\\debug\\lib\\debug.js"
+IDS_451 "node_modules\\node-inspector\\node_modules\\express\\.travis.yml"
+IDS_452 "node_modules\\node-inspector\\node_modules\\express\\index.js"
+IDS_453 "node_modules\\node-inspector\\node_modules\\express\\LICENSE"
+IDS_454 "node_modules\\node-inspector\\node_modules\\express\\package.json"
+IDS_455 "node_modules\\node-inspector\\node_modules\\express\\bin\\express"
+IDS_456 "node_modules\\node-inspector\\node_modules\\express\\lib\\application.js"
+IDS_457 "node_modules\\node-inspector\\node_modules\\express\\lib\\express.js"
+IDS_458 "node_modules\\node-inspector\\node_modules\\express\\lib\\middleware.js"
+IDS_459 "node_modules\\node-inspector\\node_modules\\express\\lib\\request.js"
+IDS_460 "node_modules\\node-inspector\\node_modules\\express\\lib\\response.js"
+IDS_461 "node_modules\\node-inspector\\node_modules\\express\\lib\\utils.js"
+IDS_462 "node_modules\\node-inspector\\node_modules\\express\\lib\\view.js"
+IDS_463 "node_modules\\node-inspector\\node_modules\\express\\lib\\router\\index.js"
+IDS_464 "node_modules\\node-inspector\\node_modules\\express\\lib\\router\\route.js"
+IDS_465 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\.bin\\mkdirp"
+IDS_466 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\.bin\\mkdirp.cmd"
+IDS_467 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\.travis.yml"
+IDS_468 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\index.js"
+IDS_469 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\package.json"
+IDS_470 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\tests\\crc.test.js"
+IDS_471 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\index.js"
+IDS_472 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\package.json"
+IDS_473 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\index.js"
+IDS_474 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\package.json"
+IDS_475 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\test.js"
+IDS_476 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\.travis.yml"
+IDS_477 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\index.js"
+IDS_478 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\LICENSE"
+IDS_479 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\package.json"
+IDS_480 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\cache.js"
+IDS_481 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\connect.js"
+IDS_482 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\index.js"
+IDS_483 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\patch.js"
+IDS_484 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\proto.js"
+IDS_485 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\utils.js"
+IDS_486 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\basicAuth.js"
+IDS_487 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\bodyParser.js"
+IDS_488 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\compress.js"
+IDS_489 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\cookieParser.js"
+IDS_490 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\cookieSession.js"
+IDS_491 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\csrf.js"
+IDS_492 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\directory.js"
+IDS_493 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\errorHandler.js"
+IDS_494 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\favicon.js"
+IDS_495 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\json.js"
+IDS_496 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\limit.js"
+IDS_497 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\logger.js"
+IDS_498 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\methodOverride.js"
+IDS_499 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\multipart.js"
+IDS_500 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\query.js"
+IDS_501 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\responseTime.js"
+IDS_502 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\session.js"
+IDS_503 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\static.js"
+IDS_504 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\staticCache.js"
+IDS_505 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\timeout.js"
+IDS_506 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\urlencoded.js"
+IDS_507 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\vhost.js"
+IDS_508 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\.travis.yml"
+IDS_509 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\index.js"
+IDS_510 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\package.json"
+IDS_511 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\component.json"
+IDS_512 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\index.js"
+IDS_513 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\package.json"
+IDS_514 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\.travis.yml"
+IDS_515 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\index.js"
+IDS_516 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\package.json"
+IDS_517 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\component.json"
+IDS_518 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\index.js"
+IDS_519 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\package.json"
+IDS_520 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\.travis.yml"
+IDS_521 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\bench.js"
+IDS_522 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\index.js"
+IDS_523 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\package.json"
+IDS_524 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\specifications.json"
+IDS_525 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\test.js"
+IDS_526 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\LICENSE"
+IDS_527 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\package.json"
+IDS_528 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\accept.js"
+IDS_529 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\charset.js"
+IDS_530 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\encoding.js"
+IDS_531 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\language.js"
+IDS_532 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\charset.js"
+IDS_533 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\encoding.js"
+IDS_534 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\language.js"
+IDS_535 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\mediaType.js"
+IDS_536 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\negotiator.js"
+IDS_537 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\charset.js"
+IDS_538 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\encoding.js"
+IDS_539 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\language.js"
+IDS_540 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\mediaType.js"
+IDS_541 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\.travis.yml"
+IDS_542 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\index.js"
+IDS_543 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\package.json"
+IDS_544 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\index.js"
+IDS_545 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\package.json"
+IDS_546 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\lib\\parse.js"
+IDS_547 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\.travis.yml"
+IDS_548 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\index.js"
+IDS_549 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\LICENSE"
+IDS_550 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\package.json"
+IDS_551 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\mocha.opts"
+IDS_552 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\parse.js"
+IDS_553 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\serialize.js"
+IDS_554 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\test\\cookieParser.js"
+IDS_555 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\.travis.yml"
+IDS_556 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\index.js"
+IDS_557 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\LICENSE"
+IDS_558 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\package.json"
+IDS_559 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\.travis.yml"
+IDS_560 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\index.js"
+IDS_561 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\package.json"
+IDS_562 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\benchmark\\benchmark.js"
+IDS_563 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\test\\test.js"
+IDS_564 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\index.js"
+IDS_565 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\LICENSE"
+IDS_566 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\package.json"
+IDS_567 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\.travis.yml"
+IDS_568 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\index.js"
+IDS_569 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\package.json"
+IDS_570 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\public\\error.html"
+IDS_571 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\public\\style.css"
+IDS_572 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\index.js"
+IDS_573 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\package.json"
+IDS_574 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\.travis.yml"
+IDS_575 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\index.js"
+IDS_576 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\LICENSE"
+IDS_577 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\package.json"
+IDS_578 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\mocha.opts"
+IDS_579 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\parse.js"
+IDS_580 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\serialize.js"
+IDS_581 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\debug.js"
+IDS_582 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\index.js"
+IDS_583 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\package.json"
+IDS_584 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\lib\\debug.js"
+IDS_585 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\index.js"
+IDS_586 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\LICENSE"
+IDS_587 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\package.json"
+IDS_588 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\.travis.yml"
+IDS_589 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\index.js"
+IDS_590 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\LICENSE"
+IDS_591 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\package.json"
+IDS_592 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\cookie.js"
+IDS_593 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\memory.js"
+IDS_594 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\session.js"
+IDS_595 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\store.js"
+IDS_596 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\test\\session.js"
+IDS_597 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\.travis.yml"
+IDS_598 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\index.js"
+IDS_599 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\package.json"
+IDS_600 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\index.js"
+IDS_601 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\package.json"
+IDS_602 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\component.json"
+IDS_603 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\index.js"
+IDS_604 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\package.json"
+IDS_605 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\.jshintrc"
+IDS_606 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\.travis.yml"
+IDS_607 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\CHANGELOG.md"
+IDS_608 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\index.js"
+IDS_609 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\LICENSE"
+IDS_610 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\package.json"
+IDS_611 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\azureblobstorage.js"
+IDS_612 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\s3.js"
+IDS_613 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\upload.js"
+IDS_614 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\duplex.js"
+IDS_615 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\float.patch"
+IDS_616 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\LICENSE"
+IDS_617 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\package.json"
+IDS_618 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\passthrough.js"
+IDS_619 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\readable.js"
+IDS_620 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\transform.js"
+IDS_621 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\writable.js"
+IDS_622 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_duplex.js"
+IDS_623 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_passthrough.js"
+IDS_624 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_readable.js"
+IDS_625 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_transform.js"
+IDS_626 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_writable.js"
+IDS_627 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\float.patch"
+IDS_628 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\package.json"
+IDS_629 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\util.js"
+IDS_630 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\lib\\util.js"
+IDS_631 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\inherits.js"
+IDS_632 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\inherits_browser.js"
+IDS_633 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\LICENSE"
+IDS_634 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\package.json"
+IDS_635 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\test.js"
+IDS_636 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\component.json"
+IDS_637 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\index.js"
+IDS_638 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\package.json"
+IDS_639 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\build\\build.js"
+IDS_640 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\index.js"
+IDS_641 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\LICENSE"
+IDS_642 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\package.json"
+IDS_643 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\index.js"
+IDS_644 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\package.json"
+IDS_645 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\test\\test.js"
+IDS_646 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\test\\test.txt"
+IDS_647 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\bench-multipart-parser.js"
+IDS_648 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\record.js"
+IDS_649 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\test.js"
+IDS_650 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\multipart.js"
+IDS_651 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\multi_video.upload"
+IDS_652 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\beta-sticker-1.png"
+IDS_653 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\binaryfile.tar.gz"
+IDS_654 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\blank.gif"
+IDS_655 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\funkyfilename.txt"
+IDS_656 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\menu_separator.png"
+IDS_657 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\pf1y5.png"
+IDS_658 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\plain.txt"
+IDS_659 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\beta-sticker-1.png.http"
+IDS_660 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\binaryfile.tar.gz.http"
+IDS_661 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\blank.gif.http"
+IDS_662 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\menu_seperator.png.http"
+IDS_663 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\pf1y5.png.http"
+IDS_664 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\plain.txt.http"
+IDS_665 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\no-filename\\filename-name.http"
+IDS_666 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\no-filename\\generic.http"
+IDS_667 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\preamble\\crlf.http"
+IDS_668 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\preamble\\preamble.http"
+IDS_669 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\info.md"
+IDS_670 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-chrome-13.http"
+IDS_671 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-firefox-3.6.http"
+IDS_672 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-safari-5.http"
+IDS_673 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-chrome-12.http"
+IDS_674 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-ie-7.http"
+IDS_675 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-ie-8.http"
+IDS_676 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-safari-5.http"
+IDS_677 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\workarounds\\missing-hyphens1.http"
+IDS_678 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\workarounds\\missing-hyphens2.http"
+IDS_679 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\encoding.js"
+IDS_680 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\no-filename.js"
+IDS_681 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\preamble.js"
+IDS_682 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\special-chars-in-filename.js"
+IDS_683 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\workarounds.js"
+IDS_684 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-connection-aborted.js"
+IDS_685 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-content-transfer-encoding.js"
+IDS_686 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-invalid.js"
+IDS_687 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-15.js"
+IDS_688 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-19.js"
+IDS_689 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-21.js"
+IDS_690 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-4.js"
+IDS_691 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-46.js"
+IDS_692 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-5.js"
+IDS_693 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\pause\\index.js"
+IDS_694 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\pause\\package.json"
+IDS_695 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\.gitmodules"
+IDS_696 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\index.js"
+IDS_697 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\package.json"
+IDS_698 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\.travis.yml"
+IDS_699 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\index.js"
+IDS_700 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\package.json"
+IDS_701 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\response-time\\index.js"
+IDS_702 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\response-time\\package.json"
+IDS_703 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\.travis.yml"
+IDS_704 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\index.js"
+IDS_705 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\LICENSE"
+IDS_706 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\package.json"
+IDS_707 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\component.json"
+IDS_708 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\index.js"
+IDS_709 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\package.json"
+IDS_710 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\.travis.yml"
+IDS_711 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\LICENSE"
+IDS_712 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\package.json"
+IDS_713 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\accept.js"
+IDS_714 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\charset.js"
+IDS_715 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\encoding.js"
+IDS_716 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\language.js"
+IDS_717 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\charset.js"
+IDS_718 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\encoding.js"
+IDS_719 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\language.js"
+IDS_720 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\mediaType.js"
+IDS_721 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\negotiator.js"
+IDS_722 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\charset.js"
+IDS_723 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\encoding.js"
+IDS_724 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\language.js"
+IDS_725 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\mediaType.js"
+IDS_726 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\directory.html"
+IDS_727 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\style.css"
+IDS_728 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\application_xp.png"
+IDS_729 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\application_xp_terminal.png"
+IDS_730 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\box.png"
+IDS_731 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\cd.png"
+IDS_732 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\controller.png"
+IDS_733 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\drive.png"
+IDS_734 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\film.png"
+IDS_735 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\folder.png"
+IDS_736 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\font.png"
+IDS_737 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\image.png"
+IDS_738 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\map.png"
+IDS_739 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page.png"
+IDS_740 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_add.png"
+IDS_741 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_attach.png"
+IDS_742 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_code.png"
+IDS_743 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_copy.png"
+IDS_744 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_delete.png"
+IDS_745 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_edit.png"
+IDS_746 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_error.png"
+IDS_747 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_excel.png"
+IDS_748 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_find.png"
+IDS_749 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_gear.png"
+IDS_750 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_go.png"
+IDS_751 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_green.png"
+IDS_752 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_key.png"
+IDS_753 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_lightning.png"
+IDS_754 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_link.png"
+IDS_755 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_paintbrush.png"
+IDS_756 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_paste.png"
+IDS_757 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_red.png"
+IDS_758 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_refresh.png"
+IDS_759 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_save.png"
+IDS_760 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white.png"
+IDS_761 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_acrobat.png"
+IDS_762 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_actionscript.png"
+IDS_763 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_add.png"
+IDS_764 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_c.png"
+IDS_765 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_camera.png"
+IDS_766 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cd.png"
+IDS_767 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_code.png"
+IDS_768 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_code_red.png"
+IDS_769 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_coldfusion.png"
+IDS_770 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_compressed.png"
+IDS_771 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_copy.png"
+IDS_772 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cplusplus.png"
+IDS_773 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_csharp.png"
+IDS_774 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cup.png"
+IDS_775 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_database.png"
+IDS_776 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_delete.png"
+IDS_777 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_dvd.png"
+IDS_778 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_edit.png"
+IDS_779 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_error.png"
+IDS_780 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_excel.png"
+IDS_781 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_find.png"
+IDS_782 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_flash.png"
+IDS_783 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_freehand.png"
+IDS_784 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_gear.png"
+IDS_785 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_get.png"
+IDS_786 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_go.png"
+IDS_787 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_h.png"
+IDS_788 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_horizontal.png"
+IDS_789 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_key.png"
+IDS_790 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_lightning.png"
+IDS_791 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_link.png"
+IDS_792 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_magnify.png"
+IDS_793 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_medal.png"
+IDS_794 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_office.png"
+IDS_795 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paint.png"
+IDS_796 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paintbrush.png"
+IDS_797 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paste.png"
+IDS_798 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_php.png"
+IDS_799 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_picture.png"
+IDS_800 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_powerpoint.png"
+IDS_801 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_put.png"
+IDS_802 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_ruby.png"
+IDS_803 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_stack.png"
+IDS_804 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_star.png"
+IDS_805 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_swoosh.png"
+IDS_806 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_text.png"
+IDS_807 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_text_width.png"
+IDS_808 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_tux.png"
+IDS_809 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_vector.png"
+IDS_810 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_visualstudio.png"
+IDS_811 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_width.png"
+IDS_812 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_word.png"
+IDS_813 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_world.png"
+IDS_814 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_wrench.png"
+IDS_815 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_zip.png"
+IDS_816 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_word.png"
+IDS_817 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_world.png"
+IDS_818 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\.travis.yml"
+IDS_819 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\index.js"
+IDS_820 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\LICENSE"
+IDS_821 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\package.json"
+IDS_822 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\node_modules\\parseurl\\index.js"
+IDS_823 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\node_modules\\parseurl\\package.json"
+IDS_824 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\LICENSE.txt"
+IDS_825 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\package.json"
+IDS_826 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\setImmediate.js"
+IDS_827 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\runner.htm"
+IDS_828 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\selfClose.htm"
+IDS_829 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\tests.js"
+IDS_830 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\worker.js"
+IDS_831 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\lib\\qunit.css"
+IDS_832 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\lib\\qunit.js"
+IDS_833 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\.travis.yml"
+IDS_834 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\favicon.ico"
+IDS_835 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\index.js"
+IDS_836 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\LICENSE"
+IDS_837 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\package.json"
+IDS_838 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\.travis.yml"
+IDS_839 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\index.js"
+IDS_840 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\package.json"
+IDS_841 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\index.js"
+IDS_842 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\LICENSE"
+IDS_843 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\package.json"
+IDS_844 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie-signature\\index.js"
+IDS_845 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie-signature\\package.json"
+IDS_846 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\fresh\\index.js"
+IDS_847 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\fresh\\package.json"
+IDS_848 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\component.json"
+IDS_849 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\index.js"
+IDS_850 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\package.json"
+IDS_851 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\methods\\index.js"
+IDS_852 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\methods\\package.json"
+IDS_853 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\.travis.yml"
+IDS_854 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\index.js"
+IDS_855 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\LICENSE"
+IDS_856 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\package.json"
+IDS_857 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\readme.markdown"
+IDS_858 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\bin\\cmd.js"
+IDS_859 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\bin\\usage.txt"
+IDS_860 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\examples\\pow.js"
+IDS_861 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\chmod.js"
+IDS_862 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\clobber.js"
+IDS_863 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\mkdirp.js"
+IDS_864 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\perm.js"
+IDS_865 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\perm_sync.js"
+IDS_866 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\race.js"
+IDS_867 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\rel.js"
+IDS_868 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\return.js"
+IDS_869 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\return_sync.js"
+IDS_870 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\root.js"
+IDS_871 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\sync.js"
+IDS_872 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\umask.js"
+IDS_873 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\umask_sync.js"
+IDS_874 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\range-parser\\index.js"
+IDS_875 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\range-parser\\package.json"
+IDS_876 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\index.js"
+IDS_877 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\package.json"
+IDS_878 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\lib\\send.js"
+IDS_879 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\lib\\utils.js"
+IDS_880 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\debug.js"
+IDS_881 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\package.json"
+IDS_882 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\lib\\debug.js"
+IDS_883 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\LICENSE"
+IDS_884 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\mime.js"
+IDS_885 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\package.json"
+IDS_886 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\test.js"
+IDS_887 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\types\\mime.types"
+IDS_888 "node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\types\\node.types"
+IDS_889 "node_modules\\node-inspector\\node_modules\\glob\\.travis.yml"
+IDS_890 "node_modules\\node-inspector\\node_modules\\glob\\glob.js"
+IDS_891 "node_modules\\node-inspector\\node_modules\\glob\\LICENSE"
+IDS_892 "node_modules\\node-inspector\\node_modules\\glob\\package.json"
+IDS_893 "node_modules\\node-inspector\\node_modules\\glob\\examples\\g.js"
+IDS_894 "node_modules\\node-inspector\\node_modules\\glob\\examples\\usr-local.js"
+IDS_895 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\inherits.js"
+IDS_896 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\inherits_browser.js"
+IDS_897 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\LICENSE"
+IDS_898 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\package.json"
+IDS_899 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\test.js"
+IDS_900 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\LICENSE"
+IDS_901 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\minimatch.js"
+IDS_902 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\package.json"
+IDS_903 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\CONTRIBUTORS"
+IDS_904 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\LICENSE"
+IDS_905 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\package.json"
+IDS_906 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\lib\\lru-cache.js"
+IDS_907 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\basic.js"
+IDS_908 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\foreach.js"
+IDS_909 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\memory-leak.js"
+IDS_910 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\bench.js"
+IDS_911 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\LICENSE"
+IDS_912 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\package.json"
+IDS_913 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\sigmund.js"
+IDS_914 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\test\\basic.js"
+IDS_915 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\basic.js"
+IDS_916 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\brace-expand.js"
+IDS_917 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\caching.js"
+IDS_918 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\defaults.js"
+IDS_919 "node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\extglob-ending-with-state-char.js"
+IDS_920 "node_modules\\node-inspector\\node_modules\\glob\\test\\00-setup.js"
+IDS_921 "node_modules\\node-inspector\\node_modules\\glob\\test\\bash-comparison.js"
+IDS_922 "node_modules\\node-inspector\\node_modules\\glob\\test\\bash-results.json"
+IDS_923 "node_modules\\node-inspector\\node_modules\\glob\\test\\cwd-test.js"
+IDS_924 "node_modules\\node-inspector\\node_modules\\glob\\test\\globstar-match.js"
+IDS_925 "node_modules\\node-inspector\\node_modules\\glob\\test\\mark.js"
+IDS_926 "node_modules\\node-inspector\\node_modules\\glob\\test\\new-glob-optional-options.js"
+IDS_927 "node_modules\\node-inspector\\node_modules\\glob\\test\\nocase-nomagic.js"
+IDS_928 "node_modules\\node-inspector\\node_modules\\glob\\test\\pause-resume.js"
+IDS_929 "node_modules\\node-inspector\\node_modules\\glob\\test\\readme-issue.js"
+IDS_930 "node_modules\\node-inspector\\node_modules\\glob\\test\\root-nomount.js"
+IDS_931 "node_modules\\node-inspector\\node_modules\\glob\\test\\root.js"
+IDS_932 "node_modules\\node-inspector\\node_modules\\glob\\test\\stat.js"
+IDS_933 "node_modules\\node-inspector\\node_modules\\glob\\test\\zz-cleanup.js"
+IDS_934 "node_modules\\node-inspector\\node_modules\\opener\\LICENSE.txt"
+IDS_935 "node_modules\\node-inspector\\node_modules\\opener\\opener.js"
+IDS_936 "node_modules\\node-inspector\\node_modules\\opener\\package.json"
+IDS_937 "node_modules\\node-inspector\\node_modules\\rc\\browser.js"
+IDS_938 "node_modules\\node-inspector\\node_modules\\rc\\index.js"
+IDS_939 "node_modules\\node-inspector\\node_modules\\rc\\LICENSE.APACHE2"
+IDS_940 "node_modules\\node-inspector\\node_modules\\rc\\LICENSE.BSD"
+IDS_941 "node_modules\\node-inspector\\node_modules\\rc\\LICENSE.MIT"
+IDS_942 "node_modules\\node-inspector\\node_modules\\rc\\package.json"
+IDS_943 "node_modules\\node-inspector\\node_modules\\rc\\lib\\utils.js"
+IDS_944 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\index.js"
+IDS_945 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\LICENSE"
+IDS_946 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\package.json"
+IDS_947 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\ini.js"
+IDS_948 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\LICENSE"
+IDS_949 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\package.json"
+IDS_950 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\bar.js"
+IDS_951 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\foo.js"
+IDS_952 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\fixtures\\foo.ini"
+IDS_953 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\.travis.yml"
+IDS_954 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\index.js"
+IDS_955 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\LICENSE"
+IDS_956 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\package.json"
+IDS_957 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\readme.markdown"
+IDS_958 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\example\\parse.js"
+IDS_959 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\bool.js"
+IDS_960 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\dash.js"
+IDS_961 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\default_bool.js"
+IDS_962 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\dotted.js"
+IDS_963 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\long.js"
+IDS_964 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\num.js"
+IDS_965 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\parse.js"
+IDS_966 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\parse_modified.js"
+IDS_967 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\short.js"
+IDS_968 "node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\whitespace.js"
+IDS_969 "node_modules\\node-inspector\\node_modules\\rc\\test\\ini.js"
+IDS_970 "node_modules\\node-inspector\\node_modules\\rc\\test\\test.js"
+IDS_971 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.jshintrc"
+IDS_972 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.travis.yml"
+IDS_973 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\index.js"
+IDS_974 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\LICENSE"
+IDS_975 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\package.json"
+IDS_976 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\.name"
+IDS_977 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\data-uri.iml"
+IDS_978 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\encodings.xml"
+IDS_979 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\jsLibraryMappings.xml"
+IDS_980 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\misc.xml"
+IDS_981 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\modules.xml"
+IDS_982 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\vcs.xml"
+IDS_983 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\workspace.xml"
+IDS_984 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\inspectionProfiles\\profiles_settings.xml"
+IDS_985 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\inspectionProfiles\\Project_Default.xml"
+IDS_986 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\jsLinters\\jshint.xml"
+IDS_987 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\scopes\\scope_settings.xml"
+IDS_988 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\package.json"
+IDS_989 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\test.js"
+IDS_990 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\truncate.js"
+IDS_991 "node_modules\\node-inspector\\node_modules\\strong-data-uri\\test\\decode.js"
+IDS_992 "node_modules\\node-inspector\\node_modules\\which\\LICENSE"
+IDS_993 "node_modules\\node-inspector\\node_modules\\which\\package.json"
+IDS_994 "node_modules\\node-inspector\\node_modules\\which\\which.js"
+IDS_995 "node_modules\\node-inspector\\node_modules\\which\\bin\\which"
+IDS_996 "node_modules\\node-inspector\\node_modules\\ws\\.travis.yml"
+IDS_997 "node_modules\\node-inspector\\node_modules\\ws\\binding.gyp"
+IDS_998 "node_modules\\node-inspector\\node_modules\\ws\\builderror.log"
+IDS_999 "node_modules\\node-inspector\\node_modules\\ws\\index.js"
+IDS_1000 "node_modules\\node-inspector\\node_modules\\ws\\package.json"
+IDS_1001 "node_modules\\node-inspector\\node_modules\\ws\\bench\\parser.benchmark.js"
+IDS_1002 "node_modules\\node-inspector\\node_modules\\ws\\bench\\sender.benchmark.js"
+IDS_1003 "node_modules\\node-inspector\\node_modules\\ws\\bench\\speed.js"
+IDS_1004 "node_modules\\node-inspector\\node_modules\\ws\\bench\\util.js"
+IDS_1005 "node_modules\\node-inspector\\node_modules\\ws\\bin\\wscat"
+IDS_1006 "node_modules\\node-inspector\\node_modules\\ws\\build\\binding.sln"
+IDS_1007 "node_modules\\node-inspector\\node_modules\\ws\\build\\bufferutil.vcxproj"
+IDS_1008 "node_modules\\node-inspector\\node_modules\\ws\\build\\bufferutil.vcxproj.filters"
+IDS_1009 "node_modules\\node-inspector\\node_modules\\ws\\build\\config.gypi"
+IDS_1010 "node_modules\\node-inspector\\node_modules\\ws\\build\\validation.vcxproj"
+IDS_1011 "node_modules\\node-inspector\\node_modules\\ws\\build\\validation.vcxproj.filters"
+IDS_1012 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.exp"
+IDS_1013 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.lib"
+IDS_1014 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.node"
+IDS_1015 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.pdb"
+IDS_1016 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.exp"
+IDS_1017 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.lib"
+IDS_1018 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.node"
+IDS_1019 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.pdb"
+IDS_1020 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.lastbuildstate"
+IDS_1021 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.obj"
+IDS_1022 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.write.1.tlog"
+IDS_1023 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\cl.command.1.tlog"
+IDS_1024 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\CL.read.1.tlog"
+IDS_1025 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\CL.write.1.tlog"
+IDS_1026 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-cvtres.read.1.tlog"
+IDS_1027 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-cvtres.write.1.tlog"
+IDS_1028 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-rc.read.1.tlog"
+IDS_1029 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-rc.write.1.tlog"
+IDS_1030 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.command.1.tlog"
+IDS_1031 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.read.1.tlog"
+IDS_1032 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.write.1.tlog"
+IDS_1033 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\vc110.pdb"
+IDS_1034 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\cl.command.1.tlog"
+IDS_1035 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\CL.read.1.tlog"
+IDS_1036 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\CL.write.1.tlog"
+IDS_1037 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-cvtres.read.1.tlog"
+IDS_1038 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-cvtres.write.1.tlog"
+IDS_1039 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-rc.read.1.tlog"
+IDS_1040 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-rc.write.1.tlog"
+IDS_1041 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.command.1.tlog"
+IDS_1042 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.read.1.tlog"
+IDS_1043 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.write.1.tlog"
+IDS_1044 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.lastbuildstate"
+IDS_1045 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.obj"
+IDS_1046 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.write.1.tlog"
+IDS_1047 "node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\vc110.pdb"
+IDS_1048 "node_modules\\node-inspector\\node_modules\\ws\\doc\\ws.md"
+IDS_1049 "node_modules\\node-inspector\\node_modules\\ws\\examples\\ssl.js"
+IDS_1050 "node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\package.json"
+IDS_1051 "node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\server.js"
+IDS_1052 "node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\app.js"
+IDS_1053 "node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\index.html"
+IDS_1054 "node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\uploader.js"
+IDS_1055 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\package.json"
+IDS_1056 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\server.js"
+IDS_1057 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\public\\index.html"
+IDS_1058 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\package.json"
+IDS_1059 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\server.js"
+IDS_1060 "node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\public\\index.html"
+IDS_1061 "node_modules\\node-inspector\\node_modules\\ws\\lib\\browser.js"
+IDS_1062 "node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferPool.js"
+IDS_1063 "node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferUtil.fallback.js"
+IDS_1064 "node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferUtil.js"
+IDS_1065 "node_modules\\node-inspector\\node_modules\\ws\\lib\\ErrorCodes.js"
+IDS_1066 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Receiver.hixie.js"
+IDS_1067 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Receiver.js"
+IDS_1068 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Sender.hixie.js"
+IDS_1069 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Sender.js"
+IDS_1070 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Validation.fallback.js"
+IDS_1071 "node_modules\\node-inspector\\node_modules\\ws\\lib\\Validation.js"
+IDS_1072 "node_modules\\node-inspector\\node_modules\\ws\\lib\\WebSocket.js"
+IDS_1073 "node_modules\\node-inspector\\node_modules\\ws\\lib\\WebSocketServer.js"
+IDS_1074 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\.travis.yml"
+IDS_1075 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\index.js"
+IDS_1076 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\package.json"
+IDS_1077 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\lib\\commander.js"
+IDS_1078 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\.index.js"
+IDS_1079 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\LICENSE"
+IDS_1080 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\nan.h"
+IDS_1081 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\package.json"
+IDS_1082 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\package.json"
+IDS_1083 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\lib\\options.js"
+IDS_1084 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\test\\options.test.js"
+IDS_1085 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\test\\fixtures\\test.conf"
+IDS_1086 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\example.js"
+IDS_1087 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\package.json"
+IDS_1088 "node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\tinycolor.js"
+IDS_1089 "node_modules\\node-inspector\\node_modules\\ws\\src\\bufferutil.cc"
+IDS_1090 "node_modules\\node-inspector\\node_modules\\ws\\src\\validation.cc"
+IDS_1091 "node_modules\\node-inspector\\node_modules\\ws\\test\\autobahn-server.js"
+IDS_1092 "node_modules\\node-inspector\\node_modules\\ws\\test\\autobahn.js"
+IDS_1093 "node_modules\\node-inspector\\node_modules\\ws\\test\\BufferPool.test.js"
+IDS_1094 "node_modules\\node-inspector\\node_modules\\ws\\test\\hybi-common.js"
+IDS_1095 "node_modules\\node-inspector\\node_modules\\ws\\test\\Receiver.hixie.test.js"
+IDS_1096 "node_modules\\node-inspector\\node_modules\\ws\\test\\Receiver.test.js"
+IDS_1097 "node_modules\\node-inspector\\node_modules\\ws\\test\\Sender.hixie.test.js"
+IDS_1098 "node_modules\\node-inspector\\node_modules\\ws\\test\\Sender.test.js"
+IDS_1099 "node_modules\\node-inspector\\node_modules\\ws\\test\\testserver.js"
+IDS_1100 "node_modules\\node-inspector\\node_modules\\ws\\test\\Validation.test.js"
+IDS_1101 "node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocket.integration.js"
+IDS_1102 "node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocket.test.js"
+IDS_1103 "node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocketServer.test.js"
+IDS_1104 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\agent1-cert.pem"
+IDS_1105 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\agent1-key.pem"
+IDS_1106 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\ca1-cert.pem"
+IDS_1107 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\ca1-key.pem"
+IDS_1108 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\certificate.pem"
+IDS_1109 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\key.pem"
+IDS_1110 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\request.pem"
+IDS_1111 "node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\textfile"
+IDS_1112 "node_modules\\node-inspector\\node_modules\\yargs\\.travis.yml"
+IDS_1113 "node_modules\\node-inspector\\node_modules\\yargs\\index.js"
+IDS_1114 "node_modules\\node-inspector\\node_modules\\yargs\\LICENSE"
+IDS_1115 "node_modules\\node-inspector\\node_modules\\yargs\\package.json"
+IDS_1116 "node_modules\\node-inspector\\node_modules\\yargs\\example\\bool.js"
+IDS_1117 "node_modules\\node-inspector\\node_modules\\yargs\\example\\boolean_double.js"
+IDS_1118 "node_modules\\node-inspector\\node_modules\\yargs\\example\\boolean_single.js"
+IDS_1119 "node_modules\\node-inspector\\node_modules\\yargs\\example\\count.js"
+IDS_1120 "node_modules\\node-inspector\\node_modules\\yargs\\example\\default_hash.js"
+IDS_1121 "node_modules\\node-inspector\\node_modules\\yargs\\example\\default_singles.js"
+IDS_1122 "node_modules\\node-inspector\\node_modules\\yargs\\example\\demand_count.js"
+IDS_1123 "node_modules\\node-inspector\\node_modules\\yargs\\example\\divide.js"
+IDS_1124 "node_modules\\node-inspector\\node_modules\\yargs\\example\\implies.js"
+IDS_1125 "node_modules\\node-inspector\\node_modules\\yargs\\example\\implies_hash.js"
+IDS_1126 "node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count.js"
+IDS_1127 "node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count_options.js"
+IDS_1128 "node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count_wrap.js"
+IDS_1129 "node_modules\\node-inspector\\node_modules\\yargs\\example\\nonopt.js"
+IDS_1130 "node_modules\\node-inspector\\node_modules\\yargs\\example\\short.js"
+IDS_1131 "node_modules\\node-inspector\\node_modules\\yargs\\example\\string.js"
+IDS_1132 "node_modules\\node-inspector\\node_modules\\yargs\\example\\usage-options.js"
+IDS_1133 "node_modules\\node-inspector\\node_modules\\yargs\\example\\xup.js"
+IDS_1134 "node_modules\\node-inspector\\node_modules\\yargs\\lib\\minimist.js"
+IDS_1135 "node_modules\\node-inspector\\node_modules\\yargs\\lib\\wordwrap.js"
+IDS_1136 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\.travis.yml"
+IDS_1137 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\index.js"
+IDS_1138 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\LICENSE"
+IDS_1139 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\package.json"
+IDS_1140 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\readme.markdown"
+IDS_1141 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\example\\parse.js"
+IDS_1142 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\bool.js"
+IDS_1143 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\dash.js"
+IDS_1144 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\default_bool.js"
+IDS_1145 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\dotted.js"
+IDS_1146 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\long.js"
+IDS_1147 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\num.js"
+IDS_1148 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\parse.js"
+IDS_1149 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\parse_modified.js"
+IDS_1150 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\short.js"
+IDS_1151 "node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\whitespace.js"
+IDS_1152 "node_modules\\node-inspector\\node_modules\\yargs\\test\\config.json"
+IDS_1153 "node_modules\\node-inspector\\node_modules\\yargs\\test\\count.js"
+IDS_1154 "node_modules\\node-inspector\\node_modules\\yargs\\test\\dash.js"
+IDS_1155 "node_modules\\node-inspector\\node_modules\\yargs\\test\\mocha.opts"
+IDS_1156 "node_modules\\node-inspector\\node_modules\\yargs\\test\\parse.js"
+IDS_1157 "node_modules\\node-inspector\\node_modules\\yargs\\test\\parse_modified.js"
+IDS_1158 "node_modules\\node-inspector\\node_modules\\yargs\\test\\short.js"
+IDS_1159 "node_modules\\node-inspector\\node_modules\\yargs\\test\\usage.js"
+IDS_1160 "node_modules\\node-inspector\\node_modules\\yargs\\test\\whitespace.js"
+IDS_1161 "node_modules\\node-inspector\\node_modules\\yargs\\test\\_.js"
+IDS_1162 "node_modules\\node-inspector\\node_modules\\yargs\\test\\_\\bin.js"
+END
+F1 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\.jshintignore"
+F2 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\.jshintrc"
+F3 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\AUTHORS"
+F4 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\config.json"
+F5 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\index.js"
+F6 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\LICENSE"
+F7 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\package.json"
+F8 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\bin\\inspector.js"
+F9 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\bin\\node-debug.js"
+F10 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\bin\\run-repl.js"
+F11 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\build\\config.gypi"
+F12 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\docs\\embedding.md"
+F13 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AdvancedSearchController.js"
+F14 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ApplicationCacheItemsView.js"
+F15 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ApplicationCacheModel.js"
+F16 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditCategories.js"
+F17 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditController.js"
+F18 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditFormatters.js"
+F19 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditLauncherView.js"
+F20 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditResultView.js"
+F21 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditRules.js"
+F22 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\auditsPanel.css"
+F23 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\AuditsPanel.js"
+F24 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\BottomUpProfileDataGridTree.js"
+F25 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\breadcrumbList.css"
+F26 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\BreakpointManager.js"
+F27 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\breakpointsList.css"
+F28 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\BreakpointsSidebarPane.js"
+F29 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\buildSystemOnly.js"
+F30 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CallStackSidebarPane.js"
+F31 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\canvasProfiler.css"
+F32 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CanvasProfileView.js"
+F33 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CanvasReplayStateView.js"
+F34 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Checkbox.js"
+F35 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CodeMirrorTextEditor.js"
+F36 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CodeMirrorUtils.js"
+F37 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Color.js"
+F38 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CompilerScriptMapping.js"
+F39 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CompletionDictionary.js"
+F40 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ConsoleMessage.js"
+F41 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ConsoleModel.js"
+F42 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ConsolePanel.js"
+F43 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ConsoleView.js"
+F44 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ContentProvider.js"
+F45 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ContentProviderBasedProjectDelegate.js"
+F46 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ContentProviders.js"
+F47 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ContextMenu.js"
+F48 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CookieItemsView.js"
+F49 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CookieParser.js"
+F50 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CookiesTable.js"
+F51 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CPUProfileView.js"
+F52 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CSSMetadata.js"
+F53 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CSSNamedFlowCollectionsView.js"
+F54 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cssNamedFlows.css"
+F55 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CSSNamedFlowView.js"
+F56 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CSSStyleModel.js"
+F57 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\CSSStyleSheetMapping.js"
+F58 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Database.js"
+F59 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DatabaseQueryView.js"
+F60 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DatabaseTableView.js"
+F61 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\dataGrid.css"
+F62 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DataGrid.js"
+F63 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DebuggerModel.js"
+F64 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DebuggerScriptMapping.js"
+F65 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DefaultScriptMapping.js"
+F66 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DevToolsExtensionAPI.js"
+F67 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\dialog.css"
+F68 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Dialog.js"
+F69 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DirectoryContentView.js"
+F70 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DockController.js"
+F71 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMAgent.js"
+F72 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMBreakpointsSidebarPane.js"
+F73 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMCountersGraph.js"
+F74 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMExtension.js"
+F75 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMPresentationUtils.js"
+F76 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMStorage.js"
+F77 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMStorageItemsView.js"
+F78 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\DOMSyntaxHighlighter.js"
+F79 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Drawer.js"
+F80 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\EditFileSystemDialog.js"
+F81 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\elementsPanel.css"
+F82 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ElementsPanel.js"
+F83 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ElementsPanelDescriptor.js"
+F84 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ElementsTreeOutline.js"
+F85 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\EmptyView.js"
+F86 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\EventListenersSidebarPane.js"
+F87 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionAPI.js"
+F88 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionAuditCategory.js"
+F89 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionPanel.js"
+F90 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionRegistryStub.js"
+F91 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionServer.js"
+F92 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ExtensionView.js"
+F93 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\externs.js"
+F94 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileContentView.js"
+F95 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileManager.js"
+F96 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FilePathScoreFunction.js"
+F97 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileSystemMapping.js"
+F98 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileSystemModel.js"
+F99 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileSystemProjectDelegate.js"
+F100 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileSystemView.js"
+F101 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FileUtils.js"
+F102 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\filteredItemSelectionDialog.css"
+F103 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FilteredItemSelectionDialog.js"
+F104 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\flameChart.css"
+F105 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FlameChart.js"
+F106 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\FontView.js"
+F107 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\GoToLineDialog.js"
+F108 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HandlerRegistry.js"
+F109 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HAREntry.js"
+F110 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\heapProfiler.css"
+F111 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshot.js"
+F112 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotDataGrids.js"
+F113 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotGridNodes.js"
+F114 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotLoader.js"
+F115 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotProxy.js"
+F116 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotView.js"
+F117 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotWorker.js"
+F118 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HeapSnapshotWorkerDispatcher.js"
+F119 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\helpScreen.css"
+F120 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\HelpScreen.js"
+F121 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ImageView.js"
+F122 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\IndexedDBModel.js"
+F123 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\indexedDBViews.css"
+F124 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\IndexedDBViews.js"
+F125 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectElementModeController.js"
+F126 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\inspector.css"
+F127 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\inspector.html"
+F128 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\inspector.js"
+F129 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectorBackend.js"
+F130 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectorBackendCommands.js"
+F131 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\inspectorCommon.css"
+F132 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectorFrontendAPI.js"
+F133 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectorFrontendHostStub.js"
+F134 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\inspectorSyntaxHighlight.css"
+F135 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\InspectorView.js"
+F136 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\IsolatedFileSystem.js"
+F137 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\IsolatedFileSystemManager.js"
+F138 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\JavaScriptFormatter.js"
+F139 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\JavaScriptSourceFrame.js"
+F140 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\jsdifflib.js"
+F141 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\JSHeapSnapshot.js"
+F142 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\KeyboardShortcut.js"
+F143 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LayerDetailsView.js"
+F144 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Layers3DView.js"
+F145 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\layersPanel.css"
+F146 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LayersPanel.js"
+F147 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LayersPanelDescriptor.js"
+F148 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LayerTree.js"
+F149 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LayerTreeModel.js"
+F150 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Linkifier.js"
+F151 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\LiveEditSupport.js"
+F152 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\MemoryStatistics.js"
+F153 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\MetricsSidebarPane.js"
+F154 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NativeBreakpointsSidebarPane.js"
+F155 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NavigatorOverlayController.js"
+F156 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\navigatorView.css"
+F157 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NavigatorView.js"
+F158 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkItemView.js"
+F159 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkLog.js"
+F160 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\networkLogView.css"
+F161 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkManager.js"
+F162 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\networkPanel.css"
+F163 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkPanel.js"
+F164 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkPanelDescriptor.js"
+F165 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkRequest.js"
+F166 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\NetworkUISourceCodeProvider.js"
+F167 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Object.js"
+F168 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ObjectPopoverHelper.js"
+F169 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ObjectPropertiesSection.js"
+F170 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\OverridesSupport.js"
+F171 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\OverridesView.js"
+F172 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\OverviewGrid.js"
+F173 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\OWNERS"
+F174 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Panel.js"
+F175 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\panelEnablerView.css"
+F176 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ParsedURL.js"
+F177 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Placard.js"
+F178 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\PlatformFontsSidebarPane.js"
+F179 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\popover.css"
+F180 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Popover.js"
+F181 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\PresentationConsoleMessageHelper.js"
+F182 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ProfileDataGridTree.js"
+F183 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ProfileLauncherView.js"
+F184 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\profilesPanel.css"
+F185 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ProfilesPanel.js"
+F186 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ProfilesPanelDescriptor.js"
+F187 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Progress.js"
+F188 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ProgressIndicator.js"
+F189 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\PropertiesSection.js"
+F190 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\PropertiesSidebarPane.js"
+F191 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RawSourceCode.js"
+F192 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RemoteObject.js"
+F193 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestCookiesView.js"
+F194 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestHeadersView.js"
+F195 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestHTMLView.js"
+F196 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestJSONView.js"
+F197 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestPreviewView.js"
+F198 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestResponseView.js"
+F199 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestTimingView.js"
+F200 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RequestView.js"
+F201 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Resource.js"
+F202 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceScriptMapping.js"
+F203 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\resourcesPanel.css"
+F204 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourcesPanel.js"
+F205 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceTreeModel.js"
+F206 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceType.js"
+F207 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceUtils.js"
+F208 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\resourceView.css"
+F209 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceView.js"
+F210 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ResourceWebSocketFrameView.js"
+F211 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\revisionHistory.css"
+F212 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RevisionHistoryView.js"
+F213 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\RuntimeModel.js"
+F214 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SASSSourceMapping.js"
+F215 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScopeChainSidebarPane.js"
+F216 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\screencastView.css"
+F217 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScreencastView.js"
+F218 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Script.js"
+F219 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptFormatter.js"
+F220 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptFormatterWorker.js"
+F221 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptsNavigator.js"
+F222 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptSnippetModel.js"
+F223 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\scriptsPanel.css"
+F224 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptsPanel.js"
+F225 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptsPanelDescriptor.js"
+F226 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ScriptsSearchScope.js"
+F227 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SearchController.js"
+F228 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Section.js"
+F229 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Settings.js"
+F230 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SettingsScreen.js"
+F231 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ShortcutsScreen.js"
+F232 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ShowMoreDataGridNode.js"
+F233 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SidebarOverlay.js"
+F234 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\sidebarPane.css"
+F235 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SidebarPane.js"
+F236 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SidebarTreeElement.js"
+F237 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SidebarView.js"
+F238 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SimpleWorkspaceProvider.js"
+F239 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SnippetStorage.js"
+F240 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SoftContextMenu.js"
+F241 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SourceFrame.js"
+F242 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SourceMap.js"
+F243 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SourceMapping.js"
+F244 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\spectrum.css"
+F245 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Spectrum.js"
+F246 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\splitView.css"
+F247 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SplitView.js"
+F248 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\StatusBarButton.js"
+F249 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\StyleSheetOutlineDialog.js"
+F250 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\StylesSidebarPane.js"
+F251 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\StylesSourceMapping.js"
+F252 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\SuggestBox.js"
+F253 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TabbedEditorContainer.js"
+F254 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\tabbedPane.css"
+F255 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TabbedPane.js"
+F256 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\test-runner.html"
+F257 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TestController.js"
+F258 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Tests.js"
+F259 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TextEditor.js"
+F260 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\textPrompt.css"
+F261 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TextPrompt.js"
+F262 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TextRange.js"
+F263 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TextUtils.js"
+F264 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelineFrameController.js"
+F265 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelineGrid.js"
+F266 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelineManager.js"
+F267 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelineModel.js"
+F268 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelineOverviewPane.js"
+F269 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\timelinePanel.css"
+F270 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelinePanel.js"
+F271 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelinePanelDescriptor.js"
+F272 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TimelinePresentationModel.js"
+F273 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Toolbar.js"
+F274 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TopDownProfileDataGridTree.js"
+F275 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\TracingAgent.js"
+F276 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\treeoutline.js"
+F277 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UISourceCode.js"
+F278 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UISourceCodeFrame.js"
+F279 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UIString.js"
+F280 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UIUtils.js"
+F281 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UserMetrics.js"
+F282 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\utilities.js"
+F283 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\View.js"
+F284 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\ViewportControl.js"
+F285 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\WatchExpressionsSidebarPane.js"
+F286 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\WorkerManager.js"
+F287 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\WorkersSidebarPane.js"
+F288 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Workspace.js"
+F289 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\WorkspaceController.js"
+F290 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\clike.js"
+F291 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\closebrackets.js"
+F292 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\cmdevtools.css"
+F293 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\codemirror.css"
+F294 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\codemirror.js"
+F295 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\coffeescript.js"
+F296 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\comment.js"
+F297 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\css.js"
+F298 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\headlesscodemirror.js"
+F299 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\htmlembedded.js"
+F300 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\htmlmixed.js"
+F301 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\javascript.js"
+F302 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\LICENSE"
+F303 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\LICENSE_python"
+F304 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\markselection.js"
+F305 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\matchbrackets.js"
+F306 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\overlay.js"
+F307 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\php.js"
+F308 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\python.js"
+F309 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\shell.js"
+F310 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\cm\\xml.js"
+F311 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\addIcon.png"
+F312 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\applicationCache.png"
+F313 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\back.png"
+F314 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpoint2.png"
+F315 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpoint2_2x.png"
+F316 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointBorder.png"
+F317 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointConditional2.png"
+F318 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointConditional2_2x.png"
+F319 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointConditionalBorder.png"
+F320 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointConditionalCounterBorder.png"
+F321 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\breakpointCounterBorder.png"
+F322 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\checker.png"
+F323 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\cookie.png"
+F324 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\database.png"
+F325 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\databaseTable.png"
+F326 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\deleteIcon.png"
+F327 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\domain.png"
+F328 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\fileSystem.png"
+F329 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\forward.png"
+F330 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\frame.png"
+F331 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\glossyHeader.png"
+F332 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\glossyHeaderPressed.png"
+F333 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\glossyHeaderSelected.png"
+F334 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\glossyHeaderSelectedPressed.png"
+F335 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\graphLabelCalloutLeft.png"
+F336 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\graphLabelCalloutRight.png"
+F337 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\indexedDB.png"
+F338 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\indexedDBIndex.png"
+F339 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\indexedDBObjectStore.png"
+F340 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\localStorage.png"
+F341 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\namedFlowOverflow.png"
+F342 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\paneAddButtons.png"
+F343 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\paneElementStateButtons.png"
+F344 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\paneFilterButtons.png"
+F345 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\paneRefreshButtons.png"
+F346 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\paneSettingsButtons.png"
+F347 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\popoverArrows.png"
+F348 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\popoverBackground.png"
+F349 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\profileGroupIcon.png"
+F350 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\profileIcon.png"
+F351 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\profileSmallIcon.png"
+F352 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\programCounterBorder.png"
+F353 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\radioDot.png"
+F354 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\regionEmpty.png"
+F355 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\regionFit.png"
+F356 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\regionOverset.png"
+F357 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourceCSSIcon.png"
+F358 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourceDocumentIcon.png"
+F359 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourceDocumentIconSmall.png"
+F360 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourceJSIcon.png"
+F361 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourcePlainIcon.png"
+F362 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourcePlainIconSmall.png"
+F363 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\resourcesTimeGraphIcon.png"
+F364 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchNext.png"
+F365 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchPrev.png"
+F366 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchSmallBlue.png"
+F367 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchSmallBrightBlue.png"
+F368 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchSmallGray.png"
+F369 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\searchSmallWhite.png"
+F370 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segment.png"
+F371 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segmentEnd.png"
+F372 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segmentHover.png"
+F373 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segmentHoverEnd.png"
+F374 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segmentSelected.png"
+F375 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\segmentSelectedEnd.png"
+F376 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\sessionStorage.png"
+F377 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\settingsListRemove.png"
+F378 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\settingsListRemove_2x.png"
+F379 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\spinner.gif"
+F380 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\spinnerActive.gif"
+F381 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\spinnerActiveSelected.gif"
+F382 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\spinnerInactive.gif"
+F383 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\spinnerInactiveSelected.gif"
+F384 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\statusbarButtonGlyphs.png"
+F385 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\statusbarButtonGlyphs2x.png"
+F386 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\statusbarResizerHorizontal.png"
+F387 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\statusbarResizerVertical.png"
+F388 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbActiveHoriz.png"
+F389 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbActiveVert.png"
+F390 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbHoriz.png"
+F391 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbHoverHoriz.png"
+F392 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbHoverVert.png"
+F393 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\thumbVert.png"
+F394 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillBlue.png"
+F395 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillGray.png"
+F396 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillGreen.png"
+F397 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillOrange.png"
+F398 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillPurple.png"
+F399 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillRed.png"
+F400 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelineHollowPillYellow.png"
+F401 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillBlue.png"
+F402 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillGray.png"
+F403 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillGreen.png"
+F404 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillOrange.png"
+F405 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillPurple.png"
+F406 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillRed.png"
+F407 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\timelinePillYellow.png"
+F408 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\toolbarItemSelected.png"
+F409 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\trackHoriz.png"
+F410 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\trackVert.png"
+F411 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\src\\breakpoints2.svg"
+F412 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\src\\settingListRemove.svg"
+F413 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\Images\\src\\statusbarButtonGlyphs.svg"
+F414 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end\\UglifyJS\\parse-js.js"
+F415 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\front-end-node\\Overrides.js"
+F416 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\BreakEventHandler.js"
+F417 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\callback.js"
+F418 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\CallFramesProvider.js"
+F419 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\config.js"
+F420 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\convert.js"
+F421 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\debug-server.js"
+F422 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\debugger.js"
+F423 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\DebuggerAgent.js"
+F424 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\DebuggerClient.js"
+F425 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\FrontendClient.js"
+F426 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\FrontendCommandHandler.js"
+F427 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\NetworkAgent.js"
+F428 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\PageAgent.js"
+F429 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\RuntimeAgent.js"
+F430 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\ScriptFileStorage.js"
+F431 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\ScriptManager.js"
+F432 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\lib\\session.js"
+F433 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\express"
+F434 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\express.cmd"
+F435 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\opener"
+F436 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\opener.cmd"
+F437 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\rc"
+F438 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\rc.cmd"
+F439 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\which"
+F440 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\which.cmd"
+F441 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\wscat"
+F442 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\.bin\\wscat.cmd"
+F443 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\async\\.travis.yml"
+F444 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\async\\component.json"
+F445 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\async\\LICENSE"
+F446 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\async\\package.json"
+F447 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\async\\lib\\async.js"
+F448 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\debug\\debug.js"
+F449 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\debug\\package.json"
+F450 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\debug\\lib\\debug.js"
+F451 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\.travis.yml"
+F452 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\index.js"
+F453 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\LICENSE"
+F454 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\package.json"
+F455 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\bin\\express"
+F456 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\application.js"
+F457 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\express.js"
+F458 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\middleware.js"
+F459 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\request.js"
+F460 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\response.js"
+F461 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\utils.js"
+F462 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\view.js"
+F463 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\router\\index.js"
+F464 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\lib\\router\\route.js"
+F465 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\.bin\\mkdirp"
+F466 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\.bin\\mkdirp.cmd"
+F467 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\.travis.yml"
+F468 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\index.js"
+F469 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\package.json"
+F470 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\buffer-crc32\\tests\\crc.test.js"
+F471 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\index.js"
+F472 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\package.json"
+F473 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\index.js"
+F474 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\package.json"
+F475 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\commander\\node_modules\\keypress\\test.js"
+F476 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\.travis.yml"
+F477 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\index.js"
+F478 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\LICENSE"
+F479 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\package.json"
+F480 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\cache.js"
+F481 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\connect.js"
+F482 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\index.js"
+F483 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\patch.js"
+F484 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\proto.js"
+F485 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\utils.js"
+F486 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\basicAuth.js"
+F487 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\bodyParser.js"
+F488 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\compress.js"
+F489 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\cookieParser.js"
+F490 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\cookieSession.js"
+F491 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\csrf.js"
+F492 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\directory.js"
+F493 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\errorHandler.js"
+F494 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\favicon.js"
+F495 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\json.js"
+F496 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\limit.js"
+F497 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\logger.js"
+F498 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\methodOverride.js"
+F499 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\multipart.js"
+F500 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\query.js"
+F501 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\responseTime.js"
+F502 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\session.js"
+F503 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\static.js"
+F504 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\staticCache.js"
+F505 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\timeout.js"
+F506 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\urlencoded.js"
+F507 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\lib\\middleware\\vhost.js"
+F508 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\.travis.yml"
+F509 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\index.js"
+F510 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\basic-auth-connect\\package.json"
+F511 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\component.json"
+F512 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\index.js"
+F513 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\bytes\\package.json"
+F514 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\.travis.yml"
+F515 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\index.js"
+F516 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\package.json"
+F517 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\component.json"
+F518 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\index.js"
+F519 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\bytes\\package.json"
+F520 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\.travis.yml"
+F521 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\bench.js"
+F522 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\index.js"
+F523 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\package.json"
+F524 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\specifications.json"
+F525 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\compressible\\test.js"
+F526 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\LICENSE"
+F527 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\package.json"
+F528 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\accept.js"
+F529 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\charset.js"
+F530 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\encoding.js"
+F531 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\examples\\language.js"
+F532 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\charset.js"
+F533 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\encoding.js"
+F534 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\language.js"
+F535 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\mediaType.js"
+F536 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\lib\\negotiator.js"
+F537 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\charset.js"
+F538 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\encoding.js"
+F539 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\language.js"
+F540 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\compression\\node_modules\\negotiator\\test\\mediaType.js"
+F541 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\.travis.yml"
+F542 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\index.js"
+F543 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\connect-timeout\\package.json"
+F544 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\index.js"
+F545 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\package.json"
+F546 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\lib\\parse.js"
+F547 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\.travis.yml"
+F548 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\index.js"
+F549 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\LICENSE"
+F550 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\package.json"
+F551 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\mocha.opts"
+F552 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\parse.js"
+F553 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\node_modules\\cookie\\test\\serialize.js"
+F554 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\cookie-parser\\test\\cookieParser.js"
+F555 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\.travis.yml"
+F556 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\index.js"
+F557 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\LICENSE"
+F558 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\package.json"
+F559 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\.travis.yml"
+F560 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\index.js"
+F561 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\package.json"
+F562 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\benchmark\\benchmark.js"
+F563 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\scmp\\test\\test.js"
+F564 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\index.js"
+F565 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\LICENSE"
+F566 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\csurf\\node_modules\\uid2\\package.json"
+F567 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\.travis.yml"
+F568 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\index.js"
+F569 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\package.json"
+F570 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\public\\error.html"
+F571 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\errorhandler\\public\\style.css"
+F572 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\index.js"
+F573 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\package.json"
+F574 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\.travis.yml"
+F575 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\index.js"
+F576 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\LICENSE"
+F577 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\package.json"
+F578 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\mocha.opts"
+F579 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\parse.js"
+F580 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\cookie\\test\\serialize.js"
+F581 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\debug.js"
+F582 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\index.js"
+F583 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\package.json"
+F584 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\debug\\lib\\debug.js"
+F585 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\index.js"
+F586 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\LICENSE"
+F587 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\uid2\\package.json"
+F588 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\.travis.yml"
+F589 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\index.js"
+F590 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\LICENSE"
+F591 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\node_modules\\utils-merge\\package.json"
+F592 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\cookie.js"
+F593 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\memory.js"
+F594 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\session.js"
+F595 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\session\\store.js"
+F596 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\express-session\\test\\session.js"
+F597 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\.travis.yml"
+F598 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\index.js"
+F599 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\method-override\\package.json"
+F600 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\index.js"
+F601 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\package.json"
+F602 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\component.json"
+F603 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\index.js"
+F604 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\morgan\\node_modules\\bytes\\package.json"
+F605 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\.jshintrc"
+F606 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\.travis.yml"
+F607 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\CHANGELOG.md"
+F608 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\index.js"
+F609 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\LICENSE"
+F610 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\package.json"
+F611 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\azureblobstorage.js"
+F612 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\s3.js"
+F613 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\examples\\upload.js"
+F614 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\duplex.js"
+F615 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\float.patch"
+F616 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\LICENSE"
+F617 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\package.json"
+F618 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\passthrough.js"
+F619 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\readable.js"
+F620 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\transform.js"
+F621 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\writable.js"
+F622 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_duplex.js"
+F623 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_passthrough.js"
+F624 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_readable.js"
+F625 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_transform.js"
+F626 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\lib\\_stream_writable.js"
+F627 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\float.patch"
+F628 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\package.json"
+F629 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\util.js"
+F630 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\core-util-is\\lib\\util.js"
+F631 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\inherits.js"
+F632 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\inherits_browser.js"
+F633 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\LICENSE"
+F634 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\package.json"
+F635 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\inherits\\test.js"
+F636 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\component.json"
+F637 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\index.js"
+F638 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\package.json"
+F639 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\isarray\\build\\build.js"
+F640 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\index.js"
+F641 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\LICENSE"
+F642 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\readable-stream\\node_modules\\string_decoder\\package.json"
+F643 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\index.js"
+F644 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\package.json"
+F645 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\test\\test.js"
+F646 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\node_modules\\stream-counter\\test\\test.txt"
+F647 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\bench-multipart-parser.js"
+F648 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\record.js"
+F649 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\test.js"
+F650 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\multipart.js"
+F651 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\multi_video.upload"
+F652 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\beta-sticker-1.png"
+F653 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\binaryfile.tar.gz"
+F654 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\blank.gif"
+F655 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\funkyfilename.txt"
+F656 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\menu_separator.png"
+F657 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\pf1y5.png"
+F658 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\file\\plain.txt"
+F659 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\beta-sticker-1.png.http"
+F660 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\binaryfile.tar.gz.http"
+F661 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\blank.gif.http"
+F662 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\menu_seperator.png.http"
+F663 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\pf1y5.png.http"
+F664 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\encoding\\plain.txt.http"
+F665 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\no-filename\\filename-name.http"
+F666 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\no-filename\\generic.http"
+F667 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\preamble\\crlf.http"
+F668 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\preamble\\preamble.http"
+F669 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\info.md"
+F670 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-chrome-13.http"
+F671 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-firefox-3.6.http"
+F672 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\osx-safari-5.http"
+F673 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-chrome-12.http"
+F674 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-ie-7.http"
+F675 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-ie-8.http"
+F676 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\special-chars-in-filename\\xp-safari-5.http"
+F677 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\workarounds\\missing-hyphens1.http"
+F678 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\http\\workarounds\\missing-hyphens2.http"
+F679 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\encoding.js"
+F680 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\no-filename.js"
+F681 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\preamble.js"
+F682 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\special-chars-in-filename.js"
+F683 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\fixture\\js\\workarounds.js"
+F684 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-connection-aborted.js"
+F685 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-content-transfer-encoding.js"
+F686 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-invalid.js"
+F687 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-15.js"
+F688 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-19.js"
+F689 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-21.js"
+F690 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-4.js"
+F691 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-46.js"
+F692 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\multiparty\\test\\standalone\\test-issue-5.js"
+F693 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\pause\\index.js"
+F694 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\pause\\package.json"
+F695 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\.gitmodules"
+F696 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\index.js"
+F697 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\qs\\package.json"
+F698 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\.travis.yml"
+F699 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\index.js"
+F700 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\raw-body\\package.json"
+F701 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\response-time\\index.js"
+F702 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\response-time\\package.json"
+F703 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\.travis.yml"
+F704 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\index.js"
+F705 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\LICENSE"
+F706 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\package.json"
+F707 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\component.json"
+F708 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\index.js"
+F709 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\batch\\package.json"
+F710 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\.travis.yml"
+F711 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\LICENSE"
+F712 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\package.json"
+F713 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\accept.js"
+F714 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\charset.js"
+F715 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\encoding.js"
+F716 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\examples\\language.js"
+F717 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\charset.js"
+F718 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\encoding.js"
+F719 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\language.js"
+F720 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\mediaType.js"
+F721 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\lib\\negotiator.js"
+F722 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\charset.js"
+F723 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\encoding.js"
+F724 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\language.js"
+F725 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\node_modules\\negotiator\\test\\mediaType.js"
+F726 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\directory.html"
+F727 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\style.css"
+F728 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\application_xp.png"
+F729 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\application_xp_terminal.png"
+F730 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\box.png"
+F731 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\cd.png"
+F732 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\controller.png"
+F733 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\drive.png"
+F734 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\film.png"
+F735 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\folder.png"
+F736 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\font.png"
+F737 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\image.png"
+F738 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\map.png"
+F739 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page.png"
+F740 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_add.png"
+F741 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_attach.png"
+F742 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_code.png"
+F743 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_copy.png"
+F744 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_delete.png"
+F745 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_edit.png"
+F746 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_error.png"
+F747 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_excel.png"
+F748 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_find.png"
+F749 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_gear.png"
+F750 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_go.png"
+F751 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_green.png"
+F752 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_key.png"
+F753 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_lightning.png"
+F754 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_link.png"
+F755 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_paintbrush.png"
+F756 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_paste.png"
+F757 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_red.png"
+F758 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_refresh.png"
+F759 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_save.png"
+F760 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white.png"
+F761 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_acrobat.png"
+F762 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_actionscript.png"
+F763 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_add.png"
+F764 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_c.png"
+F765 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_camera.png"
+F766 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cd.png"
+F767 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_code.png"
+F768 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_code_red.png"
+F769 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_coldfusion.png"
+F770 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_compressed.png"
+F771 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_copy.png"
+F772 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cplusplus.png"
+F773 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_csharp.png"
+F774 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_cup.png"
+F775 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_database.png"
+F776 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_delete.png"
+F777 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_dvd.png"
+F778 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_edit.png"
+F779 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_error.png"
+F780 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_excel.png"
+F781 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_find.png"
+F782 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_flash.png"
+F783 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_freehand.png"
+F784 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_gear.png"
+F785 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_get.png"
+F786 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_go.png"
+F787 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_h.png"
+F788 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_horizontal.png"
+F789 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_key.png"
+F790 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_lightning.png"
+F791 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_link.png"
+F792 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_magnify.png"
+F793 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_medal.png"
+F794 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_office.png"
+F795 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paint.png"
+F796 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paintbrush.png"
+F797 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_paste.png"
+F798 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_php.png"
+F799 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_picture.png"
+F800 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_powerpoint.png"
+F801 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_put.png"
+F802 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_ruby.png"
+F803 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_stack.png"
+F804 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_star.png"
+F805 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_swoosh.png"
+F806 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_text.png"
+F807 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_text_width.png"
+F808 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_tux.png"
+F809 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_vector.png"
+F810 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_visualstudio.png"
+F811 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_width.png"
+F812 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_word.png"
+F813 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_world.png"
+F814 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_wrench.png"
+F815 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_white_zip.png"
+F816 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_word.png"
+F817 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-index\\public\\icons\\page_world.png"
+F818 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\.travis.yml"
+F819 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\index.js"
+F820 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\LICENSE"
+F821 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\package.json"
+F822 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\node_modules\\parseurl\\index.js"
+F823 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\serve-static\\node_modules\\parseurl\\package.json"
+F824 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\LICENSE.txt"
+F825 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\package.json"
+F826 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\setImmediate.js"
+F827 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\runner.htm"
+F828 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\selfClose.htm"
+F829 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\tests.js"
+F830 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\worker.js"
+F831 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\lib\\qunit.css"
+F832 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\setimmediate\\qUnitTest\\lib\\qunit.js"
+F833 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\.travis.yml"
+F834 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\favicon.ico"
+F835 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\index.js"
+F836 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\LICENSE"
+F837 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\static-favicon\\package.json"
+F838 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\.travis.yml"
+F839 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\index.js"
+F840 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\connect\\node_modules\\vhost\\package.json"
+F841 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\index.js"
+F842 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\LICENSE"
+F843 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie\\package.json"
+F844 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie-signature\\index.js"
+F845 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\cookie-signature\\package.json"
+F846 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\fresh\\index.js"
+F847 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\fresh\\package.json"
+F848 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\component.json"
+F849 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\index.js"
+F850 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\merge-descriptors\\package.json"
+F851 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\methods\\index.js"
+F852 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\methods\\package.json"
+F853 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\.travis.yml"
+F854 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\index.js"
+F855 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\LICENSE"
+F856 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\package.json"
+F857 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\readme.markdown"
+F858 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\bin\\cmd.js"
+F859 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\bin\\usage.txt"
+F860 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\examples\\pow.js"
+F861 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\chmod.js"
+F862 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\clobber.js"
+F863 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\mkdirp.js"
+F864 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\perm.js"
+F865 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\perm_sync.js"
+F866 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\race.js"
+F867 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\rel.js"
+F868 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\return.js"
+F869 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\return_sync.js"
+F870 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\root.js"
+F871 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\sync.js"
+F872 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\umask.js"
+F873 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\mkdirp\\test\\umask_sync.js"
+F874 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\range-parser\\index.js"
+F875 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\range-parser\\package.json"
+F876 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\index.js"
+F877 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\package.json"
+F878 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\lib\\send.js"
+F879 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\lib\\utils.js"
+F880 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\debug.js"
+F881 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\package.json"
+F882 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\debug\\lib\\debug.js"
+F883 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\LICENSE"
+F884 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\mime.js"
+F885 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\package.json"
+F886 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\test.js"
+F887 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\types\\mime.types"
+F888 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\express\\node_modules\\send\\node_modules\\mime\\types\\node.types"
+F889 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\.travis.yml"
+F890 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\glob.js"
+F891 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\LICENSE"
+F892 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\package.json"
+F893 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\examples\\g.js"
+F894 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\examples\\usr-local.js"
+F895 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\inherits.js"
+F896 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\inherits_browser.js"
+F897 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\LICENSE"
+F898 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\package.json"
+F899 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\inherits\\test.js"
+F900 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\LICENSE"
+F901 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\minimatch.js"
+F902 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\package.json"
+F903 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\CONTRIBUTORS"
+F904 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\LICENSE"
+F905 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\package.json"
+F906 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\lib\\lru-cache.js"
+F907 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\basic.js"
+F908 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\foreach.js"
+F909 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\lru-cache\\test\\memory-leak.js"
+F910 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\bench.js"
+F911 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\LICENSE"
+F912 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\package.json"
+F913 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\sigmund.js"
+F914 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\node_modules\\sigmund\\test\\basic.js"
+F915 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\basic.js"
+F916 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\brace-expand.js"
+F917 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\caching.js"
+F918 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\defaults.js"
+F919 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\node_modules\\minimatch\\test\\extglob-ending-with-state-char.js"
+F920 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\00-setup.js"
+F921 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\bash-comparison.js"
+F922 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\bash-results.json"
+F923 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\cwd-test.js"
+F924 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\globstar-match.js"
+F925 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\mark.js"
+F926 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\new-glob-optional-options.js"
+F927 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\nocase-nomagic.js"
+F928 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\pause-resume.js"
+F929 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\readme-issue.js"
+F930 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\root-nomount.js"
+F931 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\root.js"
+F932 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\stat.js"
+F933 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\glob\\test\\zz-cleanup.js"
+F934 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\opener\\LICENSE.txt"
+F935 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\opener\\opener.js"
+F936 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\opener\\package.json"
+F937 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\browser.js"
+F938 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\index.js"
+F939 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\LICENSE.APACHE2"
+F940 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\LICENSE.BSD"
+F941 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\LICENSE.MIT"
+F942 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\package.json"
+F943 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\lib\\utils.js"
+F944 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\index.js"
+F945 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\LICENSE"
+F946 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\deep-extend\\package.json"
+F947 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\ini.js"
+F948 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\LICENSE"
+F949 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\package.json"
+F950 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\bar.js"
+F951 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\foo.js"
+F952 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\ini\\test\\fixtures\\foo.ini"
+F953 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\.travis.yml"
+F954 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\index.js"
+F955 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\LICENSE"
+F956 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\package.json"
+F957 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\readme.markdown"
+F958 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\example\\parse.js"
+F959 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\bool.js"
+F960 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\dash.js"
+F961 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\default_bool.js"
+F962 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\dotted.js"
+F963 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\long.js"
+F964 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\num.js"
+F965 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\parse.js"
+F966 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\parse_modified.js"
+F967 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\short.js"
+F968 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\node_modules\\minimist\\test\\whitespace.js"
+F969 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\test\\ini.js"
+F970 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\rc\\test\\test.js"
+F971 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.jshintrc"
+F972 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.travis.yml"
+F973 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\index.js"
+F974 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\LICENSE"
+F975 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\package.json"
+F976 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\.name"
+F977 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\data-uri.iml"
+F978 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\encodings.xml"
+F979 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\jsLibraryMappings.xml"
+F980 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\misc.xml"
+F981 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\modules.xml"
+F982 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\vcs.xml"
+F983 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\workspace.xml"
+F984 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\inspectionProfiles\\profiles_settings.xml"
+F985 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\inspectionProfiles\\Project_Default.xml"
+F986 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\jsLinters\\jshint.xml"
+F987 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\.idea\\scopes\\scope_settings.xml"
+F988 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\package.json"
+F989 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\test.js"
+F990 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\node_modules\\truncate\\truncate.js"
+F991 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\strong-data-uri\\test\\decode.js"
+F992 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\which\\LICENSE"
+F993 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\which\\package.json"
+F994 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\which\\which.js"
+F995 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\which\\bin\\which"
+F996 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\.travis.yml"
+F997 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\binding.gyp"
+F998 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\builderror.log"
+F999 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\index.js"
+F1000 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\package.json"
+F1001 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\bench\\parser.benchmark.js"
+F1002 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\bench\\sender.benchmark.js"
+F1003 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\bench\\speed.js"
+F1004 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\bench\\util.js"
+F1005 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\bin\\wscat"
+F1006 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\binding.sln"
+F1007 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\bufferutil.vcxproj"
+F1008 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\bufferutil.vcxproj.filters"
+F1009 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\config.gypi"
+F1010 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\validation.vcxproj"
+F1011 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\validation.vcxproj.filters"
+F1012 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.exp"
+F1013 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.lib"
+F1014 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.node"
+F1015 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\bufferutil.pdb"
+F1016 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.exp"
+F1017 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.lib"
+F1018 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.node"
+F1019 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\validation.pdb"
+F1020 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.lastbuildstate"
+F1021 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.obj"
+F1022 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\bufferutil.write.1.tlog"
+F1023 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\cl.command.1.tlog"
+F1024 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\CL.read.1.tlog"
+F1025 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\CL.write.1.tlog"
+F1026 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-cvtres.read.1.tlog"
+F1027 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-cvtres.write.1.tlog"
+F1028 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-rc.read.1.tlog"
+F1029 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link-rc.write.1.tlog"
+F1030 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.command.1.tlog"
+F1031 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.read.1.tlog"
+F1032 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\link.write.1.tlog"
+F1033 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\bufferutil\\vc110.pdb"
+F1034 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\cl.command.1.tlog"
+F1035 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\CL.read.1.tlog"
+F1036 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\CL.write.1.tlog"
+F1037 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-cvtres.read.1.tlog"
+F1038 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-cvtres.write.1.tlog"
+F1039 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-rc.read.1.tlog"
+F1040 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link-rc.write.1.tlog"
+F1041 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.command.1.tlog"
+F1042 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.read.1.tlog"
+F1043 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\link.write.1.tlog"
+F1044 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.lastbuildstate"
+F1045 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.obj"
+F1046 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\validation.write.1.tlog"
+F1047 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\build\\Release\\obj\\validation\\vc110.pdb"
+F1048 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\doc\\ws.md"
+F1049 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\ssl.js"
+F1050 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\package.json"
+F1051 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\server.js"
+F1052 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\app.js"
+F1053 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\index.html"
+F1054 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\fileapi\\public\\uploader.js"
+F1055 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\package.json"
+F1056 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\server.js"
+F1057 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats\\public\\index.html"
+F1058 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\package.json"
+F1059 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\server.js"
+F1060 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\examples\\serverstats-express_3\\public\\index.html"
+F1061 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\browser.js"
+F1062 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferPool.js"
+F1063 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferUtil.fallback.js"
+F1064 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\BufferUtil.js"
+F1065 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\ErrorCodes.js"
+F1066 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Receiver.hixie.js"
+F1067 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Receiver.js"
+F1068 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Sender.hixie.js"
+F1069 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Sender.js"
+F1070 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Validation.fallback.js"
+F1071 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\Validation.js"
+F1072 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\WebSocket.js"
+F1073 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\lib\\WebSocketServer.js"
+F1074 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\.travis.yml"
+F1075 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\index.js"
+F1076 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\package.json"
+F1077 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\commander\\lib\\commander.js"
+F1078 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\.index.js"
+F1079 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\LICENSE"
+F1080 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\nan.h"
+F1081 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\nan\\package.json"
+F1082 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\package.json"
+F1083 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\lib\\options.js"
+F1084 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\test\\options.test.js"
+F1085 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\options\\test\\fixtures\\test.conf"
+F1086 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\example.js"
+F1087 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\package.json"
+F1088 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\node_modules\\tinycolor\\tinycolor.js"
+F1089 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\src\\bufferutil.cc"
+F1090 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\src\\validation.cc"
+F1091 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\autobahn-server.js"
+F1092 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\autobahn.js"
+F1093 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\BufferPool.test.js"
+F1094 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\hybi-common.js"
+F1095 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\Receiver.hixie.test.js"
+F1096 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\Receiver.test.js"
+F1097 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\Sender.hixie.test.js"
+F1098 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\Sender.test.js"
+F1099 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\testserver.js"
+F1100 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\Validation.test.js"
+F1101 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocket.integration.js"
+F1102 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocket.test.js"
+F1103 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\WebSocketServer.test.js"
+F1104 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\agent1-cert.pem"
+F1105 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\agent1-key.pem"
+F1106 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\ca1-cert.pem"
+F1107 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\ca1-key.pem"
+F1108 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\certificate.pem"
+F1109 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\key.pem"
+F1110 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\request.pem"
+F1111 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\ws\\test\\fixtures\\textfile"
+F1112 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\.travis.yml"
+F1113 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\index.js"
+F1114 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\LICENSE"
+F1115 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\package.json"
+F1116 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\bool.js"
+F1117 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\boolean_double.js"
+F1118 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\boolean_single.js"
+F1119 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\count.js"
+F1120 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\default_hash.js"
+F1121 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\default_singles.js"
+F1122 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\demand_count.js"
+F1123 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\divide.js"
+F1124 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\implies.js"
+F1125 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\implies_hash.js"
+F1126 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count.js"
+F1127 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count_options.js"
+F1128 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\line_count_wrap.js"
+F1129 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\nonopt.js"
+F1130 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\short.js"
+F1131 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\string.js"
+F1132 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\usage-options.js"
+F1133 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\example\\xup.js"
+F1134 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\lib\\minimist.js"
+F1135 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\lib\\wordwrap.js"
+F1136 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\.travis.yml"
+F1137 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\index.js"
+F1138 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\LICENSE"
+F1139 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\package.json"
+F1140 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\readme.markdown"
+F1141 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\example\\parse.js"
+F1142 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\bool.js"
+F1143 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\dash.js"
+F1144 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\default_bool.js"
+F1145 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\dotted.js"
+F1146 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\long.js"
+F1147 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\num.js"
+F1148 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\parse.js"
+F1149 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\parse_modified.js"
+F1150 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\short.js"
+F1151 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\node_modules\\minimist\\test\\whitespace.js"
+F1152 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\config.json"
+F1153 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\count.js"
+F1154 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\dash.js"
+F1155 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\mocha.opts"
+F1156 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\parse.js"
+F1157 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\parse_modified.js"
+F1158 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\short.js"
+F1159 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\usage.js"
+F1160 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\whitespace.js"
+F1161 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\_.js"
+F1162 DEBUGGERFILE "node-inspector-0.7.3\\node_modules\\node-inspector\\node_modules\\yargs\\test\\_\\bin.js"
diff --git a/src/iisnode/iisnode-inspector-0.7.3.def b/src/iisnode/iisnode-inspector-0.7.3.def
new file mode 100644
index 00000000..15b3d4a1
--- /dev/null
+++ b/src/iisnode/iisnode-inspector-0.7.3.def
@@ -0,0 +1,3 @@
+LIBRARY	"iisnode-inspector-0.7.3"
+
+EXPORTS
diff --git a/src/iisnode/iisnode-inspector-0.7.3.vcxproj b/src/iisnode/iisnode-inspector-0.7.3.vcxproj
new file mode 100644
index 00000000..c4f3661d
--- /dev/null
+++ b/src/iisnode/iisnode-inspector-0.7.3.vcxproj
@@ -0,0 +1,199 @@
+
+
+  
+    
+      Debug
+      Win32
+    
+    
+      Debug
+      x64
+    
+    
+      Release
+      Win32
+    
+    
+      Release
+      x64
+    
+  
+  
+    iisnode-inspector-0.7.3
+    {79D88BF0-FD48-49C6-8CFD-F6B3605378B3}
+    iisnode-inspector-0.7.3
+  
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+  
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+  
+    <_ProjectFileVersion>10.0.30319.1
+    $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    AllRules.ruleset
+    AllRules.ruleset
+    
+    
+    
+    
+    AllRules.ruleset
+    AllRules.ruleset
+    
+    
+    
+    
+    $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+    $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\
+  
+  
+    
+      Disabled
+      %(AdditionalIncludeDirectories)
+      WIN32;%(PreprocessorDefinitions)
+      Use
+      precomp-inspector.h
+      $(IntDir)$(TargetName).pch
+      ProgramDatabase
+    
+    
+      iisnode-inspector-0.7.3.def
+      true
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genDebuggerRc-0.7.3.bat" > "$(ProjectDir)\debugger_autogenerated_0.7.3.rc"
+    
+    
+      copy /y $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\iisnode-inspector-0.7.3.dll $(SolutionDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+  
+  
+    
+      Disabled
+      %(AdditionalIncludeDirectories)
+      WIN64;%(PreprocessorDefinitions)
+      Use
+      precomp-inspector.h
+      $(IntDir)$(TargetName).pch
+      ProgramDatabase
+    
+    
+      iisnode-inspector-0.7.3.def
+      true
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genDebuggerRc-0.7.3.bat" > "$(ProjectDir)\debugger_autogenerated_0.7.3.rc"
+    
+    
+      copy /y $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\iisnode-inspector-0.7.3.dll $(SolutionDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+  
+  
+    
+      WIN32;%(PreprocessorDefinitions)
+    
+    
+      iisnode-inspector-0.7.3.def
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genDebuggerRc-0.7.3.bat" > "$(ProjectDir)\debugger_autogenerated_0.7.3.rc"
+    
+    
+      copy /y $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\iisnode-inspector-0.7.3.dll $(SolutionDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+  
+  
+    
+      WIN64;%(PreprocessorDefinitions)
+    
+    
+      iisnode-inspector-0.7.3.def
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genDebuggerRc-0.7.3.bat" > "$(ProjectDir)\debugger_autogenerated_0.7.3.rc"
+    
+    
+      copy /y $(SolutionDir)iisnode-inspector-0.7.3\$(Configuration)\$(PlatformShortName)\iisnode-inspector-0.7.3.dll $(SolutionDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+  
+  
+    
+    
+      Create
+      Create
+    
+    
+  
+  
+    
+  
+  
+    
+  
+  
+  
+  
+  
+    
+    
+  
+  
+    BuildWow64;$(BuildDependsOn)
+  
+  
+    
+    
+  
+  
+    BuildWow64;$(BuildDependsOn)
+  
+
\ No newline at end of file
diff --git a/src/iisnode/iisnode.sln b/src/iisnode/iisnode.sln
index ca4f6c07..38c0d455 100644
--- a/src/iisnode/iisnode.sln
+++ b/src/iisnode/iisnode.sln
@@ -1,67 +1,107 @@
-
-Microsoft Visual Studio Solution File, Format Version 11.00
-# Visual Studio 2010
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisnode", "iisnode.vcxproj", "{D1F7201F-064B-48AB-868C-FED22464841C}"
-	ProjectSection(ProjectDependencies) = postProject
-		{D1F7201F-064B-48AB-868C-FED22464841D} = {D1F7201F-064B-48AB-868C-FED22464841D}
-	EndProjectSection
-EndProject
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-express-msi", "..\setup\iisnode-express-msi\iisnode-express-msi.wixproj", "{36D6E303-E057-4963-A093-C7AAE0FD92B3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisnode-inspector", "iisnode-inspector.vcxproj", "{D1F7201F-064B-48AB-868C-FED22464841D}"
-EndProject
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-msi-core", "..\setup\iisnode-msi\iisnode-msi-core.wixproj", "{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}"
-EndProject
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-msi-full", "..\setup\iisnode-msi\iisnode-msi-full.wixproj", "{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}"
-EndProject
-Global
-	GlobalSection(SolutionConfigurationPlatforms) = preSolution
-		Debug|Win32 = Debug|Win32
-		Debug|x64 = Debug|x64
-		Release|Win32 = Release|Win32
-		Release|x64 = Release|x64
-	EndGlobalSection
-	GlobalSection(ProjectConfigurationPlatforms) = postSolution
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Win32.Build.0 = Debug|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|x64.ActiveCfg = Debug|x64
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|x64.Build.0 = Debug|x64
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Win32.ActiveCfg = Release|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Win32.Build.0 = Release|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|x64.ActiveCfg = Release|x64
-		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|x64.Build.0 = Release|x64
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Win32.ActiveCfg = Debug|x86
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Win32.Build.0 = Debug|x86
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|x64.ActiveCfg = Debug|x86
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Win32.ActiveCfg = Release|x86
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Win32.Build.0 = Release|x86
-		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|x64.ActiveCfg = Release|x86
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Win32.ActiveCfg = Debug|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Win32.Build.0 = Debug|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|x64.ActiveCfg = Debug|x64
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|x64.Build.0 = Debug|x64
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Win32.ActiveCfg = Release|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Win32.Build.0 = Release|Win32
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|x64.ActiveCfg = Release|x64
-		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|x64.Build.0 = Release|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Win32.ActiveCfg = Debug|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Win32.Build.0 = Debug|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|x64.ActiveCfg = Debug|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|x64.Build.0 = Debug|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Win32.ActiveCfg = Release|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Win32.Build.0 = Release|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|x64.ActiveCfg = Release|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|x64.Build.0 = Release|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Win32.ActiveCfg = Debug|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Win32.Build.0 = Debug|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|x64.ActiveCfg = Debug|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|x64.Build.0 = Debug|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Win32.ActiveCfg = Release|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Win32.Build.0 = Release|x86
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|x64.ActiveCfg = Release|x64
-		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|x64.Build.0 = Release|x64
-	EndGlobalSection
-	GlobalSection(SolutionProperties) = preSolution
-		HideSolutionNode = FALSE
-	EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisnode", "iisnode.vcxproj", "{D1F7201F-064B-48AB-868C-FED22464841C}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D1F7201F-064B-48AB-868C-FED22464841D} = {D1F7201F-064B-48AB-868C-FED22464841D}
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3} = {79D88BF0-FD48-49C6-8CFD-F6B3605378B3}
+	EndProjectSection
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-express-msi", "..\setup\iisnode-express-msi\iisnode-express-msi.wixproj", "{36D6E303-E057-4963-A093-C7AAE0FD92B3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisnode-inspector", "iisnode-inspector.vcxproj", "{D1F7201F-064B-48AB-868C-FED22464841D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "iisnode-inspector-0.7.3", "iisnode-inspector-0.7.3.vcxproj", "{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}"
+	ProjectSection(ProjectDependencies) = postProject
+		{D1F7201F-064B-48AB-868C-FED22464841D} = {D1F7201F-064B-48AB-868C-FED22464841D}
+	EndProjectSection
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-msi-core", "..\setup\iisnode-msi\iisnode-msi-core.wixproj", "{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}"
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "iisnode-msi-full", "..\setup\iisnode-msi\iisnode-msi-full.wixproj", "{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Mixed Platforms = Debug|Mixed Platforms
+		Debug|Win32 = Debug|Win32
+		Debug|x64 = Debug|x64
+		Release|Mixed Platforms = Release|Mixed Platforms
+		Release|Win32 = Release|Win32
+		Release|x64 = Release|x64
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|Win32.Build.0 = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|x64.ActiveCfg = Debug|x64
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Debug|x64.Build.0 = Debug|x64
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Win32.ActiveCfg = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|Win32.Build.0 = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|x64.ActiveCfg = Release|x64
+		{D1F7201F-064B-48AB-868C-FED22464841C}.Release|x64.Build.0 = Release|x64
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Win32.ActiveCfg = Debug|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|Win32.Build.0 = Debug|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Debug|x64.ActiveCfg = Debug|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Mixed Platforms.Build.0 = Release|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Win32.ActiveCfg = Release|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|Win32.Build.0 = Release|x86
+		{36D6E303-E057-4963-A093-C7AAE0FD92B3}.Release|x64.ActiveCfg = Release|x86
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Win32.ActiveCfg = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|Win32.Build.0 = Debug|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|x64.ActiveCfg = Debug|x64
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Debug|x64.Build.0 = Debug|x64
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Win32.ActiveCfg = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|Win32.Build.0 = Release|Win32
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|x64.ActiveCfg = Release|x64
+		{D1F7201F-064B-48AB-868C-FED22464841D}.Release|x64.Build.0 = Release|x64
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|Win32.ActiveCfg = Debug|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|Win32.Build.0 = Debug|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|x64.ActiveCfg = Debug|x64
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Debug|x64.Build.0 = Debug|x64
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|Mixed Platforms.Build.0 = Release|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|Win32.ActiveCfg = Release|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|Win32.Build.0 = Release|Win32
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|x64.ActiveCfg = Release|x64
+		{79D88BF0-FD48-49C6-8CFD-F6B3605378B3}.Release|x64.Build.0 = Release|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Win32.ActiveCfg = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|Win32.Build.0 = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|x64.ActiveCfg = Debug|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Debug|x64.Build.0 = Debug|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Mixed Platforms.Build.0 = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Win32.ActiveCfg = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|Win32.Build.0 = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|x64.ActiveCfg = Release|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94B}.Release|x64.Build.0 = Release|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Mixed Platforms.ActiveCfg = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Mixed Platforms.Build.0 = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Win32.ActiveCfg = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|Win32.Build.0 = Debug|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|x64.ActiveCfg = Debug|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Debug|x64.Build.0 = Debug|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Mixed Platforms.ActiveCfg = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Mixed Platforms.Build.0 = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Win32.ActiveCfg = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|Win32.Build.0 = Release|x86
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|x64.ActiveCfg = Release|x64
+		{E2C84D6A-20EA-48A8-858E-BDD64D98A94C}.Release|x64.Build.0 = Release|x64
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/src/iisnode/iisnode.vcxproj b/src/iisnode/iisnode.vcxproj
index 12d620c7..4b267b39 100644
--- a/src/iisnode/iisnode.vcxproj
+++ b/src/iisnode/iisnode.vcxproj
@@ -1,103 +1,103 @@
-
-
-  
-    
-      Debug
-      Win32
-    
-    
-      Debug
-      x64
-    
-    
-      Release
-      Win32
-    
-    
-      Release
-      x64
-    
-  
-  
-    iisnode
-    {D1F7201F-064B-48AB-868C-FED22464841C}
-    IIS7NativeModule
-  
-  
-  
-    DynamicLibrary
-    v110
-  
-  
-    DynamicLibrary
-    v110
-  
-  
-    DynamicLibrary
-    v110
-  
-  
-    DynamicLibrary
-    v110
-  
-  
-  
-  
-  
-    
-  
-  
-    
-  
-  
-    
-  
-  
-    
-  
-  
-  
-    <_ProjectFileVersion>10.0.30319.1
-    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
-    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
-    $(Configuration)\$(PlatformShortName)\
-    $(Configuration)\$(PlatformShortName)\
-    $(Configuration)\$(PlatformShortName)\
-    $(Configuration)\$(PlatformShortName)\
-    AllRules.ruleset
-    AllRules.ruleset
-    
-    
-    
-    
-    AllRules.ruleset
-    AllRules.ruleset
-    
-    
-    
-    
-    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
-    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
-  
-  
-    
-      Disabled
-      %(AdditionalIncludeDirectories)
-      PSAPI_VERSION=1;WIN32;%(PreprocessorDefinitions)
-      Use
-      precomp.h
-      $(IntDir)$(TargetName).pch
-      ProgramDatabase
-      MultiThreaded
-    
-    
-      iisnode.def
-      true
-      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
-      
-      
-    
-    
+
+
+  
+    
+      Debug
+      Win32
+    
+    
+      Debug
+      x64
+    
+    
+      Release
+      Win32
+    
+    
+      Release
+      x64
+    
+  
+  
+    iisnode
+    {D1F7201F-064B-48AB-868C-FED22464841C}
+    IIS7NativeModule
+  
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+    DynamicLibrary
+    v110
+  
+  
+  
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+    
+  
+  
+  
+    <_ProjectFileVersion>10.0.30319.1
+    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
+    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
+    $(Configuration)\$(PlatformShortName)\
+    $(Configuration)\$(PlatformShortName)\
+    $(Configuration)\$(PlatformShortName)\
+    $(Configuration)\$(PlatformShortName)\
+    AllRules.ruleset
+    AllRules.ruleset
+    
+    
+    
+    
+    AllRules.ruleset
+    AllRules.ruleset
+    
+    
+    
+    
+    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
+    $(SolutionDir)$(Configuration)\$(PlatformShortName)\
+  
+  
+    
+      Disabled
+      %(AdditionalIncludeDirectories)
+      PSAPI_VERSION=1;WIN32;%(PreprocessorDefinitions)
+      Use
+      precomp.h
+      $(IntDir)$(TargetName).pch
+      ProgramDatabase
+      MultiThreaded
+    
+    
+      iisnode.def
+      true
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
+      
+      
+    
+    
       del /q $(ProjectDir)\..\..\build\$(Configuration)\iisnode.*
 del /q $(ProjectDir)\..\..\build\$(Configuration)\license.txt
 del /q $(ProjectDir)\..\..\build\$(Configuration)\readme.md
@@ -107,34 +107,34 @@ copy /y $(ProjectDir)\..\..\readme.md $(ProjectDir)\..\..\build\$(Configuration)
 copy /y $(OutDir)\iisnode.dll $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(OutDir)\iisnode.pdb $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(ProjectDir)\..\scripts\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-    
-    
-      $(IntDir)\$(MSBuildProjectName).log
-    
-    
-      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
-    
-  
-  
-    
-      Disabled
-      %(AdditionalIncludeDirectories)
-      PSAPI_VERSION=1;WIN64;%(PreprocessorDefinitions)
-      Use
-      precomp.h
-      $(IntDir)$(TargetName).pch
-      ProgramDatabase
-      MultiThreaded
-    
-    
-      iisnode.def
-      true
-      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
-      
-      
-    
-    
+copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
+    
+  
+  
+    
+      Disabled
+      %(AdditionalIncludeDirectories)
+      PSAPI_VERSION=1;WIN64;%(PreprocessorDefinitions)
+      Use
+      precomp.h
+      $(IntDir)$(TargetName).pch
+      ProgramDatabase
+      MultiThreaded
+    
+    
+      iisnode.def
+      true
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
+      
+      
+    
+    
       del /q $(ProjectDir)\..\..\build\$(Configuration)\iisnode.*
 del /q $(ProjectDir)\..\..\build\$(Configuration)\license.txt
 del /q $(ProjectDir)\..\..\build\$(Configuration)\readme.md
@@ -144,28 +144,28 @@ copy /y $(ProjectDir)\..\..\readme.md $(ProjectDir)\..\..\build\$(Configuration)
 copy /y $(OutDir)\iisnode.dll $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(OutDir)\iisnode.pdb $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(ProjectDir)\..\scripts\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-    
-    
-      $(IntDir)\$(MSBuildProjectName).log
-    
-    
-      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
-    
-  
-  
-    
-      PSAPI_VERSION=1;WIN32;%(PreprocessorDefinitions)
-      MultiThreaded
-    
-    
-      iisnode.def
-      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
-      true
-      
-      
-    
-    
+copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
+    
+  
+  
+    
+      PSAPI_VERSION=1;WIN32;%(PreprocessorDefinitions)
+      MultiThreaded
+    
+    
+      iisnode.def
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
+      true
+      
+      
+    
+    
       del /q $(ProjectDir)\..\..\build\$(Configuration)\iisnode.*
 del /q $(ProjectDir)\..\..\build\$(Configuration)\license.txt
 del /q $(ProjectDir)\..\..\build\$(Configuration)\readme.md
@@ -175,28 +175,28 @@ copy /y $(ProjectDir)\..\..\readme.md $(ProjectDir)\..\..\build\$(Configuration)
 copy /y $(OutDir)\iisnode.dll $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(OutDir)\iisnode.pdb $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(ProjectDir)\..\scripts\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-    
-    
-      $(IntDir)\$(MSBuildProjectName).log
-    
-    
-      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
-    
-  
-  
-    
-      PSAPI_VERSION=1;WIN64;%(PreprocessorDefinitions)
-      MultiThreaded
-    
-    
-      iisnode.def
-      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
-      true
-      
-      
-    
-    
+copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
+    
+  
+  
+    
+      PSAPI_VERSION=1;WIN64;%(PreprocessorDefinitions)
+      MultiThreaded
+    
+    
+      iisnode.def
+      rpcrt4.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;psapi.lib;%(AdditionalDependencies)
+      true
+      
+      
+    
+    
       del /q $(ProjectDir)\..\..\build\$(Configuration)\iisnode.*
 del /q $(ProjectDir)\..\..\build\$(Configuration)\license.txt
 del /q $(ProjectDir)\..\..\build\$(Configuration)\readme.md
@@ -206,261 +206,263 @@ copy /y $(ProjectDir)\..\..\readme.md $(ProjectDir)\..\..\build\$(Configuration)
 copy /y $(OutDir)\iisnode.dll $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(OutDir)\iisnode.pdb $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
 copy /y $(ProjectDir)\..\scripts\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
-    
-    
-      $(IntDir)\$(MSBuildProjectName).log
-    
-    
-      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-      Create
-      Create
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-      Designer
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-      Designer
-    
-    
-    
-    
-    
-    
-      Designer
-    
-    
-      Designer
-    
-    
-    
-    
-      true
-    
-    
-    
-    
-      true
-    
-    
-    
-    
-      true
-    
-    
-    
-    
-      true
-    
-    
-    
-      true
-    
-    
-    
-      true
-    
-    
-    
-    
-      true
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-  
-  
-    
-  
-  
-  
-  
-  
-    
-    
-  
-  
-    BuildWow64;$(BuildDependsOn)
-    false
-    false
-    false
-    false
-  
+copy /y $(ProjectDir)\..\config\* $(ProjectDir)\..\..\build\$(Configuration)\$(PlatformShortName)
+    
+    
+      $(IntDir)\$(MSBuildProjectName).log
+    
+    
+      call "$(ProjectDir)\scripts\genVersionHeader.bat" > "$(ProjectDir)\version_autogenerated.h"
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+      Create
+      Create
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+      Designer
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+      Designer
+    
+    
+    
+    
+    
+    
+      Designer
+    
+    
+      Designer
+    
+    
+    
+    
+      true
+    
+    
+    
+    
+      true
+    
+    
+    
+    
+      true
+    
+    
+    
+    
+      true
+    
+    
+    
+      true
+    
+    
+    
+      true
+    
+    
+    
+    
+      true
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+  
+  
+    
+  
+  
+  
+  
+  
+    
+    
+  
+  
+    BuildWow64;$(BuildDependsOn)
+    false
+    false
+    false
+    false
+  
 
\ No newline at end of file
diff --git a/src/iisnode/iisnode.vcxproj.filters b/src/iisnode/iisnode.vcxproj.filters
index a791ff65..aff6aaac 100644
--- a/src/iisnode/iisnode.vcxproj.filters
+++ b/src/iisnode/iisnode.vcxproj.filters
@@ -1,787 +1,793 @@
-
-
-  
-    
-      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
-      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
-    
-    
-      {93995380-89BD-4b04-88EB-625FBE52EBFB}
-      h;hpp;hxx;hm;inl;inc;xsd
-    
-    
-      {2b36376a-4b5a-424d-a0b0-6c8d3da4fb72}
-    
-    
-      {3618da7b-2bb0-4a0a-a4b4-2832b6311a4c}
-    
-    
-      {48ac4939-8c79-4589-a6d3-666e7beb2dae}
-    
-    
-      {a03bb42f-f23f-4af6-93e8-998401231a7d}
-    
-    
-      {43f3d8e0-aecd-4f50-8d4e-37998bb1e257}
-    
-    
-      {f07a5931-154f-4980-a9ed-245f530c1110}
-    
-    
-      {08cdec16-3583-4ae0-8fd2-2ae9209a9f27}
-    
-    
-      {ef0693b6-03e4-4dd5-9871-95e7ebdad97a}
-    
-    
-      {c2b92f3e-7cfe-4356-93eb-5ea1aedc7a23}
-    
-    
-      {b9c8fafc-d71f-4060-b14b-fe9218b2a0d7}
-    
-    
-      {78694b12-f339-40b1-b5ff-1ba72d430f6e}
-    
-    
-      {0f89b7c4-dc5b-490f-93c8-1b992c568a62}
-    
-    
-      {6ce18280-2588-47d7-ac4b-2940b30ae9fc}
-    
-    
-      {3cf35ea1-e79e-4005-80c2-83de193d43d7}
-    
-    
-      {1e33b6a1-9db3-4e09-b02d-2fc269243dd8}
-    
-    
-      {c8e343a1-df1c-4683-a1a7-d85206b36862}
-    
-    
-      {c48f575c-4e53-4e0e-88ae-da27ebe4589d}
-    
-    
-      {82399d26-206c-4d05-8815-34655e5d5079}
-    
-    
-      {0e9835dc-cb6d-4014-8ffb-b9e35b05160a}
-    
-    
-      {368ed79c-099f-4196-bc66-4ce324df08cb}
-    
-    
-      {053097ae-c9f4-4c00-8a31-a2c83ea57b14}
-    
-    
-      {eabfd5d6-7e45-439a-90c1-fd0f7ed538a1}
-    
-    
-      {f69631ee-6910-4fa3-9e6f-36786970c51e}
-    
-    
-      {cc6d4108-5cc9-4576-adf4-6ddc7d186998}
-    
-    
-      {f56c1f46-66cb-4585-adde-0ae7b04c5ee4}
-    
-    
-      {babb03c5-c688-4393-beaa-65f34782c77c}
-    
-    
-      {b806867c-572b-4438-a6d4-7d24825fc492}
-    
-    
-      {2d285139-9862-4a82-be6a-768c87f19c20}
-    
-    
-      {5df8227d-9e97-4693-a70e-82e98c6bd301}
-    
-    
-      {4242898e-a656-4ae5-bc35-eb202a42a304}
-    
-    
-      {7409b3df-834a-45c3-a74b-79719f9e60cc}
-    
-    
-      {0fe4a6c4-1e40-4914-ab19-ee48a4084e5c}
-    
-    
-      {6b173a34-4fbb-49ac-9e03-33cde5a6e50f}
-    
-    
-      {5e0f95ef-1256-4223-a412-f5146a7713cc}
-    
-    
-      {994959e7-12c0-43f7-a10b-24899813a857}
-    
-    
-      {500f40cf-c2f5-4264-b061-b4f1e59f50f5}
-    
-    
-      {ac86a901-4e59-4b58-82ce-a7674d8c587c}
-    
-    
-      {dd3b1edf-b406-49ff-988a-4b417fe9ce3c}
-    
-    
-      {4595469d-4085-4631-836b-08584244a9e7}
-    
-    
-      {39ff35f2-9b08-4689-8185-a10773c03ab0}
-    
-    
-      {53a23746-6411-4600-8315-bc8a1b2120da}
-    
-    
-      {53b5e674-69d5-4bae-9629-49cd8b7c7c45}
-    
-    
-      {18d24dd3-6582-41ad-856d-949ed0626792}
-    
-    
-      {ebde3d11-88f9-44b3-ba68-1752293b7729}
-    
-    
-      {e8b955a6-1062-48cf-8799-e5481a1c759b}
-    
-    
-      {11747cf2-9384-4591-992e-4bc85c6fe7c8}
-    
-    
-      {3ed37931-60f3-4898-98ac-01d5b0b19b07}
-    
-    
-      {43a77b03-30e9-4377-9dcd-a8bbcb255b5a}
-    
-    
-      {c186f452-9528-4731-97e6-f9a3d797bb10}
-    
-    
-      {e5dade76-fb92-4baa-a16b-41d7df056829}
-    
-    
-      {8b577c52-0888-4778-8c01-308bf573cb77}
-    
-    
-      {2081befc-0e1b-498c-b3ca-056e0c37305b}
-    
-    
-      {44ee30b6-3875-4e2d-99f0-f9e5cf6b38ac}
-    
-    
-      {d55c12ae-4311-4695-855b-76a504d76888}
-    
-    
-      {c9b72a3c-ca3e-48a9-90a0-d86d681918fa}
-    
-  
-  
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-    
-      Source Files
-    
-  
-  
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-    
-      Header Files
-    
-  
-  
-    
-      Source Files
-    
-    
-      Config
-    
-    
-      Samples\helloworld
-    
-    
-      Samples\helloworld
-    
-    
-      Samples\defaultdocument
-    
-    
-      Samples\defaultdocument
-    
-    
-      Samples\logging
-    
-    
-      Samples\logging
-    
-    
-      Samples\configuration
-    
-    
-      Samples
-    
-    
-      Samples\configuration
-    
-    
-      Samples\express
-    
-    
-      Samples\express
-    
-    
-      Samples\urlrewrite
-    
-    
-      Samples\urlrewrite
-    
-    
-      Samples\urlrewrite
-    
-    
-      Samples\helloworld
-    
-    
-      Samples\configuration
-    
-    
-      Samples\defaultdocument
-    
-    
-      Samples\logging
-    
-    
-      Samples\express
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\100_helloworld
-    
-    
-      Tests\functional\www\100_helloworld
-    
-    
-      Tests\functional\tests\node_modules
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\101_helloworld_sequence
-    
-    
-      Tests\functional\www\101_helloworld_sequence
-    
-    
-      Tests\functional\www\102_defaultdocument
-    
-    
-      Tests\functional\www\102_defaultdocument
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\103_urlrewrite
-    
-    
-      Tests\functional\www\103_urlrewrite
-    
-    
-      Tests\functional
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests\parts
-    
-    
-      Tests\functional\www\104_echo
-    
-    
-      Tests\functional\www\104_echo
-    
-    
-      Tests\functional\www\105_logging
-    
-    
-      Tests\functional\www\105_logging
-    
-    
-      Tests\functional\www\106_autoupdate
-    
-    
-      Tests\functional\www\106_autoupdate
-    
-    
-      Tests\functional\www\106_autoupdate
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests\parts
-    
-    
-      Tests\functional\tests\parts
-    
-    
-      Tests\functional\scripts
-    
-    
-      Tests\functional\scripts
-    
-    
-      Scripts
-    
-    
-      Config
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\107_filesystem
-    
-    
-      Tests\functional\www\107_filesystem
-    
-    
-      Tests\functional\www\107_filesystem
-    
-    
-      Tests\functional\www\108_appsettings
-    
-    
-      Tests\functional\www\108_appsettings
-    
-    
-      Tests\functional\tests
-    
-    
-      Scripts
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\110_log_size_quota
-    
-    
-      Tests\functional\www\110_log_size_quota
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\111_node_env
-    
-    
-      Tests\functional\www\111_node_env
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\112_dev_errors\off
-    
-    
-      Tests\functional\www\112_dev_errors\off
-    
-    
-      Tests\functional\www\112_dev_errors\on
-    
-    
-      Tests\functional\www\112_dev_errors\on
-    
-    
-      Tests\performance
-    
-    
-      Tests\performance
-    
-    
-      Tests\performance
-    
-    
-      Tests\performance\www\default
-    
-    
-      Tests\performance\www\default
-    
-    
-      Tests\performance\www\default
-    
-    
-      Tests\performance
-    
-    
-      Tests\functional\www\113_encoding
-    
-    
-      Tests\functional\www\113_encoding
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\115_customheaders
-    
-    
-      Tests\functional\www\115_customheaders
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\116_configerror
-    
-    
-      Tests\functional\www\116_configerror
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests\parts
-    
-    
-      Tests\functional\tests\parts
-    
-    
-      Tests\functional\www\117_autoupdate_dependency
-    
-    
-      Tests\functional\www\117_autoupdate_dependency
-    
-    
-      Tests\functional\www\117_autoupdate_dependency
-    
-    
-      Tests\functional\www\117_autoupdate_dependency
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\118_xff
-    
-    
-      Tests\functional\www\118_xff
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\119_servervars
-    
-    
-      Tests\functional\www\119_servervars
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\120_dev_errors_exception
-    
-    
-      Tests\functional\www\120_dev_errors_exception
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\121_watchedFiles
-    
-    
-      Tests\functional\www\121_watchedFiles
-    
-    
-      Tests\functional\www\122_multipleResponseHeaders
-    
-    
-      Tests\functional\www\122_multipleResponseHeaders
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\123_upload
-    
-    
-      Tests\functional\www\123_upload
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\124_node_config_override
-    
-    
-      Tests\functional\www\124_node_config_override
-    
-    
-      Tests\functional\www\125_node_config_autoupdate
-    
-    
-      Tests\functional\www\125_node_config_autoupdate
-    
-    
-      Tests\functional\www\125_node_config_autoupdate
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\126_node_config_syntax
-    
-    
-      Tests\functional\www\126_node_config_syntax
-    
-    
-      Tests\functional\www\126_node_config_syntax
-    
-    
-      Tests\functional\tests
-    
-    
-      Samples\configuration
-    
-    
-      Tests\functional\www\124_node_config_override
-    
-    
-      Scripts
-    
-    
-      Scripts
-    
-    
-      Config
-    
-    
-      Config
-    
-    
-      Config
-    
-    
-      Config
-    
-    
-      Config
-    
-    
-      Tests\functional\www\130_websocket_onetwothree
-    
-    
-      Tests\functional\www\130_websocket_onetwothree
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\131_websocket_echo
-    
-    
-      Tests\functional\www\131_websocket_echo
-    
-    
-      Tests\functional\www\132_debug_header
-    
-    
-      Tests\functional\www\132_debug_header
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\stress\130_websocket_chat
-    
-    
-      Tests\stress\130_websocket_chat
-    
-    
-      Tests\stress\130_websocket_chat
-    
-    
-      Tests\stress\131_websocket_connections
-    
-    
-      Tests\stress\131_websocket_connections
-    
-    
-      Tests\stress\131_websocket_connections
-    
-    
-      Tests\stress\131_websocket_connections
-    
-    
-      Tests\stress\130_websocket_chat
-    
-    
-      Tests\stress\132_websocket_latency
-    
-    
-      Tests\stress\132_websocket_latency
-    
-    
-      Tests\stress\132_websocket_latency
-    
-    
-      Tests\stress\132_websocket_latency
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\140_large_download
-    
-    
-      Tests\functional\www\140_large_download
-    
-    
-      Tests\functional\tests
-    
-    
-      Tests\functional\www\141_large_upload
-    
-    
-      Tests\functional\www\141_large_upload
-    
-    
-      Tests\functional\tests
-    
-  
-  
-    
-  
+
+
+  
+    
+      {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+      cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+    
+    
+      {93995380-89BD-4b04-88EB-625FBE52EBFB}
+      h;hpp;hxx;hm;inl;inc;xsd
+    
+    
+      {2b36376a-4b5a-424d-a0b0-6c8d3da4fb72}
+    
+    
+      {3618da7b-2bb0-4a0a-a4b4-2832b6311a4c}
+    
+    
+      {48ac4939-8c79-4589-a6d3-666e7beb2dae}
+    
+    
+      {a03bb42f-f23f-4af6-93e8-998401231a7d}
+    
+    
+      {43f3d8e0-aecd-4f50-8d4e-37998bb1e257}
+    
+    
+      {f07a5931-154f-4980-a9ed-245f530c1110}
+    
+    
+      {08cdec16-3583-4ae0-8fd2-2ae9209a9f27}
+    
+    
+      {ef0693b6-03e4-4dd5-9871-95e7ebdad97a}
+    
+    
+      {c2b92f3e-7cfe-4356-93eb-5ea1aedc7a23}
+    
+    
+      {b9c8fafc-d71f-4060-b14b-fe9218b2a0d7}
+    
+    
+      {78694b12-f339-40b1-b5ff-1ba72d430f6e}
+    
+    
+      {0f89b7c4-dc5b-490f-93c8-1b992c568a62}
+    
+    
+      {6ce18280-2588-47d7-ac4b-2940b30ae9fc}
+    
+    
+      {3cf35ea1-e79e-4005-80c2-83de193d43d7}
+    
+    
+      {1e33b6a1-9db3-4e09-b02d-2fc269243dd8}
+    
+    
+      {c8e343a1-df1c-4683-a1a7-d85206b36862}
+    
+    
+      {c48f575c-4e53-4e0e-88ae-da27ebe4589d}
+    
+    
+      {82399d26-206c-4d05-8815-34655e5d5079}
+    
+    
+      {0e9835dc-cb6d-4014-8ffb-b9e35b05160a}
+    
+    
+      {368ed79c-099f-4196-bc66-4ce324df08cb}
+    
+    
+      {053097ae-c9f4-4c00-8a31-a2c83ea57b14}
+    
+    
+      {eabfd5d6-7e45-439a-90c1-fd0f7ed538a1}
+    
+    
+      {f69631ee-6910-4fa3-9e6f-36786970c51e}
+    
+    
+      {cc6d4108-5cc9-4576-adf4-6ddc7d186998}
+    
+    
+      {f56c1f46-66cb-4585-adde-0ae7b04c5ee4}
+    
+    
+      {babb03c5-c688-4393-beaa-65f34782c77c}
+    
+    
+      {b806867c-572b-4438-a6d4-7d24825fc492}
+    
+    
+      {2d285139-9862-4a82-be6a-768c87f19c20}
+    
+    
+      {5df8227d-9e97-4693-a70e-82e98c6bd301}
+    
+    
+      {4242898e-a656-4ae5-bc35-eb202a42a304}
+    
+    
+      {7409b3df-834a-45c3-a74b-79719f9e60cc}
+    
+    
+      {0fe4a6c4-1e40-4914-ab19-ee48a4084e5c}
+    
+    
+      {6b173a34-4fbb-49ac-9e03-33cde5a6e50f}
+    
+    
+      {5e0f95ef-1256-4223-a412-f5146a7713cc}
+    
+    
+      {994959e7-12c0-43f7-a10b-24899813a857}
+    
+    
+      {500f40cf-c2f5-4264-b061-b4f1e59f50f5}
+    
+    
+      {ac86a901-4e59-4b58-82ce-a7674d8c587c}
+    
+    
+      {dd3b1edf-b406-49ff-988a-4b417fe9ce3c}
+    
+    
+      {4595469d-4085-4631-836b-08584244a9e7}
+    
+    
+      {39ff35f2-9b08-4689-8185-a10773c03ab0}
+    
+    
+      {53a23746-6411-4600-8315-bc8a1b2120da}
+    
+    
+      {53b5e674-69d5-4bae-9629-49cd8b7c7c45}
+    
+    
+      {18d24dd3-6582-41ad-856d-949ed0626792}
+    
+    
+      {ebde3d11-88f9-44b3-ba68-1752293b7729}
+    
+    
+      {e8b955a6-1062-48cf-8799-e5481a1c759b}
+    
+    
+      {11747cf2-9384-4591-992e-4bc85c6fe7c8}
+    
+    
+      {3ed37931-60f3-4898-98ac-01d5b0b19b07}
+    
+    
+      {43a77b03-30e9-4377-9dcd-a8bbcb255b5a}
+    
+    
+      {c186f452-9528-4731-97e6-f9a3d797bb10}
+    
+    
+      {e5dade76-fb92-4baa-a16b-41d7df056829}
+    
+    
+      {8b577c52-0888-4778-8c01-308bf573cb77}
+    
+    
+      {2081befc-0e1b-498c-b3ca-056e0c37305b}
+    
+    
+      {44ee30b6-3875-4e2d-99f0-f9e5cf6b38ac}
+    
+    
+      {d55c12ae-4311-4695-855b-76a504d76888}
+    
+    
+      {c9b72a3c-ca3e-48a9-90a0-d86d681918fa}
+    
+  
+  
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+    
+      Source Files
+    
+  
+  
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+    
+      Header Files
+    
+  
+  
+    
+      Source Files
+    
+    
+      Config
+    
+    
+      Samples\helloworld
+    
+    
+      Samples\helloworld
+    
+    
+      Samples\defaultdocument
+    
+    
+      Samples\defaultdocument
+    
+    
+      Samples\logging
+    
+    
+      Samples\logging
+    
+    
+      Samples\configuration
+    
+    
+      Samples
+    
+    
+      Samples\configuration
+    
+    
+      Samples\express
+    
+    
+      Samples\express
+    
+    
+      Samples\urlrewrite
+    
+    
+      Samples\urlrewrite
+    
+    
+      Samples\urlrewrite
+    
+    
+      Samples\helloworld
+    
+    
+      Samples\configuration
+    
+    
+      Samples\defaultdocument
+    
+    
+      Samples\logging
+    
+    
+      Samples\express
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\100_helloworld
+    
+    
+      Tests\functional\www\100_helloworld
+    
+    
+      Tests\functional\tests\node_modules
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\101_helloworld_sequence
+    
+    
+      Tests\functional\www\101_helloworld_sequence
+    
+    
+      Tests\functional\www\102_defaultdocument
+    
+    
+      Tests\functional\www\102_defaultdocument
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\103_urlrewrite
+    
+    
+      Tests\functional\www\103_urlrewrite
+    
+    
+      Tests\functional
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests\parts
+    
+    
+      Tests\functional\www\104_echo
+    
+    
+      Tests\functional\www\104_echo
+    
+    
+      Tests\functional\www\105_logging
+    
+    
+      Tests\functional\www\105_logging
+    
+    
+      Tests\functional\www\106_autoupdate
+    
+    
+      Tests\functional\www\106_autoupdate
+    
+    
+      Tests\functional\www\106_autoupdate
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests\parts
+    
+    
+      Tests\functional\tests\parts
+    
+    
+      Tests\functional\scripts
+    
+    
+      Tests\functional\scripts
+    
+    
+      Scripts
+    
+    
+      Config
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\107_filesystem
+    
+    
+      Tests\functional\www\107_filesystem
+    
+    
+      Tests\functional\www\107_filesystem
+    
+    
+      Tests\functional\www\108_appsettings
+    
+    
+      Tests\functional\www\108_appsettings
+    
+    
+      Tests\functional\tests
+    
+    
+      Scripts
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\110_log_size_quota
+    
+    
+      Tests\functional\www\110_log_size_quota
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\111_node_env
+    
+    
+      Tests\functional\www\111_node_env
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\112_dev_errors\off
+    
+    
+      Tests\functional\www\112_dev_errors\off
+    
+    
+      Tests\functional\www\112_dev_errors\on
+    
+    
+      Tests\functional\www\112_dev_errors\on
+    
+    
+      Tests\performance
+    
+    
+      Tests\performance
+    
+    
+      Tests\performance
+    
+    
+      Tests\performance\www\default
+    
+    
+      Tests\performance\www\default
+    
+    
+      Tests\performance\www\default
+    
+    
+      Tests\performance
+    
+    
+      Tests\functional\www\113_encoding
+    
+    
+      Tests\functional\www\113_encoding
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\115_customheaders
+    
+    
+      Tests\functional\www\115_customheaders
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\116_configerror
+    
+    
+      Tests\functional\www\116_configerror
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests\parts
+    
+    
+      Tests\functional\tests\parts
+    
+    
+      Tests\functional\www\117_autoupdate_dependency
+    
+    
+      Tests\functional\www\117_autoupdate_dependency
+    
+    
+      Tests\functional\www\117_autoupdate_dependency
+    
+    
+      Tests\functional\www\117_autoupdate_dependency
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\118_xff
+    
+    
+      Tests\functional\www\118_xff
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\119_servervars
+    
+    
+      Tests\functional\www\119_servervars
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\120_dev_errors_exception
+    
+    
+      Tests\functional\www\120_dev_errors_exception
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\121_watchedFiles
+    
+    
+      Tests\functional\www\121_watchedFiles
+    
+    
+      Tests\functional\www\122_multipleResponseHeaders
+    
+    
+      Tests\functional\www\122_multipleResponseHeaders
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\123_upload
+    
+    
+      Tests\functional\www\123_upload
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\124_node_config_override
+    
+    
+      Tests\functional\www\124_node_config_override
+    
+    
+      Tests\functional\www\125_node_config_autoupdate
+    
+    
+      Tests\functional\www\125_node_config_autoupdate
+    
+    
+      Tests\functional\www\125_node_config_autoupdate
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\126_node_config_syntax
+    
+    
+      Tests\functional\www\126_node_config_syntax
+    
+    
+      Tests\functional\www\126_node_config_syntax
+    
+    
+      Tests\functional\tests
+    
+    
+      Samples\configuration
+    
+    
+      Tests\functional\www\124_node_config_override
+    
+    
+      Scripts
+    
+    
+      Scripts
+    
+    
+      Config
+    
+    
+      Config
+    
+    
+      Config
+    
+    
+      Config
+    
+    
+      Config
+    
+    
+      Tests\functional\www\130_websocket_onetwothree
+    
+    
+      Tests\functional\www\130_websocket_onetwothree
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\131_websocket_echo
+    
+    
+      Tests\functional\www\131_websocket_echo
+    
+    
+      Tests\functional\www\132_debug_header
+    
+    
+      Tests\functional\www\132_debug_header
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\stress\130_websocket_chat
+    
+    
+      Tests\stress\130_websocket_chat
+    
+    
+      Tests\stress\130_websocket_chat
+    
+    
+      Tests\stress\131_websocket_connections
+    
+    
+      Tests\stress\131_websocket_connections
+    
+    
+      Tests\stress\131_websocket_connections
+    
+    
+      Tests\stress\131_websocket_connections
+    
+    
+      Tests\stress\130_websocket_chat
+    
+    
+      Tests\stress\132_websocket_latency
+    
+    
+      Tests\stress\132_websocket_latency
+    
+    
+      Tests\stress\132_websocket_latency
+    
+    
+      Tests\stress\132_websocket_latency
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\140_large_download
+    
+    
+      Tests\functional\www\140_large_download
+    
+    
+      Tests\functional\tests
+    
+    
+      Tests\functional\www\141_large_upload
+    
+    
+      Tests\functional\www\141_large_upload
+    
+    
+      Tests\functional\tests
+    
+  
+  
+    
+  
 
\ No newline at end of file
diff --git a/src/iisnode/main.cpp b/src/iisnode/main.cpp
index 820960a4..a2c2c543 100644
--- a/src/iisnode/main.cpp
+++ b/src/iisnode/main.cpp
@@ -12,6 +12,7 @@ HRESULT __stdcall RegisterModule(
     HRESULT hr;
     HMODULE hNtDll;
     CNodeHttpModuleFactory* pFactory = NULL;
+    CNodeGlobalModule* pGlobalModule = NULL;
 
     ErrorIf(pModuleInfo == NULL || pHttpServer == NULL, HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
 
@@ -26,6 +27,10 @@ HRESULT __stdcall RegisterModule(
 
     CheckError(pModuleInfo->SetRequestNotifications(pFactory, RQ_EXECUTE_REQUEST_HANDLER | RQ_SEND_RESPONSE, 0));
     
+    ErrorIf(NULL == (pGlobalModule = new CNodeGlobalModule(pFactory->GetNodeApplicationManager())), E_OUTOFMEMORY);
+
+    CheckError(pModuleInfo->SetGlobalNotifications( pGlobalModule, GL_CONFIGURATION_CHANGE ));
+
     return S_OK;
 
 Error:
@@ -33,7 +38,12 @@ HRESULT __stdcall RegisterModule(
     if ( pFactory != NULL )
     {
         delete pFactory;
-    }   
+    }
+
+    if( pGlobalModule != NULL )
+    {
+        delete pGlobalModule;
+    }
 
     return hr;
 }
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintignore b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintignore
new file mode 100644
index 00000000..239e2a56
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintignore
@@ -0,0 +1,2 @@
+node_modules
+/front-end
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintrc b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintrc
new file mode 100644
index 00000000..a660584f
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/.jshintrc
@@ -0,0 +1,20 @@
+{
+"node": true,
+"eqnull" : true,
+"indent": 2,
+"undef": true,
+"quotmark": "single",
+"maxlen": 105,
+"trailing": true,
+"newcap": true,
+"nonew": true,
+"sub": true,
+"globals": {
+  "describe": true,
+  "it": true,
+  "before": true,
+  "beforeEach": true,
+  "after": true,
+  "afterEach": true
+}
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/AUTHORS b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/AUTHORS
new file mode 100644
index 00000000..ca104ea6
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/AUTHORS
@@ -0,0 +1,30 @@
+Danny Coates 
+Miroslav Bajtoš 
+
+3y3 <3y3@bk.ru>
+Adam Hořčica 
+Akzhan Abdulin 
+cattail 
+ChrisWren 
+Dave 
+Vasil Dininski 
+Dick Hardt 
+Gary Katsevman 
+Glenn Block 
+Ionică Bizău 
+Ionuț G. Stan 
+Karan Batra-Daitch 
+Kasper Ligaard 
+Kenneth Auchenberg 
+Lennon Pulda-Grealy 
+Mark Constable 
+Matthew O'Riordan 
+Michael Schoonmaker 
+Panagiotis Astithas 
+Peter Lyons 
+Peter Flannery 
+Philip Tellis 
+Pritam Baral 
+Sam Roberts 
+Sergey Krilov 
+ssafejava 
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/LICENSE b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/LICENSE
new file mode 100644
index 00000000..25e81f0f
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/LICENSE
@@ -0,0 +1,8 @@
+Copyright (c) 2011, Danny Coates
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/inspector.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/inspector.js
new file mode 100644
index 00000000..48ed2421
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/inspector.js
@@ -0,0 +1,76 @@
+#!/usr/bin/env node
+
+var DebugServer = require('../lib/debug-server').DebugServer,
+    fs = require('fs'),
+    path = require('path'),
+    config = require('../lib/config'),
+    packageJson = require('../package.json'),
+    notifyParentProcess = getNotifyParentProcessFn();
+
+if (config.help || config.h) {
+  console.log('Usage:');
+  console.log('    node-inspector [options]');
+  console.log('\nOptions:');
+  console.log(config._describeOptions());
+  console.log();
+  process.exit();
+}
+
+if (config.version || config.v) {
+  console.log('v' + require('../package.json').version);
+  process.exit();
+}
+
+console.log('Node Inspector v%s', packageJson.version);
+
+config.webPort = process.env.PORT || config.webPort;
+config.debugPort = process.env.DEBUGPORT || config.debugPort;
+
+var debugServer = new DebugServer();
+debugServer.on('error', onError);
+debugServer.on('listening', onListening);
+debugServer.on('close', function () {
+  process.exit();
+});
+debugServer.start(config);
+
+function onError(err) {
+  console.error(
+    'Cannot start the server at %s:%s. Error: %s.',
+    config.webHost || '0.0.0.0',
+    config.webPort,
+    err.message || err
+  );
+
+  if (err.code === 'EADDRINUSE') {
+    console.error(
+      'There is another process already listening at this address.\n' +
+      'Run `node-inspector --web-port={port}` to use a different port.'
+    );
+  }
+
+  notifyParentProcess({
+    event: 'SERVER.ERROR',
+    error: err
+  });
+}
+
+function onListening() {
+  var address = this.address();
+  console.log('Visit %s to start debugging.', address.url);
+
+  notifyParentProcess({
+    event: 'SERVER.LISTENING',
+    address: address
+  });
+}
+
+function getNotifyParentProcessFn() {
+  if (!process.send) {
+    return function(msg) {};
+  }
+
+  return function(msg) {
+    process.send(msg);
+  };
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/node-debug.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/node-debug.js
new file mode 100644
index 00000000..d8d63668
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/node-debug.js
@@ -0,0 +1,276 @@
+#!/usr/bin/env node
+
+var fork = require('child_process').fork;
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var open = require('opener');
+var yargs = require('yargs');
+var whichSync = require('which').sync;
+var inspector = require('..');
+
+var argvOptions = {
+  'debug-brk': {
+    alias: 'b',
+    default: true,
+    description: 'Break on the first line (`node --debug-brk`)'
+  },
+  'web-port': {
+    alias: ['p', 'port'],
+    type: 'number',
+    description: 'Node Inspector port (`node-inspector --web-port={port}`)'
+  },
+  'debug-port': {
+    alias: 'd',
+    type: 'number',
+    description: 'Node/V8 debugger port (`node --debug={port}`)'
+  },
+  cli: {
+    alias: 'c',
+    type: 'boolean',
+    description: 'CLI mode, do not open browser.'
+  },
+  version: {
+    alias: 'v',
+    type: 'boolean',
+    description: 'Print Node Inspector\'s version.'
+  },
+  help: {
+    alias: 'h',
+    type: 'boolean',
+    description: 'Show this help.'
+  }
+};
+
+var argvParser = createYargs();
+
+module.exports = main;
+module.exports.parseArgs = parseArgs;
+
+if (require.main == module)
+  main();
+
+//-- Implementation --
+
+var config;
+
+/**
+ * By default:
+ *
+ * 1. Runs node-inspector.
+ * 2. Runs the supplied script in debug mode
+ * 3. Opens the user's browser, pointing it at the inspector.
+ *
+ * NOTE: Finishes with a call to process.exit() when running without arguments
+ * or when an error occured.
+ */
+function main() {
+  config = parseArgs(process.argv);
+  if (config.options.help) {
+    argvParser.showHelp(console.log);
+    console.log('The [script] argument is resolved relative to the current working\n' +
+      'directory. If no such file exists, then env.PATH is searched.\n');
+    console.log('The default mode is to break on the first line of the script, to run\n' +
+      'immediately on start use `--no-debug-brk` or press the Resume button.\n');
+    console.log('When there is no script specified, the module in the current working\n' +
+      'directory is loaded in the REPL session as `m`. This allows you to call\n' +
+      'and debug arbitrary functions exported by the current module.\n');
+    process.exit();
+  }
+
+  if (config.options.version) {
+    console.log('v' + require('../package.json').version);
+    process.exit();
+  }
+
+  startInspector(function(err) {
+    if (err) {
+      console.error(formatNodeInspectorError(err));
+      process.exit(1);
+    }
+
+    startDebuggedProcess(function(err) {
+      if (err) {
+        console.error(
+          'Cannot start %s: %s',
+          config.subproc.script,
+          err.message || err
+        );
+        process.exit(2);
+      }
+
+      openBrowserAndPrintInfo();
+    });
+  });
+}
+
+function parseArgs(argv) {
+  argv = argv.slice(2);
+  var options = argvParser.parse(argv);
+  var script = options._[0];
+  var printScript = true;
+
+  var subprocArgs;
+
+  if (script) {
+    // We want to pass along subarguments, but re-parse our arguments.
+    subprocArgs = argv.splice(argv.indexOf(script) + 1);
+  } else {
+    script = require.resolve('./run-repl');
+    subprocArgs = [];
+    printScript = false;
+    process.env.CMD = process.env.CMD || process.argv[1];
+  }
+
+  options = argvParser.parse(argv);
+
+  var subprocPort = options['debug-port'] || 5858;
+  var subprocExecArgs = ['--debug=' + subprocPort];
+
+  if (options['debug-brk']) {
+    subprocExecArgs.push('--debug-brk');
+  }
+
+  var inspectorPort = options['web-port'] || 8080;
+  var inspectorArgs = extractPassThroughArgs(options, argvOptions)
+    .concat(['--web-port=' + inspectorPort]);
+
+  return {
+    printScript: printScript,
+    options: options,
+    subproc: {
+      script: script,
+      args: subprocArgs,
+      execArgs:  subprocExecArgs,
+      debugPort: subprocPort
+    },
+    inspector: {
+      port: inspectorPort,
+      args: inspectorArgs
+    }
+  };
+}
+
+function createYargs() {
+  var y = yargs
+    .options(argvOptions)
+    .usage('Usage:\n' +
+      '    $0 [node-inspector-options] [options] script [script-arguments]');
+  y.$0 = getCmd();
+  return y;
+}
+
+function getCmd() {
+  return process.env.CMD || path.basename(process.argv[1]);
+}
+
+function extractPassThroughArgs(options, argvOptions) {
+  var result = [];
+  var optionsToSkip = { _: true, $0: true };
+
+  // Skip options handled by node-debug
+  Object.keys(argvOptions).forEach(function(key) {
+    optionsToSkip[key] = true;
+    var alias = argvOptions[key].alias;
+    if (Array.isArray(alias)) {
+      alias.forEach(function(opt) { optionsToSkip[opt] = true; });
+    } else if (alias) {
+      optionsToSkip[alias] = true;
+    }
+  });
+
+  // Filter options not handled by node-debug
+  Object.keys(options).forEach(function(key) {
+    if (optionsToSkip[key]) return;
+    var value = options[key];
+    if (value === undefined) return;
+    if (value === true) {
+      result.push('--' + key);
+    } else if (value === true) {
+      result.push('--no-' + key);
+    } else {
+      result.push('--' + key);
+      result.push(value);
+    }
+  });
+
+  return result;
+}
+
+function startInspector(callback) {
+  var inspectorProcess = fork(
+    require.resolve('./inspector'),
+    config.inspector.args,
+    { silent: true }
+  );
+
+  inspectorProcess.once('message', function(msg) {
+    switch (msg.event) {
+    case 'SERVER.LISTENING':
+      return callback(null, msg.address);
+    case 'SERVER.ERROR':
+      return callback(msg.error);
+    default:
+      console.warn('Unknown Node Inspector event: %s', msg.event);
+      return callback(
+        null,
+        {
+          address: 'localhost',
+          port: config.inspector.port
+        }
+      );
+    }
+  });
+
+  process.on('exit', function() {
+    inspectorProcess.kill();
+  });
+}
+
+function formatNodeInspectorError(err) {
+  var reason = err.message || err.code || err;
+  if (err.code === 'EADDRINUSE') {
+    reason += '\nThere is another process already listening at 0.0.0.0:' +
+      config.inspector.port + '.\n' +
+      'Run `' + getCmd() + ' -p {port}` to use a different port.';
+  }
+
+  return util.format('Cannot start Node Inspector:', reason);
+}
+
+function startDebuggedProcess(callback) {
+  var script = path.resolve(process.cwd(), config.subproc.script);
+  if (!fs.existsSync(script)) {
+    try {
+      script = whichSync(config.subproc.script);
+    } catch (err) {
+      return  callback(err);
+    }
+  }
+
+  var debuggedProcess = fork(
+    script,
+    config.subproc.args,
+    {
+      execArgv: config.subproc.execArgs
+    }
+  );
+  debuggedProcess.on('exit', function() { process.exit(); });
+  callback();
+}
+
+function openBrowserAndPrintInfo() {
+  var url = inspector.buildInspectorUrl(
+    'localhost',
+    config.inspector.port,
+    config.subproc.debugPort
+  );
+
+  if (!config.options.cli) {
+    open(url);
+  }
+
+  console.log('Node Inspector is now available from %s', url);
+  if (config.printScript)
+    console.log('Debugging `%s`\n', config.subproc.script);
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/run-repl.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/run-repl.js
new file mode 100644
index 00000000..62f03e1d
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/bin/run-repl.js
@@ -0,0 +1,81 @@
+// Load the module contained in the current directory (cwd) and start REPL
+// NOTE: Calls process.exit() after REPL was closed
+
+var Module = require('module');
+var path = require('path');
+var repl = require('repl');
+var util = require('util');
+
+var location = process.cwd();
+
+var moduleToDebug;
+var sampleLine;
+var prompt;
+
+try {
+  loadAndDescribeModuleInCwd();
+} catch (e) {
+  sampleLine = util.format(
+    'The module in the current directory was not loaded: %s.',
+    e.message || e
+  );
+}
+
+startRepl();
+
+//---- Implementation ----
+
+function loadAndDescribeModuleInCwd() {
+// Hack: Trick node into changing process.mainScript to moduleToDebug
+  moduleToDebug = Module._load(location, module, true);
+
+  var sample = getSampleCommand();
+  sampleLine = util.format('You can access your module as `m`%s.', sample);
+
+  prompt = getModuleName() + '> ';
+}
+
+function startRepl() {
+  var cmd = process.env.CMD || process.argv[1];
+
+  console.log(
+    '\nStarting the interactive shell (REPL). Type `.help` for help.\n' +
+      '%s\n' +
+      'Didn\'t want to start REPL? Run `%s .` instead.',
+    sampleLine,
+    cmd
+  );
+
+  var r = repl.start( { prompt: prompt });
+  if (moduleToDebug !== undefined)
+    r.context.m = moduleToDebug;
+  r.on('exit', onReplExit);
+}
+
+function onReplExit() {
+  console.log('\nLeaving the interactive shell (REPL).');
+  process.exit();
+}
+
+function getModuleName() {
+  try {
+    var packageJson = require(path.join(location, 'package.json'));
+    if (packageJson.name)
+      return packageJson.name;
+  } catch (e) {
+    // ignore missing package.json
+  }
+
+  return path.basename(location);
+}
+
+function getSampleCommand() {
+  var exportedSymbols = Object.keys(moduleToDebug);
+  if (!exportedSymbols.length) return '';
+
+  var sample = exportedSymbols[0];
+  if (typeof(moduleToDebug[sample]) === 'function')
+    sample += '()';
+
+  return ', e.g. `m.' + sample + '`';
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/build/config.gypi b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/build/config.gypi
new file mode 100644
index 00000000..67a015f0
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/build/config.gypi
@@ -0,0 +1,38 @@
+# Do not edit. File was generated by node-gyp's "configure" step
+{
+  "target_defaults": {
+    "cflags": [],
+    "default_configuration": "Release",
+    "defines": [],
+    "include_dirs": [],
+    "libraries": []
+  },
+  "variables": {
+    "clang": 0,
+    "host_arch": "ia32",
+    "node_install_npm": "true",
+    "node_prefix": "",
+    "node_shared_cares": "false",
+    "node_shared_http_parser": "false",
+    "node_shared_libuv": "false",
+    "node_shared_openssl": "false",
+    "node_shared_v8": "false",
+    "node_shared_zlib": "false",
+    "node_tag": "",
+    "node_unsafe_optimizations": 0,
+    "node_use_dtrace": "false",
+    "node_use_etw": "true",
+    "node_use_openssl": "true",
+    "node_use_perfctr": "true",
+    "node_use_systemtap": "false",
+    "python": "c:\\python27\\python.exe",
+    "target_arch": "x64",
+    "v8_enable_gdbjit": 0,
+    "v8_no_strict_aliasing": 1,
+    "v8_use_snapshot": "true",
+    "visibility": "",
+    "nodedir": "C:\\Users\\ranjithr\\.node-gyp\\0.10.28",
+    "copy_dev_lib": "true",
+    "standalone_static_library": 1
+  }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/config.json b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/config.json
new file mode 100644
index 00000000..759f256b
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/config.json
@@ -0,0 +1,7 @@
+{
+  "webPort": 8080,
+  "webHost": null,
+  "debugPort": 5858,
+  "saveLiveEdit": false,
+  "hidden": []
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/docs/embedding.md b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/docs/embedding.md
new file mode 100644
index 00000000..52ef6086
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/docs/embedding.md
@@ -0,0 +1,85 @@
+# HOWTO embed Node Inspector
+
+Node Inspector provides two ways of embedding in third-party
+applications.
+
+## 1. Running in a new node process
+
+1. Start the Node Inspector in a new process using
+  [child_process.fork()](http://nodejs.org/api/child_process.html#child_process_child_process_fork_modulepath_args_options)
+2. Add `message` handler to get notified about Node Inspector events, use
+  `msg.event` to check which event was emitted.
+
+```js
+var fork = require('child_process').fork;
+
+var inspectorArgs = [];
+var forkOptions = { silent: true };
+var inspector = fork(
+  require.resolve('node-inspector/bin/inspector'),
+  inspectorArgs,
+  forkOptions
+);
+
+inspector.on('message', handleInspectorMessage);
+
+function handleInspectorMessage(msg) {
+  switch(msg.event) {
+    case 'SERVER.LISTENING':
+      console.log('Visit %s to start debugging.', msg.address.url);
+      break;
+    case 'SERVER.ERROR':
+      console.log('Cannot start the server: %s.', msg.error.code);
+      break;
+  }
+}
+```
+
+### Event: 'SERVER.LISTENING'
+
+Emitted when the HTTP server was bound and is ready to accept connections.
+
+Properties:
+
+ * `address` - Server address as returned by `DebugServer.address()` (see
+   below).
+
+### Event: 'SERVER.ERROR'
+
+Emitted when there was an error while setting up the HTTP server.
+
+Properties:
+
+ * `error` - The error.
+
+## 2. Running in an existing process
+
+To be done. [index.js](../index.js) should expose method for creating and starting
+a DebugServer instance with a given config.
+
+DebugServer is already exposing the following API:
+
+### debugServer.address()
+
+Returns the result of `server.address()` plus the URL of the Node Inspector
+page to open in browser.
+
+Example:
+```js
+{
+  port: 8080,
+  address: '0.0.0.0',
+  url: 'http://localhost:8080/debug?port=5858'
+}
+```
+
+### Event: 'listening'
+
+Emitted when the HTTP server was bound and is ready to accept connections.
+
+### Event: 'error'
+
+* Error Object
+
+Emitted when there is an error in setting up the HTTP server.
+
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end-node/Overrides.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end-node/Overrides.js
new file mode 100644
index 00000000..2696e2ea
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end-node/Overrides.js
@@ -0,0 +1,194 @@
+/*jshint browser:true */
+/*global WebInspector:true, InspectorFrontendHost:true, InspectorBackend:true, importScript:true */
+/*global Preferences:true */
+
+// Wire up websocket to talk to backend
+WebInspector.loaded = function() {
+
+  var webSocketUrl = function() {
+    var a = document.createElement('a');
+    // browser will resolve this relative path to an absolute one
+    a.href = 'ws';
+    a.search = window.location.search;
+    a.protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
+    return a.href;
+  }();
+
+  WebInspector.socket = new WebSocket(webSocketUrl);
+
+  WebInspector.socket.onmessage = onWebSocketMessage;
+  WebInspector.socket.onerror = onWebSocketError;
+  WebInspector.socket.onopen = onWebSocketConnected;
+};
+
+var _inspectorInitialized = false;
+
+function onWebSocketError(error) {
+  console.error(error);
+}
+
+function onWebSocketConnected() {
+  if (_inspectorInitialized) return;
+  InspectorFrontendHost.sendMessageToBackend = WebInspector.socket.send.bind(WebInspector.socket);
+
+  WebInspector.dockController = new WebInspector.DockController();
+  WebInspector.doLoadedDone();
+
+  _inspectorInitialized = true;
+}
+
+function onWebSocketMessage(response) {
+
+  var message = response.data;
+
+  if (!message) return;
+
+  if (message === 'showConsole') {
+    WebInspector.showConsole();
+  } else {
+    InspectorBackend.dispatch(message);
+  }
+}
+
+// Disable HTML & CSS inspections
+WebInspector.queryParamsObject['isSharedWorker'] = true;
+
+// disable everything besides scripts and console
+// that means 'profiles' and 'timeline' at the moment
+WebInspector._orig_panelDescriptors = WebInspector._panelDescriptors;
+WebInspector._panelDescriptors = function() {
+  var panelDescriptors = this._orig_panelDescriptors();
+  return panelDescriptors.filter(function(pd) {
+    return ['scripts', 'console'].indexOf(pd.name()) != -1;
+  });
+};
+
+// Patch the expression used as an initial value for a new watch.
+// DevTools' value "\n" breaks the debugger protocol.
+importScript('WatchExpressionsSidebarPane.js');
+WebInspector.WatchExpressionsSection.NewWatchExpression = '\'\'';
+
+Preferences.localizeUI = false;
+Preferences.applicationTitle = 'Node Inspector';
+
+WebInspector._platformFlavor = WebInspector.PlatformFlavor.MacLeopard;
+
+// Front-end uses `eval location.href` to get url of inspected page
+// This does not work in node.js from obvious reasons, and cause
+// a 'null' message to be printed in front-end console.
+// Since Preferences.applicationTitle does not include inspected url,
+// we can return arbitrary string as inspected URL.
+WebInspector.WorkerManager._calculateWorkerInspectorTitle = function() {
+  InspectorFrontendHost.inspectedURLChanged('');
+};
+
+// Do not offer download of the edited file when saving changes to V8.
+// DevTools' implementation changes window.location which closes
+// web-socket connection to the server and thus breaks the inspector.
+InspectorFrontendHost.close = function(url, content, forceSaveAs) {
+  delete this._fileBuffers[url];
+};
+
+// Let DevTools know we can save the content of modified files,
+// so that a warning icon is not displayed in the file tab header.
+// See UISourceCode.hasUnsavedCommittedChanges to understand why.
+WebInspector.extensionServer._onSubscribe(
+  {
+    type:WebInspector.extensionAPI.Events.ResourceContentCommitted
+  },
+  {
+    postMessage: function(msg) {
+      // no-op
+    }
+  }
+);
+
+// Front-end intercepts Cmd+R, Ctrl+R and F5 keys and reloads the debugged
+// page instead of the front-end page.  We want to disable this behaviour.
+WebInspector._orig_documentKeyDown = WebInspector.documentKeyDown;
+WebInspector.documentKeyDown = function(event) {
+  switch (event.keyIdentifier) {
+    case 'U+0052': // R key
+    case 'F5':
+      return;
+  }
+  WebInspector._orig_documentKeyDown(event);
+};
+
+var orig_createResourceFromFramePayload =
+  WebInspector.ResourceTreeModel.prototype._createResourceFromFramePayload;
+
+WebInspector.ResourceTreeModel.prototype._createResourceFromFramePayload =
+  function(frame, url, type, mimeType) {
+    // Force Script type for all node frames.
+    // Front-end assigns Document type (i.e. HTML) to our main script file.
+    if (frame._isNodeInspectorScript) {
+      type = WebInspector.resourceTypes.Script;
+    }
+
+    return orig_createResourceFromFramePayload(frame, url, type, mimeType);
+  };
+
+//
+// Open the main application file on startup
+//
+
+WebInspector.notifications.addEventListener(
+  WebInspector.Events.InspectorLoaded,
+  function() {
+    WebInspector.resourceTreeModel.addEventListener(
+      WebInspector.ResourceTreeModel.EventTypes.CachedResourcesLoaded,
+      showMainAppFile,
+      null
+    );
+  },
+  null
+);
+
+
+function showMainAppFile() {
+  var fileTabs = WebInspector.showPanel('scripts')._editorContainer._files;
+  if (Object.keys(fileTabs).length > 0){
+    // Some files are already opened - do not change user's workspace
+    return;
+  }
+
+  var uiSourceCodes = getAllUiSourceCodes();
+  var uriToShow = WebInspector.inspectedPageURL;
+
+  for (var i in uiSourceCodes) {
+    if (uiSourceCodes[i].uri() !== uriToShow) continue;
+    WebInspector.showPanel('scripts').showUISourceCode(uiSourceCodes[i]);
+    return true;
+  }
+
+  console.error('Cannot show the main application file ', uriToShow);
+}
+
+function getAllUiSourceCodes() {
+  // Based on FilteredItemSectionDialog.js > SelectUISourceCodeDialog()
+  var projects = WebInspector.workspace.projects();
+  var uiSourceCodes = [];
+  var projectFiles;
+
+  for (var i = 0; i < projects.length; ++i) {
+    projectFiles = projects[i]
+      .uiSourceCodes()
+      .filter(nameIsNotEmpty);
+    uiSourceCodes = uiSourceCodes.concat(projectFiles);
+  }
+
+  return uiSourceCodes;
+
+  function nameIsNotEmpty(p) {
+    return p.name();
+  }
+}
+
+var oldDetached = WebInspector.detached;
+WebInspector.detached = function () {
+  oldDetached.apply(this, arguments);
+  setTimeout(function () {
+    location.reload();
+  }, 400);
+};
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AdvancedSearchController.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AdvancedSearchController.js
new file mode 100644
index 00000000..821b7be0
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AdvancedSearchController.js
@@ -0,0 +1,748 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
+ * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.AdvancedSearchController = function()
+{
+    this._shortcut = WebInspector.AdvancedSearchController.createShortcut();
+    this._searchId = 0;
+    
+    WebInspector.settings.advancedSearchConfig = WebInspector.settings.createSetting("advancedSearchConfig", new WebInspector.SearchConfig("", true, false));
+    
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
+}
+
+/**
+ * @return {!WebInspector.KeyboardShortcut.Descriptor}
+ */
+WebInspector.AdvancedSearchController.createShortcut = function()
+{
+    if (WebInspector.isMac())
+        return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Meta | WebInspector.KeyboardShortcut.Modifiers.Alt);
+    else
+        return WebInspector.KeyboardShortcut.makeDescriptor("f", WebInspector.KeyboardShortcut.Modifiers.Ctrl | WebInspector.KeyboardShortcut.Modifiers.Shift);
+}
+
+WebInspector.AdvancedSearchController.prototype = {
+    /**
+     * @param {KeyboardEvent} event
+     * @return {boolean}
+     */
+    handleShortcut: function(event)
+    {
+        if (WebInspector.KeyboardShortcut.makeKeyFromEvent(event) === this._shortcut.key) {
+            if (!this._searchView || !this._searchView.isShowing() || this._searchView._search !== document.activeElement) {
+                WebInspector.showPanel("scripts");
+                this.show();
+            } else
+                this.close();
+            event.consume(true);
+            return true;
+        }
+        return false;
+    },
+
+    _frameNavigated: function()
+    {
+        this.resetSearch();
+    },
+
+    /**
+     * @param {WebInspector.SearchScope} searchScope
+     */
+    registerSearchScope: function(searchScope)
+    {
+        // FIXME: implement multiple search scopes.
+        this._searchScope = searchScope;
+    },
+
+    show: function()
+    {
+        if (!this._searchView)
+            this._searchView = new WebInspector.SearchView(this);
+        
+        this._searchView.syncToSelection();
+
+        if (this._searchView.isShowing())
+            this._searchView.focus();
+        else
+            WebInspector.showViewInDrawer(this._searchView._searchPanelElement, this._searchView, this.stopSearch.bind(this));
+        this.startIndexing();
+    },
+
+    close: function()
+    {
+        this.stopSearch();
+        WebInspector.closeViewInDrawer();
+    },
+
+    /**
+     * @param {boolean} finished
+     */
+    _onIndexingFinished: function(finished)
+    {
+        delete this._isIndexing;
+        this._searchView.indexingFinished(finished);
+        if (!finished)
+            delete this._pendingSearchConfig;
+        if (!this._pendingSearchConfig)
+            return;
+        var searchConfig = this._pendingSearchConfig
+        delete this._pendingSearchConfig;
+        this._innerStartSearch(searchConfig);
+    },
+
+    startIndexing: function()
+    {
+        this._isIndexing = true;
+        // FIXME: this._currentSearchScope should be initialized based on searchConfig
+        this._currentSearchScope = this._searchScope;
+        if (this._progressIndicator)
+            this._progressIndicator.done();
+        this._progressIndicator = new WebInspector.ProgressIndicator();
+        this._searchView.indexingStarted(this._progressIndicator);
+        this._currentSearchScope.performIndexing(this._progressIndicator, this._onIndexingFinished.bind(this));
+    },
+
+    /**
+     * @param {number} searchId
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     */
+    _onSearchResult: function(searchId, searchResult)
+    {
+        if (searchId !== this._searchId)
+            return;
+        this._searchView.addSearchResult(searchResult);
+        if (!searchResult.searchMatches.length)
+            return;
+        if (!this._searchResultsPane) 
+            this._searchResultsPane = this._currentSearchScope.createSearchResultsPane(this._searchConfig);
+        this._searchView.resultsPane = this._searchResultsPane; 
+        this._searchResultsPane.addSearchResult(searchResult);
+    },
+    
+    /**
+     * @param {number} searchId
+     * @param {boolean} finished
+     */
+    _onSearchFinished: function(searchId, finished)
+    {
+        if (searchId !== this._searchId)
+            return;
+        if (!this._searchResultsPane)
+            this._searchView.nothingFound();
+        this._searchView.searchFinished(finished);
+        delete this._searchConfig;
+    },
+    
+    /**
+     * @param {WebInspector.SearchConfig} searchConfig
+     */
+    startSearch: function(searchConfig)
+    {
+        this.resetSearch();
+        ++this._searchId;
+        if (!this._isIndexing)
+            this.startIndexing();
+        this._pendingSearchConfig = searchConfig;
+    },
+
+    /**
+     * @param {WebInspector.SearchConfig} searchConfig
+     */
+    _innerStartSearch: function(searchConfig)
+    {
+        this._searchConfig = searchConfig;
+        // FIXME: this._currentSearchScope should be initialized based on searchConfig
+        this._currentSearchScope = this._searchScope;
+
+        if (this._progressIndicator)
+            this._progressIndicator.done();
+        this._progressIndicator = new WebInspector.ProgressIndicator();
+        var totalSearchResultsCount = this._currentSearchScope.performSearch(searchConfig, this._progressIndicator, this._onSearchResult.bind(this, this._searchId), this._onSearchFinished.bind(this, this._searchId));
+        this._searchView.searchStarted(this._progressIndicator);
+    },
+    
+    resetSearch: function()
+    {
+        this.stopSearch();
+
+        if (this._searchResultsPane) {
+            this._searchView.resetResults();
+            delete this._searchResultsPane;
+        }
+    },
+    
+    stopSearch: function()
+    {
+        if (this._progressIndicator)
+            this._progressIndicator.cancel();
+        if (this._currentSearchScope)
+            this._currentSearchScope.stopSearch();
+        delete this._searchConfig;
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {WebInspector.AdvancedSearchController} controller
+ */
+WebInspector.SearchView = function(controller)
+{
+    WebInspector.View.call(this);
+
+    this._controller = controller;
+
+    this.element.className = "search-view";
+
+    this._searchPanelElement = document.createElement("span");
+    this._searchPanelElement.className = "search-drawer-header";
+    this._searchPanelElement.addEventListener("keydown", this._onKeyDown.bind(this), false);
+    
+    this._searchResultsElement = this.element.createChild("div");
+    this._searchResultsElement.className = "search-results";
+    
+    this._searchLabel = this._searchPanelElement.createChild("span");
+    this._searchLabel.textContent = WebInspector.UIString("Search sources");
+    this._search = this._searchPanelElement.createChild("input");
+    this._search.setAttribute("type", "search");
+    this._search.addStyleClass("search-config-search");
+    this._search.setAttribute("results", "0");
+    this._search.setAttribute("size", 30);
+
+    this._ignoreCaseLabel = this._searchPanelElement.createChild("label");
+    this._ignoreCaseLabel.addStyleClass("search-config-label");
+    this._ignoreCaseCheckbox = this._ignoreCaseLabel.createChild("input");
+    this._ignoreCaseCheckbox.setAttribute("type", "checkbox");
+    this._ignoreCaseCheckbox.addStyleClass("search-config-checkbox");
+    this._ignoreCaseLabel.appendChild(document.createTextNode(WebInspector.UIString("Ignore case")));
+    
+    this._regexLabel = this._searchPanelElement.createChild("label");
+    this._regexLabel.addStyleClass("search-config-label");
+    this._regexCheckbox = this._regexLabel.createChild("input");
+    this._regexCheckbox.setAttribute("type", "checkbox");
+    this._regexCheckbox.addStyleClass("search-config-checkbox");
+    this._regexLabel.appendChild(document.createTextNode(WebInspector.UIString("Regular expression")));
+    
+    this._searchStatusBarElement = document.createElement("div");
+    this._searchStatusBarElement.className = "search-status-bar-item";
+    this._searchMessageElement = this._searchStatusBarElement.createChild("div");
+    this._searchMessageElement.className = "search-status-bar-message";
+
+    this._searchResultsMessageElement = document.createElement("span");
+    this._searchResultsMessageElement.className = "search-results-status-bar-message";
+
+    this._load();
+}
+
+// Number of recent search queries to store.
+WebInspector.SearchView.maxQueriesCount = 20;
+
+WebInspector.SearchView.prototype = {
+    /**
+     * @return {Array.}
+     */
+    get statusBarItems()
+    {
+        return [this._searchStatusBarElement, this._searchResultsMessageElement];
+    },
+
+    /**
+     * @return {WebInspector.SearchConfig}
+     */
+    get searchConfig()
+    {
+        return new WebInspector.SearchConfig(this._search.value, this._ignoreCaseCheckbox.checked, this._regexCheckbox.checked);
+    },
+
+    syncToSelection: function()
+    {
+        var selection = window.getSelection();
+        if (selection.rangeCount) {
+            var queryCandidate = selection.toString().replace(/\r?\n.*/, "");
+            if (queryCandidate)
+                this._search.value = queryCandidate;
+        }
+    },
+    
+    /**
+     * @type {WebInspector.SearchResultsPane}
+     */
+    set resultsPane(resultsPane)
+    {
+        this.resetResults();
+        this._searchResultsElement.appendChild(resultsPane.element);
+    },
+    
+    /**
+     * @param {WebInspector.ProgressIndicator} progressIndicator
+     */
+    searchStarted: function(progressIndicator)
+    {
+        this.resetResults();
+        this._resetCounters();
+
+        this._searchMessageElement.textContent = WebInspector.UIString("Searching...");
+        progressIndicator.show(this._searchStatusBarElement);
+        this._updateSearchResultsMessage();
+
+        if (!this._searchingView)
+            this._searchingView = new WebInspector.EmptyView(WebInspector.UIString("Searching..."));
+        this._searchingView.show(this._searchResultsElement);
+    },
+
+    /**
+     * @param {WebInspector.ProgressIndicator} progressIndicator
+     */
+    indexingStarted: function(progressIndicator)
+    {
+        this._searchMessageElement.textContent = WebInspector.UIString("Indexing...");
+        progressIndicator.show(this._searchStatusBarElement);
+    },
+
+    /**
+     * @param {boolean} finished
+     */
+    indexingFinished: function(finished)
+    {
+        this._searchMessageElement.textContent = finished ? "" : WebInspector.UIString("Indexing interrupted.");
+    },
+
+    _updateSearchResultsMessage: function()
+    {
+        if (this._searchMatchesCount && this._searchResultsCount)
+            this._searchResultsMessageElement.textContent = WebInspector.UIString("Found %d matches in %d files.", this._searchMatchesCount, this._nonEmptySearchResultsCount);
+        else
+            this._searchResultsMessageElement.textContent = "";
+    },
+
+    resetResults: function()
+    {
+        if (this._searchingView)
+            this._searchingView.detach();
+        if (this._notFoundView)
+            this._notFoundView.detach();
+        this._searchResultsElement.removeChildren();
+    },
+
+    _resetCounters: function()
+    {
+        this._searchMatchesCount = 0;
+        this._searchResultsCount = 0;
+        this._nonEmptySearchResultsCount = 0;
+    },
+
+    nothingFound: function()
+    {
+        this.resetResults();
+
+        if (!this._notFoundView)
+            this._notFoundView = new WebInspector.EmptyView(WebInspector.UIString("No matches found."));
+        this._notFoundView.show(this._searchResultsElement);
+        this._searchResultsMessageElement.textContent = WebInspector.UIString("No matches found.");
+    },
+
+    /**
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     */
+    addSearchResult: function(searchResult)
+    {
+        this._searchMatchesCount += searchResult.searchMatches.length;
+        this._searchResultsCount++;
+        if (searchResult.searchMatches.length)
+            this._nonEmptySearchResultsCount++;
+        this._updateSearchResultsMessage();
+    },
+
+    /**
+     * @param {boolean} finished
+     */
+    searchFinished: function(finished)
+    {
+        this._searchMessageElement.textContent = finished ? WebInspector.UIString("Search finished.") : WebInspector.UIString("Search interrupted.");
+    },
+
+    focus: function()
+    {
+        WebInspector.setCurrentFocusElement(this._search);
+        this._search.select();
+    },
+
+    wasShown: function()
+    {
+        this.focus();
+    },
+
+    willHide: function()
+    {
+        this._controller.stopSearch();
+    },
+
+    /**
+     * @param {Event} event
+     */
+    _onKeyDown: function(event)
+    {
+        switch (event.keyCode) {
+        case WebInspector.KeyboardShortcut.Keys.Enter.code:
+            this._onAction();
+            break;
+        case WebInspector.KeyboardShortcut.Keys.Esc.code:
+            this._controller.close();
+            event.consume(true);
+            break;
+        }        
+    },
+    
+    _save: function()
+    {
+        var searchConfig = new WebInspector.SearchConfig(this.searchConfig.query, this.searchConfig.ignoreCase, this.searchConfig.isRegex); 
+        WebInspector.settings.advancedSearchConfig.set(searchConfig);
+    },
+    
+    _load: function()
+    {
+        var searchConfig = WebInspector.settings.advancedSearchConfig.get();
+        this._search.value = searchConfig.query;
+        this._ignoreCaseCheckbox.checked = searchConfig.ignoreCase;
+        this._regexCheckbox.checked = searchConfig.isRegex;
+    },
+
+    _onAction: function()
+    {
+        if (!this.searchConfig.query || !this.searchConfig.query.length)
+            return;
+        
+        this._save();
+        this._controller.startSearch(this.searchConfig);
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+
+/**
+ * @constructor
+ * @param {string} query
+ * @param {boolean} ignoreCase
+ * @param {boolean} isRegex
+ */
+WebInspector.SearchConfig = function(query, ignoreCase, isRegex)
+{
+    this.query = query;
+    this.ignoreCase = ignoreCase;
+    this.isRegex = isRegex;
+}
+
+/**
+ * @interface
+ */
+WebInspector.SearchScope = function()
+{
+}
+
+WebInspector.SearchScope.prototype = {
+    /**
+     * @param {WebInspector.SearchConfig} searchConfig
+     * @param {WebInspector.Progress} progress
+     * @param {function(WebInspector.FileBasedSearchResultsPane.SearchResult)} searchResultCallback
+     * @param {function(boolean)} searchFinishedCallback
+     */
+    performSearch: function(searchConfig, progress, searchResultCallback, searchFinishedCallback) { },
+
+    stopSearch: function() { },
+    
+    /**
+     * @param {WebInspector.SearchConfig} searchConfig
+     * @return {WebInspector.SearchResultsPane}
+     */
+    createSearchResultsPane: function(searchConfig) { }
+}
+
+/**
+ * @constructor
+ * @param {number} offset
+ * @param {number} length
+ */
+WebInspector.SearchResult = function(offset, length)
+{
+    this.offset = offset;
+    this.length = length;    
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.SearchConfig} searchConfig
+ */
+WebInspector.SearchResultsPane = function(searchConfig)
+{
+    this._searchConfig = searchConfig;
+    this.element = document.createElement("div");
+}
+
+WebInspector.SearchResultsPane.prototype = {
+    /**
+     * @return {WebInspector.SearchConfig}
+     */
+    get searchConfig()
+    {
+        return this._searchConfig;
+    },
+
+    /**
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     */
+    addSearchResult: function(searchResult) { }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SearchResultsPane} 
+ * @param {WebInspector.SearchConfig} searchConfig
+ */
+WebInspector.FileBasedSearchResultsPane = function(searchConfig)
+{
+    WebInspector.SearchResultsPane.call(this, searchConfig);
+    
+    this._searchResults = [];
+
+    this.element.id ="search-results-pane-file-based";
+    
+    this._treeOutlineElement = document.createElement("ol");
+    this._treeOutlineElement.className = "search-results-outline-disclosure";
+    this.element.appendChild(this._treeOutlineElement);
+    this._treeOutline = new TreeOutline(this._treeOutlineElement);
+    
+    this._matchesExpandedCount = 0;
+}
+
+WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount = 20;
+WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce = 20;
+
+WebInspector.FileBasedSearchResultsPane.prototype = {
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {Element}
+     */
+    _createAnchor: function(uiSourceCode, lineNumber, columnNumber)
+    {
+        var anchor = document.createElement("a");
+        anchor.preferredPanel = "scripts";
+        anchor.href = sanitizeHref(uiSourceCode.originURL());
+        anchor.uiSourceCode = uiSourceCode;
+        anchor.lineNumber = lineNumber;
+        return anchor;
+    },
+
+    /**
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     */
+    addSearchResult: function(searchResult)
+    {
+        this._searchResults.push(searchResult);
+        var uiSourceCode = searchResult.uiSourceCode;
+        if (!uiSourceCode)
+            return;
+        var searchMatches = searchResult.searchMatches;
+
+        var fileTreeElement = this._addFileTreeElement(uiSourceCode.fullDisplayName(), searchMatches.length, this._searchResults.length - 1);
+    },
+
+    /**
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     * @param {TreeElement} fileTreeElement
+     */
+    _fileTreeElementExpanded: function(searchResult, fileTreeElement)
+    {
+        if (fileTreeElement._initialized)
+            return;
+        
+        var toIndex = Math.min(searchResult.searchMatches.length, WebInspector.FileBasedSearchResultsPane.fileMatchesShownAtOnce);
+        if (toIndex < searchResult.searchMatches.length) {
+            this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex - 1);
+            this._appendShowMoreMatchesElement(fileTreeElement, searchResult, toIndex - 1);
+        } else
+            this._appendSearchMatches(fileTreeElement, searchResult, 0, toIndex);
+        
+        fileTreeElement._initialized = true;
+    },
+
+    /**
+     * @param {TreeElement} fileTreeElement
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     * @param {number} fromIndex
+     * @param {number} toIndex
+     */
+    _appendSearchMatches: function(fileTreeElement, searchResult, fromIndex, toIndex)
+    {
+        var uiSourceCode = searchResult.uiSourceCode;
+        var searchMatches = searchResult.searchMatches;
+
+        var regex = createSearchRegex(this._searchConfig.query, !this._searchConfig.ignoreCase, this._searchConfig.isRegex);
+        for (var i = fromIndex; i < toIndex; ++i) {
+            var lineNumber = searchMatches[i].lineNumber;
+            var lineContent = searchMatches[i].lineContent;
+            var matchRanges = this._regexMatchRanges(lineContent, regex);
+            
+            var anchor = this._createAnchor(uiSourceCode, lineNumber, matchRanges[0].offset);
+            
+            var numberString = numberToStringWithSpacesPadding(lineNumber + 1, 4);
+            var lineNumberSpan = document.createElement("span");
+            lineNumberSpan.addStyleClass("search-match-line-number");
+            lineNumberSpan.textContent = numberString;
+            anchor.appendChild(lineNumberSpan);
+            
+            var contentSpan = this._createContentSpan(lineContent, matchRanges);
+            anchor.appendChild(contentSpan);
+            
+            var searchMatchElement = new TreeElement("", null, false);
+            searchMatchElement.selectable = false;
+            fileTreeElement.appendChild(searchMatchElement);
+            searchMatchElement.listItemElement.className = "search-match source-code";
+            searchMatchElement.listItemElement.appendChild(anchor);
+        }
+    },
+
+    /**
+     * @param {TreeElement} fileTreeElement
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     * @param {number} startMatchIndex
+     */
+    _appendShowMoreMatchesElement: function(fileTreeElement, searchResult, startMatchIndex)
+    {
+        var matchesLeftCount = searchResult.searchMatches.length - startMatchIndex;
+        var showMoreMatchesText = WebInspector.UIString("Show all matches (%d more).", matchesLeftCount);
+        var showMoreMatchesElement = new TreeElement(showMoreMatchesText, null, false);
+        fileTreeElement.appendChild(showMoreMatchesElement);
+        showMoreMatchesElement.listItemElement.addStyleClass("show-more-matches");
+        showMoreMatchesElement.onselect = this._showMoreMatchesElementSelected.bind(this, searchResult, startMatchIndex, showMoreMatchesElement);
+    },
+
+    /**
+     * @param {WebInspector.FileBasedSearchResultsPane.SearchResult} searchResult
+     * @param {number} startMatchIndex
+     * @param {TreeElement} showMoreMatchesElement
+     */
+    _showMoreMatchesElementSelected: function(searchResult, startMatchIndex, showMoreMatchesElement)
+    {
+        var fileTreeElement = showMoreMatchesElement.parent;
+        fileTreeElement.removeChild(showMoreMatchesElement);
+        this._appendSearchMatches(fileTreeElement, searchResult, startMatchIndex, searchResult.searchMatches.length);
+    },
+
+    /**
+     * @param {string} fileName
+     * @param {number} searchMatchesCount
+     * @param {number} searchResultIndex
+     */
+    _addFileTreeElement: function(fileName, searchMatchesCount, searchResultIndex)
+    {
+        var fileTreeElement = new TreeElement("", null, true);
+        fileTreeElement.toggleOnClick = true;
+        fileTreeElement.selectable = false;
+
+        this._treeOutline.appendChild(fileTreeElement);
+        fileTreeElement.listItemElement.addStyleClass("search-result");
+
+        var fileNameSpan = document.createElement("span");
+        fileNameSpan.className = "search-result-file-name";
+        fileNameSpan.textContent = fileName;
+        fileTreeElement.listItemElement.appendChild(fileNameSpan);
+
+        var matchesCountSpan = document.createElement("span");
+        matchesCountSpan.className = "search-result-matches-count";
+        if (searchMatchesCount === 1)
+            matchesCountSpan.textContent = WebInspector.UIString("(%d match)", searchMatchesCount);
+        else
+            matchesCountSpan.textContent = WebInspector.UIString("(%d matches)", searchMatchesCount);
+        
+        fileTreeElement.listItemElement.appendChild(matchesCountSpan);
+        
+        var searchResult = this._searchResults[searchResultIndex];
+        fileTreeElement.onexpand = this._fileTreeElementExpanded.bind(this, searchResult, fileTreeElement);
+
+        // Expand until at least certain amount of matches is expanded.
+        if (this._matchesExpandedCount < WebInspector.FileBasedSearchResultsPane.matchesExpandedByDefaultCount)
+            fileTreeElement.expand();
+        this._matchesExpandedCount += searchResult.searchMatches.length;
+
+        return fileTreeElement; 
+    },
+
+    /**
+     * @param {string} lineContent
+     * @param {RegExp} regex
+     * @return {Array.}
+     */
+    _regexMatchRanges: function(lineContent, regex)
+    {
+        regex.lastIndex = 0;
+        var match;
+        var offset = 0;
+        var matchRanges = [];
+        while ((regex.lastIndex < lineContent.length) && (match = regex.exec(lineContent)))
+            matchRanges.push(new WebInspector.SearchResult(match.index, match[0].length));
+
+        return matchRanges;
+    },
+    
+    /**
+     * @param {string} lineContent
+     * @param {Array.} matchRanges
+     */
+    _createContentSpan: function(lineContent, matchRanges)
+    {
+        var contentSpan = document.createElement("span");
+        contentSpan.className = "search-match-content";
+        contentSpan.textContent = lineContent;
+        WebInspector.highlightRangesWithStyleClass(contentSpan, matchRanges, "highlighted-match");
+        return contentSpan;
+    },
+
+    __proto__: WebInspector.SearchResultsPane.prototype
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.UISourceCode} uiSourceCode
+ * @param {Array.} searchMatches
+ */
+WebInspector.FileBasedSearchResultsPane.SearchResult = function(uiSourceCode, searchMatches) {
+    this.uiSourceCode = uiSourceCode;
+    this.searchMatches = searchMatches;
+}
+
+/**
+ * @type {WebInspector.AdvancedSearchController}
+ */
+WebInspector.advancedSearchController = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheItemsView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheItemsView.js
new file mode 100644
index 00000000..630fd6d5
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheItemsView.js
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.ApplicationCacheItemsView = function(model, frameId)
+{
+    WebInspector.View.call(this);
+    
+    this._model = model;
+
+    this.element.addStyleClass("storage-view");
+    this.element.addStyleClass("table");
+
+    // FIXME: Needs better tooltip. (Localized)
+    this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
+    this.deleteButton.visible = false;
+    this.deleteButton.addEventListener("click", this._deleteButtonClicked, this);
+
+    this.connectivityIcon = document.createElement("div");
+    this.connectivityMessage = document.createElement("span");
+    this.connectivityMessage.className = "storage-application-cache-connectivity";
+    this.connectivityMessage.textContent = "";
+
+    this.divider = document.createElement("span");
+    this.divider.className = "status-bar-item status-bar-divider";
+
+    this.statusIcon = document.createElement("div");
+    this.statusMessage = document.createElement("span");
+    this.statusMessage.className = "storage-application-cache-status";
+    this.statusMessage.textContent = "";
+
+    this._frameId = frameId;
+
+    this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("No Application Cache information available."));
+    this._emptyView.show(this.element);
+
+    this._markDirty();
+    
+    var status = this._model.frameManifestStatus(frameId);
+    this.updateStatus(status);
+    
+    this.updateNetworkState(this._model.onLine);
+
+    // FIXME: Status bar items don't work well enough yet, so they are being hidden.
+    // http://webkit.org/b/41637 Web Inspector: Give Semantics to "Refresh" and "Delete" Buttons in ApplicationCache DataGrid
+    this.deleteButton.element.style.display = "none";
+}
+
+WebInspector.ApplicationCacheItemsView.prototype = {
+    get statusBarItems()
+    {
+        return [
+            this.deleteButton.element,
+            this.connectivityIcon, this.connectivityMessage, this.divider,
+            this.statusIcon, this.statusMessage
+        ];
+    },
+
+    wasShown: function()
+    {
+        this._maybeUpdate();
+    },
+
+    willHide: function()
+    {
+        this.deleteButton.visible = false;
+    },
+
+    _maybeUpdate: function()
+    {
+        if (!this.isShowing() || !this._viewDirty)
+            return;
+        
+        this._update();
+        this._viewDirty = false;
+    },
+
+    _markDirty: function()
+    {
+        this._viewDirty = true;
+    },
+
+    /**
+     * @param {number} status
+     */
+    updateStatus: function(status)
+    {
+        var oldStatus = this._status;
+        this._status = status;
+        
+        var statusInformation = {};
+        // We should never have UNCACHED status, since we remove frames with UNCACHED application cache status from the tree. 
+        statusInformation[applicationCache.UNCACHED]    = { className: "red-ball", text: "UNCACHED" };
+        statusInformation[applicationCache.IDLE]        = { className: "green-ball", text: "IDLE" };
+        statusInformation[applicationCache.CHECKING]    = { className: "orange-ball",  text: "CHECKING" };
+        statusInformation[applicationCache.DOWNLOADING] = { className: "orange-ball",  text: "DOWNLOADING" };
+        statusInformation[applicationCache.UPDATEREADY] = { className: "green-ball",  text: "UPDATEREADY" };
+        statusInformation[applicationCache.OBSOLETE]    = { className: "red-ball",      text: "OBSOLETE" };
+
+        var info = statusInformation[status] || statusInformation[applicationCache.UNCACHED];
+
+        this.statusIcon.className = "storage-application-cache-status-icon " + info.className;
+        this.statusMessage.textContent = info.text;
+
+        if (this.isShowing() && this._status === applicationCache.IDLE && (oldStatus === applicationCache.UPDATEREADY || !this._resources))
+            this._markDirty();
+        this._maybeUpdate();
+    },
+
+    /**
+     * @param {boolean} isNowOnline
+     */
+    updateNetworkState: function(isNowOnline)
+    {
+        if (isNowOnline) {
+            this.connectivityIcon.className = "storage-application-cache-connectivity-icon green-ball";
+            this.connectivityMessage.textContent = WebInspector.UIString("Online");
+        } else {
+            this.connectivityIcon.className = "storage-application-cache-connectivity-icon red-ball";
+            this.connectivityMessage.textContent = WebInspector.UIString("Offline");
+        }
+    },
+
+    _update: function()
+    {
+        this._model.requestApplicationCache(this._frameId, this._updateCallback.bind(this));
+    },
+
+    /**
+     * @param {Object} applicationCache
+     */
+    _updateCallback: function(applicationCache)
+    {
+        if (!applicationCache || !applicationCache.manifestURL) {
+            delete this._manifest;
+            delete this._creationTime;
+            delete this._updateTime;
+            delete this._size;
+            delete this._resources;
+            
+            this._emptyView.show(this.element);
+            this.deleteButton.visible = false;
+            if (this._dataGrid)
+                this._dataGrid.element.addStyleClass("hidden");
+            return;
+        }
+        // FIXME: are these variables needed anywhere else?
+        this._manifest = applicationCache.manifestURL;
+        this._creationTime = applicationCache.creationTime;
+        this._updateTime = applicationCache.updateTime;
+        this._size = applicationCache.size;
+        this._resources = applicationCache.resources;
+
+        if (!this._dataGrid)
+            this._createDataGrid();
+
+        this._populateDataGrid();
+        this._dataGrid.autoSizeColumns(20, 80);
+        this._dataGrid.element.removeStyleClass("hidden");
+        this._emptyView.detach();
+        this.deleteButton.visible = true;
+
+        // FIXME: For Chrome, put creationTime and updateTime somewhere.
+        // NOTE: localizedString has not yet been added.
+        // WebInspector.UIString("(%s) Created: %s Updated: %s", this._size, this._creationTime, this._updateTime);
+    },
+
+    _createDataGrid: function()
+    {
+        var columns = [
+            {title: WebInspector.UIString("Resource"), sort: WebInspector.DataGrid.Order.Ascending, sortable: true},
+            {title: WebInspector.UIString("Type"), sortable: true},
+            {title: WebInspector.UIString("Size"), align: WebInspector.DataGrid.Align.Right, sortable: true}
+        ];
+        this._dataGrid = new WebInspector.DataGrid(columns);
+        this._dataGrid.show(this.element);
+        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._populateDataGrid, this);
+    },
+
+    _populateDataGrid: function()
+    {
+        var selectedResource = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.resource : null;
+        var sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1;
+
+        function numberCompare(field, resource1, resource2)
+        {
+            return sortDirection * (resource1[field] - resource2[field]);
+        }
+        function localeCompare(field, resource1, resource2)
+        {
+             return sortDirection * (resource1[field] + "").localeCompare(resource2[field] + "")
+        }
+
+        var comparator;
+        switch (parseInt(this._dataGrid.sortColumnIdentifier(), 10)) {
+            case 0: comparator = localeCompare.bind(this, "name"); break;
+            case 1: comparator = localeCompare.bind(this, "type"); break;
+            case 2: comparator = numberCompare.bind(this, "size"); break;
+            default: localeCompare.bind(this, "resource"); // FIXME: comparator = ?
+        }
+
+        this._resources.sort(comparator);
+        this._dataGrid.rootNode().removeChildren();
+
+        var nodeToSelect;
+        for (var i = 0; i < this._resources.length; ++i) {
+            var data = {};
+            var resource = this._resources[i];
+            data[0] = resource.url;
+            data[1] = resource.type;
+            data[2] = Number.bytesToString(resource.size);
+            var node = new WebInspector.DataGridNode(data);
+            node.resource = resource;
+            node.selectable = true;
+            this._dataGrid.rootNode().appendChild(node);
+            if (resource === selectedResource) {
+                nodeToSelect = node;
+                nodeToSelect.selected = true;
+            }
+        }
+
+        if (!nodeToSelect && this._dataGrid.rootNode().children.length)
+            this._dataGrid.rootNode().children[0].selected = true;
+    },
+
+    _deleteButtonClicked: function(event)
+    {
+        if (!this._dataGrid || !this._dataGrid.selectedNode)
+            return;
+
+        // FIXME: Delete Button semantics are not yet defined. (Delete a single, or all?)
+        this._deleteCallback(this._dataGrid.selectedNode);
+    },
+
+    _deleteCallback: function(node)
+    {
+        // FIXME: Should we delete a single (selected) resource or all resources?
+        // InspectorBackend.deleteCachedResource(...)
+        // this._update();
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheModel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheModel.js
new file mode 100644
index 00000000..7f408306
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ApplicationCacheModel.js
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
+ * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.ApplicationCacheModel = function()
+{
+    ApplicationCacheAgent.enable();
+    InspectorBackend.registerApplicationCacheDispatcher(new WebInspector.ApplicationCacheDispatcher(this));
+    
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameNavigated, this._frameNavigated, this);
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameDetached, this._frameDetached, this);
+    
+    this._statuses = {};
+    this._manifestURLsByFrame = {};
+
+    this._mainFrameNavigated();
+    
+    this._onLine = true;
+}
+
+WebInspector.ApplicationCacheModel.EventTypes = {
+    FrameManifestStatusUpdated: "FrameManifestStatusUpdated",
+    FrameManifestAdded: "FrameManifestAdded",
+    FrameManifestRemoved: "FrameManifestRemoved",
+    NetworkStateChanged: "NetworkStateChanged"
+}
+
+WebInspector.ApplicationCacheModel.prototype = {
+    _frameNavigated: function(event)
+    {
+        var frame = /** @type {WebInspector.ResourceTreeFrame} */ (event.data);
+        if (frame.isMainFrame()) {
+            this._mainFrameNavigated();
+            return;
+        }
+
+        ApplicationCacheAgent.getManifestForFrame(frame.id, this._manifestForFrameLoaded.bind(this, frame.id));
+    },
+    
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameDetached: function(event)
+    {
+        var frame = /** @type {WebInspector.ResourceTreeFrame} */ (event.data);
+        this._frameManifestRemoved(frame.id);
+    },
+    
+    _mainFrameNavigated: function()
+    {
+        ApplicationCacheAgent.getFramesWithManifests(this._framesWithManifestsLoaded.bind(this));
+    },
+
+    /**
+     * @param {string} frameId
+     * @param {?Protocol.Error} error
+     * @param {string} manifestURL
+     */
+    _manifestForFrameLoaded: function(frameId, error, manifestURL)
+    {
+        if (error) {
+            console.error(error);
+            return;
+        }
+        
+        if (!manifestURL)
+            this._frameManifestRemoved(frameId);
+    },
+    
+    /**
+     * @param {?Protocol.Error} error
+     * @param {Array.} framesWithManifests
+     */
+    _framesWithManifestsLoaded: function(error, framesWithManifests)
+    {
+        if (error) {
+            console.error(error);
+            return;
+        }
+
+        for (var i = 0; i < framesWithManifests.length; ++i)
+            this._frameManifestUpdated(framesWithManifests[i].frameId, framesWithManifests[i].manifestURL, framesWithManifests[i].status);
+    },
+    
+    /**
+     * @param {string} frameId
+     * @param {string} manifestURL
+     * @param {number} status
+     */
+    _frameManifestUpdated: function(frameId, manifestURL, status)
+    {
+        if (status === applicationCache.UNCACHED) {
+            this._frameManifestRemoved(frameId);
+            return;
+        }
+            
+        if (!manifestURL)
+            return;
+            
+        if (this._manifestURLsByFrame[frameId] && manifestURL !== this._manifestURLsByFrame[frameId])
+            this._frameManifestRemoved(frameId);
+        
+        var statusChanged = this._statuses[frameId] !== status;
+        this._statuses[frameId] = status;
+        
+        if (!this._manifestURLsByFrame[frameId]) {
+            this._manifestURLsByFrame[frameId] = manifestURL;
+            this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestAdded, frameId);
+        }
+            
+        if (statusChanged)
+            this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestStatusUpdated, frameId);
+    },
+    
+    /**
+     * @param {string} frameId
+     */
+    _frameManifestRemoved: function(frameId)
+    {
+        if (!this._manifestURLsByFrame[frameId])
+            return;
+
+        var manifestURL = this._manifestURLsByFrame[frameId];
+        delete this._manifestURLsByFrame[frameId];
+        delete this._statuses[frameId];
+        
+        this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.FrameManifestRemoved, frameId);
+    },
+    
+    /**
+     * @param {string} frameId
+     * @return {string}
+     */
+    frameManifestURL: function(frameId)
+    {
+        return this._manifestURLsByFrame[frameId] || "";
+    },
+    
+    /**
+     * @param {string} frameId
+     * @return {number}
+     */
+    frameManifestStatus: function(frameId)
+    {
+        return this._statuses[frameId] || applicationCache.UNCACHED;
+    },
+    
+    /**
+     * @return {boolean}
+     */
+    get onLine()
+    {
+        return this._onLine;
+    },
+    
+    /**
+     * @param {string} frameId
+     * @param {string} manifestURL
+     * @param {number} status
+     */
+    _statusUpdated: function(frameId, manifestURL, status)
+    {
+        this._frameManifestUpdated(frameId, manifestURL, status);
+    },
+    
+    /**
+     * @param {string} frameId
+     * @param {function(Object)} callback
+     */
+    requestApplicationCache: function(frameId, callback)
+    {
+        function callbackWrapper(error, applicationCache)
+        {
+            if (error) {
+                console.error(error);
+                callback(null);
+                return;
+            }
+            
+            callback(applicationCache);
+        }
+        
+        ApplicationCacheAgent.getApplicationCacheForFrame(frameId, callbackWrapper.bind(this));
+    },
+    
+    /**
+     * @param {boolean} isNowOnline
+     */
+    _networkStateUpdated: function(isNowOnline)
+    {
+        this._onLine = isNowOnline;
+        this.dispatchEventToListeners(WebInspector.ApplicationCacheModel.EventTypes.NetworkStateChanged, isNowOnline);
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {ApplicationCacheAgent.Dispatcher}
+ */
+WebInspector.ApplicationCacheDispatcher = function(applicationCacheModel)
+{
+    this._applicationCacheModel = applicationCacheModel;
+}
+
+WebInspector.ApplicationCacheDispatcher.prototype = {
+    /**
+     * @param {string} frameId
+     * @param {string} manifestURL
+     * @param {number} status
+     */
+    applicationCacheStatusUpdated: function(frameId, manifestURL, status)
+    {
+        this._applicationCacheModel._statusUpdated(frameId, manifestURL, status);
+    },
+    
+    /**
+     * @param {boolean} isNowOnline
+     */
+    networkStateUpdated: function(isNowOnline)
+    {
+        this._applicationCacheModel._networkStateUpdated(isNowOnline);
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditCategories.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditCategories.js
new file mode 100644
index 00000000..ffd3f634
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditCategories.js
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditCategory}
+ */
+WebInspector.AuditCategories.PagePerformance = function() {
+    WebInspector.AuditCategory.call(this, WebInspector.AuditCategories.PagePerformance.AuditCategoryName);
+}
+
+WebInspector.AuditCategories.PagePerformance.AuditCategoryName = "Web Page Performance";
+
+WebInspector.AuditCategories.PagePerformance.prototype = {
+    initialize: function()
+    {
+        this.addRule(new WebInspector.AuditRules.UnusedCssRule(), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.CssInHeadRule(), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.StylesScriptsOrderRule(), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.VendorPrefixedCSSProperties(), WebInspector.AuditRule.Severity.Warning);
+    },
+
+    __proto__: WebInspector.AuditCategory.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditCategory}
+ */
+WebInspector.AuditCategories.NetworkUtilization = function() {
+    WebInspector.AuditCategory.call(this, WebInspector.AuditCategories.NetworkUtilization.AuditCategoryName);
+}
+
+WebInspector.AuditCategories.NetworkUtilization.AuditCategoryName = "Network Utilization";
+
+WebInspector.AuditCategories.NetworkUtilization.prototype = {
+    initialize: function()
+    {
+        this.addRule(new WebInspector.AuditRules.GzipRule(), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.ImageDimensionsRule(), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.CookieSizeRule(400), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.StaticCookielessRule(5), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.CombineJsResourcesRule(2), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.CombineCssResourcesRule(2), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.MinimizeDnsLookupsRule(4), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.ParallelizeDownloadRule(4, 10, 0.5), WebInspector.AuditRule.Severity.Warning);
+        this.addRule(new WebInspector.AuditRules.BrowserCacheControlRule(), WebInspector.AuditRule.Severity.Severe);
+        this.addRule(new WebInspector.AuditRules.ProxyCacheControlRule(), WebInspector.AuditRule.Severity.Warning);
+    },
+
+    __proto__: WebInspector.AuditCategory.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditController.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditController.js
new file mode 100644
index 00000000..475fb6d5
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditController.js
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.AuditsPanel} auditsPanel
+ */
+WebInspector.AuditController = function(auditsPanel)
+{
+    this._auditsPanel = auditsPanel;
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.Load, this._didMainResourceLoad, this);
+}
+
+WebInspector.AuditController.prototype = {
+    /**
+     * @param {!Array.} categories
+     * @param {function(string, !Array.)} resultCallback
+     */
+    _executeAudit: function(categories, resultCallback)
+    {
+        this._progress.setTitle(WebInspector.UIString("Running audit"));
+
+        function ruleResultReadyCallback(categoryResult, ruleResult)
+        {
+            if (ruleResult && ruleResult.children)
+                categoryResult.addRuleResult(ruleResult);
+
+            if (this._progress.isCanceled())
+                this._progress.done();
+        }
+
+        var results = [];
+        var mainResourceURL = WebInspector.inspectedPageURL;
+        var categoriesDone = 0;
+        function categoryDoneCallback()
+        {
+            if (++categoriesDone !== categories.length)
+                return;
+            this._progress.done();
+            resultCallback(mainResourceURL, results)
+        }
+
+        var requests = WebInspector.networkLog.requests.slice();
+        var compositeProgress = new WebInspector.CompositeProgress(this._progress);
+        var subprogresses = [];
+        for (var i = 0; i < categories.length; ++i)
+            subprogresses.push(compositeProgress.createSubProgress());
+        for (var i = 0; i < categories.length; ++i) {
+            var category = categories[i];
+            var result = new WebInspector.AuditCategoryResult(category);
+            results.push(result);
+            category.run(requests, ruleResultReadyCallback.bind(this, result), categoryDoneCallback.bind(this), subprogresses[i]);
+        }
+    },
+
+    /**
+     * @param {function()} launcherCallback
+     * @param {string} mainResourceURL
+     * @param {!Array.} results
+     */
+    _auditFinishedCallback: function(launcherCallback, mainResourceURL, results)
+    {
+        this._auditsPanel.auditFinishedCallback(mainResourceURL, results);
+        if (!this._progress.isCanceled())
+            launcherCallback();
+    },
+
+    /**
+     * @param {Array.} categoryIds
+     * @param {WebInspector.Progress} progress
+     * @param {boolean} runImmediately
+     * @param {function()} startedCallback
+     * @param {function()} finishedCallback
+     */
+    initiateAudit: function(categoryIds, progress, runImmediately, startedCallback, finishedCallback)
+    {
+        if (!categoryIds || !categoryIds.length)
+            return;
+
+        this._progress = progress;
+
+        var categories = [];
+        for (var i = 0; i < categoryIds.length; ++i)
+            categories.push(this._auditsPanel.categoriesById[categoryIds[i]]);
+
+        function startAuditWhenResourcesReady()
+        {
+            startedCallback();
+            this._executeAudit(categories, this._auditFinishedCallback.bind(this, finishedCallback));
+        }
+
+        if (runImmediately)
+            startAuditWhenResourcesReady.call(this);
+        else
+            this._reloadResources(startAuditWhenResourcesReady.bind(this));
+
+        WebInspector.userMetrics.AuditsStarted.record();
+    },
+
+    /**
+     * @param {function()=} callback
+     */
+    _reloadResources: function(callback)
+    {
+        this._pageReloadCallback = callback;
+        PageAgent.reload(false);
+    },
+
+    _didMainResourceLoad: function()
+    {
+        if (this._pageReloadCallback) {
+            var callback = this._pageReloadCallback;
+            delete this._pageReloadCallback;
+            callback();
+        }
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditFormatters.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditFormatters.js
new file mode 100644
index 00000000..efb04854
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditFormatters.js
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.AuditFormatters = function()
+{
+}
+
+WebInspector.AuditFormatters.Registry = {
+    text: function(text)
+    {
+        return document.createTextNode(text);
+    },
+
+    snippet: function(snippetText)
+    {
+        var div = document.createElement("div");
+        div.textContent = snippetText;
+        div.className = "source-code";
+        return div;
+    },
+
+    concat: function()
+    {
+        var parent = document.createElement("span");
+        for (var arg = 0; arg < arguments.length; ++arg)
+            parent.appendChild(WebInspector.auditFormatters.apply(arguments[arg]));
+        return parent;
+    },
+
+    url: function(url, displayText, allowExternalNavigation)
+    {
+        var a = document.createElement("a");
+        a.href = sanitizeHref(url);
+        a.title = url;
+        a.textContent = displayText || url;
+        if (allowExternalNavigation)
+            a.target = "_blank";
+        return a;
+    },
+
+    resourceLink: function(url, line)
+    {
+        // FIXME: use WebInspector.Linkifier
+        return WebInspector.linkifyResourceAsNode(url, line, "console-message-url webkit-html-resource-link");
+    }
+};
+
+WebInspector.AuditFormatters.prototype = {
+    /**
+     * @param {string|boolean|number|Object} value
+     */
+    apply: function(value)
+    {
+        var formatter;
+        var type = typeof value;
+        var args;
+
+        switch (type) {
+        case "string":
+        case "boolean":
+        case "number":
+            formatter = WebInspector.AuditFormatters.Registry.text;
+        args = [ value.toString() ];
+        break;
+
+        case "object":
+            if (value instanceof Node)
+                return value;
+            if (value instanceof Array) {
+                formatter = WebInspector.AuditFormatters.Registry.concat;
+                args = value;
+            } else if (value.type && value.arguments) {
+                formatter = WebInspector.AuditFormatters.Registry[value.type];
+                args = value.arguments;
+            }
+        }
+        if (!formatter)
+            throw "Invalid value or formatter: " + type + JSON.stringify(value);
+
+        return formatter.apply(null, args);
+    },
+
+    /**
+     * @param {Object} formatters
+     * @param {Object} thisArgument
+     * @param {string|boolean|number|Object} value
+     */
+    partiallyApply: function(formatters, thisArgument, value)
+    {
+        if (value instanceof Array)
+            return value.map(this.partiallyApply.bind(this, formatters, thisArgument));
+        if (typeof value === "object" && typeof formatters[value.type] === "function" && value.arguments)
+            return formatters[value.type].apply(thisArgument, value.arguments);
+        return value;
+    }
+}
+
+WebInspector.auditFormatters = new WebInspector.AuditFormatters();
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditLauncherView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditLauncherView.js
new file mode 100644
index 00000000..1d4a6742
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditLauncherView.js
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.AuditController} auditController
+ * @extends {WebInspector.View}
+ */
+WebInspector.AuditLauncherView = function(auditController)
+{
+    WebInspector.View.call(this);
+
+    this._auditController = auditController;
+
+    this._categoryIdPrefix = "audit-category-item-";
+    this._auditRunning = false;
+
+    this.element.addStyleClass("audit-launcher-view");
+    this.element.addStyleClass("panel-enabler-view");
+
+    this._contentElement = document.createElement("div");
+    this._contentElement.className = "audit-launcher-view-content";
+    this.element.appendChild(this._contentElement);
+    this._boundCategoryClickListener = this._categoryClicked.bind(this);
+
+    this._resetResourceCount();
+
+    this._sortedCategories = [];
+
+    this._headerElement = document.createElement("h1");
+    this._headerElement.className = "no-audits";
+    this._headerElement.textContent = WebInspector.UIString("No audits to run");
+    this._contentElement.appendChild(this._headerElement);
+
+    WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestStarted, this._onRequestStarted, this);
+    WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.RequestFinished, this._onRequestFinished, this);
+
+    var defaultSelectedAuditCategory = {};
+    defaultSelectedAuditCategory[WebInspector.AuditLauncherView.AllCategoriesKey] = true;
+    this._selectedCategoriesSetting = WebInspector.settings.createSetting("selectedAuditCategories", defaultSelectedAuditCategory);
+}
+
+WebInspector.AuditLauncherView.AllCategoriesKey = "__AllCategories";
+
+WebInspector.AuditLauncherView.prototype = {
+    _resetResourceCount: function()
+    {
+        this._loadedResources = 0;
+        this._totalResources = 0;
+    },
+
+    _onRequestStarted: function(event)
+    {
+        var request = /** @type {WebInspector.NetworkRequest} */ (event.data);
+        // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway.
+        if (request.type === WebInspector.resourceTypes.WebSocket)
+            return;
+        ++this._totalResources;
+        this._updateResourceProgress();
+    },
+
+    _onRequestFinished: function(event)
+    {
+        var request = /** @type {WebInspector.NetworkRequest} */ (event.data);
+        // See resorceStarted for details.
+        if (request.type === WebInspector.resourceTypes.WebSocket)
+            return;
+        ++this._loadedResources;
+        this._updateResourceProgress();
+    },
+
+    /**
+     * @param {!WebInspector.AuditCategory} category
+     */
+    addCategory: function(category)
+    {
+        if (!this._sortedCategories.length)
+            this._createLauncherUI();
+
+        var selectedCategories = this._selectedCategoriesSetting.get();
+        var categoryElement = this._createCategoryElement(category.displayName, category.id);
+        category._checkboxElement = categoryElement.firstChild;
+        if (this._selectAllCheckboxElement.checked || selectedCategories[category.displayName]) {
+            category._checkboxElement.checked = true;
+            ++this._currentCategoriesCount;
+        }
+
+        /**
+         * @param {!WebInspector.AuditCategory} a
+         * @param {!WebInspector.AuditCategory} b
+         * @return {number}
+         */
+        function compareCategories(a, b)
+        {
+            var aTitle = a.displayName || "";
+            var bTitle = b.displayName || "";
+            return aTitle.localeCompare(bTitle);
+        }
+        var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories);
+        this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]);
+        this._sortedCategories.splice(insertBefore, 0, category);
+        this._selectedCategoriesUpdated();
+    },
+
+    /**
+     * @param {boolean} auditRunning
+     */
+    _setAuditRunning: function(auditRunning)
+    {
+        if (this._auditRunning === auditRunning)
+            return;
+        this._auditRunning = auditRunning;
+        this._updateButton();
+        this._toggleUIComponents(this._auditRunning);
+        if (this._auditRunning)
+            this._startAudit();
+        else
+            this._stopAudit();
+    },
+
+    _startAudit: function()
+    {
+        var catIds = [];
+        for (var category = 0; category < this._sortedCategories.length; ++category) {
+            if (this._sortedCategories[category]._checkboxElement.checked)
+                catIds.push(this._sortedCategories[category].id);
+        }
+
+        this._resetResourceCount();
+        this._progressIndicator = new WebInspector.ProgressIndicator();
+        this._buttonContainerElement.appendChild(this._progressIndicator.element);
+        this._displayResourceLoadingProgress = true;
+
+        function onAuditStarted()
+        {
+            this._displayResourceLoadingProgress = false;
+        }
+        this._auditController.initiateAudit(catIds, this._progressIndicator, this._auditPresentStateElement.checked, onAuditStarted.bind(this), this._setAuditRunning.bind(this, false));
+    },
+
+    _stopAudit: function()
+    {
+        this._displayResourceLoadingProgress = false;
+        this._progressIndicator.cancel();
+        this._progressIndicator.done();
+        delete this._progressIndicator;
+    },
+
+    /**
+     * @param {boolean} disable
+     */
+    _toggleUIComponents: function(disable)
+    {
+        this._selectAllCheckboxElement.disabled = disable;
+        this._categoriesElement.disabled = disable;
+        this._auditPresentStateElement.disabled = disable;
+        this._auditReloadedStateElement.disabled = disable;
+    },
+
+    _launchButtonClicked: function(event)
+    {
+        this._setAuditRunning(!this._auditRunning);
+    },
+
+    /**
+     * @param {boolean} checkCategories
+     * @param {boolean=} userGesture
+     */
+    _selectAllClicked: function(checkCategories, userGesture)
+    {
+        var childNodes = this._categoriesElement.childNodes;
+        for (var i = 0, length = childNodes.length; i < length; ++i)
+            childNodes[i].firstChild.checked = checkCategories;
+        this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0;
+        this._selectedCategoriesUpdated(userGesture);
+    },
+
+    _categoryClicked: function(event)
+    {
+        this._currentCategoriesCount += event.target.checked ? 1 : -1;
+        this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length;
+        this._selectedCategoriesUpdated(true);
+    },
+
+    /**
+     * @param {string} title
+     * @param {string} id
+     */
+    _createCategoryElement: function(title, id)
+    {
+        var labelElement = document.createElement("label");
+        labelElement.id = this._categoryIdPrefix + id;
+
+        var element = document.createElement("input");
+        element.type = "checkbox";
+        if (id !== "")
+            element.addEventListener("click", this._boundCategoryClickListener, false);
+        labelElement.appendChild(element);
+        labelElement.appendChild(document.createTextNode(title));
+        labelElement.__displayName = title;
+
+        return labelElement;
+    },
+
+    _createLauncherUI: function()
+    {
+        this._headerElement = document.createElement("h1");
+        this._headerElement.textContent = WebInspector.UIString("Select audits to run");
+
+        for (var child = 0; child < this._contentElement.children.length; ++child)
+            this._contentElement.removeChild(this._contentElement.children[child]);
+
+        this._contentElement.appendChild(this._headerElement);
+
+        function handleSelectAllClick(event)
+        {
+            this._selectAllClicked(event.target.checked, true);
+        }
+        var categoryElement = this._createCategoryElement(WebInspector.UIString("Select All"), "");
+        categoryElement.id = "audit-launcher-selectall";
+        this._selectAllCheckboxElement = categoryElement.firstChild;
+        this._selectAllCheckboxElement.checked = this._selectedCategoriesSetting.get()[WebInspector.AuditLauncherView.AllCategoriesKey];
+        this._selectAllCheckboxElement.addEventListener("click", handleSelectAllClick.bind(this), false);
+        this._contentElement.appendChild(categoryElement);
+
+        this._categoriesElement = this._contentElement.createChild("fieldset", "audit-categories-container");
+        this._currentCategoriesCount = 0;
+
+        this._contentElement.createChild("div", "flexible-space");
+
+        this._buttonContainerElement = this._contentElement.createChild("div", "button-container");
+
+        var labelElement = this._buttonContainerElement.createChild("label");
+        this._auditPresentStateElement = labelElement.createChild("input");
+        this._auditPresentStateElement.name = "audit-mode";
+        this._auditPresentStateElement.type = "radio";
+        this._auditPresentStateElement.checked = true;
+        this._auditPresentStateLabelElement = document.createTextNode(WebInspector.UIString("Audit Present State"));
+        labelElement.appendChild(this._auditPresentStateLabelElement);
+
+        labelElement = this._buttonContainerElement.createChild("label");
+        this._auditReloadedStateElement = labelElement.createChild("input");
+        this._auditReloadedStateElement.name = "audit-mode";
+        this._auditReloadedStateElement.type = "radio";
+        labelElement.appendChild(document.createTextNode("Reload Page and Audit on Load"));
+
+        this._launchButton = this._buttonContainerElement.createChild("button");
+        this._launchButton.textContent = WebInspector.UIString("Run");
+        this._launchButton.addEventListener("click", this._launchButtonClicked.bind(this), false);
+
+        this._selectAllClicked(this._selectAllCheckboxElement.checked);
+    },
+
+    _updateResourceProgress: function()
+    {
+        if (this._displayResourceLoadingProgress)
+            this._progressIndicator.setTitle(WebInspector.UIString("Loading (%d of %d)", this._loadedResources, this._totalResources));
+    },
+
+    /**
+     * @param {boolean=} userGesture
+     */
+    _selectedCategoriesUpdated: function(userGesture)
+    {
+        // Save present categories only upon user gesture to clean up junk from past versions and removed extensions.
+        // Do not remove old categories if not handling a user gesture, as there's chance categories will be added
+        // later during start-up.
+        var selectedCategories = userGesture ? {} : this._selectedCategoriesSetting.get();
+        var childNodes = this._categoriesElement.childNodes;
+        for (var i = 0, length = childNodes.length; i < length; ++i)
+            selectedCategories[childNodes[i].__displayName] = childNodes[i].firstChild.checked;
+        selectedCategories[WebInspector.AuditLauncherView.AllCategoriesKey] = this._selectAllCheckboxElement.checked;
+        this._selectedCategoriesSetting.set(selectedCategories);
+        this._updateButton();
+    },
+
+    _updateButton: function()
+    {
+        this._launchButton.textContent = this._auditRunning ? WebInspector.UIString("Stop") : WebInspector.UIString("Run");
+        this._launchButton.disabled = !this._currentCategoriesCount;
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditResultView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditResultView.js
new file mode 100644
index 00000000..bfeb6f1b
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditResultView.js
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPaneStack}
+ * @param {!Array.} categoryResults
+ */
+WebInspector.AuditResultView = function(categoryResults)
+{
+    WebInspector.SidebarPaneStack.call(this);
+    this.element.addStyleClass("audit-result-view");
+
+    function categorySorter(a, b) {
+        return (a.title || "").localeCompare(b.title || "");
+    }
+    categoryResults.sort(categorySorter);
+    for (var i = 0; i < categoryResults.length; ++i)
+        this.addPane(new WebInspector.AuditCategoryResultPane(categoryResults[i]));
+}
+
+WebInspector.AuditResultView.prototype = {
+    __proto__: WebInspector.SidebarPaneStack.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPane}
+ * @param {!WebInspector.AuditCategoryResult} categoryResult
+ */
+WebInspector.AuditCategoryResultPane = function(categoryResult)
+{
+    WebInspector.SidebarPane.call(this, categoryResult.title);
+    var treeOutlineElement = document.createElement("ol");
+    this.bodyElement.addStyleClass("audit-result-tree");
+    this.bodyElement.appendChild(treeOutlineElement);
+
+    this._treeOutline = new TreeOutline(treeOutlineElement);
+    this._treeOutline.expandTreeElementsWhenArrowing = true;
+
+    function ruleSorter(a, b)
+    {
+        var result = WebInspector.AuditRule.SeverityOrder[a.severity || 0] - WebInspector.AuditRule.SeverityOrder[b.severity || 0];
+        if (!result)
+            result = (a.value || "").localeCompare(b.value || "");
+        return result;
+    }
+
+    categoryResult.ruleResults.sort(ruleSorter);
+
+    for (var i = 0; i < categoryResult.ruleResults.length; ++i) {
+        var ruleResult = categoryResult.ruleResults[i];
+        var treeElement = this._appendResult(this._treeOutline, ruleResult);
+        treeElement.listItemElement.addStyleClass("audit-result");
+
+        if (ruleResult.severity) {
+            var severityElement = document.createElement("div");
+            severityElement.className = "severity-" + ruleResult.severity;
+            treeElement.listItemElement.appendChild(severityElement);
+        }
+    }
+    this.expand();
+}
+
+WebInspector.AuditCategoryResultPane.prototype = {
+    /**
+     * @param {(TreeOutline|TreeElement)} parentTreeElement
+     * @param {!WebInspector.AuditRuleResult} result
+     */
+    _appendResult: function(parentTreeElement, result)
+    {
+        var title = "";
+
+        if (typeof result.value === "string") {
+            title = result.value;
+            if (result.violationCount)
+                title = String.sprintf("%s (%d)", title, result.violationCount);
+        }
+
+        var treeElement = new TreeElement(null, null, !!result.children);
+        treeElement.title = title;
+        parentTreeElement.appendChild(treeElement);
+
+        if (result.className)
+            treeElement.listItemElement.addStyleClass(result.className);
+        if (typeof result.value !== "string")
+            treeElement.listItemElement.appendChild(WebInspector.auditFormatters.apply(result.value));
+
+        if (result.children) {
+            for (var i = 0; i < result.children.length; ++i)
+                this._appendResult(treeElement, result.children[i]);
+        }
+        if (result.expanded) {
+            treeElement.listItemElement.removeStyleClass("parent");
+            treeElement.listItemElement.addStyleClass("parent-expanded");
+            treeElement.expand();
+        }
+        return treeElement;
+    },
+
+    __proto__: WebInspector.SidebarPane.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditRules.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditRules.js
new file mode 100644
index 00000000..93820287
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditRules.js
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.AuditRules.IPAddressRegexp = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;
+
+WebInspector.AuditRules.CacheableResponseCodes =
+{
+    200: true,
+    203: true,
+    206: true,
+    300: true,
+    301: true,
+    410: true,
+
+    304: true // Underlying request is cacheable
+}
+
+/**
+ * @param {!Array.} requests
+ * @param {Array.} types
+ * @param {boolean} needFullResources
+ * @return {(Object.>|Object.>)}
+ */
+WebInspector.AuditRules.getDomainToResourcesMap = function(requests, types, needFullResources)
+{
+    var domainToResourcesMap = {};
+    for (var i = 0, size = requests.length; i < size; ++i) {
+        var request = requests[i];
+        if (types && types.indexOf(request.type) === -1)
+            continue;
+        var parsedURL = request.url.asParsedURL();
+        if (!parsedURL)
+            continue;
+        var domain = parsedURL.host;
+        var domainResources = domainToResourcesMap[domain];
+        if (domainResources === undefined) {
+          domainResources = [];
+          domainToResourcesMap[domain] = domainResources;
+        }
+        domainResources.push(needFullResources ? request : request.url);
+    }
+    return domainToResourcesMap;
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.GzipRule = function()
+{
+    WebInspector.AuditRule.call(this, "network-gzip", "Enable gzip compression");
+}
+
+WebInspector.AuditRules.GzipRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var totalSavings = 0;
+        var compressedSize = 0;
+        var candidateSize = 0;
+        var summary = result.addChild("", true);
+        for (var i = 0, length = requests.length; i < length; ++i) {
+            var request = requests[i];
+            if (request.statusCode === 304)
+                continue; // Do not test 304 Not Modified requests as their contents are always empty.
+            if (this._shouldCompress(request)) {
+                var size = request.resourceSize;
+                candidateSize += size;
+                if (this._isCompressed(request)) {
+                    compressedSize += size;
+                    continue;
+                }
+                var savings = 2 * size / 3;
+                totalSavings += savings;
+                summary.addFormatted("%r could save ~%s", request.url, Number.bytesToString(savings));
+                result.violationCount++;
+            }
+        }
+        if (!totalSavings)
+            return callback(null);
+        summary.value = String.sprintf("Compressing the following resources with gzip could reduce their transfer size by about two thirds (~%s):", Number.bytesToString(totalSavings));
+        callback(result);
+    },
+
+    _isCompressed: function(request)
+    {
+        var encodingHeader = request.responseHeaderValue("Content-Encoding");
+        if (!encodingHeader)
+            return false;
+
+        return /\b(?:gzip|deflate)\b/.test(encodingHeader);
+    },
+
+    _shouldCompress: function(request)
+    {
+        return request.type.isTextType() && request.parsedURL.host && request.resourceSize !== undefined && request.resourceSize > 150;
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.CombineExternalResourcesRule = function(id, name, type, resourceTypeName, allowedPerDomain)
+{
+    WebInspector.AuditRule.call(this, id, name);
+    this._type = type;
+    this._resourceTypeName = resourceTypeName;
+    this._allowedPerDomain = allowedPerDomain;
+}
+
+WebInspector.AuditRules.CombineExternalResourcesRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests, [this._type], false);
+        var penalizedResourceCount = 0;
+        // TODO: refactor according to the chosen i18n approach
+        var summary = result.addChild("", true);
+        for (var domain in domainToResourcesMap) {
+            var domainResources = domainToResourcesMap[domain];
+            var extraResourceCount = domainResources.length - this._allowedPerDomain;
+            if (extraResourceCount <= 0)
+                continue;
+            penalizedResourceCount += extraResourceCount - 1;
+            summary.addChild(String.sprintf("%d %s resources served from %s.", domainResources.length, this._resourceTypeName, WebInspector.AuditRuleResult.resourceDomain(domain)));
+            result.violationCount += domainResources.length;
+        }
+        if (!penalizedResourceCount)
+            return callback(null);
+
+        summary.value = "There are multiple resources served from same domain. Consider combining them into as few files as possible.";
+        callback(result);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CombineExternalResourcesRule}
+ */
+WebInspector.AuditRules.CombineJsResourcesRule = function(allowedPerDomain) {
+    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externaljs", "Combine external JavaScript", WebInspector.resourceTypes.Script, "JavaScript", allowedPerDomain);
+}
+
+WebInspector.AuditRules.CombineJsResourcesRule.prototype = {
+    __proto__: WebInspector.AuditRules.CombineExternalResourcesRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CombineExternalResourcesRule}
+ */
+WebInspector.AuditRules.CombineCssResourcesRule = function(allowedPerDomain) {
+    WebInspector.AuditRules.CombineExternalResourcesRule.call(this, "page-externalcss", "Combine external CSS", WebInspector.resourceTypes.Stylesheet, "CSS", allowedPerDomain);
+}
+
+WebInspector.AuditRules.CombineCssResourcesRule.prototype = {
+    __proto__: WebInspector.AuditRules.CombineExternalResourcesRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.MinimizeDnsLookupsRule = function(hostCountThreshold) {
+    WebInspector.AuditRule.call(this, "network-minimizelookups", "Minimize DNS lookups");
+    this._hostCountThreshold = hostCountThreshold;
+}
+
+WebInspector.AuditRules.MinimizeDnsLookupsRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var summary = result.addChild("");
+        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests, null, false);
+        for (var domain in domainToResourcesMap) {
+            if (domainToResourcesMap[domain].length > 1)
+                continue;
+            var parsedURL = domain.asParsedURL();
+            if (!parsedURL)
+                continue;
+            if (!parsedURL.host.search(WebInspector.AuditRules.IPAddressRegexp))
+                continue; // an IP address
+            summary.addSnippet(domain);
+            result.violationCount++;
+        }
+        if (!summary.children || summary.children.length <= this._hostCountThreshold)
+            return callback(null);
+
+        summary.value = "The following domains only serve one resource each. If possible, avoid the extra DNS lookups by serving these resources from existing domains.";
+        callback(result);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.ParallelizeDownloadRule = function(optimalHostnameCount, minRequestThreshold, minBalanceThreshold)
+{
+    WebInspector.AuditRule.call(this, "network-parallelizehosts", "Parallelize downloads across hostnames");
+    this._optimalHostnameCount = optimalHostnameCount;
+    this._minRequestThreshold = minRequestThreshold;
+    this._minBalanceThreshold = minBalanceThreshold;
+}
+
+WebInspector.AuditRules.ParallelizeDownloadRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        function hostSorter(a, b)
+        {
+            var aCount = domainToResourcesMap[a].length;
+            var bCount = domainToResourcesMap[b].length;
+            return (aCount < bCount) ? 1 : (aCount == bCount) ? 0 : -1;
+        }
+
+        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(
+            requests,
+            [WebInspector.resourceTypes.Stylesheet, WebInspector.resourceTypes.Image],
+            true);
+
+        var hosts = [];
+        for (var url in domainToResourcesMap)
+            hosts.push(url);
+
+        if (!hosts.length)
+            return callback(null); // no hosts (local file or something)
+
+        hosts.sort(hostSorter);
+
+        var optimalHostnameCount = this._optimalHostnameCount;
+        if (hosts.length > optimalHostnameCount)
+            hosts.splice(optimalHostnameCount);
+
+        var busiestHostResourceCount = domainToResourcesMap[hosts[0]].length;
+        var requestCountAboveThreshold = busiestHostResourceCount - this._minRequestThreshold;
+        if (requestCountAboveThreshold <= 0)
+            return callback(null);
+
+        var avgResourcesPerHost = 0;
+        for (var i = 0, size = hosts.length; i < size; ++i)
+            avgResourcesPerHost += domainToResourcesMap[hosts[i]].length;
+
+        // Assume optimal parallelization.
+        avgResourcesPerHost /= optimalHostnameCount;
+        avgResourcesPerHost = Math.max(avgResourcesPerHost, 1);
+
+        var pctAboveAvg = (requestCountAboveThreshold / avgResourcesPerHost) - 1.0;
+        var minBalanceThreshold = this._minBalanceThreshold;
+        if (pctAboveAvg < minBalanceThreshold)
+            return callback(null);
+
+        var requestsOnBusiestHost = domainToResourcesMap[hosts[0]];
+        var entry = result.addChild(String.sprintf("This page makes %d parallelizable requests to %s. Increase download parallelization by distributing the following requests across multiple hostnames.", busiestHostResourceCount, hosts[0]), true);
+        for (var i = 0; i < requestsOnBusiestHost.length; ++i)
+            entry.addURL(requestsOnBusiestHost[i].url);
+
+        result.violationCount = requestsOnBusiestHost.length;
+        callback(result);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * The reported CSS rule size is incorrect (parsed != original in WebKit),
+ * so use percentages instead, which gives a better approximation.
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.UnusedCssRule = function()
+{
+    WebInspector.AuditRule.call(this, "page-unusedcss", "Remove unused CSS rules");
+}
+
+WebInspector.AuditRules.UnusedCssRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var self = this;
+
+        function evalCallback(styleSheets) {
+            if (progress.isCanceled())
+                return;
+
+            if (!styleSheets.length)
+                return callback(null);
+
+            var selectors = [];
+            var testedSelectors = {};
+            for (var i = 0; i < styleSheets.length; ++i) {
+                var styleSheet = styleSheets[i];
+                for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
+                    var selectorText = styleSheet.rules[curRule].selectorText;
+                    if (testedSelectors[selectorText])
+                        continue;
+                    selectors.push(selectorText);
+                    testedSelectors[selectorText] = 1;
+                }
+            }
+
+            function selectorsCallback(callback, styleSheets, testedSelectors, foundSelectors)
+            {
+                if (progress.isCanceled())
+                    return;
+
+                var inlineBlockOrdinal = 0;
+                var totalStylesheetSize = 0;
+                var totalUnusedStylesheetSize = 0;
+                var summary;
+
+                for (var i = 0; i < styleSheets.length; ++i) {
+                    var styleSheet = styleSheets[i];
+                    var unusedRules = [];
+                    for (var curRule = 0; curRule < styleSheet.rules.length; ++curRule) {
+                        var rule = styleSheet.rules[curRule];
+                        if (!testedSelectors[rule.selectorText] || foundSelectors[rule.selectorText])
+                            continue;
+                        unusedRules.push(rule.selectorText);
+                    }
+                    totalStylesheetSize += styleSheet.rules.length;
+                    totalUnusedStylesheetSize += unusedRules.length;
+
+                    if (!unusedRules.length)
+                        continue;
+
+                    var resource = WebInspector.resourceForURL(styleSheet.sourceURL);
+                    var isInlineBlock = resource && resource.request && resource.request.type == WebInspector.resourceTypes.Document;
+                    var url = !isInlineBlock ? WebInspector.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) : String.sprintf("Inline block #%d", ++inlineBlockOrdinal);
+                    var pctUnused = Math.round(100 * unusedRules.length / styleSheet.rules.length);
+                    if (!summary)
+                        summary = result.addChild("", true);
+                    var entry = summary.addFormatted("%s: %d% is not used by the current page.", url, pctUnused);
+
+                    for (var j = 0; j < unusedRules.length; ++j)
+                        entry.addSnippet(unusedRules[j]);
+
+                    result.violationCount += unusedRules.length;
+                }
+
+                if (!totalUnusedStylesheetSize)
+                    return callback(null);
+
+                var totalUnusedPercent = Math.round(100 * totalUnusedStylesheetSize / totalStylesheetSize);
+                summary.value = String.sprintf("%s rules (%d%) of CSS not used by the current page.", totalUnusedStylesheetSize, totalUnusedPercent);
+
+                callback(result);
+            }
+
+            var foundSelectors = {};
+            function queryCallback(boundSelectorsCallback, selector, styleSheets, testedSelectors, nodeId)
+            {
+                if (nodeId)
+                    foundSelectors[selector] = true;
+                if (boundSelectorsCallback)
+                    boundSelectorsCallback(foundSelectors);
+            }
+
+            function documentLoaded(selectors, document) {
+                var pseudoSelectorRegexp = /::?(?:[\w-]+)(?:\(.*?\))?/g;
+                for (var i = 0; i < selectors.length; ++i) {
+                    if (progress.isCanceled())
+                        return;
+                    var effectiveSelector = selectors[i].replace(pseudoSelectorRegexp, "");
+                    WebInspector.domAgent.querySelector(document.id, effectiveSelector, queryCallback.bind(null, i === selectors.length - 1 ? selectorsCallback.bind(null, callback, styleSheets, testedSelectors) : null, selectors[i], styleSheets, testedSelectors));
+                }
+            }
+
+            WebInspector.domAgent.requestDocument(documentLoaded.bind(null, selectors));
+        }
+
+        function styleSheetCallback(styleSheets, sourceURL, continuation, styleSheet)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (styleSheet) {
+                styleSheet.sourceURL = sourceURL;
+                styleSheets.push(styleSheet);
+            }
+            if (continuation)
+                continuation(styleSheets);
+        }
+
+        function allStylesCallback(error, styleSheetInfos)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (error || !styleSheetInfos || !styleSheetInfos.length)
+                return evalCallback([]);
+            var styleSheets = [];
+            for (var i = 0; i < styleSheetInfos.length; ++i) {
+                var info = styleSheetInfos[i];
+                WebInspector.CSSStyleSheet.createForId(info.styleSheetId, styleSheetCallback.bind(null, styleSheets, info.sourceURL, i == styleSheetInfos.length - 1 ? evalCallback : null));
+            }
+        }
+
+        CSSAgent.getAllStyleSheets(allStylesCallback);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.CacheControlRule = function(id, name)
+{
+    WebInspector.AuditRule.call(this, id, name);
+}
+
+WebInspector.AuditRules.CacheControlRule.MillisPerMonth = 1000 * 60 * 60 * 24 * 30;
+
+WebInspector.AuditRules.CacheControlRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var cacheableAndNonCacheableResources = this._cacheableAndNonCacheableResources(requests);
+        if (cacheableAndNonCacheableResources[0].length)
+            this.runChecks(cacheableAndNonCacheableResources[0], result);
+        this.handleNonCacheableResources(cacheableAndNonCacheableResources[1], result);
+
+        callback(result);
+    },
+
+    handleNonCacheableResources: function(requests, result)
+    {
+    },
+
+    _cacheableAndNonCacheableResources: function(requests)
+    {
+        var processedResources = [[], []];
+        for (var i = 0; i < requests.length; ++i) {
+            var request = requests[i];
+            if (!this.isCacheableResource(request))
+                continue;
+            if (this._isExplicitlyNonCacheable(request))
+                processedResources[1].push(request);
+            else
+                processedResources[0].push(request);
+        }
+        return processedResources;
+    },
+
+    execCheck: function(messageText, requestCheckFunction, requests, result)
+    {
+        var requestCount = requests.length;
+        var urls = [];
+        for (var i = 0; i < requestCount; ++i) {
+            if (requestCheckFunction.call(this, requests[i]))
+                urls.push(requests[i].url);
+        }
+        if (urls.length) {
+            var entry = result.addChild(messageText, true);
+            entry.addURLs(urls);
+            result.violationCount += urls.length;
+        }
+    },
+
+    freshnessLifetimeGreaterThan: function(request, timeMs)
+    {
+        var dateHeader = this.responseHeader(request, "Date");
+        if (!dateHeader)
+            return false;
+
+        var dateHeaderMs = Date.parse(dateHeader);
+        if (isNaN(dateHeaderMs))
+            return false;
+
+        var freshnessLifetimeMs;
+        var maxAgeMatch = this.responseHeaderMatch(request, "Cache-Control", "max-age=(\\d+)");
+
+        if (maxAgeMatch)
+            freshnessLifetimeMs = (maxAgeMatch[1]) ? 1000 * maxAgeMatch[1] : 0;
+        else {
+            var expiresHeader = this.responseHeader(request, "Expires");
+            if (expiresHeader) {
+                var expDate = Date.parse(expiresHeader);
+                if (!isNaN(expDate))
+                    freshnessLifetimeMs = expDate - dateHeaderMs;
+            }
+        }
+
+        return (isNaN(freshnessLifetimeMs)) ? false : freshnessLifetimeMs > timeMs;
+    },
+
+    responseHeader: function(request, header)
+    {
+        return request.responseHeaderValue(header);
+    },
+
+    hasResponseHeader: function(request, header)
+    {
+        return request.responseHeaderValue(header) !== undefined;
+    },
+
+    isCompressible: function(request)
+    {
+        return request.type.isTextType();
+    },
+
+    isPubliclyCacheable: function(request)
+    {
+        if (this._isExplicitlyNonCacheable(request))
+            return false;
+
+        if (this.responseHeaderMatch(request, "Cache-Control", "public"))
+            return true;
+
+        return request.url.indexOf("?") == -1 && !this.responseHeaderMatch(request, "Cache-Control", "private");
+    },
+
+    responseHeaderMatch: function(request, header, regexp)
+    {
+        return request.responseHeaderValue(header)
+            ? request.responseHeaderValue(header).match(new RegExp(regexp, "im"))
+            : undefined;
+    },
+
+    hasExplicitExpiration: function(request)
+    {
+        return this.hasResponseHeader(request, "Date") &&
+            (this.hasResponseHeader(request, "Expires") || this.responseHeaderMatch(request, "Cache-Control", "max-age"));
+    },
+
+    _isExplicitlyNonCacheable: function(request)
+    {
+        var hasExplicitExp = this.hasExplicitExpiration(request);
+        return this.responseHeaderMatch(request, "Cache-Control", "(no-cache|no-store|must-revalidate)") ||
+            this.responseHeaderMatch(request, "Pragma", "no-cache") ||
+            (hasExplicitExp && !this.freshnessLifetimeGreaterThan(request, 0)) ||
+            (!hasExplicitExp && request.url && request.url.indexOf("?") >= 0) ||
+            (!hasExplicitExp && !this.isCacheableResource(request));
+    },
+
+    isCacheableResource: function(request)
+    {
+        return request.statusCode !== undefined && WebInspector.AuditRules.CacheableResponseCodes[request.statusCode];
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CacheControlRule}
+ */
+WebInspector.AuditRules.BrowserCacheControlRule = function()
+{
+    WebInspector.AuditRules.CacheControlRule.call(this, "http-browsercache", "Leverage browser caching");
+}
+
+WebInspector.AuditRules.BrowserCacheControlRule.prototype = {
+    handleNonCacheableResources: function(requests, result)
+    {
+        if (requests.length) {
+            var entry = result.addChild("The following resources are explicitly non-cacheable. Consider making them cacheable if possible:", true);
+            result.violationCount += requests.length;
+            for (var i = 0; i < requests.length; ++i)
+                entry.addURL(requests[i].url);
+        }
+    },
+
+    runChecks: function(requests, result, callback)
+    {
+        this.execCheck("The following resources are missing a cache expiration. Resources that do not specify an expiration may not be cached by browsers:",
+            this._missingExpirationCheck, requests, result);
+        this.execCheck("The following resources specify a \"Vary\" header that disables caching in most versions of Internet Explorer:",
+            this._varyCheck, requests, result);
+        this.execCheck("The following cacheable resources have a short freshness lifetime:",
+            this._oneMonthExpirationCheck, requests, result);
+
+        // Unable to implement the favicon check due to the WebKit limitations.
+        this.execCheck("To further improve cache hit rate, specify an expiration one year in the future for the following cacheable resources:",
+            this._oneYearExpirationCheck, requests, result);
+    },
+
+    _missingExpirationCheck: function(request)
+    {
+        return this.isCacheableResource(request) && !this.hasResponseHeader(request, "Set-Cookie") && !this.hasExplicitExpiration(request);
+    },
+
+    _varyCheck: function(request)
+    {
+        var varyHeader = this.responseHeader(request, "Vary");
+        if (varyHeader) {
+            varyHeader = varyHeader.replace(/User-Agent/gi, "");
+            varyHeader = varyHeader.replace(/Accept-Encoding/gi, "");
+            varyHeader = varyHeader.replace(/[, ]*/g, "");
+        }
+        return varyHeader && varyHeader.length && this.isCacheableResource(request) && this.freshnessLifetimeGreaterThan(request, 0);
+    },
+
+    _oneMonthExpirationCheck: function(request)
+    {
+        return this.isCacheableResource(request) &&
+            !this.hasResponseHeader(request, "Set-Cookie") &&
+            !this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
+            this.freshnessLifetimeGreaterThan(request, 0);
+    },
+
+    _oneYearExpirationCheck: function(request)
+    {
+        return this.isCacheableResource(request) &&
+            !this.hasResponseHeader(request, "Set-Cookie") &&
+            !this.freshnessLifetimeGreaterThan(request, 11 * WebInspector.AuditRules.CacheControlRule.MillisPerMonth) &&
+            this.freshnessLifetimeGreaterThan(request, WebInspector.AuditRules.CacheControlRule.MillisPerMonth);
+    },
+
+    __proto__: WebInspector.AuditRules.CacheControlRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CacheControlRule}
+ */
+WebInspector.AuditRules.ProxyCacheControlRule = function() {
+    WebInspector.AuditRules.CacheControlRule.call(this, "http-proxycache", "Leverage proxy caching");
+}
+
+WebInspector.AuditRules.ProxyCacheControlRule.prototype = {
+    runChecks: function(requests, result, callback)
+    {
+        this.execCheck("Resources with a \"?\" in the URL are not cached by most proxy caching servers:",
+            this._questionMarkCheck, requests, result);
+        this.execCheck("Consider adding a \"Cache-Control: public\" header to the following resources:",
+            this._publicCachingCheck, requests, result);
+        this.execCheck("The following publicly cacheable resources contain a Set-Cookie header. This security vulnerability can cause cookies to be shared by multiple users.",
+            this._setCookieCacheableCheck, requests, result);
+    },
+
+    _questionMarkCheck: function(request)
+    {
+        return request.url.indexOf("?") >= 0 && !this.hasResponseHeader(request, "Set-Cookie") && this.isPubliclyCacheable(request);
+    },
+
+    _publicCachingCheck: function(request)
+    {
+        return this.isCacheableResource(request) &&
+            !this.isCompressible(request) &&
+            !this.responseHeaderMatch(request, "Cache-Control", "public") &&
+            !this.hasResponseHeader(request, "Set-Cookie");
+    },
+
+    _setCookieCacheableCheck: function(request)
+    {
+        return this.hasResponseHeader(request, "Set-Cookie") && this.isPubliclyCacheable(request);
+    },
+
+    __proto__: WebInspector.AuditRules.CacheControlRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.ImageDimensionsRule = function()
+{
+    WebInspector.AuditRule.call(this, "page-imagedims", "Specify image dimensions");
+}
+
+WebInspector.AuditRules.ImageDimensionsRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var urlToNoDimensionCount = {};
+
+        function doneCallback()
+        {
+            for (var url in urlToNoDimensionCount) {
+                var entry = entry || result.addChild("A width and height should be specified for all images in order to speed up page display. The following image(s) are missing a width and/or height:", true);
+                var format = "%r";
+                if (urlToNoDimensionCount[url] > 1)
+                    format += " (%d uses)";
+                entry.addFormatted(format, url, urlToNoDimensionCount[url]);
+                result.violationCount++;
+            }
+            callback(entry ? result : null);
+        }
+
+        function imageStylesReady(imageId, styles, isLastStyle, computedStyle)
+        {
+            if (progress.isCanceled())
+                return;
+
+            const node = WebInspector.domAgent.nodeForId(imageId);
+            var src = node.getAttribute("src");
+            if (!src.asParsedURL()) {
+                for (var frameOwnerCandidate = node; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
+                    if (frameOwnerCandidate.baseURL) {
+                        var completeSrc = WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, src);
+                        break;
+                    }
+                }
+            }
+            if (completeSrc)
+                src = completeSrc;
+
+            if (computedStyle.getPropertyValue("position") === "absolute") {
+                if (isLastStyle)
+                    doneCallback();
+                return;
+            }
+
+            if (styles.attributesStyle) {
+                var widthFound = !!styles.attributesStyle.getLiveProperty("width");
+                var heightFound = !!styles.attributesStyle.getLiveProperty("height");
+            }
+
+            var inlineStyle = styles.inlineStyle;
+            if (inlineStyle) {
+                if (inlineStyle.getPropertyValue("width") !== "")
+                    widthFound = true;
+                if (inlineStyle.getPropertyValue("height") !== "")
+                    heightFound = true;
+            }
+
+            for (var i = styles.matchedCSSRules.length - 1; i >= 0 && !(widthFound && heightFound); --i) {
+                var style = styles.matchedCSSRules[i].style;
+                if (style.getPropertyValue("width") !== "")
+                    widthFound = true;
+                if (style.getPropertyValue("height") !== "")
+                    heightFound = true;
+            }
+
+            if (!widthFound || !heightFound) {
+                if (src in urlToNoDimensionCount)
+                    ++urlToNoDimensionCount[src];
+                else
+                    urlToNoDimensionCount[src] = 1;
+            }
+
+            if (isLastStyle)
+                doneCallback();
+        }
+
+        function getStyles(nodeIds)
+        {
+            if (progress.isCanceled())
+                return;
+            var targetResult = {};
+
+            function inlineCallback(inlineStyle, attributesStyle)
+            {
+                targetResult.inlineStyle = inlineStyle;
+                targetResult.attributesStyle = attributesStyle;
+            }
+
+            function matchedCallback(result)
+            {
+                if (result)
+                    targetResult.matchedCSSRules = result.matchedCSSRules;
+            }
+
+            if (!nodeIds || !nodeIds.length)
+                doneCallback();
+
+            for (var i = 0; nodeIds && i < nodeIds.length; ++i) {
+                WebInspector.cssModel.getMatchedStylesAsync(nodeIds[i], false, false, matchedCallback);
+                WebInspector.cssModel.getInlineStylesAsync(nodeIds[i], inlineCallback);
+                WebInspector.cssModel.getComputedStyleAsync(nodeIds[i], imageStylesReady.bind(null, nodeIds[i], targetResult, i === nodeIds.length - 1));
+            }
+        }
+
+        function onDocumentAvailable(root)
+        {
+            if (progress.isCanceled())
+                return;
+            WebInspector.domAgent.querySelectorAll(root.id, "img[src]", getStyles);
+        }
+
+        if (progress.isCanceled())
+            return;
+        WebInspector.domAgent.requestDocument(onDocumentAvailable);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.CssInHeadRule = function()
+{
+    WebInspector.AuditRule.call(this, "page-cssinhead", "Put CSS in the document head");
+}
+
+WebInspector.AuditRules.CssInHeadRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        function evalCallback(evalResult)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!evalResult)
+                return callback(null);
+
+            var summary = result.addChild("");
+
+            var outputMessages = [];
+            for (var url in evalResult) {
+                var urlViolations = evalResult[url];
+                if (urlViolations[0]) {
+                    result.addFormatted("%s style block(s) in the %r body should be moved to the document head.", urlViolations[0], url);
+                    result.violationCount += urlViolations[0];
+                }
+                for (var i = 0; i < urlViolations[1].length; ++i)
+                    result.addFormatted("Link node %r should be moved to the document head in %r", urlViolations[1][i], url);
+                result.violationCount += urlViolations[1].length;
+            }
+            summary.value = String.sprintf("CSS in the document body adversely impacts rendering performance.");
+            callback(result);
+        }
+
+        function externalStylesheetsReceived(root, inlineStyleNodeIds, nodeIds)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!nodeIds)
+                return;
+            var externalStylesheetNodeIds = nodeIds;
+            var result = null;
+            if (inlineStyleNodeIds.length || externalStylesheetNodeIds.length) {
+                var urlToViolationsArray = {};
+                var externalStylesheetHrefs = [];
+                for (var j = 0; j < externalStylesheetNodeIds.length; ++j) {
+                    var linkNode = WebInspector.domAgent.nodeForId(externalStylesheetNodeIds[j]);
+                    var completeHref = WebInspector.ParsedURL.completeURL(linkNode.ownerDocument.baseURL, linkNode.getAttribute("href"));
+                    externalStylesheetHrefs.push(completeHref || "");
+                }
+                urlToViolationsArray[root.documentURL] = [inlineStyleNodeIds.length, externalStylesheetHrefs];
+                result = urlToViolationsArray;
+            }
+            evalCallback(result);
+        }
+
+        function inlineStylesReceived(root, nodeIds)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!nodeIds)
+                return;
+            WebInspector.domAgent.querySelectorAll(root.id, "body link[rel~='stylesheet'][href]", externalStylesheetsReceived.bind(null, root, nodeIds));
+        }
+
+        function onDocumentAvailable(root)
+        {
+            if (progress.isCanceled())
+                return;
+
+            WebInspector.domAgent.querySelectorAll(root.id, "body style", inlineStylesReceived.bind(null, root));
+        }
+
+        WebInspector.domAgent.requestDocument(onDocumentAvailable);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.StylesScriptsOrderRule = function()
+{
+    WebInspector.AuditRule.call(this, "page-stylescriptorder", "Optimize the order of styles and scripts");
+}
+
+WebInspector.AuditRules.StylesScriptsOrderRule.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        function evalCallback(resultValue)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!resultValue)
+                return callback(null);
+
+            var lateCssUrls = resultValue[0];
+            var cssBeforeInlineCount = resultValue[1];
+
+            var entry = result.addChild("The following external CSS files were included after an external JavaScript file in the document head. To ensure CSS files are downloaded in parallel, always include external CSS before external JavaScript.", true);
+            entry.addURLs(lateCssUrls);
+            result.violationCount += lateCssUrls.length;
+
+            if (cssBeforeInlineCount) {
+                result.addChild(String.sprintf(" %d inline script block%s found in the head between an external CSS file and another resource. To allow parallel downloading, move the inline script before the external CSS file, or after the next resource.", cssBeforeInlineCount, cssBeforeInlineCount > 1 ? "s were" : " was"));
+                result.violationCount += cssBeforeInlineCount;
+            }
+            callback(result);
+        }
+
+        function cssBeforeInlineReceived(lateStyleIds, nodeIds)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!nodeIds)
+                return;
+
+            var cssBeforeInlineCount = nodeIds.length;
+            var result = null;
+            if (lateStyleIds.length || cssBeforeInlineCount) {
+                var lateStyleUrls = [];
+                for (var i = 0; i < lateStyleIds.length; ++i) {
+                    var lateStyleNode = WebInspector.domAgent.nodeForId(lateStyleIds[i]);
+                    var completeHref = WebInspector.ParsedURL.completeURL(lateStyleNode.ownerDocument.baseURL, lateStyleNode.getAttribute("href"));
+                    lateStyleUrls.push(completeHref || "");
+                }
+                result = [ lateStyleUrls, cssBeforeInlineCount ];
+            }
+
+            evalCallback(result);
+        }
+
+        function lateStylesReceived(root, nodeIds)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!nodeIds)
+                return;
+
+            WebInspector.domAgent.querySelectorAll(root.id, "head link[rel~='stylesheet'][href] ~ script:not([src])", cssBeforeInlineReceived.bind(null, nodeIds));
+        }
+
+        function onDocumentAvailable(root)
+        {
+            if (progress.isCanceled())
+                return;
+
+            WebInspector.domAgent.querySelectorAll(root.id, "head script[src] ~ link[rel~='stylesheet'][href]", lateStylesReceived.bind(null, root));
+        }
+
+        WebInspector.domAgent.requestDocument(onDocumentAvailable);
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.CSSRuleBase = function(id, name)
+{
+    WebInspector.AuditRule.call(this, id, name);
+}
+
+WebInspector.AuditRules.CSSRuleBase.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        CSSAgent.getAllStyleSheets(sheetsCallback.bind(this));
+
+        function sheetsCallback(error, headers)
+        {
+            if (error)
+                return callback(null);
+
+            if (!headers.length)
+                return callback(null);
+            for (var i = 0; i < headers.length; ++i) {
+                var header = headers[i];
+                if (header.disabled)
+                    continue; // Do not check disabled stylesheets.
+
+                this._visitStyleSheet(header.styleSheetId, i === headers.length - 1 ? finishedCallback : null, result, progress);
+            }
+        }
+
+        function finishedCallback()
+        {
+            callback(result);
+        }
+    },
+
+    _visitStyleSheet: function(styleSheetId, callback, result, progress)
+    {
+        WebInspector.CSSStyleSheet.createForId(styleSheetId, sheetCallback.bind(this));
+
+        function sheetCallback(styleSheet)
+        {
+            if (progress.isCanceled())
+                return;
+
+            if (!styleSheet) {
+                if (callback)
+                    callback();
+                return;
+            }
+
+            this.visitStyleSheet(styleSheet, result);
+
+            for (var i = 0; i < styleSheet.rules.length; ++i)
+                this._visitRule(styleSheet, styleSheet.rules[i], result);
+
+            this.didVisitStyleSheet(styleSheet, result);
+
+            if (callback)
+                callback();
+        }
+    },
+
+    _visitRule: function(styleSheet, rule, result)
+    {
+        this.visitRule(styleSheet, rule, result);
+        var allProperties = rule.style.allProperties;
+        for (var i = 0; i < allProperties.length; ++i)
+            this.visitProperty(styleSheet, allProperties[i], result);
+        this.didVisitRule(styleSheet, rule, result);
+    },
+
+    visitStyleSheet: function(styleSheet, result)
+    {
+        // Subclasses can implement.
+    },
+
+    didVisitStyleSheet: function(styleSheet, result)
+    {
+        // Subclasses can implement.
+    },
+    
+    visitRule: function(styleSheet, rule, result)
+    {
+        // Subclasses can implement.
+    },
+
+    didVisitRule: function(styleSheet, rule, result)
+    {
+        // Subclasses can implement.
+    },
+    
+    visitProperty: function(styleSheet, property, result)
+    {
+        // Subclasses can implement.
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CSSRuleBase}
+ */
+WebInspector.AuditRules.VendorPrefixedCSSProperties = function()
+{
+    WebInspector.AuditRules.CSSRuleBase.call(this, "page-vendorprefixedcss", "Use normal CSS property names instead of vendor-prefixed ones");
+    this._webkitPrefix = "-webkit-";
+}
+
+WebInspector.AuditRules.VendorPrefixedCSSProperties.supportedProperties = [
+    "background-clip", "background-origin", "background-size",
+    "border-radius", "border-bottom-left-radius", "border-bottom-right-radius", "border-top-left-radius", "border-top-right-radius",
+    "box-shadow", "box-sizing", "opacity", "text-shadow"
+].keySet();
+
+WebInspector.AuditRules.VendorPrefixedCSSProperties.prototype = {
+    didVisitStyleSheet: function(styleSheet)
+    {
+        delete this._styleSheetResult;
+    },
+
+    visitRule: function(rule)
+    {
+        this._mentionedProperties = {};
+    },
+
+    didVisitRule: function()
+    {
+        delete this._ruleResult;
+        delete this._mentionedProperties;
+    },
+
+    visitProperty: function(styleSheet, property, result)
+    {
+        if (!property.name.startsWith(this._webkitPrefix))
+            return;
+
+        var normalPropertyName = property.name.substring(this._webkitPrefix.length).toLowerCase(); // Start just after the "-webkit-" prefix.
+        if (WebInspector.AuditRules.VendorPrefixedCSSProperties.supportedProperties[normalPropertyName] && !this._mentionedProperties[normalPropertyName]) {
+            var style = property.ownerStyle;
+            var liveProperty = style.getLiveProperty(normalPropertyName);
+            if (liveProperty && !liveProperty.styleBased)
+                return; // WebCore can provide normal versions of prefixed properties automatically, so be careful to skip only normal source-based properties.
+
+            var rule = style.parentRule;
+            this._mentionedProperties[normalPropertyName] = true;
+            if (!this._styleSheetResult)
+                this._styleSheetResult = result.addChild(rule.sourceURL ? WebInspector.linkifyResourceAsNode(rule.sourceURL) : "");
+            if (!this._ruleResult) {
+                var anchor = WebInspector.linkifyURLAsNode(rule.sourceURL, rule.selectorText);
+                anchor.preferredPanel = "resources";
+                anchor.lineNumber = rule.lineNumberInSource();
+                this._ruleResult = this._styleSheetResult.addChild(anchor);
+            }
+            ++result.violationCount;
+            this._ruleResult.addSnippet(String.sprintf("\"" + this._webkitPrefix + "%s\" is used, but \"%s\" is supported.", normalPropertyName, normalPropertyName));
+        }
+    },
+
+    __proto__: WebInspector.AuditRules.CSSRuleBase.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRule}
+ */
+WebInspector.AuditRules.CookieRuleBase = function(id, name)
+{
+    WebInspector.AuditRule.call(this, id, name);
+}
+
+WebInspector.AuditRules.CookieRuleBase.prototype = {
+    /**
+     * @param {!Array.} requests
+     * @param {!WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        var self = this;
+        function resultCallback(receivedCookies) {
+            if (progress.isCanceled())
+                return;
+
+            self.processCookies(receivedCookies, requests, result);
+            callback(result);
+        }
+
+        WebInspector.Cookies.getCookiesAsync(resultCallback);
+    },
+
+    mapResourceCookies: function(requestsByDomain, allCookies, callback)
+    {
+        for (var i = 0; i < allCookies.length; ++i) {
+            for (var requestDomain in requestsByDomain) {
+                if (WebInspector.Cookies.cookieDomainMatchesResourceDomain(allCookies[i].domain(), requestDomain))
+                    this._callbackForResourceCookiePairs(requestsByDomain[requestDomain], allCookies[i], callback);
+            }
+        }
+    },
+
+    _callbackForResourceCookiePairs: function(requests, cookie, callback)
+    {
+        if (!requests)
+            return;
+        for (var i = 0; i < requests.length; ++i) {
+            if (WebInspector.Cookies.cookieMatchesResourceURL(cookie, requests[i].url))
+                callback(requests[i], cookie);
+        }
+    },
+
+    __proto__: WebInspector.AuditRule.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CookieRuleBase}
+ */
+WebInspector.AuditRules.CookieSizeRule = function(avgBytesThreshold)
+{
+    WebInspector.AuditRules.CookieRuleBase.call(this, "http-cookiesize", "Minimize cookie size");
+    this._avgBytesThreshold = avgBytesThreshold;
+    this._maxBytesThreshold = 1000;
+}
+
+WebInspector.AuditRules.CookieSizeRule.prototype = {
+    _average: function(cookieArray)
+    {
+        var total = 0;
+        for (var i = 0; i < cookieArray.length; ++i)
+            total += cookieArray[i].size();
+        return cookieArray.length ? Math.round(total / cookieArray.length) : 0;
+    },
+
+    _max: function(cookieArray)
+    {
+        var result = 0;
+        for (var i = 0; i < cookieArray.length; ++i)
+            result = Math.max(cookieArray[i].size(), result);
+        return result;
+    },
+
+    processCookies: function(allCookies, requests, result)
+    {
+        function maxSizeSorter(a, b)
+        {
+            return b.maxCookieSize - a.maxCookieSize;
+        }
+
+        function avgSizeSorter(a, b)
+        {
+            return b.avgCookieSize - a.avgCookieSize;
+        }
+
+        var cookiesPerResourceDomain = {};
+
+        function collectorCallback(request, cookie)
+        {
+            var cookies = cookiesPerResourceDomain[request.parsedURL.host];
+            if (!cookies) {
+                cookies = [];
+                cookiesPerResourceDomain[request.parsedURL.host] = cookies;
+            }
+            cookies.push(cookie);
+        }
+
+        if (!allCookies.length)
+            return;
+
+        var sortedCookieSizes = [];
+
+        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests,
+                null,
+                true);
+        var matchingResourceData = {};
+        this.mapResourceCookies(domainToResourcesMap, allCookies, collectorCallback.bind(this));
+
+        for (var requestDomain in cookiesPerResourceDomain) {
+            var cookies = cookiesPerResourceDomain[requestDomain];
+            sortedCookieSizes.push({
+                domain: requestDomain,
+                avgCookieSize: this._average(cookies),
+                maxCookieSize: this._max(cookies)
+            });
+        }
+        var avgAllCookiesSize = this._average(allCookies);
+
+        var hugeCookieDomains = [];
+        sortedCookieSizes.sort(maxSizeSorter);
+
+        for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
+            var maxCookieSize = sortedCookieSizes[i].maxCookieSize;
+            if (maxCookieSize > this._maxBytesThreshold)
+                hugeCookieDomains.push(WebInspector.AuditRuleResult.resourceDomain(sortedCookieSizes[i].domain) + ": " + Number.bytesToString(maxCookieSize));
+        }
+
+        var bigAvgCookieDomains = [];
+        sortedCookieSizes.sort(avgSizeSorter);
+        for (var i = 0, len = sortedCookieSizes.length; i < len; ++i) {
+            var domain = sortedCookieSizes[i].domain;
+            var avgCookieSize = sortedCookieSizes[i].avgCookieSize;
+            if (avgCookieSize > this._avgBytesThreshold && avgCookieSize < this._maxBytesThreshold)
+                bigAvgCookieDomains.push(WebInspector.AuditRuleResult.resourceDomain(domain) + ": " + Number.bytesToString(avgCookieSize));
+        }
+        result.addChild(String.sprintf("The average cookie size for all requests on this page is %s", Number.bytesToString(avgAllCookiesSize)));
+
+        var message;
+        if (hugeCookieDomains.length) {
+            var entry = result.addChild("The following domains have a cookie size in excess of 1KB. This is harmful because requests with cookies larger than 1KB typically cannot fit into a single network packet.", true);
+            entry.addURLs(hugeCookieDomains);
+            result.violationCount += hugeCookieDomains.length;
+        }
+
+        if (bigAvgCookieDomains.length) {
+            var entry = result.addChild(String.sprintf("The following domains have an average cookie size in excess of %d bytes. Reducing the size of cookies for these domains can reduce the time it takes to send requests.", this._avgBytesThreshold), true);
+            entry.addURLs(bigAvgCookieDomains);
+            result.violationCount += bigAvgCookieDomains.length;
+        }
+    },
+
+    __proto__: WebInspector.AuditRules.CookieRuleBase.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.AuditRules.CookieRuleBase}
+ */
+WebInspector.AuditRules.StaticCookielessRule = function(minResources)
+{
+    WebInspector.AuditRules.CookieRuleBase.call(this, "http-staticcookieless", "Serve static content from a cookieless domain");
+    this._minResources = minResources;
+}
+
+WebInspector.AuditRules.StaticCookielessRule.prototype = {
+    processCookies: function(allCookies, requests, result)
+    {
+        var domainToResourcesMap = WebInspector.AuditRules.getDomainToResourcesMap(requests,
+                [WebInspector.resourceTypes.Stylesheet,
+                 WebInspector.resourceTypes.Image],
+                true);
+        var totalStaticResources = 0;
+        for (var domain in domainToResourcesMap)
+            totalStaticResources += domainToResourcesMap[domain].length;
+        if (totalStaticResources < this._minResources)
+            return;
+        var matchingResourceData = {};
+        this.mapResourceCookies(domainToResourcesMap, allCookies, this._collectorCallback.bind(this, matchingResourceData));
+
+        var badUrls = [];
+        var cookieBytes = 0;
+        for (var url in matchingResourceData) {
+            badUrls.push(url);
+            cookieBytes += matchingResourceData[url]
+        }
+        if (badUrls.length < this._minResources)
+            return;
+
+        var entry = result.addChild(String.sprintf("%s of cookies were sent with the following static resources. Serve these static resources from a domain that does not set cookies:", Number.bytesToString(cookieBytes)), true);
+        entry.addURLs(badUrls);
+        result.violationCount = badUrls.length;
+    },
+
+    _collectorCallback: function(matchingResourceData, request, cookie)
+    {
+        matchingResourceData[request.url] = (matchingResourceData[request.url] || 0) + cookie.size();
+    },
+
+    __proto__: WebInspector.AuditRules.CookieRuleBase.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditsPanel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditsPanel.js
new file mode 100644
index 00000000..c3475003
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/AuditsPanel.js
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Panel}
+ */
+WebInspector.AuditsPanel = function()
+{
+    WebInspector.Panel.call(this, "audits");
+    this.registerRequiredCSS("panelEnablerView.css");
+    this.registerRequiredCSS("auditsPanel.css");
+
+    this.createSidebarViewWithTree();
+    this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true);
+    this.sidebarTree.appendChild(this.auditsTreeElement);
+    this.auditsTreeElement.listItemElement.addStyleClass("hidden");
+
+    this.auditsItemTreeElement = new WebInspector.AuditsSidebarTreeElement(this);
+    this.auditsTreeElement.appendChild(this.auditsItemTreeElement);
+
+    this.auditResultsTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("RESULTS"), {}, true);
+    this.sidebarTree.appendChild(this.auditResultsTreeElement);
+    this.auditResultsTreeElement.expand();
+
+    this.clearResultsButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear audit results."), "clear-status-bar-item");
+    this.clearResultsButton.addEventListener("click", this._clearButtonClicked, this);
+
+    this.viewsContainerElement = this.splitView.mainElement;
+
+    this._constructCategories();
+
+    this._auditController = new WebInspector.AuditController(this);
+    this._launcherView = new WebInspector.AuditLauncherView(this._auditController);
+    for (var id in this.categoriesById)
+        this._launcherView.addCategory(this.categoriesById[id]);
+}
+
+WebInspector.AuditsPanel.prototype = {
+    get statusBarItems()
+    {
+        return [this.clearResultsButton.element];
+    },
+
+    /**
+     * @return {!Object.}
+     */
+    get categoriesById()
+    {
+        return this._auditCategoriesById;
+    },
+
+    /**
+     * @param {!WebInspector.AuditCategory} category
+     */
+    addCategory: function(category)
+    {
+        this.categoriesById[category.id] = category;
+        this._launcherView.addCategory(category);
+    },
+
+    /**
+     * @param {string} id
+     * @return {WebInspector.AuditCategory}
+     */
+    getCategory: function(id)
+    {
+        return this.categoriesById[id];
+    },
+
+    _constructCategories: function()
+    {
+        this._auditCategoriesById = {};
+        for (var categoryCtorID in WebInspector.AuditCategories) {
+            var auditCategory = new WebInspector.AuditCategories[categoryCtorID]();
+            auditCategory._id = categoryCtorID;
+            this.categoriesById[categoryCtorID] = auditCategory;
+        }
+    },
+
+    /**
+     * @param {string} mainResourceURL
+     * @param {!Array.} results
+     */
+    auditFinishedCallback: function(mainResourceURL, results)
+    {
+        var children = this.auditResultsTreeElement.children;
+        var ordinal = 1;
+        for (var i = 0; i < children.length; ++i) {
+            if (children[i].mainResourceURL === mainResourceURL)
+                ordinal++;
+        }
+
+        var resultTreeElement = new WebInspector.AuditResultSidebarTreeElement(this, results, mainResourceURL, ordinal);
+        this.auditResultsTreeElement.appendChild(resultTreeElement);
+        resultTreeElement.revealAndSelect();
+    },
+
+    /**
+     * @param {!Array.} categoryResults
+     */
+    showResults: function(categoryResults)
+    {
+        if (!categoryResults._resultView)
+            categoryResults._resultView = new WebInspector.AuditResultView(categoryResults);
+
+        this.visibleView = categoryResults._resultView;
+    },
+
+    showLauncherView: function()
+    {
+        this.visibleView = this._launcherView;
+    },
+
+    get visibleView()
+    {
+        return this._visibleView;
+    },
+
+    set visibleView(x)
+    {
+        if (this._visibleView === x)
+            return;
+
+        if (this._visibleView)
+            this._visibleView.detach();
+
+        this._visibleView = x;
+
+        if (x)
+            x.show(this.viewsContainerElement);
+    },
+
+    wasShown: function()
+    {
+        WebInspector.Panel.prototype.wasShown.call(this);
+        if (!this._visibleView)
+            this.auditsItemTreeElement.select();
+    },
+
+    _clearButtonClicked: function()
+    {
+        this.auditsItemTreeElement.revealAndSelect();
+        this.auditResultsTreeElement.removeChildren();
+    },
+
+    __proto__: WebInspector.Panel.prototype
+}
+
+/**
+ * @constructor
+ * @param {string} displayName
+ */
+WebInspector.AuditCategory = function(displayName)
+{
+    this._displayName = displayName;
+    this._rules = [];
+}
+
+WebInspector.AuditCategory.prototype = {
+    /**
+     * @return {string}
+     */
+    get id()
+    {
+        // this._id value is injected at construction time.
+        return this._id;
+    },
+
+    /**
+     * @return {string}
+     */
+    get displayName()
+    {
+        return this._displayName;
+    },
+
+    /**
+     * @param {!WebInspector.AuditRule} rule
+     * @param {!WebInspector.AuditRule.Severity} severity
+     */
+    addRule: function(rule, severity)
+    {
+        rule.severity = severity;
+        this._rules.push(rule);
+    },
+
+    /**
+     * @param {!Array.} requests
+     * @param {function(WebInspector.AuditRuleResult)} ruleResultCallback
+     * @param {function()} categoryDoneCallback
+     * @param {!WebInspector.Progress} progress
+     */
+    run: function(requests, ruleResultCallback, categoryDoneCallback, progress)
+    {
+        this._ensureInitialized();
+        var remainingRulesCount = this._rules.length;
+        progress.setTotalWork(remainingRulesCount);
+        function callbackWrapper(result)
+        {
+            ruleResultCallback(result);
+            progress.worked();
+            if (!--remainingRulesCount)
+                categoryDoneCallback();
+        }
+        for (var i = 0; i < this._rules.length; ++i)
+            this._rules[i].run(requests, callbackWrapper, progress);
+    },
+
+    _ensureInitialized: function()
+    {
+        if (!this._initialized) {
+            if ("initialize" in this)
+                this.initialize();
+            this._initialized = true;
+        }
+    }
+}
+
+/**
+ * @constructor
+ * @param {string} id
+ * @param {string} displayName
+ */
+WebInspector.AuditRule = function(id, displayName)
+{
+    this._id = id;
+    this._displayName = displayName;
+}
+
+/**
+ * @enum {string}
+ */
+WebInspector.AuditRule.Severity = {
+    Info: "info",
+    Warning: "warning",
+    Severe: "severe"
+}
+
+/**
+ * @type {Object.}
+ */
+WebInspector.AuditRule.SeverityOrder = {
+    "info": 3,
+    "warning": 2,
+    "severe": 1
+}
+
+WebInspector.AuditRule.prototype = {
+    get id()
+    {
+        return this._id;
+    },
+
+    get displayName()
+    {
+        return this._displayName;
+    },
+
+    /**
+     * @param {WebInspector.AuditRule.Severity} severity
+     */
+    set severity(severity)
+    {
+        this._severity = severity;
+    },
+
+    /**
+     * @param {!Array.} requests
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {!WebInspector.Progress} progress
+     */
+    run: function(requests, callback, progress)
+    {
+        if (progress.isCanceled())
+            return;
+
+        var result = new WebInspector.AuditRuleResult(this.displayName);
+        result.severity = this._severity;
+        this.doRun(requests, result, callback, progress);
+    },
+
+    /**
+     * @param {Array.} requests
+     * @param {WebInspector.AuditRuleResult} result
+     * @param {function(WebInspector.AuditRuleResult)} callback
+     * @param {WebInspector.Progress} progress
+     */
+    doRun: function(requests, result, callback, progress)
+    {
+        throw new Error("doRun() not implemented");
+    }
+}
+
+/**
+ * @constructor
+ * @param {!WebInspector.AuditCategory} category
+ */
+WebInspector.AuditCategoryResult = function(category)
+{
+    this.title = category.displayName;
+    this.ruleResults = [];
+}
+
+WebInspector.AuditCategoryResult.prototype = {
+    /**
+     * @param {!WebInspector.AuditCategoryResult} ruleResult
+     */
+    addRuleResult: function(ruleResult)
+    {
+        this.ruleResults.push(ruleResult);
+    }
+}
+
+/**
+ * @constructor
+ * @param {(string|boolean|number|Object)} value
+ * @param {boolean=} expanded
+ * @param {string=} className
+ */
+WebInspector.AuditRuleResult = function(value, expanded, className)
+{
+    this.value = value;
+    this.className = className;
+    this.expanded = expanded;
+    this.violationCount = 0;
+    this._formatters = {
+        r: WebInspector.AuditRuleResult.linkifyDisplayName
+    };
+    var standardFormatters = Object.keys(String.standardFormatters);
+    for (var i = 0; i < standardFormatters.length; ++i)
+        this._formatters[standardFormatters[i]] = String.standardFormatters[standardFormatters[i]];
+}
+
+/**
+ * @param {string} url
+ * @return {!Element}
+ */
+WebInspector.AuditRuleResult.linkifyDisplayName = function(url)
+{
+    return WebInspector.linkifyURLAsNode(url, WebInspector.displayNameForURL(url));
+}
+
+WebInspector.AuditRuleResult.resourceDomain = function(domain)
+{
+    return domain || WebInspector.UIString("[empty domain]");
+}
+
+WebInspector.AuditRuleResult.prototype = {
+    /**
+     * @param {(string|boolean|number|Object)} value
+     * @param {boolean=} expanded
+     * @param {string=} className
+     * @return {!WebInspector.AuditRuleResult}
+     */
+    addChild: function(value, expanded, className)
+    {
+        if (!this.children)
+            this.children = [];
+        var entry = new WebInspector.AuditRuleResult(value, expanded, className);
+        this.children.push(entry);
+        return entry;
+    },
+
+    /**
+     * @param {string} url
+     */
+    addURL: function(url)
+    {
+        this.addChild(WebInspector.AuditRuleResult.linkifyDisplayName(url));
+    },
+
+    /**
+     * @param {!Array.} urls
+     */
+    addURLs: function(urls)
+    {
+        for (var i = 0; i < urls.length; ++i)
+            this.addURL(urls[i]);
+    },
+
+    /**
+     * @param {string} snippet
+     */
+    addSnippet: function(snippet)
+    {
+        this.addChild(snippet, false, "source-code");
+    },
+
+    /**
+     * @param {string} format
+     * @param {...*} vararg
+     * @return {!WebInspector.AuditRuleResult}
+     */
+    addFormatted: function(format, vararg)
+    {
+        var substitutions = Array.prototype.slice.call(arguments, 1);
+        var fragment = document.createDocumentFragment();
+
+        function append(a, b)
+        {
+            if (!(b instanceof Node))
+                b = document.createTextNode(b);
+            a.appendChild(b);
+            return a;
+        }
+
+        var formattedResult = String.format(format, substitutions, this._formatters, fragment, append).formattedResult;
+        if (formattedResult instanceof Node)
+            formattedResult.normalize();
+        return this.addChild(formattedResult);
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarTreeElement}
+ * @param {WebInspector.AuditsPanel} panel
+ */
+WebInspector.AuditsSidebarTreeElement = function(panel)
+{
+    this._panel = panel;
+    this.small = false;
+    WebInspector.SidebarTreeElement.call(this, "audits-sidebar-tree-item", WebInspector.UIString("Audits"), "", null, false);
+}
+
+WebInspector.AuditsSidebarTreeElement.prototype = {
+    onattach: function()
+    {
+        WebInspector.SidebarTreeElement.prototype.onattach.call(this);
+    },
+
+    onselect: function()
+    {
+        this._panel.showLauncherView();
+    },
+
+    get selectable()
+    {
+        return true;
+    },
+
+    refresh: function()
+    {
+        this.refreshTitles();
+    },
+
+    __proto__: WebInspector.SidebarTreeElement.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarTreeElement}
+ * @param {!WebInspector.AuditsPanel} panel
+ * @param {!Array.} results
+ * @param {string} mainResourceURL
+ * @param {number} ordinal
+ */
+WebInspector.AuditResultSidebarTreeElement = function(panel, results, mainResourceURL, ordinal)
+{
+    this._panel = panel;
+    this.results = results;
+    this.mainResourceURL = mainResourceURL;
+    WebInspector.SidebarTreeElement.call(this, "audit-result-sidebar-tree-item", String.sprintf("%s (%d)", mainResourceURL, ordinal), "", {}, false);
+}
+
+WebInspector.AuditResultSidebarTreeElement.prototype = {
+    onselect: function()
+    {
+        this._panel.showResults(this.results);
+    },
+
+    get selectable()
+    {
+        return true;
+    },
+
+    __proto__: WebInspector.SidebarTreeElement.prototype
+}
+
+// Contributed audit rules should go into this namespace.
+WebInspector.AuditRules = {};
+
+/**
+ * Contributed audit categories should go into this namespace.
+ * @type {Object.}
+ */
+WebInspector.AuditCategories = {};
+
+importScript("AuditCategories.js");
+importScript("AuditController.js");
+importScript("AuditFormatters.js");
+importScript("AuditLauncherView.js");
+importScript("AuditResultView.js");
+importScript("AuditRules.js");
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BottomUpProfileDataGridTree.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BottomUpProfileDataGridTree.js
new file mode 100644
index 00000000..5f533bc5
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BottomUpProfileDataGridTree.js
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2009 280 North Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Bottom Up Profiling shows the entire callstack backwards:
+// The root node is a representation of each individual function called, and each child of that node represents
+// a reverse-callstack showing how many of those calls came from it. So, unlike top-down, the statistics in
+// each child still represent the root node. We have to be particularly careful of recursion with this mode
+// because a root node can represent itself AND an ancestor.
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileDataGridNode}
+ * @param {!ProfilerAgent.CPUProfileNode} profileNode
+ * @param {!WebInspector.TopDownProfileDataGridTree} owningTree
+ */
+WebInspector.BottomUpProfileDataGridNode = function(profileNode, owningTree)
+{
+    WebInspector.ProfileDataGridNode.call(this, profileNode, owningTree, this._willHaveChildren(profileNode));
+
+    this._remainingNodeInfos = [];
+}
+
+WebInspector.BottomUpProfileDataGridNode.prototype = {
+    /**
+     * @param {!WebInspector.ProfileDataGridNode} profileDataGridNode
+     */
+    _takePropertiesFromProfileDataGridNode: function(profileDataGridNode)
+    {
+        this._save();
+
+        this.selfTime = profileDataGridNode.selfTime;
+        this.totalTime = profileDataGridNode.totalTime;
+    },
+
+    /**
+     * When focusing, we keep just the members of the callstack.
+     * @param {!WebInspector.ProfileDataGridNode} child
+     */
+    _keepOnlyChild: function(child)
+    {
+        this._save();
+
+        this.removeChildren();
+        this.appendChild(child);
+    },
+
+    _exclude: function(aCallUID)
+    {
+        if (this._remainingNodeInfos)
+            this.populate();
+
+        this._save();
+
+        var children = this.children;
+        var index = this.children.length;
+
+        while (index--)
+            children[index]._exclude(aCallUID);
+
+        var child = this.childrenByCallUID[aCallUID];
+
+        if (child)
+            this._merge(child, true);
+    },
+
+    _restore: function()
+    {
+        WebInspector.ProfileDataGridNode.prototype._restore();
+
+        if (!this.children.length)
+            this.hasChildren = this._willHaveChildren(this.profileNode);
+    },
+
+    /**
+     * @param {!WebInspector.ProfileDataGridNode} child
+     * @param {boolean} shouldAbsorb
+     */
+    _merge: function(child, shouldAbsorb)
+    {
+        this.selfTime -= child.selfTime;
+
+        WebInspector.ProfileDataGridNode.prototype._merge.call(this, child, shouldAbsorb);
+    },
+
+    _sharedPopulate: function()
+    {
+        var remainingNodeInfos = this._remainingNodeInfos;
+        var count = remainingNodeInfos.length;
+
+        for (var index = 0; index < count; ++index) {
+            var nodeInfo = remainingNodeInfos[index];
+            var ancestor = nodeInfo.ancestor;
+            var focusNode = nodeInfo.focusNode;
+            var child = this.findChild(ancestor);
+
+            // If we already have this child, then merge the data together.
+            if (child) {
+                var totalTimeAccountedFor = nodeInfo.totalTimeAccountedFor;
+
+                child.selfTime += focusNode.selfTime;
+
+                if (!totalTimeAccountedFor)
+                    child.totalTime += focusNode.totalTime;
+            } else {
+                // If not, add it as a true ancestor.
+                // In heavy mode, we take our visual identity from ancestor node...
+                child = new WebInspector.BottomUpProfileDataGridNode(ancestor, this.tree);
+
+                if (ancestor !== focusNode) {
+                    // but the actual statistics from the "root" node (bottom of the callstack).
+                    child.selfTime = focusNode.selfTime;
+                    child.totalTime = focusNode.totalTime;
+                }
+
+                this.appendChild(child);
+            }
+
+            var parent = ancestor.parent;
+            if (parent && parent.parent) {
+                nodeInfo.ancestor = parent;
+                child._remainingNodeInfos.push(nodeInfo);
+            }
+        }
+
+        delete this._remainingNodeInfos;
+    },
+
+    _willHaveChildren: function(profileNode)
+    {
+        // In bottom up mode, our parents are our children since we display an inverted tree.
+        // However, we don't want to show the very top parent since it is redundant.
+        return !!(profileNode.parent && profileNode.parent.parent);
+    },
+
+    __proto__: WebInspector.ProfileDataGridNode.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileDataGridTree}
+ * @param {WebInspector.CPUProfileView} profileView
+ * @param {ProfilerAgent.CPUProfileNode} rootProfileNode
+ */
+WebInspector.BottomUpProfileDataGridTree = function(profileView, rootProfileNode)
+{
+    WebInspector.ProfileDataGridTree.call(this, profileView, rootProfileNode);
+
+    // Iterate each node in pre-order.
+    var profileNodeUIDs = 0;
+    var profileNodeGroups = [[], [rootProfileNode]];
+    var visitedProfileNodesForCallUID = {};
+
+    this._remainingNodeInfos = [];
+
+    for (var profileNodeGroupIndex = 0; profileNodeGroupIndex < profileNodeGroups.length; ++profileNodeGroupIndex) {
+        var parentProfileNodes = profileNodeGroups[profileNodeGroupIndex];
+        var profileNodes = profileNodeGroups[++profileNodeGroupIndex];
+        var count = profileNodes.length;
+
+        for (var index = 0; index < count; ++index) {
+            var profileNode = profileNodes[index];
+
+            if (!profileNode.UID)
+                profileNode.UID = ++profileNodeUIDs;
+
+            if (profileNode.head && profileNode !== profileNode.head) {
+                // The total time of this ancestor is accounted for if we're in any form of recursive cycle.
+                var visitedNodes = visitedProfileNodesForCallUID[profileNode.callUID];
+                var totalTimeAccountedFor = false;
+
+                if (!visitedNodes) {
+                    visitedNodes = {}
+                    visitedProfileNodesForCallUID[profileNode.callUID] = visitedNodes;
+                } else {
+                    // The total time for this node has already been accounted for iff one of it's parents has already been visited.
+                    // We can do this check in this style because we are traversing the tree in pre-order.
+                    var parentCount = parentProfileNodes.length;
+                    for (var parentIndex = 0; parentIndex < parentCount; ++parentIndex) {
+                        if (visitedNodes[parentProfileNodes[parentIndex].UID]) {
+                            totalTimeAccountedFor = true;
+                            break;
+                        }
+                    }
+                }
+
+                visitedNodes[profileNode.UID] = true;
+
+                this._remainingNodeInfos.push({ ancestor:profileNode, focusNode:profileNode, totalTimeAccountedFor:totalTimeAccountedFor });
+            }
+
+            var children = profileNode.children;
+            if (children.length) {
+                profileNodeGroups.push(parentProfileNodes.concat([profileNode]))
+                profileNodeGroups.push(children);
+            }
+        }
+    }
+
+    // Populate the top level nodes.
+    var any = /** @type{*} */(this);
+    var node = /** @type{WebInspector.ProfileDataGridNode} */(any);
+    WebInspector.BottomUpProfileDataGridNode.prototype.populate.call(node);
+
+    return this;
+}
+
+WebInspector.BottomUpProfileDataGridTree.prototype = {
+    /**
+     * When focusing, we keep the entire callstack up to this ancestor.
+     * @param {!WebInspector.ProfileDataGridNode} profileDataGridNode
+     */
+    focus: function(profileDataGridNode)
+    {
+        if (!profileDataGridNode)
+            return;
+
+        this._save();
+
+        var currentNode = profileDataGridNode;
+        var focusNode = profileDataGridNode;
+
+        while (currentNode.parent && (currentNode instanceof WebInspector.ProfileDataGridNode)) {
+            currentNode._takePropertiesFromProfileDataGridNode(profileDataGridNode);
+
+            focusNode = currentNode;
+            currentNode = currentNode.parent;
+
+            if (currentNode instanceof WebInspector.ProfileDataGridNode)
+                currentNode._keepOnlyChild(focusNode);
+        }
+
+        this.children = [focusNode];
+        this.totalTime = profileDataGridNode.totalTime;
+    },
+
+    /**
+     * @param {!WebInspector.ProfileDataGridNode} profileDataGridNode
+     */
+    exclude: function(profileDataGridNode)
+    {
+        if (!profileDataGridNode)
+            return;
+
+        this._save();
+
+        var excludedCallUID = profileDataGridNode.callUID;
+        var excludedTopLevelChild = this.childrenByCallUID[excludedCallUID];
+
+        // If we have a top level node that is excluded, get rid of it completely (not keeping children),
+        // since bottom up data relies entirely on the root node.
+        if (excludedTopLevelChild)
+            this.children.remove(excludedTopLevelChild);
+
+        var children = this.children;
+        var count = children.length;
+
+        for (var index = 0; index < count; ++index)
+            children[index]._exclude(excludedCallUID);
+
+        if (this.lastComparator)
+            this.sort(this.lastComparator, true);
+    },
+
+    _sharedPopulate: WebInspector.BottomUpProfileDataGridNode.prototype._sharedPopulate,
+
+    __proto__: WebInspector.ProfileDataGridTree.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointManager.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointManager.js
new file mode 100644
index 00000000..99176f18
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointManager.js
@@ -0,0 +1,674 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {WebInspector.Setting} breakpointStorage
+ * @param {WebInspector.DebuggerModel} debuggerModel
+ * @param {WebInspector.Workspace} workspace
+ */
+WebInspector.BreakpointManager = function(breakpointStorage, debuggerModel, workspace)
+{
+    this._storage = new WebInspector.BreakpointManager.Storage(this, breakpointStorage);
+    this._debuggerModel = debuggerModel;
+    this._workspace = workspace;
+
+    this._breakpoints = new Map();
+    this._breakpointForDebuggerId = {};
+    this._breakpointsForUISourceCode = new Map();
+    this._sourceFilesWithRestoredBreakpoints = {};
+
+    this._debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointResolved, this._breakpointResolved, this);
+    this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectWillReset, this._projectWillReset, this);
+    this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this);
+}
+
+WebInspector.BreakpointManager.Events = {
+    BreakpointAdded: "breakpoint-added",
+    BreakpointRemoved: "breakpoint-removed"
+}
+
+WebInspector.BreakpointManager.sourceFileId = function(uiSourceCode)
+{
+    if (!uiSourceCode.url)
+        return "";
+    var deobfuscatedPrefix = uiSourceCode.formatted() ? "deobfuscated:" : "";
+    return deobfuscatedPrefix + uiSourceCode.uri();
+}
+
+WebInspector.BreakpointManager.prototype = {
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     */
+    _restoreBreakpoints: function(uiSourceCode)
+    {
+        var sourceFileId = WebInspector.BreakpointManager.sourceFileId(uiSourceCode);
+        if (!sourceFileId || this._sourceFilesWithRestoredBreakpoints[sourceFileId])
+            return;
+        this._sourceFilesWithRestoredBreakpoints[sourceFileId] = true;
+
+        // Erase provisional breakpoints prior to restoring them.
+        for (var debuggerId in this._breakpointForDebuggerId) {
+            var breakpoint = this._breakpointForDebuggerId[debuggerId];
+            if (breakpoint._sourceFileId !== sourceFileId)
+                continue;
+            breakpoint.remove(true);
+        }
+        this._storage._restoreBreakpoints(uiSourceCode);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _uiSourceCodeAdded: function(event)
+    {
+        var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.data);
+        this._restoreBreakpoints(uiSourceCode);
+        if (uiSourceCode.contentType() === WebInspector.resourceTypes.Script || uiSourceCode.contentType() === WebInspector.resourceTypes.Document) {
+            uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.SourceMappingChanged, this._uiSourceCodeMappingChanged, this);
+            uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.FormattedChanged, this._uiSourceCodeFormatted, this);
+        }
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _uiSourceCodeFormatted: function(event)
+    {
+        var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
+        this._restoreBreakpoints(uiSourceCode);
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     */
+    _resetBreakpoints: function(uiSourceCode)
+    {
+        var sourceFileId = WebInspector.BreakpointManager.sourceFileId(uiSourceCode);
+        var breakpoints = this._breakpoints.keys();
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (breakpoint._sourceFileId !== sourceFileId)
+                return;
+            if (breakpoint.enabled()) {
+                breakpoint._removeFromDebugger();
+                breakpoint._setInDebugger();
+            }
+        }
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _uiSourceCodeMappingChanged: function(event)
+    {
+        var identityHasChanged = /** @type {boolean} */ (event.data.identityHasChanged);
+        if (!identityHasChanged)
+            return;
+        var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.target);
+        this._resetBreakpoints(uiSourceCode);
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @param {string} condition
+     * @param {boolean} enabled
+     * @return {WebInspector.BreakpointManager.Breakpoint}
+     */
+    setBreakpoint: function(uiSourceCode, lineNumber, condition, enabled)
+    {
+        this._debuggerModel.setBreakpointsActive(true);
+        return this._innerSetBreakpoint(uiSourceCode, lineNumber, condition, enabled);
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @param {string} condition
+     * @param {boolean} enabled
+     * @return {WebInspector.BreakpointManager.Breakpoint}
+     */
+    _innerSetBreakpoint: function(uiSourceCode, lineNumber, condition, enabled)
+    {
+        var breakpoint = this.findBreakpoint(uiSourceCode, lineNumber);
+        if (breakpoint) {
+            breakpoint._updateBreakpoint(condition, enabled);
+            return breakpoint;
+        }
+        breakpoint = new WebInspector.BreakpointManager.Breakpoint(this, uiSourceCode, lineNumber, condition, enabled);
+        this._breakpoints.put(breakpoint);
+        return breakpoint;
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @return {?WebInspector.BreakpointManager.Breakpoint}
+     */
+    findBreakpoint: function(uiSourceCode, lineNumber)
+    {
+        var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode);
+        var lineBreakpoints = breakpoints ? breakpoints[lineNumber] : null;
+        return lineBreakpoints ? lineBreakpoints[0] : null;
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @return {Array.}
+     */
+    breakpointsForUISourceCode: function(uiSourceCode)
+    {
+        var result = [];
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            var uiLocation = breakpoint._primaryUILocation;
+            if (uiLocation.uiSourceCode === uiSourceCode)
+                result.push(breakpoint);
+        }
+        return result;
+    },
+
+    /**
+     * @return {Array.}
+     */
+    allBreakpoints: function()
+    {
+        var result = [];
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        return breakpoints;
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @return {Array.<{breakpoint: WebInspector.BreakpointManager.Breakpoint, uiLocation: WebInspector.UILocation}>}
+     */
+    breakpointLocationsForUISourceCode: function(uiSourceCode)
+    {
+        var result = [];
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            var uiLocations = Object.values(breakpoint._uiLocations);
+            for (var j = 0; j < uiLocations.length; ++j) {
+                var uiLocation = uiLocations[j];
+                if (uiLocation.uiSourceCode === uiSourceCode)
+                    result.push({breakpoint: breakpoint, uiLocation: uiLocations[j]});
+            }
+        }
+        return result;
+    },
+
+    /**
+     * @return {Array.<{breakpoint: WebInspector.BreakpointManager.Breakpoint, uiLocation: WebInspector.UILocation}>}
+     */
+    allBreakpointLocations: function()
+    {
+        var result = [];
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            var uiLocations = Object.values(breakpoint._uiLocations);
+            for (var j = 0; j < uiLocations.length; ++j)
+                result.push({breakpoint: breakpoint, uiLocation: uiLocations[j]});
+        }
+        return result;
+    },
+
+    /**
+     * @param {boolean} toggleState
+     */
+    toggleAllBreakpoints: function(toggleState)
+    {
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (breakpoint.enabled() != toggleState)
+                breakpoint.setEnabled(toggleState);
+        }
+    },
+
+    removeAllBreakpoints: function()
+    {
+        var breakpoints = /** @type {Array.} */(this._breakpoints.keys());
+        for (var i = 0; i < breakpoints.length; ++i)
+            breakpoints[i].remove();
+    },
+
+    reset: function()
+    {
+        // Remove all breakpoints from UI and debugger, do not update storage.
+        this._storage._muted = true;
+        this.removeAllBreakpoints();
+        delete this._storage._muted;
+
+        // Remove all provisional breakpoints from the debugger.
+        for (var debuggerId in this._breakpointForDebuggerId)
+            this._debuggerModel.removeBreakpoint(debuggerId);
+        this._breakpointForDebuggerId = {};
+        this._sourceFilesWithRestoredBreakpoints = {};
+    },
+
+    _projectWillReset: function(event)
+    {
+        var project = /** @type {WebInspector.Project} */ (event.data);
+        var uiSourceCodes = project.uiSourceCodes();
+        for (var i = 0; i < uiSourceCodes.length; ++i) {
+            var uiSourceCode = uiSourceCodes[i];
+            var breakpoints = this._breakpointsForUISourceCode.get(uiSourceCode) || [];
+            for (var lineNumber in breakpoints) {
+                var lineBreakpoints = breakpoints[lineNumber];
+                for (var j = 0; j < lineBreakpoints.length; ++j) {
+                    var breakpoint = lineBreakpoints[j];
+                    breakpoint._resetLocations();
+                }
+            }
+            this._breakpointsForUISourceCode.remove(uiSourceCode);
+
+            breakpoints = this.breakpointsForUISourceCode(uiSourceCode);
+            for (var j = 0; j < breakpoints.length; ++j) { 
+                var breakpoint = breakpoints[j];
+                this._breakpoints.remove(breakpoint);
+            }
+
+            var sourceFileId = WebInspector.BreakpointManager.sourceFileId(uiSourceCode);
+            delete this._sourceFilesWithRestoredBreakpoints[sourceFileId];
+        }
+    },
+
+    _breakpointResolved: function(event)
+    {
+        var breakpointId = /** @type {DebuggerAgent.BreakpointId} */ (event.data.breakpointId);
+        var location = /** @type {WebInspector.DebuggerModel.Location} */ (event.data.location);
+        var breakpoint = this._breakpointForDebuggerId[breakpointId];
+        if (!breakpoint)
+            return;
+        if (!this._breakpoints.contains(breakpoint))
+            this._breakpoints.put(breakpoint);
+        breakpoint._addResolvedLocation(location);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     * @param {boolean} removeFromStorage
+     */
+    _removeBreakpoint: function(breakpoint, removeFromStorage)
+    {
+        console.assert(!breakpoint._debuggerId)
+        this._breakpoints.remove(breakpoint);
+        if (removeFromStorage)
+            this._storage._removeBreakpoint(breakpoint);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     * @param {WebInspector.UILocation} uiLocation
+     */
+    _uiLocationAdded: function(breakpoint, uiLocation)
+    {
+        var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
+        if (!breakpoints) {
+            breakpoints = {};
+            this._breakpointsForUISourceCode.put(uiLocation.uiSourceCode, breakpoints);
+        }
+
+        var lineBreakpoints = breakpoints[uiLocation.lineNumber];
+        if (!lineBreakpoints) {
+            lineBreakpoints = [];
+            breakpoints[uiLocation.lineNumber] = lineBreakpoints;
+        }
+
+        lineBreakpoints.push(breakpoint);
+        this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointAdded, {breakpoint: breakpoint, uiLocation: uiLocation});
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     * @param {WebInspector.UILocation} uiLocation
+     */
+    _uiLocationRemoved: function(breakpoint, uiLocation)
+    {
+      var breakpoints = this._breakpointsForUISourceCode.get(uiLocation.uiSourceCode);
+        if (!breakpoints)
+            return;
+
+        var lineBreakpoints = breakpoints[uiLocation.lineNumber];
+        if (!lineBreakpoints)
+            return;
+
+        lineBreakpoints.remove(breakpoint);
+        if (!lineBreakpoints.length)
+            delete breakpoints[uiLocation.lineNumber];
+        this.dispatchEventToListeners(WebInspector.BreakpointManager.Events.BreakpointRemoved, {breakpoint: breakpoint, uiLocation: uiLocation});
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.BreakpointManager} breakpointManager
+ * @param {WebInspector.UISourceCode} uiSourceCode
+ * @param {number} lineNumber
+ * @param {string} condition
+ * @param {boolean} enabled
+ */
+WebInspector.BreakpointManager.Breakpoint = function(breakpointManager, uiSourceCode, lineNumber, condition, enabled)
+{
+    this._breakpointManager = breakpointManager;
+    this._primaryUILocation = new WebInspector.UILocation(uiSourceCode, lineNumber, 0);
+    this._sourceFileId = WebInspector.BreakpointManager.sourceFileId(uiSourceCode);
+    /** @type {Array.} */
+    this._liveLocations = [];
+    /** @type {!Object.} */
+    this._uiLocations = {};
+
+    // Force breakpoint update.
+    /** @type {string} */ this._condition;
+    /** @type {boolean} */ this._enabled;
+    this._updateBreakpoint(condition, enabled);
+}
+
+WebInspector.BreakpointManager.Breakpoint.prototype = {
+    /**
+     * @return {WebInspector.UILocation}
+     */
+    primaryUILocation: function()
+    {
+        return this._primaryUILocation;
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} location
+     */
+    _addResolvedLocation: function(location)
+    {
+        this._liveLocations.push(this._breakpointManager._debuggerModel.createLiveLocation(location, this._locationUpdated.bind(this, location)));
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} location
+     * @param {WebInspector.UILocation} uiLocation
+     */
+    _locationUpdated: function(location, uiLocation)
+    {
+        var stringifiedLocation = location.scriptId + ":" + location.lineNumber + ":" + location.columnNumber;
+        var oldUILocation = /** @type {WebInspector.UILocation} */ (this._uiLocations[stringifiedLocation]);
+        if (oldUILocation)
+            this._breakpointManager._uiLocationRemoved(this, oldUILocation);
+        if (this._uiLocations[""]) {
+            delete this._uiLocations[""];
+            this._breakpointManager._uiLocationRemoved(this, this._primaryUILocation);
+        }
+        this._uiLocations[stringifiedLocation] = uiLocation;
+        this._breakpointManager._uiLocationAdded(this, uiLocation);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    enabled: function()
+    {
+        return this._enabled;
+    },
+
+    /**
+     * @param {boolean} enabled
+     */
+    setEnabled: function(enabled)
+    {
+        this._updateBreakpoint(this._condition, enabled);
+    },
+
+    /**
+     * @return {string}
+     */
+    condition: function()
+    {
+        return this._condition;
+    },
+
+    /**
+     * @param {string} condition
+     */
+    setCondition: function(condition)
+    {
+        this._updateBreakpoint(condition, this._enabled);
+    },
+
+    /**
+     * @param {string} condition
+     * @param {boolean} enabled
+     */
+    _updateBreakpoint: function(condition, enabled)
+    {
+        if (this._enabled === enabled && this._condition === condition)
+            return;
+
+        if (this._enabled)
+            this._removeFromDebugger();
+
+        this._enabled = enabled;
+        this._condition = condition;
+        this._breakpointManager._storage._updateBreakpoint(this);
+
+        var scriptFile = this._primaryUILocation.uiSourceCode.scriptFile();
+        if (this._enabled && !(scriptFile && scriptFile.hasDivergedFromVM())) {
+            if (this._setInDebugger())
+                return;
+        }
+
+        this._fakeBreakpointAtPrimaryLocation();
+    },
+
+    /**
+     * @param {boolean=} keepInStorage
+     */
+    remove: function(keepInStorage)
+    {
+        var removeFromStorage = !keepInStorage;
+        this._resetLocations();
+        this._removeFromDebugger();
+        this._breakpointManager._removeBreakpoint(this, removeFromStorage);
+    },
+
+    _setInDebugger: function()
+    {
+        console.assert(!this._debuggerId);
+        var rawLocation = this._primaryUILocation.uiLocationToRawLocation();
+        var debuggerModelLocation = /** @type {WebInspector.DebuggerModel.Location} */ (rawLocation);
+        if (debuggerModelLocation) {
+            this._breakpointManager._debuggerModel.setBreakpointByScriptLocation(debuggerModelLocation, this._condition, this._didSetBreakpointInDebugger.bind(this));
+            return true;
+        }
+        if (this._primaryUILocation.uiSourceCode.url) {
+            this._breakpointManager._debuggerModel.setBreakpointByURL(this._primaryUILocation.uiSourceCode.url, this._primaryUILocation.lineNumber, 0, this._condition, this._didSetBreakpointInDebugger.bind(this));
+            return true;
+        }
+        return false;
+    },
+
+    /**
+    * @this {WebInspector.BreakpointManager.Breakpoint}
+    * @param {?DebuggerAgent.BreakpointId} breakpointId
+    * @param {Array.} locations
+    */
+    _didSetBreakpointInDebugger: function(breakpointId, locations)
+    {
+        if (!breakpointId) {
+            this._resetLocations();
+            this._breakpointManager._removeBreakpoint(this, false);
+            return;
+        }
+
+        this._debuggerId = breakpointId;
+        this._breakpointManager._breakpointForDebuggerId[breakpointId] = this;
+
+        if (!locations.length) {
+            this._fakeBreakpointAtPrimaryLocation();
+            return;
+        }
+
+        this._resetLocations();
+        for (var i = 0; i < locations.length; ++i) {
+            var script = this._breakpointManager._debuggerModel.scriptForId(locations[i].scriptId);
+            var uiLocation = script.rawLocationToUILocation(locations[i].lineNumber, locations[i].columnNumber);
+            if (this._breakpointManager.findBreakpoint(uiLocation.uiSourceCode, uiLocation.lineNumber)) {
+                // location clash
+                this.remove();
+                return;
+            }
+        }
+
+        for (var i = 0; i < locations.length; ++i)
+            this._addResolvedLocation(locations[i]);
+    },
+
+    _removeFromDebugger: function()
+    {
+        if (this._debuggerId) {
+            this._breakpointManager._debuggerModel.removeBreakpoint(this._debuggerId);
+            delete this._breakpointManager._breakpointForDebuggerId[this._debuggerId];
+            delete this._debuggerId;
+        }
+    },
+
+    _resetLocations: function()
+    {
+        for (var stringifiedLocation in this._uiLocations)
+            this._breakpointManager._uiLocationRemoved(this, this._uiLocations[stringifiedLocation]);
+
+        for (var i = 0; i < this._liveLocations.length; ++i)
+            this._liveLocations[i].dispose();
+        this._liveLocations = [];
+
+        this._uiLocations = {};
+    },
+
+    /**
+     * @return {string}
+     */
+    _breakpointStorageId: function()
+    {
+        if (!this._sourceFileId)
+            return "";
+        return this._sourceFileId + ":" + this._primaryUILocation.lineNumber;
+    },
+
+    _fakeBreakpointAtPrimaryLocation: function()
+    {
+        this._resetLocations();
+        this._uiLocations[""] = this._primaryUILocation;
+        this._breakpointManager._uiLocationAdded(this, this._primaryUILocation);
+    }
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.BreakpointManager} breakpointManager
+ * @param {WebInspector.Setting} setting
+ */
+WebInspector.BreakpointManager.Storage = function(breakpointManager, setting)
+{
+    this._breakpointManager = breakpointManager;
+    this._setting = setting;
+    var breakpoints = this._setting.get();
+    /** @type {Object.} */
+    this._breakpoints = {};
+    for (var i = 0; i < breakpoints.length; ++i) {
+        var breakpoint = /** @type {WebInspector.BreakpointManager.Storage.Item} */ (breakpoints[i]);
+        this._breakpoints[breakpoint.sourceFileId + ":" + breakpoint.lineNumber] = breakpoint;
+    }
+}
+
+WebInspector.BreakpointManager.Storage.prototype = {
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     */
+    _restoreBreakpoints: function(uiSourceCode)
+    {
+        this._muted = true;
+        var sourceFileId = WebInspector.BreakpointManager.sourceFileId(uiSourceCode);
+        for (var id in this._breakpoints) {
+            var breakpoint = this._breakpoints[id];
+            if (breakpoint.sourceFileId === sourceFileId)
+                this._breakpointManager._innerSetBreakpoint(uiSourceCode, breakpoint.lineNumber, breakpoint.condition, breakpoint.enabled);
+        }
+        delete this._muted;
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     */
+    _updateBreakpoint: function(breakpoint)
+    {
+        if (this._muted || !breakpoint._breakpointStorageId())
+            return;
+        this._breakpoints[breakpoint._breakpointStorageId()] = new WebInspector.BreakpointManager.Storage.Item(breakpoint);
+        this._save();
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     */
+    _removeBreakpoint: function(breakpoint)
+    {
+        if (this._muted)
+            return;
+        delete this._breakpoints[breakpoint._breakpointStorageId()];
+        this._save();
+    },
+
+    _save: function()
+    {
+        var breakpointsArray = [];
+        for (var id in this._breakpoints)
+            breakpointsArray.push(this._breakpoints[id]);
+        this._setting.set(breakpointsArray);
+    }
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+ */
+WebInspector.BreakpointManager.Storage.Item = function(breakpoint)
+{
+    var primaryUILocation = breakpoint.primaryUILocation();
+    this.sourceFileId = breakpoint._sourceFileId;
+    this.lineNumber = primaryUILocation.lineNumber;
+    this.condition = breakpoint.condition();
+    this.enabled = breakpoint.enabled();
+}
+
+/** @type {WebInspector.BreakpointManager} */
+WebInspector.breakpointManager = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointsSidebarPane.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointsSidebarPane.js
new file mode 100644
index 00000000..9e13c14a
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/BreakpointsSidebarPane.js
@@ -0,0 +1,695 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.BreakpointManager} breakpointManager
+ * @extends {WebInspector.SidebarPane}
+ */
+WebInspector.JavaScriptBreakpointsSidebarPane = function(breakpointManager, showSourceLineDelegate)
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints"));
+    this.registerRequiredCSS("breakpointsList.css");
+
+    this._breakpointManager = breakpointManager;
+    this._showSourceLineDelegate = showSourceLineDelegate;
+
+    this.listElement = document.createElement("ol");
+    this.listElement.className = "breakpoint-list";
+
+    this.emptyElement = document.createElement("div");
+    this.emptyElement.className = "info";
+    this.emptyElement.textContent = WebInspector.UIString("No Breakpoints");
+
+    this.bodyElement.appendChild(this.emptyElement);
+
+    this._items = new Map();
+    
+    var breakpointLocations = this._breakpointManager.allBreakpointLocations();
+    for (var i = 0; i < breakpointLocations.length; ++i)
+        this._addBreakpoint(breakpointLocations[i].breakpoint, breakpointLocations[i].uiLocation);
+
+    this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointAdded, this._breakpointAdded, this);
+    this._breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.BreakpointRemoved, this._breakpointRemoved, this);
+
+    this.emptyElement.addEventListener("contextmenu", this._emptyElementContextMenu.bind(this), true);
+}
+
+WebInspector.JavaScriptBreakpointsSidebarPane.prototype = {
+    _emptyElementContextMenu: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        var breakpointActive = WebInspector.debuggerModel.breakpointsActive();
+        var breakpointActiveTitle = breakpointActive ?
+            WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Deactivate breakpoints" : "Deactivate Breakpoints") :
+            WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Activate breakpoints" : "Activate Breakpoints");
+        contextMenu.appendItem(breakpointActiveTitle, WebInspector.debuggerModel.setBreakpointsActive.bind(WebInspector.debuggerModel, !breakpointActive));
+        contextMenu.show();
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _breakpointAdded: function(event)
+    {
+        this._breakpointRemoved(event);
+
+        var breakpoint = /** @type {WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
+        var uiLocation = /** @type {WebInspector.UILocation} */ (event.data.uiLocation);
+        this._addBreakpoint(breakpoint, uiLocation);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     * @param {WebInspector.UILocation} uiLocation
+     */
+    _addBreakpoint: function(breakpoint, uiLocation)
+    {
+        var element = document.createElement("li");
+        element.addStyleClass("cursor-pointer");
+        element.addEventListener("contextmenu", this._breakpointContextMenu.bind(this, breakpoint), true);
+        element.addEventListener("click", this._breakpointClicked.bind(this, uiLocation), false);
+
+        var checkbox = document.createElement("input");
+        checkbox.className = "checkbox-elem";
+        checkbox.type = "checkbox";
+        checkbox.checked = breakpoint.enabled();
+        checkbox.addEventListener("click", this._breakpointCheckboxClicked.bind(this, breakpoint), false);
+        element.appendChild(checkbox);
+
+        var labelElement = document.createTextNode(uiLocation.linkText());
+        element.appendChild(labelElement);
+
+        var snippetElement = document.createElement("div");
+        snippetElement.className = "source-text monospace";
+        element.appendChild(snippetElement);
+
+        /**
+         * @param {?string} content
+         * @param {boolean} contentEncoded
+         * @param {string} mimeType
+         */
+        function didRequestContent(content, contentEncoded, mimeType)
+        {
+            var lineEndings = content.lineEndings();
+            if (uiLocation.lineNumber < lineEndings.length)
+                snippetElement.textContent = content.substring(lineEndings[uiLocation.lineNumber - 1], lineEndings[uiLocation.lineNumber]);
+        }
+        uiLocation.uiSourceCode.requestContent(didRequestContent.bind(this));
+
+        element._data = uiLocation;
+        var currentElement = this.listElement.firstChild;
+        while (currentElement) {
+            if (currentElement._data && this._compareBreakpoints(currentElement._data, element._data) > 0)
+                break;
+            currentElement = currentElement.nextSibling;
+        }
+        this._addListElement(element, currentElement);
+
+        var breakpointItem = {};
+        breakpointItem.element = element;
+        breakpointItem.checkbox = checkbox;
+        this._items.put(breakpoint, breakpointItem);
+
+        this.expand();
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _breakpointRemoved: function(event)
+    {
+        var breakpoint = /** @type {WebInspector.BreakpointManager.Breakpoint} */ (event.data.breakpoint);
+        var uiLocation = /** @type {WebInspector.UILocation} */ (event.data.uiLocation);
+        var breakpointItem = this._items.get(breakpoint);
+        if (!breakpointItem)
+            return;
+        this._items.remove(breakpoint);
+        this._removeListElement(breakpointItem.element);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     */
+    highlightBreakpoint: function(breakpoint)
+    {
+        var breakpointItem = this._items.get(breakpoint);
+        if (!breakpointItem)
+            return;
+        breakpointItem.element.addStyleClass("breakpoint-hit");
+        this._highlightedBreakpointItem = breakpointItem;
+    },
+
+    clearBreakpointHighlight: function()
+    {
+        if (this._highlightedBreakpointItem) {
+            this._highlightedBreakpointItem.element.removeStyleClass("breakpoint-hit");
+            delete this._highlightedBreakpointItem;
+        }
+    },
+
+    _breakpointClicked: function(uiLocation, event)
+    {
+        this._showSourceLineDelegate(uiLocation.uiSourceCode, uiLocation.lineNumber);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     */
+    _breakpointCheckboxClicked: function(breakpoint, event)
+    {
+        // Breakpoint element has it's own click handler.
+        event.consume();
+        breakpoint.setEnabled(event.target.checked);
+    },
+
+    /**
+     * @param {WebInspector.BreakpointManager.Breakpoint} breakpoint
+     */
+    _breakpointContextMenu: function(breakpoint, event)
+    {
+        var breakpoints = this._items.values();
+        var contextMenu = new WebInspector.ContextMenu(event);
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), breakpoint.remove.bind(breakpoint));
+        if (breakpoints.length > 1) {
+            var removeAllTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all breakpoints" : "Remove All Breakpoints");
+            contextMenu.appendItem(removeAllTitle, this._breakpointManager.removeAllBreakpoints.bind(this._breakpointManager));
+        }
+
+        contextMenu.appendSeparator();
+        var breakpointActive = WebInspector.debuggerModel.breakpointsActive();
+        var breakpointActiveTitle = breakpointActive ?
+            WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Deactivate breakpoints" : "Deactivate Breakpoints") :
+            WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Activate breakpoints" : "Activate Breakpoints");
+        contextMenu.appendItem(breakpointActiveTitle, WebInspector.debuggerModel.setBreakpointsActive.bind(WebInspector.debuggerModel, !breakpointActive));
+
+        function enabledBreakpointCount(breakpoints)
+        {
+            var count = 0;
+            for (var i = 0; i < breakpoints.length; ++i) {
+                if (breakpoints[i].checkbox.checked)
+                    count++;
+            }
+            return count;
+        }
+        if (breakpoints.length > 1) {
+            var enableBreakpointCount = enabledBreakpointCount(breakpoints);
+            var enableTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Enable all breakpoints" : "Enable All Breakpoints");
+            var disableTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Disable all breakpoints" : "Disable All Breakpoints");
+
+            contextMenu.appendSeparator();
+
+            contextMenu.appendItem(enableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, true), !(enableBreakpointCount != breakpoints.length));
+            contextMenu.appendItem(disableTitle, this._breakpointManager.toggleAllBreakpoints.bind(this._breakpointManager, false), !(enableBreakpointCount > 1));
+        }
+
+        contextMenu.show();
+    },
+
+    _addListElement: function(element, beforeElement)
+    {
+        if (beforeElement)
+            this.listElement.insertBefore(element, beforeElement);
+        else {
+            if (!this.listElement.firstChild) {
+                this.bodyElement.removeChild(this.emptyElement);
+                this.bodyElement.appendChild(this.listElement);
+            }
+            this.listElement.appendChild(element);
+        }
+    },
+
+    _removeListElement: function(element)
+    {
+        this.listElement.removeChild(element);
+        if (!this.listElement.firstChild) {
+            this.bodyElement.removeChild(this.listElement);
+            this.bodyElement.appendChild(this.emptyElement);
+        }
+    },
+
+    _compare: function(x, y)
+    {
+        if (x !== y)
+            return x < y ? -1 : 1;
+        return 0;
+    },
+
+    _compareBreakpoints: function(b1, b2)
+    {
+        return this._compare(b1.uiSourceCode.originURL(), b2.uiSourceCode.originURL()) || this._compare(b1.lineNumber, b2.lineNumber);
+    },
+
+    reset: function()
+    {
+        this.listElement.removeChildren();
+        if (this.listElement.parentElement) {
+            this.bodyElement.removeChild(this.listElement);
+            this.bodyElement.appendChild(this.emptyElement);
+        }
+        this._items.clear();
+    },
+
+    __proto__: WebInspector.SidebarPane.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.NativeBreakpointsSidebarPane}
+ */
+WebInspector.XHRBreakpointsSidebarPane = function()
+{
+    WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("XHR Breakpoints"));
+
+    this._breakpointElements = {};
+
+    var addButton = document.createElement("button");
+    addButton.className = "pane-title-button add";
+    addButton.addEventListener("click", this._addButtonClicked.bind(this), false);
+    addButton.title = WebInspector.UIString("Add XHR breakpoint");
+    this.titleElement.appendChild(addButton);
+
+    this.emptyElement.addEventListener("contextmenu", this._emptyElementContextMenu.bind(this), true);
+
+    this._restoreBreakpoints();
+}
+
+WebInspector.XHRBreakpointsSidebarPane.prototype = {
+    _emptyElementContextMenu: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add breakpoint" : "Add Breakpoint"), this._addButtonClicked.bind(this));
+        contextMenu.show();
+    },
+
+    _addButtonClicked: function(event)
+    {
+        if (event)
+            event.consume();
+
+        this.expand();
+
+        var inputElementContainer = document.createElement("p");
+        inputElementContainer.className = "breakpoint-condition";
+        var inputElement = document.createElement("span");
+        inputElementContainer.textContent = WebInspector.UIString("Break when URL contains:");
+        inputElement.className = "editing";
+        inputElement.id = "breakpoint-condition-input";
+        inputElementContainer.appendChild(inputElement);
+        this._addListElement(inputElementContainer, this.listElement.firstChild);
+
+        function finishEditing(accept, e, text)
+        {
+            this._removeListElement(inputElementContainer);
+            if (accept) {
+                this._setBreakpoint(text, true);
+                this._saveBreakpoints();
+            }
+        }
+
+        var config = new WebInspector.EditingConfig(finishEditing.bind(this, true), finishEditing.bind(this, false));
+        WebInspector.startEditing(inputElement, config);
+    },
+
+    _setBreakpoint: function(url, enabled)
+    {
+        if (url in this._breakpointElements)
+            return;
+
+        var element = document.createElement("li");
+        element._url = url;
+        element.addEventListener("contextmenu", this._contextMenu.bind(this, url), true);
+
+        var checkboxElement = document.createElement("input");
+        checkboxElement.className = "checkbox-elem";
+        checkboxElement.type = "checkbox";
+        checkboxElement.checked = enabled;
+        checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, url), false);
+        element._checkboxElement = checkboxElement;
+        element.appendChild(checkboxElement);
+
+        var labelElement = document.createElement("span");
+        if (!url)
+            labelElement.textContent = WebInspector.UIString("Any XHR");
+        else
+            labelElement.textContent = WebInspector.UIString("URL contains \"%s\"", url);
+        labelElement.addStyleClass("cursor-auto");
+        labelElement.addEventListener("dblclick", this._labelClicked.bind(this, url), false);
+        element.appendChild(labelElement);
+
+        var currentElement = this.listElement.firstChild;
+        while (currentElement) {
+            if (currentElement._url && currentElement._url < element._url)
+                break;
+            currentElement = currentElement.nextSibling;
+        }
+        this._addListElement(element, currentElement);
+        this._breakpointElements[url] = element;
+        if (enabled)
+            DOMDebuggerAgent.setXHRBreakpoint(url);
+    },
+
+    _removeBreakpoint: function(url)
+    {
+        var element = this._breakpointElements[url];
+        if (!element)
+            return;
+
+        this._removeListElement(element);
+        delete this._breakpointElements[url];
+        if (element._checkboxElement.checked)
+            DOMDebuggerAgent.removeXHRBreakpoint(url);
+    },
+
+    _contextMenu: function(url, event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        function removeBreakpoint()
+        {
+            this._removeBreakpoint(url);
+            this._saveBreakpoints();
+        }
+        function removeAllBreakpoints()
+        {
+            for (var url in this._breakpointElements)
+                this._removeBreakpoint(url);
+            this._saveBreakpoints();
+        }
+        var removeAllTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all breakpoints" : "Remove All Breakpoints");
+
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add breakpoint" : "Add Breakpoint"), this._addButtonClicked.bind(this));
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), removeBreakpoint.bind(this));
+        contextMenu.appendItem(removeAllTitle, removeAllBreakpoints.bind(this));
+        contextMenu.show();
+    },
+
+    _checkboxClicked: function(url, event)
+    {
+        if (event.target.checked)
+            DOMDebuggerAgent.setXHRBreakpoint(url);
+        else
+            DOMDebuggerAgent.removeXHRBreakpoint(url);
+        this._saveBreakpoints();
+    },
+
+    _labelClicked: function(url)
+    {
+        var element = this._breakpointElements[url];
+        var inputElement = document.createElement("span");
+        inputElement.className = "breakpoint-condition editing";
+        inputElement.textContent = url;
+        this.listElement.insertBefore(inputElement, element);
+        element.addStyleClass("hidden");
+
+        function finishEditing(accept, e, text)
+        {
+            this._removeListElement(inputElement);
+            if (accept) {
+                this._removeBreakpoint(url);
+                this._setBreakpoint(text, element._checkboxElement.checked);
+                this._saveBreakpoints();
+            } else
+                element.removeStyleClass("hidden");
+        }
+
+        WebInspector.startEditing(inputElement, new WebInspector.EditingConfig(finishEditing.bind(this, true), finishEditing.bind(this, false)));
+    },
+
+    highlightBreakpoint: function(url)
+    {
+        var element = this._breakpointElements[url];
+        if (!element)
+            return;
+        this.expand();
+        element.addStyleClass("breakpoint-hit");
+        this._highlightedElement = element;
+    },
+
+    clearBreakpointHighlight: function()
+    {
+        if (this._highlightedElement) {
+            this._highlightedElement.removeStyleClass("breakpoint-hit");
+            delete this._highlightedElement;
+        }
+    },
+
+    _saveBreakpoints: function()
+    {
+        var breakpoints = [];
+        for (var url in this._breakpointElements)
+            breakpoints.push({ url: url, enabled: this._breakpointElements[url]._checkboxElement.checked });
+        WebInspector.settings.xhrBreakpoints.set(breakpoints);
+    },
+
+    _restoreBreakpoints: function()
+    {
+        var breakpoints = WebInspector.settings.xhrBreakpoints.get();
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (breakpoint && typeof breakpoint.url === "string")
+                this._setBreakpoint(breakpoint.url, breakpoint.enabled);
+        }
+    },
+
+    __proto__: WebInspector.NativeBreakpointsSidebarPane.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPane}
+ */
+WebInspector.EventListenerBreakpointsSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listener Breakpoints"));
+    this.registerRequiredCSS("breakpointsList.css");
+
+    this.categoriesElement = document.createElement("ol");
+    this.categoriesElement.tabIndex = 0;
+    this.categoriesElement.addStyleClass("properties-tree");
+    this.categoriesElement.addStyleClass("event-listener-breakpoints");
+    this.categoriesTreeOutline = new TreeOutline(this.categoriesElement);
+    this.bodyElement.appendChild(this.categoriesElement);
+
+    this._breakpointItems = {};
+    // FIXME: uncomment following once inspector stops being drop targer in major ports.
+    // Otherwise, inspector page reacts on drop event and tries to load the event data.
+    // this._createCategory(WebInspector.UIString("Drag"), true, ["drag", "drop", "dragstart", "dragend", "dragenter", "dragleave", "dragover"]);
+    this._createCategory(WebInspector.UIString("Animation"), false, ["requestAnimationFrame", "cancelAnimationFrame", "animationFrameFired"]);
+    this._createCategory(WebInspector.UIString("Control"), true, ["resize", "scroll", "zoom", "focus", "blur", "select", "change", "submit", "reset"]);
+    this._createCategory(WebInspector.UIString("Clipboard"), true, ["copy", "cut", "paste", "beforecopy", "beforecut", "beforepaste"]);
+    this._createCategory(WebInspector.UIString("DOM Mutation"), true, ["DOMActivate", "DOMFocusIn", "DOMFocusOut", "DOMAttrModified", "DOMCharacterDataModified", "DOMNodeInserted", "DOMNodeInsertedIntoDocument", "DOMNodeRemoved", "DOMNodeRemovedFromDocument", "DOMSubtreeModified", "DOMContentLoaded"]);
+    this._createCategory(WebInspector.UIString("Device"), true, ["deviceorientation", "devicemotion"]);
+    this._createCategory(WebInspector.UIString("Keyboard"), true, ["keydown", "keyup", "keypress", "input"]);
+    this._createCategory(WebInspector.UIString("Load"), true, ["load", "unload", "abort", "error", "hashchange"]);
+    this._createCategory(WebInspector.UIString("Mouse"), true, ["click", "dblclick", "mousedown", "mouseup", "mouseover", "mousemove", "mouseout", "mousewheel"]);
+    this._createCategory(WebInspector.UIString("Timer"), false, ["setTimer", "clearTimer", "timerFired"]);
+    this._createCategory(WebInspector.UIString("Touch"), true, ["touchstart", "touchmove", "touchend", "touchcancel"]);
+    this._createCategory(WebInspector.UIString("WebGL"), false, ["webglErrorFired", "webglWarningFired"]);
+
+    this._restoreBreakpoints();
+}
+
+WebInspector.EventListenerBreakpointsSidebarPane.categotyListener = "listener:";
+WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation = "instrumentation:";
+
+/**
+ * @param {string} eventName
+ * @param {Object=} auxData
+ * @return {string}
+ */
+WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI = function(eventName, auxData)
+{
+    if (!WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI) {
+        WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI = {
+            "instrumentation:setTimer": WebInspector.UIString("Set Timer"),
+            "instrumentation:clearTimer": WebInspector.UIString("Clear Timer"),
+            "instrumentation:timerFired": WebInspector.UIString("Timer Fired"),
+            "instrumentation:requestAnimationFrame": WebInspector.UIString("Request Animation Frame"),
+            "instrumentation:cancelAnimationFrame": WebInspector.UIString("Cancel Animation Frame"),
+            "instrumentation:animationFrameFired": WebInspector.UIString("Animation Frame Fired"),
+            "instrumentation:webglErrorFired": WebInspector.UIString("WebGL Error Fired"),
+            "instrumentation:webglWarningFired": WebInspector.UIString("WebGL Warning Fired")
+        };
+    }
+    if (auxData) {
+        if (eventName === "instrumentation:webglErrorFired" && auxData["webglErrorName"]) {
+            var errorName = auxData["webglErrorName"];
+            // If there is a hex code of the error, display only this.
+            errorName = errorName.replace(/^.*(0x[0-9a-f]+).*$/i, "$1");
+            return WebInspector.UIString("WebGL Error Fired (%s)", errorName);
+        }
+    }
+    return WebInspector.EventListenerBreakpointsSidebarPane._eventNamesForUI[eventName] || eventName.substring(eventName.indexOf(":") + 1);
+}
+
+WebInspector.EventListenerBreakpointsSidebarPane.prototype = {
+    _createCategory: function(name, isDOMEvent, eventNames)
+    {
+        var categoryItem = {};
+        categoryItem.element = new TreeElement(name);
+        this.categoriesTreeOutline.appendChild(categoryItem.element);
+        categoryItem.element.listItemElement.addStyleClass("event-category");
+        categoryItem.element.selectable = true;
+
+        categoryItem.checkbox = this._createCheckbox(categoryItem.element);
+        categoryItem.checkbox.addEventListener("click", this._categoryCheckboxClicked.bind(this, categoryItem), true);
+
+        categoryItem.children = {};
+        for (var i = 0; i < eventNames.length; ++i) {
+            var eventName = (isDOMEvent ? WebInspector.EventListenerBreakpointsSidebarPane.categotyListener :  WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation) + eventNames[i];
+
+            var breakpointItem = {};
+            var title = WebInspector.EventListenerBreakpointsSidebarPane.eventNameForUI(eventName);
+            breakpointItem.element = new TreeElement(title);
+            categoryItem.element.appendChild(breakpointItem.element);
+            var hitMarker = document.createElement("div");
+            hitMarker.className = "breakpoint-hit-marker";
+            breakpointItem.element.listItemElement.appendChild(hitMarker);
+            breakpointItem.element.listItemElement.addStyleClass("source-code");
+            breakpointItem.element.selectable = false;
+
+            breakpointItem.checkbox = this._createCheckbox(breakpointItem.element);
+            breakpointItem.checkbox.addEventListener("click", this._breakpointCheckboxClicked.bind(this, eventName), true);
+            breakpointItem.parent = categoryItem;
+
+            this._breakpointItems[eventName] = breakpointItem;
+            categoryItem.children[eventName] = breakpointItem;
+        }
+    },
+
+    _createCheckbox: function(treeElement)
+    {
+        var checkbox = document.createElement("input");
+        checkbox.className = "checkbox-elem";
+        checkbox.type = "checkbox";
+        treeElement.listItemElement.insertBefore(checkbox, treeElement.listItemElement.firstChild);
+        return checkbox;
+    },
+
+    _categoryCheckboxClicked: function(categoryItem)
+    {
+        var checked = categoryItem.checkbox.checked;
+        for (var eventName in categoryItem.children) {
+            var breakpointItem = categoryItem.children[eventName];
+            if (breakpointItem.checkbox.checked === checked)
+                continue;
+            if (checked)
+                this._setBreakpoint(eventName);
+            else
+                this._removeBreakpoint(eventName);
+        }
+        this._saveBreakpoints();
+    },
+
+    _breakpointCheckboxClicked: function(eventName, event)
+    {
+        if (event.target.checked)
+            this._setBreakpoint(eventName);
+        else
+            this._removeBreakpoint(eventName);
+        this._saveBreakpoints();
+    },
+
+    _setBreakpoint: function(eventName)
+    {
+        var breakpointItem = this._breakpointItems[eventName];
+        if (!breakpointItem)
+            return;
+        breakpointItem.checkbox.checked = true;
+        if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener))
+            DOMDebuggerAgent.setEventListenerBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener.length));
+        else if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation))
+            DOMDebuggerAgent.setInstrumentationBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation.length));
+        this._updateCategoryCheckbox(breakpointItem.parent);
+    },
+
+    _removeBreakpoint: function(eventName)
+    {
+        var breakpointItem = this._breakpointItems[eventName];
+        if (!breakpointItem)
+            return;
+        breakpointItem.checkbox.checked = false;
+        if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener))
+            DOMDebuggerAgent.removeEventListenerBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyListener.length));
+        else if (eventName.startsWith(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation))
+            DOMDebuggerAgent.removeInstrumentationBreakpoint(eventName.substring(WebInspector.EventListenerBreakpointsSidebarPane.categotyInstrumentation.length));
+        this._updateCategoryCheckbox(breakpointItem.parent);
+    },
+
+    _updateCategoryCheckbox: function(categoryItem)
+    {
+        var hasEnabled = false, hasDisabled = false;
+        for (var eventName in categoryItem.children) {
+            var breakpointItem = categoryItem.children[eventName];
+            if (breakpointItem.checkbox.checked)
+                hasEnabled = true;
+            else
+                hasDisabled = true;
+        }
+        categoryItem.checkbox.checked = hasEnabled;
+        categoryItem.checkbox.indeterminate = hasEnabled && hasDisabled;
+    },
+
+    highlightBreakpoint: function(eventName)
+    {
+        var breakpointItem = this._breakpointItems[eventName];
+        if (!breakpointItem)
+            return;
+        this.expand();
+        breakpointItem.parent.element.expand();
+        breakpointItem.element.listItemElement.addStyleClass("breakpoint-hit");
+        this._highlightedElement = breakpointItem.element.listItemElement;
+    },
+
+    clearBreakpointHighlight: function()
+    {
+        if (this._highlightedElement) {
+            this._highlightedElement.removeStyleClass("breakpoint-hit");
+            delete this._highlightedElement;
+        }
+    },
+
+    _saveBreakpoints: function()
+    {
+        var breakpoints = [];
+        for (var eventName in this._breakpointItems) {
+            if (this._breakpointItems[eventName].checkbox.checked)
+                breakpoints.push({ eventName: eventName });
+        }
+        WebInspector.settings.eventListenerBreakpoints.set(breakpoints);
+    },
+
+    _restoreBreakpoints: function()
+    {
+        var breakpoints = WebInspector.settings.eventListenerBreakpoints.get();
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (breakpoint && typeof breakpoint.eventName === "string")
+                this._setBreakpoint(breakpoint.eventName);
+        }
+    },
+
+    __proto__: WebInspector.SidebarPane.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CPUProfileView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CPUProfileView.js
new file mode 100644
index 00000000..d744b17c
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CPUProfileView.js
@@ -0,0 +1,935 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {WebInspector.CPUProfileHeader} profileHeader
+ */
+WebInspector.CPUProfileView = function(profileHeader)
+{
+    WebInspector.View.call(this);
+
+    this.element.addStyleClass("profile-view");
+    
+    this.showSelfTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowSelfTimeAsPercent", true);
+    this.showTotalTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowTotalTimeAsPercent", true);
+    this.showAverageTimeAsPercent = WebInspector.settings.createSetting("cpuProfilerShowAverageTimeAsPercent", true);
+    this._viewType = WebInspector.settings.createSetting("cpuProfilerView", WebInspector.CPUProfileView._TypeHeavy);
+
+    var columns = [];
+    columns.push({id: "self", title: WebInspector.UIString("Self"), width: "72px", sort: WebInspector.DataGrid.Order.Descending, sortable: true});
+    columns.push({id: "total", title: WebInspector.UIString("Total"), width: "72px", sortable: true});
+    columns.push({id: "function", title: WebInspector.UIString("Function"), disclosure: true, sortable: true});
+
+    this.dataGrid = new WebInspector.DataGrid(columns);
+    this.dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sortProfile, this);
+    this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true);
+    this.dataGrid.show(this.element);
+
+    this.viewSelectComboBox = new WebInspector.StatusBarComboBox(this._changeView.bind(this));
+
+    var options = {};
+    options[WebInspector.CPUProfileView._TypeFlame] = this.viewSelectComboBox.createOption(WebInspector.UIString("Flame Chart"), "", WebInspector.CPUProfileView._TypeFlame);
+    options[WebInspector.CPUProfileView._TypeHeavy] = this.viewSelectComboBox.createOption(WebInspector.UIString("Heavy (Bottom Up)"), "", WebInspector.CPUProfileView._TypeHeavy);
+    options[WebInspector.CPUProfileView._TypeTree] = this.viewSelectComboBox.createOption(WebInspector.UIString("Tree (Top Down)"), "", WebInspector.CPUProfileView._TypeTree);
+
+    var optionName = this._viewType.get() || WebInspector.CPUProfileView._TypeFlame;
+    var option = options[optionName] || options[WebInspector.CPUProfileView._TypeFlame];
+    this.viewSelectComboBox.select(option);
+
+    this._statusBarButtonsElement = document.createElement("span");
+
+    this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item");
+    this.percentButton.addEventListener("click", this._percentClicked, this);
+    this._statusBarButtonsElement.appendChild(this.percentButton.element);
+
+    this.focusButton = new WebInspector.StatusBarButton(WebInspector.UIString("Focus selected function."), "focus-profile-node-status-bar-item");
+    this.focusButton.setEnabled(false);
+    this.focusButton.addEventListener("click", this._focusClicked, this);
+    this._statusBarButtonsElement.appendChild(this.focusButton.element);
+
+    this.excludeButton = new WebInspector.StatusBarButton(WebInspector.UIString("Exclude selected function."), "exclude-profile-node-status-bar-item");
+    this.excludeButton.setEnabled(false);
+    this.excludeButton.addEventListener("click", this._excludeClicked, this);
+    this._statusBarButtonsElement.appendChild(this.excludeButton.element);
+
+    this.resetButton = new WebInspector.StatusBarButton(WebInspector.UIString("Restore all functions."), "reset-profile-status-bar-item");
+    this.resetButton.visible = false;
+    this.resetButton.addEventListener("click", this._resetClicked, this);
+    this._statusBarButtonsElement.appendChild(this.resetButton.element);
+
+    this.profileHead = /** @type {?ProfilerAgent.CPUProfileNode} */ (null);
+    this.profile = profileHeader;
+
+    this._linkifier = new WebInspector.Linkifier(new WebInspector.Linkifier.DefaultFormatter(30));
+
+    if (this.profile._profile) // If the profile has been loaded from file then use it.
+        this._processProfileData(this.profile._profile);
+    else
+        ProfilerAgent.getCPUProfile(this.profile.uid, this._getCPUProfileCallback.bind(this));
+}
+
+WebInspector.CPUProfileView._TypeFlame = "Flame";
+WebInspector.CPUProfileView._TypeTree = "Tree";
+WebInspector.CPUProfileView._TypeHeavy = "Heavy";
+
+WebInspector.CPUProfileView.prototype = {
+    /**
+     * @param {!number} timeLeft
+     * @param {!number} timeRight
+     */
+    selectRange: function(timeLeft, timeRight)
+    {
+        if (!this._flameChart)
+            return;
+        this._flameChart.selectRange(timeLeft, timeRight);
+    },
+
+    _revealProfilerNode: function(event)
+    {
+        var current = this.profileDataGridTree.children[0];
+
+        while (current && current.profileNode !== event.data)
+            current = current.traverseNextNode(false, null, false);
+
+        if (current)
+            current.revealAndSelect();
+    },
+
+    /**
+     * @param {?Protocol.Error} error
+     * @param {ProfilerAgent.CPUProfile} profile
+     */
+    _getCPUProfileCallback: function(error, profile)
+    {
+        if (error)
+            return;
+
+        if (!profile.head) {
+            // Profiling was tentatively terminated with the "Clear all profiles." button.
+            return;
+        }
+
+        this._processProfileData(profile);
+    },
+
+    _processProfileData: function(profile)
+    {
+        this.profileHead = profile.head;
+        this.samples = profile.samples;
+
+        this._calculateTimes(profile);
+
+        this._assignParentsInProfile();
+        if (this.samples)
+            this._buildIdToNodeMap();
+        this._changeView();
+        this._updatePercentButton();
+        if (this._flameChart)
+            this._flameChart.update();
+    },
+
+    get statusBarItems()
+    {
+        return [this.viewSelectComboBox.element, this._statusBarButtonsElement];
+    },
+
+    /**
+     * @return {!WebInspector.ProfileDataGridTree}
+     */
+    _getBottomUpProfileDataGridTree: function()
+    {
+        if (!this._bottomUpProfileDataGridTree)
+            this._bottomUpProfileDataGridTree = new WebInspector.BottomUpProfileDataGridTree(this, this.profileHead);
+        return this._bottomUpProfileDataGridTree;
+    },
+
+    /**
+     * @return {!WebInspector.ProfileDataGridTree}
+     */
+    _getTopDownProfileDataGridTree: function()
+    {
+        if (!this._topDownProfileDataGridTree)
+            this._topDownProfileDataGridTree = new WebInspector.TopDownProfileDataGridTree(this, this.profileHead);
+        return this._topDownProfileDataGridTree;
+    },
+
+    willHide: function()
+    {
+        this._currentSearchResultIndex = -1;
+    },
+
+    refresh: function()
+    {
+        var selectedProfileNode = this.dataGrid.selectedNode ? this.dataGrid.selectedNode.profileNode : null;
+
+        this.dataGrid.rootNode().removeChildren();
+
+        var children = this.profileDataGridTree.children;
+        var count = children.length;
+
+        for (var index = 0; index < count; ++index)
+            this.dataGrid.rootNode().appendChild(children[index]);
+
+        if (selectedProfileNode)
+            selectedProfileNode.selected = true;
+    },
+
+    refreshVisibleData: function()
+    {
+        var child = this.dataGrid.rootNode().children[0];
+        while (child) {
+            child.refresh();
+            child = child.traverseNextNode(false, null, true);
+        }
+    },
+
+    refreshShowAsPercents: function()
+    {
+        this._updatePercentButton();
+        this.refreshVisibleData();
+    },
+
+    searchCanceled: function()
+    {
+        if (this._searchResults) {
+            for (var i = 0; i < this._searchResults.length; ++i) {
+                var profileNode = this._searchResults[i].profileNode;
+
+                delete profileNode._searchMatchedSelfColumn;
+                delete profileNode._searchMatchedTotalColumn;
+                delete profileNode._searchMatchedFunctionColumn;
+
+                profileNode.refresh();
+            }
+        }
+
+        delete this._searchFinishedCallback;
+        this._currentSearchResultIndex = -1;
+        this._searchResults = [];
+    },
+
+    performSearch: function(query, finishedCallback)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled();
+
+        query = query.trim();
+
+        if (!query.length)
+            return;
+
+        this._searchFinishedCallback = finishedCallback;
+
+        var greaterThan = (query.startsWith(">"));
+        var lessThan = (query.startsWith("<"));
+        var equalTo = (query.startsWith("=") || ((greaterThan || lessThan) && query.indexOf("=") === 1));
+        var percentUnits = (query.lastIndexOf("%") === (query.length - 1));
+        var millisecondsUnits = (query.length > 2 && query.lastIndexOf("ms") === (query.length - 2));
+        var secondsUnits = (!millisecondsUnits && query.lastIndexOf("s") === (query.length - 1));
+
+        var queryNumber = parseFloat(query);
+        if (greaterThan || lessThan || equalTo) {
+            if (equalTo && (greaterThan || lessThan))
+                queryNumber = parseFloat(query.substring(2));
+            else
+                queryNumber = parseFloat(query.substring(1));
+        }
+
+        var queryNumberMilliseconds = (secondsUnits ? (queryNumber * 1000) : queryNumber);
+
+        // Make equalTo implicitly true if it wasn't specified there is no other operator.
+        if (!isNaN(queryNumber) && !(greaterThan || lessThan))
+            equalTo = true;
+
+        var matcher = createPlainTextSearchRegex(query, "i");
+
+        function matchesQuery(/*ProfileDataGridNode*/ profileDataGridNode)
+        {
+            delete profileDataGridNode._searchMatchedSelfColumn;
+            delete profileDataGridNode._searchMatchedTotalColumn;
+            delete profileDataGridNode._searchMatchedFunctionColumn;
+
+            if (percentUnits) {
+                if (lessThan) {
+                    if (profileDataGridNode.selfPercent < queryNumber)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalPercent < queryNumber)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                } else if (greaterThan) {
+                    if (profileDataGridNode.selfPercent > queryNumber)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalPercent > queryNumber)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                }
+
+                if (equalTo) {
+                    if (profileDataGridNode.selfPercent == queryNumber)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalPercent == queryNumber)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                }
+            } else if (millisecondsUnits || secondsUnits) {
+                if (lessThan) {
+                    if (profileDataGridNode.selfTime < queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalTime < queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                } else if (greaterThan) {
+                    if (profileDataGridNode.selfTime > queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalTime > queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                }
+
+                if (equalTo) {
+                    if (profileDataGridNode.selfTime == queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedSelfColumn = true;
+                    if (profileDataGridNode.totalTime == queryNumberMilliseconds)
+                        profileDataGridNode._searchMatchedTotalColumn = true;
+                }
+            }
+
+            if (profileDataGridNode.functionName.match(matcher) || (profileDataGridNode.url && profileDataGridNode.url.match(matcher)))
+                profileDataGridNode._searchMatchedFunctionColumn = true;
+
+            if (profileDataGridNode._searchMatchedSelfColumn ||
+                profileDataGridNode._searchMatchedTotalColumn ||
+                profileDataGridNode._searchMatchedFunctionColumn)
+            {
+                profileDataGridNode.refresh();
+                return true;
+            }
+
+            return false;
+        }
+
+        var current = this.profileDataGridTree.children[0];
+
+        while (current) {
+            if (matchesQuery(current)) {
+                this._searchResults.push({ profileNode: current });
+            }
+
+            current = current.traverseNextNode(false, null, false);
+        }
+
+        finishedCallback(this, this._searchResults.length);
+    },
+
+    jumpToFirstSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        this._currentSearchResultIndex = 0;
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToLastSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        this._currentSearchResultIndex = (this._searchResults.length - 1);
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (++this._currentSearchResultIndex >= this._searchResults.length)
+            this._currentSearchResultIndex = 0;
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        if (!this._searchResults || !this._searchResults.length)
+            return;
+        if (--this._currentSearchResultIndex < 0)
+            this._currentSearchResultIndex = (this._searchResults.length - 1);
+        this._jumpToSearchResult(this._currentSearchResultIndex);
+    },
+
+    showingFirstSearchResult: function()
+    {
+        return (this._currentSearchResultIndex === 0);
+    },
+
+    showingLastSearchResult: function()
+    {
+        return (this._searchResults && this._currentSearchResultIndex === (this._searchResults.length - 1));
+    },
+
+    _jumpToSearchResult: function(index)
+    {
+        var searchResult = this._searchResults[index];
+        if (!searchResult)
+            return;
+
+        var profileNode = searchResult.profileNode;
+        profileNode.revealAndSelect();
+    },
+
+    _ensureFlameChartCreated: function()
+    {
+        if (this._flameChart)
+            return;
+        this._flameChart = new WebInspector.FlameChart(this);
+        this._flameChart.addEventListener(WebInspector.FlameChart.Events.SelectedNode, this._onSelectedNode.bind(this));
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _onSelectedNode: function(event)
+    {
+        var node = event.data;
+        if (!node || !node.scriptId)
+            return;
+        var script = WebInspector.debuggerModel.scriptForId(node.scriptId)
+        if (!script)
+            return;
+        var uiLocation = script.rawLocationToUILocation(node.lineNumber);
+        if (!uiLocation)
+            return;
+        WebInspector.showPanel("scripts").showUILocation(uiLocation);
+    },
+
+    _changeView: function()
+    {
+        if (!this.profile)
+            return;
+
+        switch (this.viewSelectComboBox.selectedOption().value) {
+        case WebInspector.CPUProfileView._TypeFlame:
+            this._ensureFlameChartCreated();
+            this.dataGrid.detach();
+            this._flameChart.show(this.element);
+            this._viewType.set(WebInspector.CPUProfileView._TypeFlame);
+            this._statusBarButtonsElement.enableStyleClass("hidden", true);
+            return;
+        case WebInspector.CPUProfileView._TypeTree:
+            this.profileDataGridTree = this._getTopDownProfileDataGridTree();
+            this._sortProfile();
+            this._viewType.set(WebInspector.CPUProfileView._TypeTree);
+            break;
+        case WebInspector.CPUProfileView._TypeHeavy:
+            this.profileDataGridTree = this._getBottomUpProfileDataGridTree();
+            this._sortProfile();
+            this._viewType.set(WebInspector.CPUProfileView._TypeHeavy);
+            break;
+        }
+
+        this._statusBarButtonsElement.enableStyleClass("hidden", false);
+
+        if (this._flameChart)
+            this._flameChart.detach();
+        this.dataGrid.show(this.element);
+
+        if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults)
+            return;
+
+        // The current search needs to be performed again. First negate out previous match
+        // count by calling the search finished callback with a negative number of matches.
+        // Then perform the search again the with same query and callback.
+        this._searchFinishedCallback(this, -this._searchResults.length);
+        this.performSearch(this.currentQuery, this._searchFinishedCallback);
+    },
+
+    _percentClicked: function(event)
+    {
+        var currentState = this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get();
+        this.showSelfTimeAsPercent.set(!currentState);
+        this.showTotalTimeAsPercent.set(!currentState);
+        this.showAverageTimeAsPercent.set(!currentState);
+        this.refreshShowAsPercents();
+    },
+
+    _updatePercentButton: function()
+    {
+        if (this.showSelfTimeAsPercent.get() && this.showTotalTimeAsPercent.get() && this.showAverageTimeAsPercent.get()) {
+            this.percentButton.title = WebInspector.UIString("Show absolute total and self times.");
+            this.percentButton.toggled = true;
+        } else {
+            this.percentButton.title = WebInspector.UIString("Show total and self times as percentages.");
+            this.percentButton.toggled = false;
+        }
+    },
+
+    _focusClicked: function(event)
+    {
+        if (!this.dataGrid.selectedNode)
+            return;
+
+        this.resetButton.visible = true;
+        this.profileDataGridTree.focus(this.dataGrid.selectedNode);
+        this.refresh();
+        this.refreshVisibleData();
+    },
+
+    _excludeClicked: function(event)
+    {
+        var selectedNode = this.dataGrid.selectedNode
+
+        if (!selectedNode)
+            return;
+
+        selectedNode.deselect();
+
+        this.resetButton.visible = true;
+        this.profileDataGridTree.exclude(selectedNode);
+        this.refresh();
+        this.refreshVisibleData();
+    },
+
+    _resetClicked: function(event)
+    {
+        this.resetButton.visible = false;
+        this.profileDataGridTree.restore();
+        this._linkifier.reset();
+        this.refresh();
+        this.refreshVisibleData();
+    },
+
+    _dataGridNodeSelected: function(node)
+    {
+        this.focusButton.setEnabled(true);
+        this.excludeButton.setEnabled(true);
+    },
+
+    _dataGridNodeDeselected: function(node)
+    {
+        this.focusButton.setEnabled(false);
+        this.excludeButton.setEnabled(false);
+    },
+
+    _sortProfile: function()
+    {
+        var sortAscending = this.dataGrid.isSortOrderAscending();
+        var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier();
+        var sortProperty = {
+                "self": "selfTime",
+                "total": "totalTime",
+                "function": "functionName"
+            }[sortColumnIdentifier];
+
+        this.profileDataGridTree.sort(WebInspector.ProfileDataGridTree.propertyComparator(sortProperty, sortAscending));
+
+        this.refresh();
+    },
+
+    _mouseDownInDataGrid: function(event)
+    {
+        if (event.detail < 2)
+            return;
+
+        var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
+        if (!cell || (!cell.hasStyleClass("total-column") && !cell.hasStyleClass("self-column") && !cell.hasStyleClass("average-column")))
+            return;
+
+        if (cell.hasStyleClass("total-column"))
+            this.showTotalTimeAsPercent.set(!this.showTotalTimeAsPercent.get());
+        else if (cell.hasStyleClass("self-column"))
+            this.showSelfTimeAsPercent.set(!this.showSelfTimeAsPercent.get());
+        else if (cell.hasStyleClass("average-column"))
+            this.showAverageTimeAsPercent.set(!this.showAverageTimeAsPercent.get());
+
+        this.refreshShowAsPercents();
+
+        event.consume(true);
+    },
+
+    _calculateTimes: function(profile)
+    {
+        function totalHitCount(node) {
+            var result = node.hitCount;
+            for (var i = 0; i < node.children.length; i++)
+                result += totalHitCount(node.children[i]);
+            return result;
+        }
+        profile.totalHitCount = totalHitCount(profile.head);
+
+        var durationMs = 1000 * profile.endTime - 1000 * profile.startTime;
+        var samplingRate = profile.totalHitCount / durationMs;
+        this.samplesPerMs = samplingRate;
+
+        function calculateTimesForNode(node) {
+            node.selfTime = node.hitCount * samplingRate;
+            var totalTime = node.selfTime;
+            for (var i = 0; i < node.children.length; i++)
+                totalTime += calculateTimesForNode(node.children[i]);
+            node.totalTime = totalTime;
+            return totalTime;
+        }
+        calculateTimesForNode(profile.head);
+    },
+
+    _assignParentsInProfile: function()
+    {
+        var head = this.profileHead;
+        head.parent = null;
+        head.head = null;
+        var nodesToTraverse = [ { parent: head, children: head.children } ];
+        while (nodesToTraverse.length > 0) {
+            var pair = nodesToTraverse.pop();
+            var parent = pair.parent;
+            var children = pair.children;
+            var length = children.length;
+            for (var i = 0; i < length; ++i) {
+                children[i].head = head;
+                children[i].parent = parent;
+                if (children[i].children.length > 0)
+                    nodesToTraverse.push({ parent: children[i], children: children[i].children });
+            }
+        }
+    },
+
+    _buildIdToNodeMap: function()
+    {
+        var idToNode = this._idToNode = {};
+        var stack = [this.profileHead];
+        while (stack.length) {
+            var node = stack.pop();
+            idToNode[node.id] = node;
+            for (var i = 0; i < node.children.length; i++)
+                stack.push(node.children[i]);
+        }
+
+        var topLevelNodes = this.profileHead.children;
+        for (var i = 0; i < topLevelNodes.length; i++) {
+            var node = topLevelNodes[i];
+            if (node.functionName == "(garbage collector)") {
+                this._gcNode = node;
+                break;
+            }
+        }
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileType}
+ * @implements {ProfilerAgent.Dispatcher}
+ */
+WebInspector.CPUProfileType = function()
+{
+    WebInspector.ProfileType.call(this, WebInspector.CPUProfileType.TypeId, WebInspector.UIString("Collect JavaScript CPU Profile"));
+    InspectorBackend.registerProfilerDispatcher(this);
+    this._recording = false;
+    WebInspector.CPUProfileType.instance = this;
+}
+
+WebInspector.CPUProfileType.TypeId = "CPU";
+
+WebInspector.CPUProfileType.prototype = {
+    /**
+     * @override
+     * @return {string}
+     */
+    fileExtension: function()
+    {
+        return ".cpuprofile";
+    },
+
+    get buttonTooltip()
+    {
+        return this._recording ? WebInspector.UIString("Stop CPU profiling.") : WebInspector.UIString("Start CPU profiling.");
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    buttonClicked: function()
+    {
+        if (this._recording) {
+            this.stopRecordingProfile();
+            return false;
+        } else {
+            this.startRecordingProfile();
+            return true;
+        }
+    },
+
+    get treeItemTitle()
+    {
+        return WebInspector.UIString("CPU PROFILES");
+    },
+
+    get description()
+    {
+        return WebInspector.UIString("CPU profiles show where the execution time is spent in your page's JavaScript functions.");
+    },
+
+    /**
+     * @param {ProfilerAgent.ProfileHeader} profileHeader
+     */
+    addProfileHeader: function(profileHeader)
+    {
+        this.addProfile(this.createProfile(profileHeader));
+    },
+
+    isRecordingProfile: function()
+    {
+        return this._recording;
+    },
+
+    startRecordingProfile: function()
+    {
+        this._recording = true;
+        WebInspector.userMetrics.ProfilesCPUProfileTaken.record();
+        ProfilerAgent.start();
+    },
+
+    stopRecordingProfile: function()
+    {
+        this._recording = false;
+        ProfilerAgent.stop();
+    },
+
+    /**
+     * @param {boolean} isProfiling
+     */
+    setRecordingProfile: function(isProfiling)
+    {
+        this._recording = isProfiling;
+    },
+
+    /**
+     * @override
+     * @param {string=} title
+     * @return {!WebInspector.ProfileHeader}
+     */
+    createTemporaryProfile: function(title)
+    {
+        title = title || WebInspector.UIString("Recording\u2026");
+        return new WebInspector.CPUProfileHeader(this, title);
+    },
+
+    /**
+     * @override
+     * @param {ProfilerAgent.ProfileHeader} profile
+     * @return {!WebInspector.ProfileHeader}
+     */
+    createProfile: function(profile)
+    {
+        return new WebInspector.CPUProfileHeader(this, profile.title, profile.uid);
+    },
+
+    /**
+     * @override
+     * @param {!WebInspector.ProfileHeader} profile
+     */
+    removeProfile: function(profile)
+    {
+        WebInspector.ProfileType.prototype.removeProfile.call(this, profile);
+        if (!profile.isTemporary)
+            ProfilerAgent.removeProfile(this.id, profile.uid);
+    },
+
+    /**
+     * @override
+     * @param {function(this:WebInspector.ProfileType, ?string, Array.)} populateCallback
+     */
+    _requestProfilesFromBackend: function(populateCallback)
+    {
+        ProfilerAgent.getProfileHeaders(populateCallback);
+    },
+
+    /**
+     * @override
+     */
+    resetProfiles: function()
+    {
+        this._reset();
+    },
+
+    /** @deprecated To be removed from the protocol */
+    addHeapSnapshotChunk: function(uid, chunk)
+    {
+        throw new Error("Never called");
+    },
+
+    /** @deprecated To be removed from the protocol */
+    finishHeapSnapshot: function(uid)
+    {
+        throw new Error("Never called");
+    },
+
+    /** @deprecated To be removed from the protocol */
+    reportHeapSnapshotProgress: function(done, total)
+    {
+        throw new Error("Never called");
+    },
+
+    __proto__: WebInspector.ProfileType.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileHeader}
+ * @implements {WebInspector.OutputStream}
+ * @implements {WebInspector.OutputStreamDelegate}
+ * @param {!WebInspector.CPUProfileType} type
+ * @param {string} title
+ * @param {number=} uid
+ */
+WebInspector.CPUProfileHeader = function(type, title, uid)
+{
+    WebInspector.ProfileHeader.call(this, type, title, uid);
+}
+
+WebInspector.CPUProfileHeader.prototype = {
+    onTransferStarted: function()
+    {
+        this._jsonifiedProfile = "";
+        this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026 %s", Number.bytesToString(this._jsonifiedProfile.length));
+    },
+
+    /**
+     * @param {WebInspector.ChunkedReader} reader
+     */
+    onChunkTransferred: function(reader)
+    {
+        this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026 %d\%", Number.bytesToString(this._jsonifiedProfile.length));
+    },
+
+    onTransferFinished: function()
+    {
+
+        this.sidebarElement.subtitle = WebInspector.UIString("Parsing\u2026");
+        this._profile = JSON.parse(this._jsonifiedProfile);
+        this._jsonifiedProfile = null;
+        this.sidebarElement.subtitle = WebInspector.UIString("Loaded");
+        this.isTemporary = false;
+    },
+
+    /**
+     * @param {WebInspector.ChunkedReader} reader
+     */
+    onError: function(reader, e)
+    {
+        switch(e.target.error.code) {
+        case e.target.error.NOT_FOUND_ERR:
+            this.sidebarElement.subtitle = WebInspector.UIString("'%s' not found.", reader.fileName());
+        break;
+        case e.target.error.NOT_READABLE_ERR:
+            this.sidebarElement.subtitle = WebInspector.UIString("'%s' is not readable", reader.fileName());
+        break;
+        case e.target.error.ABORT_ERR:
+            break;
+        default:
+            this.sidebarElement.subtitle = WebInspector.UIString("'%s' error %d", reader.fileName(), e.target.error.code);
+        }
+    },
+
+    /**
+     * @param {string} text
+     */
+    write: function(text)
+    {
+        this._jsonifiedProfile += text;
+    },
+
+    close: function() { },
+
+    /**
+     * @override
+     */
+    createSidebarTreeElement: function()
+    {
+        return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Profile %d"), "profile-sidebar-tree-item");
+    },
+
+    /**
+     * @override
+     * @param {WebInspector.ProfilesPanel} profilesPanel
+     */
+    createView: function(profilesPanel)
+    {
+        return new WebInspector.CPUProfileView(this);
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    canSaveToFile: function()
+    {
+        return true;
+    },
+
+    saveToFile: function()
+    {
+        var fileOutputStream = new WebInspector.FileOutputStream();
+
+        /**
+         * @param {?Protocol.Error} error
+         * @param {ProfilerAgent.CPUProfile} profile
+         */
+        function getCPUProfileCallback(error, profile)
+        {
+            if (error) {
+                fileOutputStream.close();
+                return;
+            }
+
+            if (!profile.head) {
+                // Profiling was tentatively terminated with the "Clear all profiles." button.
+                fileOutputStream.close();
+                return;
+            }
+
+            fileOutputStream.write(JSON.stringify(profile), fileOutputStream.close.bind(fileOutputStream));
+        }
+
+        function onOpen()
+        {
+            ProfilerAgent.getCPUProfile(this.uid, getCPUProfileCallback.bind(this));
+        }
+
+        this._fileName = this._fileName || "CPU-" + new Date().toISO8601Compact() + this._profileType.fileExtension();
+        fileOutputStream.open(this._fileName, onOpen.bind(this));
+    },
+
+    /**
+     * @param {File} file
+     */
+    loadFromFile: function(file)
+    {
+        this.title = file.name;
+        this.sidebarElement.subtitle = WebInspector.UIString("Loading\u2026");
+        this.sidebarElement.wait = true;
+
+        var fileReader = new WebInspector.ChunkedFileReader(file, 10000000, this);
+        fileReader.start(this);
+    },
+
+    __proto__: WebInspector.ProfileHeader.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSMetadata.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSMetadata.js
new file mode 100644
index 00000000..be4f355e
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSMetadata.js
@@ -0,0 +1,982 @@
+/*
+ * Copyright (C) 2010 Nikita Vasilyev. All rights reserved.
+ * Copyright (C) 2010 Joseph Pecoraro. All rights reserved.
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {Array.} properties
+ */
+WebInspector.CSSMetadata = function(properties)
+{
+    this._values = /** !Array. */ ([]);
+    this._longhands = {};
+    this._shorthands = {};
+    for (var i = 0; i < properties.length; ++i) {
+        var property = properties[i];
+        if (typeof property === "string") {
+            this._values.push(property);
+            continue;
+        }
+
+        var propertyName = property.name;
+        this._values.push(propertyName);
+
+        var longhands = properties[i].longhands;
+        if (longhands) {
+            this._longhands[propertyName] = longhands;
+            for (var j = 0; j < longhands.length; ++j) {
+                var longhandName = longhands[j];
+                var shorthands = this._shorthands[longhandName];
+                if (!shorthands) {
+                    shorthands = [];
+                    this._shorthands[longhandName] = shorthands;
+                }
+                shorthands.push(propertyName);
+            }
+        }
+    }
+    this._values.sort();
+}
+
+/**
+ * @type {!WebInspector.CSSMetadata}
+ */
+WebInspector.CSSMetadata.cssPropertiesMetainfo = new WebInspector.CSSMetadata([]);
+
+WebInspector.CSSMetadata.isColorAwareProperty = function(propertyName)
+{
+    return WebInspector.CSSMetadata._colorAwareProperties[propertyName] === true;
+}
+
+WebInspector.CSSMetadata.colors = function()
+{
+    if (!WebInspector.CSSMetadata._colorsKeySet)
+        WebInspector.CSSMetadata._colorsKeySet = WebInspector.CSSMetadata._colors.keySet();
+    return WebInspector.CSSMetadata._colorsKeySet;
+}
+
+// Taken from http://www.w3.org/TR/CSS21/propidx.html.
+WebInspector.CSSMetadata.InheritedProperties = [
+    "azimuth", "border-collapse", "border-spacing", "caption-side", "color", "cursor", "direction", "elevation",
+    "empty-cells", "font-family", "font-size", "font-style", "font-variant", "font-weight", "font", "letter-spacing",
+    "line-height", "list-style-image", "list-style-position", "list-style-type", "list-style", "orphans", "pitch-range",
+    "pitch", "quotes", "resize", "richness", "speak-header", "speak-numeral", "speak-punctuation", "speak", "speech-rate", "stress",
+    "text-align", "text-indent", "text-transform", "text-shadow", "visibility", "voice-family", "volume", "white-space", "widows",
+    "word-spacing", "zoom"
+].keySet();
+
+// These non-standard Blink-specific properties augment the InheritedProperties.
+WebInspector.CSSMetadata.NonStandardInheritedProperties = [
+    "-webkit-font-smoothing"
+].keySet();
+
+/**
+ * @param {string} name
+ * @return {string}
+ */
+WebInspector.CSSMetadata.canonicalPropertyName = function(name)
+{
+    if (!name || name.length < 9 || name.charAt(0) !== "-")
+        return name.toLowerCase();
+    var match = name.match(/(?:-webkit-|-khtml-|-apple-)(.+)/);
+    if (!match)
+        return name.toLowerCase();
+    return match[1].toLowerCase();
+}
+
+/**
+ * @param {string} propertyName
+ * @return {boolean}
+ */
+WebInspector.CSSMetadata.isPropertyInherited = function(propertyName)
+{
+    return !!(WebInspector.CSSMetadata.InheritedProperties[WebInspector.CSSMetadata.canonicalPropertyName(propertyName)]
+            || WebInspector.CSSMetadata.NonStandardInheritedProperties[propertyName.toLowerCase()]);
+}
+
+WebInspector.CSSMetadata._colors = [
+    "aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "orange", "purple", "red",
+    "silver", "teal", "white", "yellow", "transparent", "currentcolor", "grey", "aliceblue", "antiquewhite",
+    "aquamarine", "azure", "beige", "bisque", "blanchedalmond", "blueviolet", "brown", "burlywood", "cadetblue",
+    "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan",
+    "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange",
+    "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey",
+    "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick",
+    "floralwhite", "forestgreen", "gainsboro", "ghostwhite", "gold", "goldenrod", "greenyellow", "honeydew", "hotpink",
+    "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue",
+    "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink",
+    "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow",
+    "limegreen", "linen", "magenta", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen",
+    "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream",
+    "mistyrose", "moccasin", "navajowhite", "oldlace", "olivedrab", "orangered", "orchid", "palegoldenrod", "palegreen",
+    "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "rosybrown",
+    "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "skyblue", "slateblue",
+    "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "thistle", "tomato", "turquoise", "violet",
+    "wheat", "whitesmoke", "yellowgreen"
+];
+
+WebInspector.CSSMetadata._colorAwareProperties = [
+    "background", "background-color", "background-image", "border", "border-color", "border-top", "border-right", "border-bottom",
+    "border-left", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", "box-shadow", "color",
+    "fill", "outline", "outline-color", "stroke", "text-line-through-color", "text-overline-color",
+    "text-shadow", "text-underline-color", "-webkit-box-shadow", "-webkit-column-rule-color",
+    "-webkit-text-decoration-color", "-webkit-text-emphasis", "-webkit-text-emphasis-color"
+].keySet();
+
+WebInspector.CSSMetadata._propertyDataMap = {
+    "table-layout": { values: [
+        "auto", "fixed"
+    ] },
+    "visibility": { values: [
+        "hidden", "visible", "collapse"
+    ] },
+    "background-repeat": { values: [
+        "repeat", "repeat-x", "repeat-y", "no-repeat", "space", "round"
+    ] },
+    "content": { values: [
+        "list-item", "close-quote", "no-close-quote", "no-open-quote", "open-quote"
+    ] },
+    "list-style-image": { values: [
+        "none"
+    ] },
+    "clear": { values: [
+        "none", "left", "right", "both"
+    ] },
+    "text-underline-mode": { values: [
+        "continuous", "skip-white-space"
+    ] },
+    "overflow-x": { values: [
+        "hidden", "auto", "visible", "overlay", "scroll"
+    ] },
+    "stroke-linejoin": { values: [
+        "round", "miter", "bevel"
+    ] },
+    "baseline-shift": { values: [
+        "baseline", "sub", "super"
+    ] },
+    "border-bottom-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "marquee-speed": { values: [
+        "normal", "slow", "fast"
+    ] },
+    "margin-top-collapse": { values: [
+        "collapse", "separate", "discard"
+    ] },
+    "max-height": { values: [
+        "none"
+    ] },
+    "box-orient": { values: [
+        "horizontal", "vertical", "inline-axis", "block-axis"
+    ], },
+    "font-stretch": { values: [
+        "normal", "wider", "narrower", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed",
+        "semi-expanded", "expanded", "extra-expanded", "ultra-expanded"
+    ] },
+    "text-underline-style": { values: [
+        "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave"
+    ] },
+    "text-overline-mode": { values: [
+        "continuous", "skip-white-space"
+    ] },
+    "-webkit-background-composite": { values: [
+        "highlight", "clear", "copy", "source-over", "source-in", "source-out", "source-atop", "destination-over",
+        "destination-in", "destination-out", "destination-atop", "xor", "plus-darker", "plus-lighter"
+    ] },
+    "border-left-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "-webkit-writing-mode": { values: [
+        "lr", "rl", "tb", "lr-tb", "rl-tb", "tb-rl", "horizontal-tb", "vertical-rl", "vertical-lr", "horizontal-bt"
+    ] },
+    "text-line-through-mode": { values: [
+        "continuous", "skip-white-space"
+    ] },
+    "border-collapse": { values: [
+        "collapse", "separate"
+    ] },
+    "page-break-inside": { values: [
+        "auto", "avoid"
+    ] },
+    "border-top-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "outline-color": { values: [
+        "invert"
+    ] },
+    "text-line-through-style": { values: [
+        "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave"
+    ] },
+    "outline-style": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "cursor": { values: [
+        "none", "copy", "auto", "crosshair", "default", "pointer", "move", "vertical-text", "cell", "context-menu",
+        "alias", "progress", "no-drop", "not-allowed", "-webkit-zoom-in", "-webkit-zoom-out", "e-resize", "ne-resize",
+        "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "ew-resize", "ns-resize",
+        "nesw-resize", "nwse-resize", "col-resize", "row-resize", "text", "wait", "help", "all-scroll", "-webkit-grab",
+        "-webkit-grabbing"
+    ] },
+    "border-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "size": { values: [
+        "a3", "a4", "a5", "b4", "b5", "landscape", "ledger", "legal", "letter", "portrait"
+    ] },
+    "background-size": { values: [
+        "contain", "cover"
+    ] },
+    "direction": { values: [
+        "ltr", "rtl"
+    ] },
+    "marquee-direction": { values: [
+        "left", "right", "auto", "reverse", "forwards", "backwards", "ahead", "up", "down"
+    ] },
+    "enable-background": { values: [
+        "accumulate", "new"
+    ] },
+    "float": { values: [
+        "none", "left", "right"
+    ] },
+    "overflow-y": { values: [
+        "hidden", "auto", "visible", "overlay", "scroll"
+    ] },
+    "margin-bottom-collapse": { values: [
+        "collapse",  "separate", "discard"
+    ] },
+    "box-reflect": { values: [
+        "left", "right", "above", "below"
+    ] },
+    "overflow": { values: [
+        "hidden", "auto", "visible", "overlay", "scroll"
+    ] },
+    "text-rendering": { values: [
+        "auto", "optimizeSpeed", "optimizeLegibility", "geometricPrecision"
+    ] },
+    "text-align": { values: [
+        "-webkit-auto", "start", "end", "left", "right", "center", "justify", "-webkit-left", "-webkit-right", "-webkit-center"
+    ] },
+    "list-style-position": { values: [
+        "outside", "inside", "hanging"
+    ] },
+    "margin-bottom": { values: [
+        "auto"
+    ] },
+    "color-interpolation": { values: [
+        "linearrgb"
+    ] },
+    "background-origin": { values: [
+        "border-box", "content-box", "padding-box"
+    ] },
+    "word-wrap": { values: [
+        "normal", "break-word"
+    ] },
+    "font-weight": { values: [
+        "normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900"
+    ] },
+    "margin-before-collapse": { values: [
+        "collapse", "separate", "discard"
+    ] },
+    "text-overline-width": { values: [
+        "normal", "medium", "auto", "thick", "thin"
+    ] },
+    "text-transform": { values: [
+        "none", "capitalize", "uppercase", "lowercase"
+    ] },
+    "border-right-style": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "border-left-style": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "-webkit-text-emphasis": { values: [
+        "circle", "filled", "open", "dot", "double-circle", "triangle", "sesame"
+    ] },
+    "font-style": { values: [
+        "italic", "oblique", "normal"
+    ] },
+    "speak": { values: [
+        "none", "normal", "spell-out", "digits", "literal-punctuation", "no-punctuation"
+    ] },
+    "color-rendering": { values: [
+        "auto", "optimizeSpeed", "optimizeQuality"
+    ] },
+    "list-style-type": { values: [
+        "none", "inline", "disc", "circle", "square", "decimal", "decimal-leading-zero", "arabic-indic", "binary", "bengali",
+        "cambodian", "khmer", "devanagari", "gujarati", "gurmukhi", "kannada", "lower-hexadecimal", "lao", "malayalam",
+        "mongolian", "myanmar", "octal", "oriya", "persian", "urdu", "telugu", "tibetan", "thai", "upper-hexadecimal",
+        "lower-roman", "upper-roman", "lower-greek", "lower-alpha", "lower-latin", "upper-alpha", "upper-latin", "afar",
+        "ethiopic-halehame-aa-et", "ethiopic-halehame-aa-er", "amharic", "ethiopic-halehame-am-et", "amharic-abegede",
+        "ethiopic-abegede-am-et", "cjk-earthly-branch", "cjk-heavenly-stem", "ethiopic", "ethiopic-halehame-gez",
+        "ethiopic-abegede", "ethiopic-abegede-gez", "hangul-consonant", "hangul", "lower-norwegian", "oromo",
+        "ethiopic-halehame-om-et", "sidama", "ethiopic-halehame-sid-et", "somali", "ethiopic-halehame-so-et", "tigre",
+        "ethiopic-halehame-tig", "tigrinya-er", "ethiopic-halehame-ti-er", "tigrinya-er-abegede",
+        "ethiopic-abegede-ti-er", "tigrinya-et", "ethiopic-halehame-ti-et", "tigrinya-et-abegede",
+        "ethiopic-abegede-ti-et", "upper-greek", "upper-norwegian", "asterisks", "footnotes", "hebrew", "armenian",
+        "lower-armenian", "upper-armenian", "georgian", "cjk-ideographic", "hiragana", "katakana", "hiragana-iroha",
+        "katakana-iroha"
+    ] },
+    "-webkit-text-combine": { values: [
+        "none", "horizontal"
+    ] },
+    "outline": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "font": { values: [
+        "caption", "icon", "menu", "message-box", "small-caption", "-webkit-mini-control", "-webkit-small-control",
+        "-webkit-control", "status-bar", "italic", "oblique", "small-caps", "normal", "bold", "bolder", "lighter",
+        "100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium",
+        "large", "x-large", "xx-large", "-webkit-xxx-large", "smaller", "larger", "serif", "sans-serif", "cursive",
+        "fantasy", "monospace", "-webkit-body", "-webkit-pictograph"
+    ] },
+    "dominant-baseline": { values: [
+        "middle", "auto", "central", "text-before-edge", "text-after-edge", "ideographic", "alphabetic", "hanging",
+        "mathematical", "use-script", "no-change", "reset-size"
+    ] },
+    "display": { values: [
+        "none", "inline", "block", "list-item", "run-in", "compact", "inline-block", "table", "inline-table",
+        "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group",
+        "table-column", "table-cell", "table-caption", "-webkit-box", "-webkit-inline-box",
+        "-webkit-flex", "-webkit-inline-flex", "-webkit-grid", "-webkit-inline-grid", "-wap-marquee"
+    ] },
+    "-webkit-text-emphasis-position": { values: [
+        "over", "under"
+    ] },
+    "image-rendering": { values: [
+        "auto", "optimizeSpeed", "optimizeQuality"
+    ] },
+    "alignment-baseline": { values: [
+        "baseline", "middle", "auto", "before-edge", "after-edge", "central", "text-before-edge", "text-after-edge",
+        "ideographic", "alphabetic", "hanging", "mathematical"
+    ] },
+    "outline-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "text-line-through-width": { values: [
+        "normal", "medium", "auto", "thick", "thin"
+    ] },
+    "box-align": { values: [
+        "baseline", "center", "stretch", "start", "end"
+    ] },
+    "border-right-width": { values: [
+        "medium", "thick", "thin"
+    ] },
+    "border-top-style": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "line-height": { values: [
+        "normal"
+    ] },
+    "text-overflow": { values: [
+        "clip", "ellipsis"
+    ] },
+    "overflow-wrap": { values: [
+        "normal", "break-word"
+    ] },
+    "box-direction": { values: [
+        "normal", "reverse"
+    ] },
+    "margin-after-collapse": { values: [
+        "collapse", "separate", "discard"
+    ] },
+    "page-break-before": { values: [
+        "left", "right", "auto", "always", "avoid"
+    ] },
+    "-webkit-hyphens": { values: [
+        "none", "auto", "manual"
+    ] },
+    "border-image": { values: [
+        "repeat", "stretch"
+    ] },
+    "text-decoration": { values: [
+        "blink", "line-through", "overline", "underline"
+    ] },
+    "position": { values: [
+        "absolute", "fixed", "relative", "static"
+    ] },
+    "font-family": { values: [
+        "serif", "sans-serif", "cursive", "fantasy", "monospace", "-webkit-body", "-webkit-pictograph"
+    ] },
+    "text-overflow-mode": { values: [
+        "clip", "ellipsis"
+    ] },
+    "border-bottom-style": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "unicode-bidi": { values: [
+        "normal", "bidi-override", "embed"
+    ] },
+    "clip-rule": { values: [
+        "nonzero", "evenodd"
+    ] },
+    "margin-left": { values: [
+        "auto"
+    ] },
+    "margin-top": { values: [
+        "auto"
+    ] },
+    "zoom": { values: [
+        "normal", "document", "reset"
+    ] },
+    "text-overline-style": { values: [
+        "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave"
+    ] },
+    "max-width": { values: [
+        "none"
+    ] },
+    "caption-side": { values: [
+        "top", "bottom"
+    ] },
+    "empty-cells": { values: [
+        "hide", "show"
+    ] },
+    "pointer-events": { values: [
+        "none", "all", "auto", "visible", "visiblepainted", "visiblefill", "visiblestroke", "painted", "fill", "stroke"
+    ] },
+    "letter-spacing": { values: [
+        "normal"
+    ] },
+    "background-clip": { values: [
+        "border-box", "content-box", "padding-box"
+    ] },
+    "-webkit-font-smoothing": { values: [
+        "none", "auto", "antialiased", "subpixel-antialiased"
+    ] },
+    "border": { values: [
+        "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double"
+    ] },
+    "font-size": { values: [
+        "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "-webkit-xxx-large", "smaller",
+        "larger"
+    ] },
+    "font-variant": { values: [
+        "small-caps", "normal"
+    ] },
+    "vertical-align": { values: [
+        "baseline", "middle", "sub", "super", "text-top", "text-bottom", "top", "bottom", "-webkit-baseline-middle"
+    ] },
+    "marquee-style": { values: [
+        "none", "scroll", "slide", "alternate"
+    ] },
+    "white-space": { values: [
+        "normal", "nowrap", "pre", "pre-line", "pre-wrap"
+    ] },
+    "text-underline-width": { values: [
+        "normal", "medium", "auto", "thick", "thin"
+    ] },
+    "box-lines": { values: [
+        "single", "multiple"
+    ] },
+    "page-break-after": { values: [
+        "left", "right", "auto", "always", "avoid"
+    ] },
+    "clip-path": { values: [
+        "none"
+    ] },
+    "margin": { values: [
+        "auto"
+    ] },
+    "marquee-repetition": { values: [
+        "infinite"
+    ] },
+    "margin-right": { values: [
+        "auto"
+    ] },
+    "word-break": { values: [
+        "normal", "break-all", "break-word"
+    ] },
+    "word-spacing": { values: [
+        "normal"
+    ] },
+    "-webkit-text-emphasis-style": { values: [
+        "circle", "filled", "open", "dot", "double-circle", "triangle", "sesame"
+    ] },
+    "-webkit-transform": { values: [
+        "scale", "scaleX", "scaleY", "scale3d", "rotate", "rotateX", "rotateY", "rotateZ", "rotate3d", "skew", "skewX", "skewY",
+        "translate", "translateX", "translateY", "translateZ", "translate3d", "matrix", "matrix3d", "perspective"
+    ] },
+    "image-resolution": { values: [
+        "from-image", "snap"
+    ] },
+    "box-sizing": { values: [
+        "content-box", "padding-box", "border-box"
+    ] },
+    "clip": { values: [
+        "auto"
+    ] },
+    "resize": { values: [
+        "none", "both", "horizontal", "vertical"
+    ] },
+    "-webkit-align-content": { values: [
+        "flex-start", "flex-end", "center", "space-between", "space-around", "stretch"
+    ] },
+    "-webkit-align-items": {  values: [
+        "flex-start", "flex-end", "center", "baseline", "stretch"
+    ] },
+    "-webkit-align-self": {  values: [
+        "auto", "flex-start", "flex-end", "center", "baseline", "stretch"
+    ] },
+    "-webkit-flex-direction": { values: [
+        "row", "row-reverse", "column", "column-reverse"
+    ] },
+    "-webkit-justify-content": { values: [
+        "flex-start", "flex-end", "center", "space-between", "space-around"
+    ] },
+    "-webkit-flex-wrap": { values: [
+        "nowrap", "wrap", "wrap-reverse"
+    ] },
+    "-webkit-animation-timing-function": { values: [
+        "ease", "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end", "steps", "cubic-bezier"
+    ] },
+    "-webkit-animation-direction": { values: [
+        "normal", "reverse", "alternate", "alternate-reverse"
+    ] },
+    "-webkit-animation-play-state": { values: [
+        "running", "paused"
+    ] },
+    "-webkit-animation-fill-mode": { values: [
+        "none", "forwards", "backwards", "both"
+    ] },
+    "-webkit-backface-visibility": { values: [
+        "visible", "hidden"
+    ] },
+    "-webkit-box-decoration-break": { values: [
+        "slice", "clone"
+    ] },
+    "-webkit-column-break-after": { values: [
+        "auto", "always", "avoid", "left", "right", "page", "column", "avoid-page", "avoid-column"
+    ] },
+    "-webkit-column-break-before": { values: [
+        "auto", "always", "avoid", "left", "right", "page", "column", "avoid-page", "avoid-column"
+    ] },
+    "-webkit-column-break-inside": { values: [
+        "auto", "avoid", "avoid-page", "avoid-column"
+    ] },
+    "-webkit-column-span": { values: [
+        "none", "all"
+    ] },
+    "-webkit-column-count": { values: [
+        "auto"
+    ] },
+    "-webkit-column-gap": { values: [
+        "normal"
+    ] },
+    "-webkit-line-break": { values: [
+        "auto", "loose", "normal", "strict"
+    ] },
+    "-webkit-perspective": { values: [
+        "none"
+    ] },
+    "-webkit-perspective-origin": { values: [
+        "left", "center", "right", "top", "bottom"
+    ] },
+    "-webkit-text-align-last": { values: [
+        "auto", "start", "end", "left", "right", "center", "justify"
+    ] },
+    "-webkit-text-decoration-line": { values: [
+        "none", "underline", "overline", "line-through", "blink"
+    ] },
+    "-webkit-text-decoration-style": { values: [
+        "solid", "double", "dotted", "dashed", "wavy"
+    ] },
+    "-webkit-text-decoration-skip": { values: [
+        "none", "objects", "spaces", "ink", "edges", "box-decoration"
+    ] },
+    "-webkit-transform-origin": { values: [
+        "left", "center", "right", "top", "bottom"
+    ] },
+    "-webkit-transform-style": { values: [
+        "flat", "preserve-3d"
+    ] },
+    "-webkit-transition-timing-function": { values: [
+        "ease", "linear", "ease-in", "ease-out", "ease-in-out", "step-start", "step-end", "steps", "cubic-bezier"
+    ] },
+
+    "-webkit-flex": { m: "flexbox" },
+    "-webkit-flex-basis": { m: "flexbox" },
+    "-webkit-flex-flow": { m: "flexbox" },
+    "-webkit-flex-grow": { m: "flexbox" },
+    "-webkit-flex-shrink": { m: "flexbox" },
+    "-webkit-animation": { m: "animations" },
+    "-webkit-animation-delay": { m: "animations" },
+    "-webkit-animation-duration": { m: "animations" },
+    "-webkit-animation-iteration-count": { m: "animations" },
+    "-webkit-animation-name": { m: "animations" },
+    "-webkit-column-rule": { m: "multicol" },
+    "-webkit-column-rule-color": { m: "multicol", a: "crc" },
+    "-webkit-column-rule-style": { m: "multicol", a: "crs" },
+    "-webkit-column-rule-width": { m: "multicol", a: "crw" },
+    "-webkit-column-width": { m: "multicol", a: "cw" },
+    "-webkit-columns": { m: "multicol" },
+    "-webkit-grid-columns": { m: "grid" },
+    "-webkit-grid-rows": { m: "grid" },
+    "-webkit-order": { m: "flexbox" },
+    "-webkit-text-decoration-color": { m: "text-decor" },
+    "-webkit-text-emphasis-color": { m: "text-decor" },
+    "-webkit-transition": { m: "transitions" },
+    "-webkit-transition-delay": { m: "transitions" },
+    "-webkit-transition-duration": { m: "transitions" },
+    "-webkit-transition-property": { m: "transitions" },
+    "background": { m: "background" },
+    "background-attachment": { m: "background" },
+    "background-color": { m: "background" },
+    "background-image": { m: "background" },
+    "background-position": { m: "background" },
+    "background-position-x": { m: "background" },
+    "background-position-y": { m: "background" },
+    "background-repeat-x": { m: "background" },
+    "background-repeat-y": { m: "background" },
+    "border-top": { m: "background" },
+    "border-right": { m: "background" },
+    "border-bottom": { m: "background" },
+    "border-left": { m: "background" },
+    "border-radius": { m: "background" },
+    "bottom": { m: "visuren" },
+    "box-shadow": { m: "background" },
+    "color": { m: "color", a: "foreground" },
+    "counter-increment": { m: "generate" },
+    "counter-reset": { m: "generate" },
+    "height": { m: "box" },
+    "image-orientation": { m: "images" },
+    "left": { m: "visuren" },
+    "list-style": { m: "lists" },
+    "min-height": { m: "box" },
+    "min-width": { m: "box" },
+    "opacity": { m: "color", a: "transparency" },
+    "orphans": { m: "page" },
+    "outline-offset": { m: "ui" },
+    "padding": { m: "box", a: "padding1" },
+    "padding-bottom": { m: "box" },
+    "padding-left": { m: "box" },
+    "padding-right": { m: "box" },
+    "padding-top": { m: "box" },
+    "page": { m: "page" },
+    "quotes": { m: "generate" },
+    "right": { m: "visuren" },
+    "tab-size": { m: "text" },
+    "text-indent": { m: "text" },
+    "text-shadow": { m: "text-decor" },
+    "top": { m: "visuren" },
+    "unicode-range": { m: "fonts", a: "descdef-unicode-range" },
+    "widows": { m: "page" },
+    "width": { m: "box" },
+    "z-index": { m: "visuren" }
+}
+
+/**
+ * @param {string} propertyName
+ * @return {!WebInspector.CSSMetadata}
+ */
+WebInspector.CSSMetadata.keywordsForProperty = function(propertyName)
+{
+    var acceptedKeywords = ["inherit", "initial"];
+    var descriptor = WebInspector.CSSMetadata.descriptor(propertyName);
+    if (descriptor && descriptor.values)
+        acceptedKeywords.push.apply(acceptedKeywords, descriptor.values);
+    if (propertyName in WebInspector.CSSMetadata._colorAwareProperties)
+        acceptedKeywords.push.apply(acceptedKeywords, WebInspector.CSSMetadata._colors);
+    return new WebInspector.CSSMetadata(acceptedKeywords);
+}
+
+/**
+ * @param {string} propertyName
+ * @return {Object}
+ */
+WebInspector.CSSMetadata.descriptor = function(propertyName)
+{
+    if (!propertyName)
+        return null;
+    var unprefixedName = propertyName.replace(/^-webkit-/, "");
+    var entry = WebInspector.CSSMetadata._propertyDataMap[propertyName];
+    if (!entry && unprefixedName !== propertyName)
+        entry = WebInspector.CSSMetadata._propertyDataMap[unprefixedName];
+    return entry || null;
+}
+
+WebInspector.CSSMetadata.requestCSSShorthandData = function()
+{
+    function propertyNamesCallback(error, properties)
+    {
+        if (!error)
+            WebInspector.CSSMetadata.cssPropertiesMetainfo = new WebInspector.CSSMetadata(properties);
+    }
+    CSSAgent.getSupportedCSSProperties(propertyNamesCallback);
+}
+
+WebInspector.CSSMetadata.cssPropertiesMetainfoKeySet = function()
+{
+    if (!WebInspector.CSSMetadata._cssPropertiesMetainfoKeySet)
+        WebInspector.CSSMetadata._cssPropertiesMetainfoKeySet = WebInspector.CSSMetadata.cssPropertiesMetainfo.keySet();
+    return WebInspector.CSSMetadata._cssPropertiesMetainfoKeySet;
+}
+
+// Weight of CSS properties based their usage on few popular websites https://gist.github.com/3751436
+WebInspector.CSSMetadata.Weight = {
+    "-webkit-animation": 1,
+    "-webkit-animation-duration": 1,
+    "-webkit-animation-iteration-count": 1,
+    "-webkit-animation-name": 1,
+    "-webkit-animation-timing-function": 1,
+    "-webkit-appearance": 1,
+    "-webkit-background-clip": 2,
+    "-webkit-border-horizontal-spacing": 1,
+    "-webkit-border-vertical-spacing": 1,
+    "-webkit-box-shadow": 24,
+    "-webkit-font-smoothing": 2,
+    "-webkit-transform": 1,
+    "-webkit-transition": 8,
+    "-webkit-transition-delay": 7,
+    "-webkit-transition-duration": 7,
+    "-webkit-transition-property": 7,
+    "-webkit-transition-timing-function": 6,
+    "-webkit-user-select": 1,
+    "background": 222,
+    "background-attachment": 144,
+    "background-clip": 143,
+    "background-color": 222,
+    "background-image": 201,
+    "background-origin": 142,
+    "background-size": 25,
+    "border": 121,
+    "border-bottom": 121,
+    "border-bottom-color": 121,
+    "border-bottom-left-radius": 50,
+    "border-bottom-right-radius": 50,
+    "border-bottom-style": 114,
+    "border-bottom-width": 120,
+    "border-collapse": 3,
+    "border-left": 95,
+    "border-left-color": 95,
+    "border-left-style": 89,
+    "border-left-width": 94,
+    "border-radius": 50,
+    "border-right": 93,
+    "border-right-color": 93,
+    "border-right-style": 88,
+    "border-right-width": 93,
+    "border-top": 111,
+    "border-top-color": 111,
+    "border-top-left-radius": 49,
+    "border-top-right-radius": 49,
+    "border-top-style": 104,
+    "border-top-width": 109,
+    "bottom": 16,
+    "box-shadow": 25,
+    "box-sizing": 2,
+    "clear": 23,
+    "color": 237,
+    "cursor": 34,
+    "direction": 4,
+    "display": 210,
+    "fill": 2,
+    "filter": 1,
+    "float": 105,
+    "font": 174,
+    "font-family": 25,
+    "font-size": 174,
+    "font-style": 9,
+    "font-weight": 89,
+    "height": 161,
+    "left": 54,
+    "letter-spacing": 3,
+    "line-height": 75,
+    "list-style": 17,
+    "list-style-image": 8,
+    "list-style-position": 8,
+    "list-style-type": 17,
+    "margin": 241,
+    "margin-bottom": 226,
+    "margin-left": 225,
+    "margin-right": 213,
+    "margin-top": 241,
+    "max-height": 5,
+    "max-width": 11,
+    "min-height": 9,
+    "min-width": 6,
+    "opacity": 24,
+    "outline": 10,
+    "outline-color": 10,
+    "outline-style": 10,
+    "outline-width": 10,
+    "overflow": 57,
+    "overflow-x": 56,
+    "overflow-y": 57,
+    "padding": 216,
+    "padding-bottom": 208,
+    "padding-left": 216,
+    "padding-right": 206,
+    "padding-top": 216,
+    "position": 136,
+    "resize": 1,
+    "right": 29,
+    "stroke": 1,
+    "stroke-width": 1,
+    "table-layout": 1,
+    "text-align": 66,
+    "text-decoration": 53,
+    "text-indent": 9,
+    "text-overflow": 8,
+    "text-shadow": 19,
+    "text-transform": 5,
+    "top": 71,
+    "unicode-bidi": 1,
+    "vertical-align": 37,
+    "visibility": 11,
+    "white-space": 24,
+    "width": 255,
+    "word-wrap": 6,
+    "z-index": 32,
+    "zoom": 10
+};
+
+
+WebInspector.CSSMetadata.prototype = {
+    /**
+     * @param {string} prefix
+     * @return {!Array.}
+     */
+    startsWith: function(prefix)
+    {
+        var firstIndex = this._firstIndexOfPrefix(prefix);
+        if (firstIndex === -1)
+            return [];
+
+        var results = [];
+        while (firstIndex < this._values.length && this._values[firstIndex].startsWith(prefix))
+            results.push(this._values[firstIndex++]);
+        return results;
+    },
+
+    /**
+     * @param {Array.} properties
+     * @return {number}
+     */
+    mostUsedOf: function(properties)
+    {
+        var maxWeight = 0;
+        var index = 0;
+        for (var i = 0; i < properties.length; i++) {
+            var weight = WebInspector.CSSMetadata.Weight[properties[i]];
+            if (weight > maxWeight) {
+                maxWeight = weight;
+                index = i;
+            }
+        }
+        return index;
+    },
+
+    _firstIndexOfPrefix: function(prefix)
+    {
+        if (!this._values.length)
+            return -1;
+        if (!prefix)
+            return 0;
+
+        var maxIndex = this._values.length - 1;
+        var minIndex = 0;
+        var foundIndex;
+
+        do {
+            var middleIndex = (maxIndex + minIndex) >> 1;
+            if (this._values[middleIndex].startsWith(prefix)) {
+                foundIndex = middleIndex;
+                break;
+            }
+            if (this._values[middleIndex] < prefix)
+                minIndex = middleIndex + 1;
+            else
+                maxIndex = middleIndex - 1;
+        } while (minIndex <= maxIndex);
+
+        if (foundIndex === undefined)
+            return -1;
+
+        while (foundIndex && this._values[foundIndex - 1].startsWith(prefix))
+            foundIndex--;
+
+        return foundIndex;
+    },
+
+    keySet: function()
+    {
+        if (!this._keySet)
+            this._keySet = this._values.keySet();
+        return this._keySet;
+    },
+
+    next: function(str, prefix)
+    {
+        return this._closest(str, prefix, 1);
+    },
+
+    previous: function(str, prefix)
+    {
+        return this._closest(str, prefix, -1);
+    },
+
+    _closest: function(str, prefix, shift)
+    {
+        if (!str)
+            return "";
+
+        var index = this._values.indexOf(str);
+        if (index === -1)
+            return "";
+
+        if (!prefix) {
+            index = (index + this._values.length + shift) % this._values.length;
+            return this._values[index];
+        }
+
+        var propertiesWithPrefix = this.startsWith(prefix);
+        var j = propertiesWithPrefix.indexOf(str);
+        j = (j + propertiesWithPrefix.length + shift) % propertiesWithPrefix.length;
+        return propertiesWithPrefix[j];
+    },
+
+    /**
+     * @param {string} shorthand
+     * @return {?Array.}
+     */
+    longhands: function(shorthand)
+    {
+        return this._longhands[shorthand];
+    },
+
+    /**
+     * @param {string} longhand
+     * @return {?Array.}
+     */
+    shorthands: function(longhand)
+    {
+        return this._shorthands[longhand];
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowCollectionsView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowCollectionsView.js
new file mode 100644
index 00000000..ccffd68d
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowCollectionsView.js
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarView}
+ */
+WebInspector.CSSNamedFlowCollectionsView = function()
+{
+    WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start);
+    this.registerRequiredCSS("cssNamedFlows.css");
+
+    this._namedFlows = {};
+    this._contentNodes = {};
+    this._regionNodes = {};
+
+    this.element.addStyleClass("css-named-flow-collections-view");
+    this.element.addStyleClass("fill");
+
+    this._statusElement = document.createElement("span");
+    this._statusElement.textContent = WebInspector.UIString("CSS Named Flows");
+
+    var sidebarHeader = this.firstElement().createChild("div", "tabbed-pane-header selected sidebar-header");
+    var tab = sidebarHeader.createChild("div", "tabbed-pane-header-tab");
+    tab.createChild("span", "tabbed-pane-header-tab-title").textContent = WebInspector.UIString("CSS Named Flows");
+
+    this._sidebarContentElement = this.firstElement().createChild("div", "sidebar-content outline-disclosure");
+    this._flowListElement = this._sidebarContentElement.createChild("ol");
+    this._flowTree = new TreeOutline(this._flowListElement);
+
+    this._emptyElement = document.createElement("div");
+    this._emptyElement.addStyleClass("info");
+    this._emptyElement.textContent = WebInspector.UIString("No CSS Named Flows");
+
+    this._tabbedPane = new WebInspector.TabbedPane();
+    this._tabbedPane.closeableTabs = true;
+    this._tabbedPane.show(this.secondElement());
+}
+
+WebInspector.CSSNamedFlowCollectionsView.prototype = {
+    showInDrawer: function()
+    {
+        WebInspector.showViewInDrawer(this._statusElement, this);
+    },
+
+    reset: function()
+    {
+        if (!this._document)
+            return;
+
+        WebInspector.cssModel.getNamedFlowCollectionAsync(this._document.id, this._resetNamedFlows.bind(this));
+    },
+
+    /**
+     * @param {WebInspector.DOMDocument} document
+     */
+    _setDocument: function(document)
+    {
+        this._document = document;
+        this.reset();
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _documentUpdated: function(event)
+    {
+        var document = /** @type {WebInspector.DOMDocument} */ (event.data);
+        this._setDocument(document);
+    },
+
+    /**
+     * @param {boolean} hasContent
+     */
+    _setSidebarHasContent: function(hasContent)
+    {
+        if (hasContent) {
+            if (!this._emptyElement.parentNode)
+                return;
+
+            this._sidebarContentElement.removeChild(this._emptyElement);
+            this._sidebarContentElement.appendChild(this._flowListElement);
+        } else {
+            if (!this._flowListElement.parentNode)
+                return;
+
+            this._sidebarContentElement.removeChild(this._flowListElement);
+            this._sidebarContentElement.appendChild(this._emptyElement);
+        }
+    },
+
+    /**
+     * @param {WebInspector.NamedFlow} flow
+     */
+    _appendNamedFlow: function(flow)
+    {
+        var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
+        var flowContainer = { flow: flow, flowHash: flowHash };
+
+        for (var i = 0; i < flow.content.length; ++i)
+            this._contentNodes[flow.content[i]] = flowHash;
+        for (var i = 0; i < flow.regions.length; ++i)
+            this._regionNodes[flow.regions[i].nodeId] = flowHash;
+
+        var flowTreeItem = new WebInspector.FlowTreeElement(flowContainer);
+        flowTreeItem.onselect = this._selectNamedFlowTab.bind(this, flowHash);
+
+        flowContainer.flowTreeItem = flowTreeItem;
+        this._namedFlows[flowHash] = flowContainer;
+
+        if (!this._flowTree.children.length)
+            this._setSidebarHasContent(true);
+        this._flowTree.appendChild(flowTreeItem);
+    },
+
+    /**
+     * @param {string} flowHash
+     */
+    _removeNamedFlow: function(flowHash)
+    {
+        var flowContainer = this._namedFlows[flowHash];
+
+        if (this._tabbedPane._tabsById[flowHash])
+            this._tabbedPane.closeTab(flowHash);
+        this._flowTree.removeChild(flowContainer.flowTreeItem);
+
+        var flow = flowContainer.flow;
+        for (var i = 0; i < flow.content.length; ++i)
+            delete this._contentNodes[flow.content[i]];
+        for (var i = 0; i < flow.regions.length; ++i)
+            delete this._regionNodes[flow.regions[i].nodeId];
+
+        delete this._namedFlows[flowHash];
+
+        if (!this._flowTree.children.length)
+            this._setSidebarHasContent(false);
+    },
+
+    /**
+     * @param {WebInspector.NamedFlow} flow
+     */
+    _updateNamedFlow: function(flow)
+    {
+        var flowHash = this._hashNamedFlow(flow.documentNodeId, flow.name);
+        var flowContainer = this._namedFlows[flowHash];
+
+        if (!flowContainer)
+            return;
+
+        var oldFlow = flowContainer.flow;
+        flowContainer.flow = flow;
+
+        for (var i = 0; i < oldFlow.content.length; ++i)
+            delete this._contentNodes[oldFlow.content[i]];
+        for (var i = 0; i < oldFlow.regions.length; ++i)
+            delete this._regionNodes[oldFlow.regions[i].nodeId];
+
+        for (var i = 0; i < flow.content.length; ++i)
+            this._contentNodes[flow.content[i]] = flowHash;
+        for (var i = 0; i < flow.regions.length; ++i)
+            this._regionNodes[flow.regions[i].nodeId] = flowHash;
+
+        flowContainer.flowTreeItem.setOverset(flow.overset);
+
+        if (flowContainer.flowView)
+            flowContainer.flowView.flow = flow;
+    },
+
+    /**
+     * @param {WebInspector.NamedFlowCollection} namedFlowCollection
+     */
+    _resetNamedFlows: function(namedFlowCollection)
+    {
+        for (var flowHash in this._namedFlows)
+            this._removeNamedFlow(flowHash);
+
+        var namedFlows = namedFlowCollection.namedFlowMap;
+        for (var flowName in namedFlows)
+            this._appendNamedFlow(namedFlows[flowName]);
+
+        if (!this._flowTree.children.length)
+            this._setSidebarHasContent(false);
+        else
+            this._showNamedFlowForNode(WebInspector.panel("elements").treeOutline.selectedDOMNode());
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _namedFlowCreated: function(event)
+    {
+        // FIXME: We only have support for Named Flows in the main document.
+        if (event.data.documentNodeId !== this._document.id)
+            return;
+
+        var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
+        this._appendNamedFlow(flow);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _namedFlowRemoved: function(event)
+    {
+        // FIXME: We only have support for Named Flows in the main document.
+        if (event.data.documentNodeId !== this._document.id)
+            return;
+
+        this._removeNamedFlow(this._hashNamedFlow(event.data.documentNodeId, event.data.flowName));
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _regionLayoutUpdated: function(event)
+    {
+        // FIXME: We only have support for Named Flows in the main document.
+        if (event.data.documentNodeId !== this._document.id)
+            return;
+
+        var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
+        this._updateNamedFlow(flow);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _regionOversetChanged: function(event)
+    {
+        // FIXME: We only have support for Named Flows in the main document.
+        if (event.data.documentNodeId !== this._document.id)
+            return;
+
+        var flow = /** @type {WebInspector.NamedFlow} */ (event.data);
+        this._updateNamedFlow(flow);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} documentNodeId
+     * @param {string} flowName
+     */
+    _hashNamedFlow: function(documentNodeId, flowName)
+    {
+        return documentNodeId + "|" + flowName;
+    },
+
+    /**
+     * @param {string} flowHash
+     */
+    _showNamedFlow: function(flowHash)
+    {
+        this._selectNamedFlowInSidebar(flowHash);
+        this._selectNamedFlowTab(flowHash);
+    },
+
+    /**
+     * @param {string} flowHash
+     */
+    _selectNamedFlowInSidebar: function(flowHash)
+    {
+        this._namedFlows[flowHash].flowTreeItem.select(true);
+    },
+
+    /**
+     * @param {string} flowHash
+     */
+    _selectNamedFlowTab: function(flowHash)
+    {
+        var flowContainer = this._namedFlows[flowHash];
+
+        if (this._tabbedPane.selectedTabId === flowHash)
+            return;
+
+        if (!this._tabbedPane.selectTab(flowHash)) {
+            if (!flowContainer.flowView)
+                flowContainer.flowView = new WebInspector.CSSNamedFlowView(flowContainer.flow);
+
+            this._tabbedPane.appendTab(flowHash, flowContainer.flow.name, flowContainer.flowView);
+            this._tabbedPane.selectTab(flowHash);
+        }
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _selectedNodeChanged: function(event)
+    {
+        var node = /** @type {WebInspector.DOMNode} */ (event.data);
+        this._showNamedFlowForNode(node);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _tabSelected: function(event)
+    {
+        this._selectNamedFlowInSidebar(event.data.tabId);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _tabClosed: function(event)
+    {
+        this._namedFlows[event.data.tabId].flowTreeItem.deselect();
+    },
+
+    /**
+     * @param {?WebInspector.DOMNode} node
+     */
+    _showNamedFlowForNode: function(node)
+    {
+        if (!node)
+            return;
+
+        if (this._regionNodes[node.id]) {
+            this._showNamedFlow(this._regionNodes[node.id]);
+            return;
+        }
+
+        while (node) {
+            if (this._contentNodes[node.id]) {
+                this._showNamedFlow(this._contentNodes[node.id]);
+                return;
+            }
+
+            node = node.parentNode;
+        }
+    },
+
+    wasShown: function()
+    {
+        WebInspector.SidebarView.prototype.wasShown.call(this);
+
+        WebInspector.domAgent.requestDocument(this._setDocument.bind(this));
+
+        WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
+
+        WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
+        WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
+        WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
+        WebInspector.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
+
+        WebInspector.panel("elements").treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
+
+        this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
+        this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
+    },
+
+    willHide: function()
+    {
+        WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this);
+
+        WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowCreated, this._namedFlowCreated, this);
+        WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, this._namedFlowRemoved, this);
+        WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, this._regionLayoutUpdated, this);
+        WebInspector.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.RegionOversetChanged, this._regionOversetChanged, this);
+
+        WebInspector.panel("elements").treeOutline.removeEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
+
+        this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
+        this._tabbedPane.removeEventListener(WebInspector.TabbedPane.EventTypes.TabClosed, this._tabClosed, this);
+    },
+
+    __proto__: WebInspector.SidebarView.prototype
+}
+
+/**
+ * @constructor
+ * @extends {TreeElement}
+ */
+WebInspector.FlowTreeElement = function(flowContainer)
+{
+    var container = document.createElement("div");
+    container.createChild("div", "selection");
+    container.createChild("span", "title").createChild("span").textContent = flowContainer.flow.name;
+
+    TreeElement.call(this, container, flowContainer, false);
+
+    this._overset = false;
+    this.setOverset(flowContainer.flow.overset);
+}
+
+WebInspector.FlowTreeElement.prototype = {
+    /**
+     * @param {boolean} newOverset
+     */
+    setOverset: function(newOverset)
+    {
+        if (this._overset === newOverset)
+            return;
+
+        if (newOverset) {
+            this.title.addStyleClass("named-flow-overflow");
+            this.tooltip = WebInspector.UIString("Overflows.");
+        } else {
+            this.title.removeStyleClass("named-flow-overflow");
+            this.tooltip = "";
+        }
+
+        this._overset = newOverset;
+    },
+
+    __proto__: TreeElement.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowView.js
new file mode 100644
index 00000000..25f3c9a0
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSNamedFlowView.js
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2012 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {WebInspector.NamedFlow} flow
+ */
+WebInspector.CSSNamedFlowView = function(flow)
+{
+    WebInspector.View.call(this);
+    this.element.addStyleClass("css-named-flow");
+    this.element.addStyleClass("outline-disclosure");
+
+    this._treeOutline = new TreeOutline(this.element.createChild("ol"), true);
+
+    this._contentTreeItem = new TreeElement(WebInspector.UIString("content"), null, true);
+    this._treeOutline.appendChild(this._contentTreeItem);
+
+    this._regionsTreeItem = new TreeElement(WebInspector.UIString("region chain"), null, true);
+    this._regionsTreeItem.expand();
+    this._treeOutline.appendChild(this._regionsTreeItem);
+
+    this._flow = flow;
+
+    var content = flow.content;
+    for (var i = 0; i < content.length; ++i)
+        this._insertContentNode(content[i]);
+
+    var regions = flow.regions;
+    for (var i = 0; i < regions.length; ++i)
+        this._insertRegion(regions[i]);
+}
+
+WebInspector.CSSNamedFlowView.OversetTypeMessageMap = {
+    empty: "empty",
+    fit: "fit",
+    overset: "overset"
+}
+
+WebInspector.CSSNamedFlowView.prototype = {
+    /**
+     * @param {WebInspector.DOMNode=} rootDOMNode
+     * @return {?WebInspector.ElementsTreeOutline}
+     */
+    _createFlowTreeOutline: function(rootDOMNode)
+    {
+        if (!rootDOMNode)
+            return null;
+
+        var treeOutline = new WebInspector.ElementsTreeOutline(false, false);
+        treeOutline.element.addStyleClass("named-flow-element");
+        treeOutline.setVisible(true);
+        treeOutline.rootDOMNode = rootDOMNode;
+        treeOutline.wireToDomAgent();
+        WebInspector.domAgent.removeEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, treeOutline._elementsTreeUpdater._documentUpdated, treeOutline._elementsTreeUpdater);
+
+        return treeOutline;
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} contentNodeId
+     * @param {number=} index
+     */
+    _insertContentNode: function(contentNodeId, index)
+    {
+        var treeOutline = this._createFlowTreeOutline(WebInspector.domAgent.nodeForId(contentNodeId));
+        var treeItem = new TreeElement(treeOutline.element, treeOutline);
+
+        if (index === undefined) {
+            this._contentTreeItem.appendChild(treeItem);
+            return;
+        }
+
+        this._contentTreeItem.insertChild(treeItem, index);
+    },
+
+    /**
+     * @param {CSSAgent.Region} region
+     * @param {number=} index
+     */
+    _insertRegion: function(region, index)
+    {
+        var treeOutline = this._createFlowTreeOutline(WebInspector.domAgent.nodeForId(region.nodeId));
+        treeOutline.element.addStyleClass("region-" + region.regionOverset);
+
+        var treeItem = new TreeElement(treeOutline.element, treeOutline);
+        var oversetText = WebInspector.UIString(WebInspector.CSSNamedFlowView.OversetTypeMessageMap[region.regionOverset]);
+        treeItem.tooltip = WebInspector.UIString("Region is %s.", oversetText);
+
+        if (index === undefined) {
+            this._regionsTreeItem.appendChild(treeItem);
+            return;
+        }
+
+        this._regionsTreeItem.insertChild(treeItem, index);
+    },
+
+    get flow()
+    {
+        return this._flow;
+    },
+
+    set flow(newFlow)
+    {
+        this._update(newFlow);
+    },
+
+    /**
+     * @param {TreeElement} regionTreeItem
+     * @param {string} newRegionOverset
+     * @param {string} oldRegionOverset
+     */
+    _updateRegionOverset: function(regionTreeItem, newRegionOverset, oldRegionOverset)
+    {
+        var element = regionTreeItem.representedObject.element;
+        element.removeStyleClass("region-" + oldRegionOverset);
+        element.addStyleClass("region-" + newRegionOverset);
+
+        var oversetText = WebInspector.UIString(WebInspector.CSSNamedFlowView.OversetTypeMessageMap[newRegionOverset]);
+        regionTreeItem.tooltip = WebInspector.UIString("Region is %s." , oversetText);
+    },
+
+    /**
+     * @param {Array.} oldContent
+     * @param {Array.} newContent
+     */
+    _mergeContentNodes: function(oldContent, newContent)
+    {
+        var nodeIdSet = {};
+        for (var i = 0; i < newContent.length; ++i)
+            nodeIdSet[newContent[i]] = true;
+
+        var oldContentIndex = 0;
+        var newContentIndex = 0;
+        var contentTreeChildIndex = 0;
+
+        while(oldContentIndex < oldContent.length || newContentIndex < newContent.length) {
+            if (oldContentIndex === oldContent.length) {
+                this._insertContentNode(newContent[newContentIndex]);
+                ++newContentIndex;
+                continue;
+            }
+
+            if (newContentIndex === newContent.length) {
+                this._contentTreeItem.removeChildAtIndex(contentTreeChildIndex);
+                ++oldContentIndex;
+                continue;
+            }
+
+            if (oldContent[oldContentIndex] === newContent[newContentIndex]) {
+                ++oldContentIndex;
+                ++newContentIndex;
+                ++contentTreeChildIndex;
+                continue;
+            }
+
+            if (nodeIdSet[oldContent[oldContentIndex]]) {
+                this._insertContentNode(newContent[newContentIndex], contentTreeChildIndex);
+                ++newContentIndex;
+                ++contentTreeChildIndex;
+                continue;
+            }
+
+            this._contentTreeItem.removeChildAtIndex(contentTreeChildIndex);
+            ++oldContentIndex;
+        }
+    },
+
+    /**
+     * @param {Array.} oldRegions
+     * @param {Array.} newRegions
+     */
+    _mergeRegions: function(oldRegions, newRegions)
+    {
+        var nodeIdSet = {};
+        for (var i = 0; i < newRegions.length; ++i)
+            nodeIdSet[newRegions[i].nodeId] = true;
+
+        var oldRegionsIndex = 0;
+        var newRegionsIndex = 0;
+        var regionsTreeChildIndex = 0;
+
+        while(oldRegionsIndex < oldRegions.length || newRegionsIndex < newRegions.length) {
+            if (oldRegionsIndex === oldRegions.length) {
+                this._insertRegion(newRegions[newRegionsIndex]);
+                ++newRegionsIndex;
+                continue;
+            }
+
+            if (newRegionsIndex === newRegions.length) {
+                this._regionsTreeItem.removeChildAtIndex(regionsTreeChildIndex);
+                ++oldRegionsIndex;
+                continue;
+            }
+
+            if (oldRegions[oldRegionsIndex].nodeId === newRegions[newRegionsIndex].nodeId) {
+                if (oldRegions[oldRegionsIndex].regionOverset !== newRegions[newRegionsIndex].regionOverset)
+                    this._updateRegionOverset(this._regionsTreeItem.children[regionsTreeChildIndex], newRegions[newRegionsIndex].regionOverset, oldRegions[oldRegionsIndex].regionOverset);
+                ++oldRegionsIndex;
+                ++newRegionsIndex;
+                ++regionsTreeChildIndex;
+                continue;
+            }
+
+            if (nodeIdSet[oldRegions[oldRegionsIndex].nodeId]) {
+                this._insertRegion(newRegions[newRegionsIndex], regionsTreeChildIndex);
+                ++newRegionsIndex;
+                ++regionsTreeChildIndex;
+                continue;
+            }
+
+            this._regionsTreeItem.removeChildAtIndex(regionsTreeChildIndex);
+            ++oldRegionsIndex;
+        }
+    },
+
+    /**
+     * @param {WebInspector.NamedFlow} newFlow
+     */
+    _update: function(newFlow)
+    {
+        this._mergeContentNodes(this._flow.content, newFlow.content);
+        this._mergeRegions(this._flow.regions, newFlow.regions);
+
+        this._flow = newFlow;
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleModel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleModel.js
new file mode 100644
index 00000000..218c7434
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleModel.js
@@ -0,0 +1,1714 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {WebInspector.Workspace} workspace
+ */
+WebInspector.CSSStyleModel = function(workspace)
+{
+    this._workspace = workspace;
+    this._pendingCommandsMajorState = [];
+    WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoRequested, this._undoRedoRequested, this);
+    WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.UndoRedoCompleted, this._undoRedoCompleted, this);
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameCreatedOrNavigated, this._mainFrameCreatedOrNavigated, this);
+    this._namedFlowCollections = {};
+    WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._resetNamedFlowCollections, this);
+    InspectorBackend.registerCSSDispatcher(new WebInspector.CSSDispatcher(this));
+    CSSAgent.enable();
+    this._resetStyleSheets();
+}
+
+/**
+ * @param {Array.} ruleArray
+ */
+WebInspector.CSSStyleModel.parseRuleArrayPayload = function(ruleArray)
+{
+    var result = [];
+    for (var i = 0; i < ruleArray.length; ++i)
+        result.push(WebInspector.CSSRule.parsePayload(ruleArray[i]));
+    return result;
+}
+    
+/**
+ * @param {Array.} matchArray
+ */
+WebInspector.CSSStyleModel.parseRuleMatchArrayPayload = function(matchArray)
+{
+    var result = [];
+    for (var i = 0; i < matchArray.length; ++i)
+        result.push(WebInspector.CSSRule.parsePayload(matchArray[i].rule, matchArray[i].matchingSelectors));
+    return result;
+}
+
+WebInspector.CSSStyleModel.Events = {
+    StyleSheetAdded: "StyleSheetAdded",
+    StyleSheetChanged: "StyleSheetChanged",
+    StyleSheetRemoved: "StyleSheetRemoved",
+    MediaQueryResultChanged: "MediaQueryResultChanged",
+    NamedFlowCreated: "NamedFlowCreated",
+    NamedFlowRemoved: "NamedFlowRemoved",
+    RegionLayoutUpdated: "RegionLayoutUpdated",
+    RegionOversetChanged: "RegionOversetChanged"
+}
+
+WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"];
+
+WebInspector.CSSStyleModel.prototype = {
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {boolean} needPseudo
+     * @param {boolean} needInherited
+     * @param {function(?*)} userCallback
+     */
+    getMatchedStylesAsync: function(nodeId, needPseudo, needInherited, userCallback)
+    {
+        /**
+         * @param {function(?*)} userCallback
+         * @param {?Protocol.Error} error
+         * @param {Array.=} matchedPayload
+         * @param {Array.=} pseudoPayload
+         * @param {Array.=} inheritedPayload
+         */
+        function callback(userCallback, error, matchedPayload, pseudoPayload, inheritedPayload)
+        {
+            if (error) {
+                if (userCallback)
+                    userCallback(null);
+                return;
+            }
+
+            var result = {};
+            if (matchedPayload)
+                result.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(matchedPayload);
+
+            if (pseudoPayload) {
+                result.pseudoElements = [];
+                for (var i = 0; i < pseudoPayload.length; ++i) {
+                    var entryPayload = pseudoPayload[i];
+                    result.pseudoElements.push({ pseudoId: entryPayload.pseudoId, rules: WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(entryPayload.matches) });
+                }
+            }
+
+            if (inheritedPayload) {
+                result.inherited = [];
+                for (var i = 0; i < inheritedPayload.length; ++i) {
+                    var entryPayload = inheritedPayload[i];
+                    var entry = {};
+                    if (entryPayload.inlineStyle)
+                        entry.inlineStyle = WebInspector.CSSStyleDeclaration.parsePayload(entryPayload.inlineStyle);
+                    if (entryPayload.matchedCSSRules)
+                        entry.matchedCSSRules = WebInspector.CSSStyleModel.parseRuleMatchArrayPayload(entryPayload.matchedCSSRules);
+                    result.inherited.push(entry);
+                }
+            }
+
+            if (userCallback)
+                userCallback(result);
+        }
+
+        CSSAgent.getMatchedStylesForNode(nodeId, needPseudo, needInherited, callback.bind(null, userCallback));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
+     */
+    getComputedStyleAsync: function(nodeId, userCallback)
+    {
+        /**
+         * @param {function(?WebInspector.CSSStyleDeclaration)} userCallback
+         */
+        function callback(userCallback, error, computedPayload)
+        {
+            if (error || !computedPayload)
+                userCallback(null);
+            else
+                userCallback(WebInspector.CSSStyleDeclaration.parseComputedStylePayload(computedPayload));
+        }
+
+        CSSAgent.getComputedStyleForNode(nodeId, callback.bind(null, userCallback));
+    },
+
+    /**
+     * @param {number} nodeId
+     * @param {function(?String, ?Array.)} callback
+     */
+    getPlatformFontsForNode: function(nodeId, callback)
+    {
+        function platformFontsCallback(error, cssFamilyName, fonts)
+        {
+            if (error)
+                callback(null, null);
+            else
+                callback(cssFamilyName, fonts);
+        }
+        CSSAgent.getPlatformFontsForNode(nodeId, platformFontsCallback);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
+     */
+    getInlineStylesAsync: function(nodeId, userCallback)
+    {
+        /**
+         * @param {function(?WebInspector.CSSStyleDeclaration, ?WebInspector.CSSStyleDeclaration)} userCallback
+         * @param {?Protocol.Error} error
+         * @param {?CSSAgent.CSSStyle=} inlinePayload
+         * @param {?CSSAgent.CSSStyle=} attributesStylePayload
+         */
+        function callback(userCallback, error, inlinePayload, attributesStylePayload)
+        {
+            if (error || !inlinePayload)
+                userCallback(null, null);
+            else
+                userCallback(WebInspector.CSSStyleDeclaration.parsePayload(inlinePayload), attributesStylePayload ? WebInspector.CSSStyleDeclaration.parsePayload(attributesStylePayload) : null);
+        }
+
+        CSSAgent.getInlineStylesForNode(nodeId, callback.bind(null, userCallback));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {?Array.|undefined} forcedPseudoClasses
+     * @param {function()=} userCallback
+     */
+    forcePseudoState: function(nodeId, forcedPseudoClasses, userCallback)
+    {
+        CSSAgent.forcePseudoState(nodeId, forcedPseudoClasses || [], userCallback);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} documentNodeId
+     * @param {function(?WebInspector.NamedFlowCollection)} userCallback
+     */
+    getNamedFlowCollectionAsync: function(documentNodeId, userCallback)
+    {
+        var namedFlowCollection = this._namedFlowCollections[documentNodeId];
+        if (namedFlowCollection) {
+            userCallback(namedFlowCollection);
+            return;
+        }
+
+        /**
+         * @param {function(?WebInspector.NamedFlowCollection)} userCallback
+         * @param {?Protocol.Error} error
+         * @param {?Array.} namedFlowPayload
+         */
+        function callback(userCallback, error, namedFlowPayload)
+        {
+            if (error || !namedFlowPayload)
+                userCallback(null);
+            else {
+                var namedFlowCollection = new WebInspector.NamedFlowCollection(namedFlowPayload);
+                this._namedFlowCollections[documentNodeId] = namedFlowCollection;
+                userCallback(namedFlowCollection);
+            }
+        }
+
+        CSSAgent.getNamedFlowCollection(documentNodeId, callback.bind(this, userCallback));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} documentNodeId
+     * @param {string} flowName
+     * @param {function(?WebInspector.NamedFlow)} userCallback
+     */
+    getFlowByNameAsync: function(documentNodeId, flowName, userCallback)
+    {
+        var namedFlowCollection = this._namedFlowCollections[documentNodeId];
+        if (namedFlowCollection) {
+            userCallback(namedFlowCollection.flowByName(flowName));
+            return;
+        }
+
+        /**
+         * @param {function(?WebInspector.NamedFlow)} userCallback
+         * @param {?WebInspector.NamedFlowCollection} namedFlowCollection
+         */
+        function callback(userCallback, namedFlowCollection)
+        {
+            if (!namedFlowCollection)
+                userCallback(null);
+            else
+                userCallback(namedFlowCollection.flowByName(flowName));
+        }
+
+        this.getNamedFlowCollectionAsync(documentNodeId, callback.bind(this, userCallback));
+    },
+
+    /**
+     * @param {CSSAgent.CSSRuleId} ruleId
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} newSelector
+     * @param {function(WebInspector.CSSRule, boolean)} successCallback
+     * @param {function()} failureCallback
+     */
+    setRuleSelector: function(ruleId, nodeId, newSelector, successCallback, failureCallback)
+    {
+        /**
+         * @param {DOMAgent.NodeId} nodeId
+         * @param {function(WebInspector.CSSRule, boolean)} successCallback
+         * @param {CSSAgent.CSSRule} rulePayload
+         * @param {?Array.} selectedNodeIds
+         */
+        function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
+        {
+            if (!selectedNodeIds)
+                return;
+            var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
+            var rule = WebInspector.CSSRule.parsePayload(rulePayload);
+            successCallback(rule, doesAffectSelectedNode);
+        }
+
+        /**
+         * @param {DOMAgent.NodeId} nodeId
+         * @param {function(WebInspector.CSSRule, boolean)} successCallback
+         * @param {function()} failureCallback
+         * @param {?Protocol.Error} error
+         * @param {string} newSelector
+         * @param {?CSSAgent.CSSRule} rulePayload
+         */
+        function callback(nodeId, successCallback, failureCallback, newSelector, error, rulePayload)
+        {
+            this._pendingCommandsMajorState.pop();
+            if (error)
+                failureCallback();
+            else {
+                WebInspector.domAgent.markUndoableState();
+                var ownerDocumentId = this._ownerDocumentId(nodeId);
+                if (ownerDocumentId)
+                    WebInspector.domAgent.querySelectorAll(ownerDocumentId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
+                else
+                    failureCallback();
+            }
+        }
+
+        this._pendingCommandsMajorState.push(true);
+        CSSAgent.setRuleSelector(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback, newSelector));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} selector
+     * @param {function(WebInspector.CSSRule, boolean)} successCallback
+     * @param {function()} failureCallback
+     */
+    addRule: function(nodeId, selector, successCallback, failureCallback)
+    {
+        /**
+         * @param {DOMAgent.NodeId} nodeId
+         * @param {function(WebInspector.CSSRule, boolean)} successCallback
+         * @param {CSSAgent.CSSRule} rulePayload
+         * @param {?Array.} selectedNodeIds
+         */
+        function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds)
+        {
+            if (!selectedNodeIds)
+                return;
+
+            var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0);
+            var rule = WebInspector.CSSRule.parsePayload(rulePayload);
+            successCallback(rule, doesAffectSelectedNode);
+        }
+
+        /**
+         * @param {function(WebInspector.CSSRule, boolean)} successCallback
+         * @param {function()} failureCallback
+         * @param {string} selector
+         * @param {?Protocol.Error} error
+         * @param {?CSSAgent.CSSRule} rulePayload
+         */
+        function callback(successCallback, failureCallback, selector, error, rulePayload)
+        {
+            this._pendingCommandsMajorState.pop();
+            if (error) {
+                // Invalid syntax for a selector
+                failureCallback();
+            } else {
+                WebInspector.domAgent.markUndoableState();
+                var ownerDocumentId = this._ownerDocumentId(nodeId);
+                if (ownerDocumentId)
+                    WebInspector.domAgent.querySelectorAll(ownerDocumentId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload));
+                else
+                    failureCallback();
+            }
+        }
+
+        this._pendingCommandsMajorState.push(true);
+        CSSAgent.addRule(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector));
+    },
+
+    mediaQueryResultChanged: function()
+    {
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged);
+    },
+
+    /**
+     * @param {!CSSAgent.StyleSheetId} id
+     * @return {WebInspector.CSSStyleSheetHeader}
+     */
+    styleSheetHeaderForId: function(id)
+    {
+        return this._styleSheetIdToHeader[id];
+    },
+
+    /**
+     * @return {Array.}
+     */
+    styleSheetHeaders: function()
+    {
+        return Object.values(this._styleSheetIdToHeader);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    _ownerDocumentId: function(nodeId)
+    {
+        var node = WebInspector.domAgent.nodeForId(nodeId);
+        if (!node)
+            return null;
+        return node.ownerDocument ? node.ownerDocument.id : null;
+    },
+
+    /**
+     * @param {CSSAgent.StyleSheetId} styleSheetId
+     */
+    _fireStyleSheetChanged: function(styleSheetId)
+    {
+        if (!this._pendingCommandsMajorState.length)
+            return;
+
+        var majorChange = this._pendingCommandsMajorState[this._pendingCommandsMajorState.length - 1];
+
+        if (!majorChange || !styleSheetId || !this.hasEventListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged))
+            return;
+
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, majorChange: majorChange });
+    },
+
+    /**
+     * @param {!CSSAgent.CSSStyleSheetHeader} header
+     */
+    _styleSheetAdded: function(header)
+    {
+        console.assert(!this._styleSheetIdToHeader[header.styleSheetId]);
+        var styleSheetHeader = new WebInspector.CSSStyleSheetHeader(header);
+        this._styleSheetIdToHeader[header.styleSheetId] = styleSheetHeader;
+        var url = styleSheetHeader.resourceURL();
+        if (!this._styleSheetIdsForURL[url])
+            this._styleSheetIdsForURL[url] = {};
+        var frameIdToStyleSheetIds = this._styleSheetIdsForURL[url];
+        var styleSheetIds = frameIdToStyleSheetIds[styleSheetHeader.frameId];
+        if (!styleSheetIds) {
+            styleSheetIds = [];
+            frameIdToStyleSheetIds[styleSheetHeader.frameId] = styleSheetIds;
+        }
+        styleSheetIds.push(styleSheetHeader.id);
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetHeader);
+    },
+
+    /**
+     * @param {!CSSAgent.StyleSheetId} id
+     */
+    _styleSheetRemoved: function(id)
+    {
+        var header = this._styleSheetIdToHeader[id];
+        console.assert(header);
+        delete this._styleSheetIdToHeader[id];
+        var url = header.resourceURL();
+        var frameIdToStyleSheetIds = this._styleSheetIdsForURL[url];
+        frameIdToStyleSheetIds[header.frameId].remove(id);
+        if (!frameIdToStyleSheetIds[header.frameId].length) {
+            delete frameIdToStyleSheetIds[header.frameId];
+            if (!Object.keys(this._styleSheetIdsForURL[url]).length)
+                delete this._styleSheetIdsForURL[url];
+        }
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, header);
+    },
+
+    /**
+     * @param {string} url
+     * @return {Array.}
+     */
+    styleSheetIdsForURL: function(url)
+    {
+        var frameIdToStyleSheetIds = this._styleSheetIdsForURL[url];
+        if (!frameIdToStyleSheetIds)
+            return [];
+
+        var result = [];
+        for (var frameId in frameIdToStyleSheetIds)
+            result = result.concat(frameIdToStyleSheetIds[frameId]);
+        return result;
+    },
+
+    /**
+     * @param {string} url
+     * @return {Object.>}
+     */
+    styleSheetIdsByFrameIdForURL: function(url)
+    {
+        var styleSheetIdsForFrame = this._styleSheetIdsForURL[url];
+        if (!styleSheetIdsForFrame)
+            return {};
+        return styleSheetIdsForFrame;
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    _namedFlowCreated: function(namedFlowPayload)
+    {
+        var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload);
+        var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId];
+
+        if (!namedFlowCollection)
+            return;
+
+        namedFlowCollection._appendNamedFlow(namedFlow);
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowCreated, namedFlow);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} documentNodeId
+     * @param {string} flowName
+     */
+    _namedFlowRemoved: function(documentNodeId, flowName)
+    {
+        var namedFlowCollection = this._namedFlowCollections[documentNodeId];
+
+        if (!namedFlowCollection)
+            return;
+
+        namedFlowCollection._removeNamedFlow(flowName);
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.NamedFlowRemoved, { documentNodeId: documentNodeId, flowName: flowName });
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    _regionLayoutUpdated: function(namedFlowPayload)
+    {
+        var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload);
+        var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId];
+
+        if (!namedFlowCollection)
+            return;
+
+        namedFlowCollection._appendNamedFlow(namedFlow);
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionLayoutUpdated, namedFlow);
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    _regionOversetChanged: function(namedFlowPayload)
+    {
+        var namedFlow = WebInspector.NamedFlow.parsePayload(namedFlowPayload);
+        var namedFlowCollection = this._namedFlowCollections[namedFlow.documentNodeId];
+
+         if (!namedFlowCollection)
+            return;
+
+        namedFlowCollection._appendNamedFlow(namedFlow);
+        this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.RegionOversetChanged, namedFlow);
+    },
+
+    /**
+     * @param {CSSAgent.StyleSheetId} styleSheetId
+     * @param {string} newText
+     * @param {boolean} majorChange
+     * @param {function(?string)} userCallback
+     */
+    setStyleSheetText: function(styleSheetId, newText, majorChange, userCallback)
+    {
+        function callback(error)
+        {
+            this._pendingCommandsMajorState.pop();
+            if (!error && majorChange)
+                WebInspector.domAgent.markUndoableState();
+            
+            if (!error && userCallback)
+                userCallback(error);
+        }
+        this._pendingCommandsMajorState.push(majorChange);
+        CSSAgent.setStyleSheetText(styleSheetId, newText, callback.bind(this));
+    },
+
+    _undoRedoRequested: function()
+    {
+        this._pendingCommandsMajorState.push(true);
+    },
+
+    _undoRedoCompleted: function()
+    {
+        this._pendingCommandsMajorState.pop();
+    },
+
+    _mainFrameCreatedOrNavigated: function()
+    {
+        this._resetStyleSheets();
+    },
+
+    _resetStyleSheets: function()
+    {
+        /** @type {!Object.>>} */
+        this._styleSheetIdsForURL = {};
+        /** @type {!Object.} */
+        this._styleSheetIdToHeader = {};
+    },
+
+    _resetNamedFlowCollections: function()
+    {
+        this._namedFlowCollections = {};
+    },
+
+    updateLocations: function()
+    {
+        var headers = Object.values(this._styleSheetIdToHeader);
+        for (var i = 0; i < headers.length; ++i)
+            headers[i].updateLocations();
+    },
+
+    /**
+     * @param {CSSAgent.StyleSheetId} styleSheetId
+     * @param {WebInspector.CSSLocation} rawLocation
+     * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
+     * @return {?WebInspector.LiveLocation}
+     */
+    createLiveLocation: function(styleSheetId, rawLocation, updateDelegate)
+    {
+        if (!rawLocation)
+            return null;
+        var header = this.styleSheetHeaderForId(styleSheetId);
+        if (!header)
+            return null;
+        return header.createLiveLocation(rawLocation, updateDelegate);
+    },
+
+    /**
+     * @param {WebInspector.CSSLocation} rawLocation
+     * @return {?WebInspector.UILocation}
+     */
+    rawLocationToUILocation: function(rawLocation)
+    {
+        var frameIdToSheetIds = this._styleSheetIdsForURL[rawLocation.url];
+        if (!frameIdToSheetIds)
+            return null;
+        var styleSheetIds = [];
+        for (var frameId in frameIdToSheetIds)
+            styleSheetIds = styleSheetIds.concat(frameIdToSheetIds[frameId]);
+        var uiLocation;
+        for (var i = 0; !uiLocation && i < styleSheetIds.length; ++i) {
+            var header = this.styleSheetHeaderForId(styleSheetIds[i]);
+            console.assert(header);
+            uiLocation = header.rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
+        }
+        return uiLocation || null;
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.LiveLocation}
+ * @param {WebInspector.CSSLocation} rawLocation
+ * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
+ */
+WebInspector.CSSStyleModel.LiveLocation = function(rawLocation, updateDelegate, header)
+{
+    WebInspector.LiveLocation.call(this, rawLocation, updateDelegate);
+    this._header = header;
+}
+
+WebInspector.CSSStyleModel.LiveLocation.prototype = {
+    /**
+     * @return {WebInspector.UILocation}
+     */
+    uiLocation: function()
+    {
+        var cssLocation = /** @type WebInspector.CSSLocation */ (this.rawLocation());
+        return this._header.rawLocationToUILocation(cssLocation.lineNumber, cssLocation.columnNumber);
+    },
+
+    dispose: function()
+    {
+        WebInspector.LiveLocation.prototype.dispose.call(this);
+        this._header._removeLocation(this);
+    },
+
+    __proto__: WebInspector.LiveLocation.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.RawLocation}
+ * @param {string} url
+ * @param {number} lineNumber
+ * @param {number=} columnNumber
+ */
+WebInspector.CSSLocation = function(url, lineNumber, columnNumber)
+{
+    this.url = url;
+    this.lineNumber = lineNumber;
+    this.columnNumber = columnNumber || 0;
+}
+
+/**
+ * @constructor
+ * @param {CSSAgent.CSSStyle} payload
+ */
+WebInspector.CSSStyleDeclaration = function(payload)
+{
+    this.id = payload.styleId;
+    this.width = payload.width;
+    this.height = payload.height;
+    this.range = payload.range;
+    this._shorthandValues = WebInspector.CSSStyleDeclaration.buildShorthandValueMap(payload.shorthandEntries);
+    this._livePropertyMap = {}; // LIVE properties (source-based or style-based) : { name -> CSSProperty }
+    this._allProperties = []; // ALL properties: [ CSSProperty ]
+    this.__disabledProperties = {}; // DISABLED properties: { index -> CSSProperty }
+    var payloadPropertyCount = payload.cssProperties.length;
+
+    var propertyIndex = 0;
+    for (var i = 0; i < payloadPropertyCount; ++i) {
+        var property = WebInspector.CSSProperty.parsePayload(this, i, payload.cssProperties[i]);
+        this._allProperties.push(property);
+        if (property.disabled)
+            this.__disabledProperties[i] = property;
+        if (!property.active && !property.styleBased)
+            continue;
+        var name = property.name;
+        this[propertyIndex] = name;
+        this._livePropertyMap[name] = property;
+        ++propertyIndex;
+    }
+    this.length = propertyIndex;
+    if ("cssText" in payload)
+        this.cssText = payload.cssText;
+}
+
+/**
+ * @param {Array.} shorthandEntries
+ * @return {Object}
+ */
+WebInspector.CSSStyleDeclaration.buildShorthandValueMap = function(shorthandEntries)
+{
+    var result = {};
+    for (var i = 0; i < shorthandEntries.length; ++i)
+        result[shorthandEntries[i].name] = shorthandEntries[i].value;
+    return result;
+}
+
+/**
+ * @param {CSSAgent.CSSStyle} payload
+ * @return {WebInspector.CSSStyleDeclaration}
+ */
+WebInspector.CSSStyleDeclaration.parsePayload = function(payload)
+{
+    return new WebInspector.CSSStyleDeclaration(payload);
+}
+
+/**
+ * @param {Array.} payload
+ * @return {WebInspector.CSSStyleDeclaration}
+ */
+WebInspector.CSSStyleDeclaration.parseComputedStylePayload = function(payload)
+{
+    var newPayload = /** @type {CSSAgent.CSSStyle} */ ({ cssProperties: [], shorthandEntries: [], width: "", height: "" });
+    if (payload)
+        newPayload.cssProperties = payload;
+
+    return new WebInspector.CSSStyleDeclaration(newPayload);
+}
+
+WebInspector.CSSStyleDeclaration.prototype = {
+    get allProperties()
+    {
+        return this._allProperties;
+    },
+
+    /**
+     * @param {string} name
+     * @return {WebInspector.CSSProperty|undefined}
+     */
+    getLiveProperty: function(name)
+    {
+        return this._livePropertyMap[name];
+    },
+
+    /**
+     * @param {string} name
+     * @return {string}
+     */
+    getPropertyValue: function(name)
+    {
+        var property = this._livePropertyMap[name];
+        return property ? property.value : "";
+    },
+
+    /**
+     * @param {string} name
+     * @return {string}
+     */
+    getPropertyPriority: function(name)
+    {
+        var property = this._livePropertyMap[name];
+        return property ? property.priority : "";
+    },
+
+    /**
+     * @param {string} name
+     * @return {boolean}
+     */
+    isPropertyImplicit: function(name)
+    {
+        var property = this._livePropertyMap[name];
+        return property ? property.implicit : "";
+    },
+
+    /**
+     * @param {string} name
+     * @return {Array.}
+     */
+    longhandProperties: function(name)
+    {
+        var longhands = WebInspector.CSSMetadata.cssPropertiesMetainfo.longhands(name);
+        var result = [];
+        for (var i = 0; longhands && i < longhands.length; ++i) {
+            var property = this._livePropertyMap[longhands[i]];
+            if (property)
+                result.push(property);
+        }
+        return result;
+    },
+
+    /**
+     * @param {string} shorthandProperty
+     * @return {string}
+     */
+    shorthandValue: function(shorthandProperty)
+    {
+        return this._shorthandValues[shorthandProperty];
+    },
+
+    /**
+     * @param {number} index
+     * @return {?WebInspector.CSSProperty}
+     */
+    propertyAt: function(index)
+    {
+        return (index < this.allProperties.length) ? this.allProperties[index] : null;
+    },
+
+    /**
+     * @return {number}
+     */
+    pastLastSourcePropertyIndex: function()
+    {
+        for (var i = this.allProperties.length - 1; i >= 0; --i) {
+            var property = this.allProperties[i];
+            if (property.active || property.disabled)
+                return i + 1;
+        }
+        return 0;
+    },
+
+    /**
+     * @param {number=} index
+     */
+    newBlankProperty: function(index)
+    {
+        index = (typeof index === "undefined") ? this.pastLastSourcePropertyIndex() : index;
+        return new WebInspector.CSSProperty(this, index, "", "", "", "active", true, false, "");
+    },
+
+    /**
+     * @param {number} index
+     * @param {string} name
+     * @param {string} value
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    insertPropertyAt: function(index, name, value, userCallback)
+    {
+        /**
+         * @param {?string} error
+         * @param {CSSAgent.CSSStyle} payload
+         */
+        function callback(error, payload)
+        {
+            WebInspector.cssModel._pendingCommandsMajorState.pop();
+            if (!userCallback)
+                return;
+
+            if (error) {
+                console.error(error);
+                userCallback(null);
+            } else
+                userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload));
+        }
+
+        if (!this.id)
+            throw "No style id";
+
+        WebInspector.cssModel._pendingCommandsMajorState.push(true);
+        CSSAgent.setPropertyText(this.id, index, name + ": " + value + ";", false, callback.bind(this));
+    },
+
+    /**
+     * @param {string} name
+     * @param {string} value
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    appendProperty: function(name, value, userCallback)
+    {
+        this.insertPropertyAt(this.allProperties.length, name, value, userCallback);
+    },
+
+    /**
+     * @param {string} text
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    setText: function(text, userCallback)
+    {
+        /**
+         * @param {?string} error
+         * @param {CSSAgent.CSSStyle} payload
+         */
+        function callback(error, payload)
+        {
+            WebInspector.cssModel._pendingCommandsMajorState.pop();
+            if (!userCallback)
+                return;
+
+            if (error) {
+                console.error(error);
+                userCallback(null);
+            } else
+                userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload));
+        }
+
+        if (!this.id)
+            throw "No style id";
+
+        if (typeof this.cssText === "undefined") {
+            userCallback(null);
+            return;
+        }
+
+        WebInspector.cssModel._pendingCommandsMajorState.push(true);
+        CSSAgent.setStyleText(this.id, text, callback);
+    }
+}
+
+/**
+ * @constructor
+ * @param {CSSAgent.CSSRule} payload
+ * @param {Array.=} matchingSelectors
+ */
+WebInspector.CSSRule = function(payload, matchingSelectors)
+{
+    this.id = payload.ruleId;
+    if (matchingSelectors)
+        this.matchingSelectors = matchingSelectors;
+    this.selectors = payload.selectorList.selectors;
+    this.selectorText = this.selectors.join(", ");
+    this.selectorRange = payload.selectorList.range;
+    this.sourceURL = payload.sourceURL;
+    this.origin = payload.origin;
+    this.style = WebInspector.CSSStyleDeclaration.parsePayload(payload.style);
+    this.style.parentRule = this;
+    if (payload.media)
+        this.media = WebInspector.CSSMedia.parseMediaArrayPayload(payload.media);
+    this._setRawLocationAndFrameId();
+}
+
+/**
+ * @param {CSSAgent.CSSRule} payload
+ * @param {Array.=} matchingIndices
+ * @return {WebInspector.CSSRule}
+ */
+WebInspector.CSSRule.parsePayload = function(payload, matchingIndices)
+{
+    return new WebInspector.CSSRule(payload, matchingIndices);
+}
+
+WebInspector.CSSRule.prototype = {
+    _setRawLocationAndFrameId: function()
+    {
+        if (!this.id)
+            return;
+        var styleSheetHeader = WebInspector.cssModel.styleSheetHeaderForId(this.id.styleSheetId);
+        this.frameId = styleSheetHeader.frameId;
+        var url = styleSheetHeader.resourceURL();
+        if (!url)
+            return;
+        this.rawLocation = new WebInspector.CSSLocation(url, this.lineNumberInSource(), this.columnNumberInSource());
+    },
+
+    /**
+     * @return {string}
+     */
+    resourceURL: function()
+    {
+        if (!this.id)
+            return "";
+        var styleSheetHeader = WebInspector.cssModel.styleSheetHeaderForId(this.id.styleSheetId);
+        return styleSheetHeader.resourceURL();
+    },
+
+    /**
+     * @return {number}
+     */
+    lineNumberInSource: function()
+    {
+        if (!this.selectorRange)
+            return 0;
+        var styleSheetHeader = WebInspector.cssModel.styleSheetHeaderForId(this.id.styleSheetId);
+        return styleSheetHeader.lineNumberInSource(this.selectorRange.startLine);
+    },
+
+    /**
+     * @return {number|undefined}
+     */
+    columnNumberInSource: function()
+    {
+        if (!this.selectorRange)
+            return undefined;
+        var styleSheetHeader = WebInspector.cssModel.styleSheetHeaderForId(this.id.styleSheetId);
+        console.assert(styleSheetHeader);
+        return styleSheetHeader.columnNumberInSource(this.selectorRange.startLine, this.selectorRange.startColumn);
+    },
+
+    get isUserAgent()
+    {
+        return this.origin === "user-agent";
+    },
+
+    get isUser()
+    {
+        return this.origin === "user";
+    },
+
+    get isViaInspector()
+    {
+        return this.origin === "inspector";
+    },
+
+    get isRegular()
+    {
+        return this.origin === "regular";
+    }
+}
+
+/**
+ * @constructor
+ * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
+ * @param {number} index
+ * @param {string} name
+ * @param {string} value
+ * @param {?string} priority
+ * @param {string} status
+ * @param {boolean} parsedOk
+ * @param {boolean} implicit
+ * @param {?string=} text
+ * @param {CSSAgent.SourceRange=} range
+ */
+WebInspector.CSSProperty = function(ownerStyle, index, name, value, priority, status, parsedOk, implicit, text, range)
+{
+    this.ownerStyle = ownerStyle;
+    this.index = index;
+    this.name = name;
+    this.value = value;
+    this.priority = priority;
+    this.status = status;
+    this.parsedOk = parsedOk;
+    this.implicit = implicit;
+    this.text = text;
+    this.range = range;
+}
+
+/**
+ * @param {?WebInspector.CSSStyleDeclaration} ownerStyle
+ * @param {number} index
+ * @param {CSSAgent.CSSProperty} payload
+ * @return {WebInspector.CSSProperty}
+ */
+WebInspector.CSSProperty.parsePayload = function(ownerStyle, index, payload)
+{
+    // The following default field values are used in the payload:
+    // priority: ""
+    // parsedOk: true
+    // implicit: false
+    // status: "style"
+    var result = new WebInspector.CSSProperty(
+        ownerStyle, index, payload.name, payload.value, payload.priority || "", payload.status || "style", ("parsedOk" in payload) ? !!payload.parsedOk : true, !!payload.implicit, payload.text, payload.range);
+    return result;
+}
+
+WebInspector.CSSProperty.prototype = {
+    get propertyText()
+    {
+        if (this.text !== undefined)
+            return this.text;
+
+        if (this.name === "")
+            return "";
+        return this.name + ": " + this.value + (this.priority ? " !" + this.priority : "") + ";";
+    },
+
+    get isLive()
+    {
+        return this.active || this.styleBased;
+    },
+
+    get active()
+    {
+        return this.status === "active";
+    },
+
+    get styleBased()
+    {
+        return this.status === "style";
+    },
+
+    get inactive()
+    {
+        return this.status === "inactive";
+    },
+
+    get disabled()
+    {
+        return this.status === "disabled";
+    },
+
+    /**
+     * Replaces "propertyName: propertyValue [!important];" in the stylesheet by an arbitrary propertyText.
+     *
+     * @param {string} propertyText
+     * @param {boolean} majorChange
+     * @param {boolean} overwrite
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    setText: function(propertyText, majorChange, overwrite, userCallback)
+    {
+        /**
+         * @param {?WebInspector.CSSStyleDeclaration} style
+         */
+        function enabledCallback(style)
+        {
+            if (userCallback)
+                userCallback(style);
+        }
+
+        /**
+         * @param {?string} error
+         * @param {?CSSAgent.CSSStyle} stylePayload
+         */
+        function callback(error, stylePayload)
+        {
+            WebInspector.cssModel._pendingCommandsMajorState.pop();
+            if (!error) {
+                if (majorChange)
+                    WebInspector.domAgent.markUndoableState();
+                this.text = propertyText;
+                var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
+                var newProperty = style.allProperties[this.index];
+
+                if (newProperty && this.disabled && !propertyText.match(/^\s*$/)) {
+                    newProperty.setDisabled(false, enabledCallback);
+                    return;
+                }
+
+                if (userCallback)
+                    userCallback(style);
+            } else {
+                if (userCallback)
+                    userCallback(null);
+            }
+        }
+
+        if (!this.ownerStyle)
+            throw "No ownerStyle for property";
+
+        if (!this.ownerStyle.id)
+            throw "No owner style id";
+
+        // An index past all the properties adds a new property to the style.
+        WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
+        CSSAgent.setPropertyText(this.ownerStyle.id, this.index, propertyText, overwrite, callback.bind(this));
+    },
+
+    /**
+     * @param {string} newValue
+     * @param {boolean} majorChange
+     * @param {boolean} overwrite
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    setValue: function(newValue, majorChange, overwrite, userCallback)
+    {
+        var text = this.name + ": " + newValue + (this.priority ? " !" + this.priority : "") + ";"
+        this.setText(text, majorChange, overwrite, userCallback);
+    },
+
+    /**
+     * @param {boolean} disabled
+     * @param {function(?WebInspector.CSSStyleDeclaration)=} userCallback
+     */
+    setDisabled: function(disabled, userCallback)
+    {
+        if (!this.ownerStyle && userCallback)
+            userCallback(null);
+        if (disabled === this.disabled && userCallback)
+            userCallback(this.ownerStyle);
+
+        /**
+         * @param {?string} error
+         * @param {CSSAgent.CSSStyle} stylePayload
+         */
+        function callback(error, stylePayload)
+        {
+            WebInspector.cssModel._pendingCommandsMajorState.pop();
+            if (error) {
+                if (userCallback)
+                    userCallback(null);
+                return;
+            }
+            WebInspector.domAgent.markUndoableState();
+            if (userCallback) {
+                var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload);
+                userCallback(style);
+            }
+        }
+
+        if (!this.ownerStyle.id)
+            throw "No owner style id";
+
+        WebInspector.cssModel._pendingCommandsMajorState.push(false);
+        CSSAgent.toggleProperty(this.ownerStyle.id, this.index, disabled, callback.bind(this));
+    },
+
+    /**
+     * @param {boolean} forName
+     * @return {WebInspector.UILocation}
+     */
+    uiLocation: function(forName)
+    {
+        if (!this.range || !this.ownerStyle || !this.ownerStyle.parentRule)
+            return null;
+
+        var url = this.ownerStyle.parentRule.resourceURL();
+        if (!url)
+            return null;
+
+        var range = this.range;
+        var line = forName ? range.startLine : range.endLine;
+        // End of range is exclusive, so subtract 1 from the end offset.
+        var column = forName ? range.startColumn : range.endColumn - (this.text && this.text.endsWith(";") ? 2 : 1);
+        var rawLocation = new WebInspector.CSSLocation(url, line, column);
+        return WebInspector.cssModel.rawLocationToUILocation(rawLocation);
+    }
+}
+
+/**
+ * @constructor
+ * @param {CSSAgent.CSSMedia} payload
+ */
+WebInspector.CSSMedia = function(payload)
+{
+    this.text = payload.text;
+    this.source = payload.source;
+    this.sourceURL = payload.sourceURL || "";
+    this.range = payload.range;
+    this.parentStyleSheetId = payload.parentStyleSheetId;
+}
+
+WebInspector.CSSMedia.Source = {
+    LINKED_SHEET: "linkedSheet",
+    INLINE_SHEET: "inlineSheet",
+    MEDIA_RULE: "mediaRule",
+    IMPORT_RULE: "importRule"
+};
+
+/**
+ * @param {CSSAgent.CSSMedia} payload
+ * @return {WebInspector.CSSMedia}
+ */
+WebInspector.CSSMedia.parsePayload = function(payload)
+{
+    return new WebInspector.CSSMedia(payload);
+}
+
+/**
+ * @param {Array.} payload
+ * @return {Array.}
+ */
+WebInspector.CSSMedia.parseMediaArrayPayload = function(payload)
+{
+    var result = [];
+    for (var i = 0; i < payload.length; ++i)
+        result.push(WebInspector.CSSMedia.parsePayload(payload[i]));
+    return result;
+}
+
+WebInspector.CSSMedia.prototype = {
+    /**
+     * @return {number|undefined}
+     */
+    lineNumberInSource: function()
+    {
+        if (!this.range)
+            return undefined;
+        var header = this.header();
+        if (!header)
+            return undefined;
+        return header.lineNumberInSource(this.range.startLine);
+    },
+
+    /**
+     * @return {number|undefined}
+     */
+    columnNumberInSource: function()
+    {
+        if (!this.range)
+            return undefined;
+        var header = this.header();
+        if (!header)
+            return undefined;
+        return header.columnNumberInSource(this.range.startLine, this.range.startColumn);
+    },
+
+    /**
+     * @return {?WebInspector.CSSStyleSheetHeader}
+     */
+    header: function()
+    {
+        return this.parentStyleSheetId ? WebInspector.cssModel.styleSheetHeaderForId(this.parentStyleSheetId) : null;
+    }
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContentProvider}
+ * @param {CSSAgent.CSSStyleSheetHeader} payload
+ */
+WebInspector.CSSStyleSheetHeader = function(payload)
+{
+    this.id = payload.styleSheetId;
+    this.frameId = payload.frameId;
+    this.sourceURL = payload.sourceURL;
+    this.hasSourceURL = !!payload.hasSourceURL;
+    this.sourceMapURL = payload.sourceMapURL;
+    this.origin = payload.origin;
+    this.title = payload.title;
+    this.disabled = payload.disabled;
+    this.isInline = payload.isInline;
+    this.startLine = payload.startLine;
+    this.startColumn = payload.startColumn;
+    /** @type {!Set.} */
+    this._locations = new Set();
+    /** @type {!Array.} */
+    this._sourceMappings = [];
+}
+
+WebInspector.CSSStyleSheetHeader.prototype = {
+    /**
+     * @return {string}
+     */
+    resourceURL: function()
+    {
+        return this.origin === "inspector" ? this._viaInspectorResourceURL() : this.sourceURL;
+    },
+
+    /**
+     * @param {WebInspector.CSSLocation} rawLocation
+     * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
+     * @return {?WebInspector.LiveLocation}
+     */
+    createLiveLocation: function(rawLocation, updateDelegate)
+    {
+        var location = new WebInspector.CSSStyleModel.LiveLocation(rawLocation, updateDelegate, this);
+        this._locations.add(location);
+        location.update();
+        return location;
+    },
+
+    updateLocations: function()
+    {
+        var items = this._locations.items();
+        for (var i = 0; i < items.length; ++i)
+            items[i].update();
+    },
+
+    /**
+     * @param {!WebInspector.CSSStyleModel.LiveLocation} location
+     */
+    _removeLocation: function(location)
+    {
+        this._locations.remove(location);
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number=} columnNumber
+     * @return {?WebInspector.UILocation}
+     */
+    rawLocationToUILocation: function(lineNumber, columnNumber)
+    {
+        var uiLocation;
+        var rawLocation = new WebInspector.CSSLocation(this.resourceURL(), lineNumber, columnNumber || 0);
+        for (var i = this._sourceMappings.length - 1; !uiLocation && i >= 0; --i)
+            uiLocation = this._sourceMappings[i].rawLocationToUILocation(rawLocation);
+        return uiLocation || null;
+    },
+
+    /**
+     * @param {!WebInspector.SourceMapping} sourceMapping
+     */
+    pushSourceMapping: function(sourceMapping)
+    {
+        this._sourceMappings.push(sourceMapping);
+        this.updateLocations();
+    },
+
+    /**
+     * @return {string}
+     */
+    _key: function()
+    {
+        return this.frameId + ":" + this.resourceURL();
+    },
+
+    /**
+     * @return {string}
+     */
+    _viaInspectorResourceURL: function()
+    {
+        var frame = WebInspector.resourceTreeModel.frameForId(this.frameId);
+        console.assert(frame);
+        var parsedURL = new WebInspector.ParsedURL(frame.url);
+        var fakeURL = "inspector://" + parsedURL.host + parsedURL.folderPathComponents;
+        if (!fakeURL.endsWith("/"))
+            fakeURL += "/";
+        fakeURL += "inspector-stylesheet";
+        return fakeURL;
+    },
+
+    /**
+     * @param {number} lineNumberInStyleSheet
+     * @return {number}
+     */
+    lineNumberInSource: function(lineNumberInStyleSheet)
+    {
+        return this.startLine + lineNumberInStyleSheet;
+    },
+
+    /**
+     * @param {number} lineNumberInStyleSheet
+     * @param {number} columnNumberInStyleSheet
+     * @return {number|undefined}
+     */
+    columnNumberInSource: function(lineNumberInStyleSheet, columnNumberInStyleSheet)
+    {
+        return (lineNumberInStyleSheet ? 0 : this.startColumn) + columnNumberInStyleSheet;
+    },
+
+    /**
+     * @override
+     */
+    contentURL: function()
+    {
+        return this.resourceURL();
+    },
+
+    /**
+     * @override
+     */
+    contentType: function()
+    {
+        return WebInspector.resourceTypes.Stylesheet;
+    },
+
+    /**
+     * @override
+     */
+    requestContent: function(callback)
+    {
+        CSSAgent.getStyleSheetText(this.id, textCallback.bind(this));
+
+        function textCallback(error, text)
+        {
+            if (error) {
+                WebInspector.log("Failed to get text for stylesheet " + this.id + ": " + error);
+                text = "";
+                // Fall through.
+            }
+            callback(text, false, "text/css");
+        }
+    },
+
+    /**
+     * @override
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback)
+    {
+        function performSearch(content)
+        {
+            callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex));
+        }
+
+        // searchInContent should call back later.
+        this.requestContent(performSearch);
+    }
+}
+
+/**
+ * @constructor
+ * @param {CSSAgent.CSSStyleSheetBody} payload
+ */
+WebInspector.CSSStyleSheet = function(payload)
+{
+    this.id = payload.styleSheetId;
+    this.rules = [];
+    this.styles = {};
+    for (var i = 0; i < payload.rules.length; ++i) {
+        var rule = WebInspector.CSSRule.parsePayload(payload.rules[i]);
+        this.rules.push(rule);
+        if (rule.style)
+            this.styles[rule.style.id] = rule.style;
+    }
+    if ("text" in payload)
+        this._text = payload.text;
+}
+
+/**
+ * @param {CSSAgent.StyleSheetId} styleSheetId
+ * @param {function(?WebInspector.CSSStyleSheet)} userCallback
+ */
+WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback)
+{
+    /**
+     * @param {?string} error
+     * @param {CSSAgent.CSSStyleSheetBody} styleSheetPayload
+     */
+    function callback(error, styleSheetPayload)
+    {
+        if (error)
+            userCallback(null);
+        else
+            userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload));
+    }
+    CSSAgent.getStyleSheet(styleSheetId, callback.bind(this));
+}
+
+WebInspector.CSSStyleSheet.prototype = {
+    /**
+     * @return {string|undefined}
+     */
+    getText: function()
+    {
+        return this._text;
+    },
+
+    /**
+     * @param {string} newText
+     * @param {boolean} majorChange
+     * @param {function(?string)=} userCallback
+     */
+    setText: function(newText, majorChange, userCallback)
+    {
+        /**
+         * @param {?string} error
+         */
+        function callback(error)
+        {
+            if (!error)
+                WebInspector.domAgent.markUndoableState();
+
+            WebInspector.cssModel._pendingCommandsMajorState.pop();
+            if (userCallback)
+                userCallback(error);
+        }
+
+        WebInspector.cssModel._pendingCommandsMajorState.push(majorChange);
+        CSSAgent.setStyleSheetText(this.id, newText, callback.bind(this));
+    }
+}
+
+/**
+ * @constructor
+ * @implements {CSSAgent.Dispatcher}
+ * @param {WebInspector.CSSStyleModel} cssModel
+ */
+WebInspector.CSSDispatcher = function(cssModel)
+{
+    this._cssModel = cssModel;
+}
+
+WebInspector.CSSDispatcher.prototype = {
+    mediaQueryResultChanged: function()
+    {
+        this._cssModel.mediaQueryResultChanged();
+    },
+
+    /**
+     * @param {CSSAgent.StyleSheetId} styleSheetId
+     */
+    styleSheetChanged: function(styleSheetId)
+    {
+        this._cssModel._fireStyleSheetChanged(styleSheetId);
+    },
+
+    /**
+     * @param {CSSAgent.CSSStyleSheetHeader} header
+     */
+    styleSheetAdded: function(header)
+    {
+        this._cssModel._styleSheetAdded(header);
+    },
+
+    /**
+     * @param {CSSAgent.StyleSheetId} id
+     */
+    styleSheetRemoved: function(id)
+    {
+        this._cssModel._styleSheetRemoved(id);
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    namedFlowCreated: function(namedFlowPayload)
+    {
+        this._cssModel._namedFlowCreated(namedFlowPayload);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} documentNodeId
+     * @param {string} flowName
+     */
+    namedFlowRemoved: function(documentNodeId, flowName)
+    {
+        this._cssModel._namedFlowRemoved(documentNodeId, flowName);
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    regionLayoutUpdated: function(namedFlowPayload)
+    {
+        this._cssModel._regionLayoutUpdated(namedFlowPayload);
+    },
+
+    /**
+     * @param {CSSAgent.NamedFlow} namedFlowPayload
+     */
+    regionOversetChanged: function(namedFlowPayload)
+    {
+        this._cssModel._regionOversetChanged(namedFlowPayload);
+    }
+}
+
+/**
+ * @constructor
+ * @param {CSSAgent.NamedFlow} payload
+ */
+WebInspector.NamedFlow = function(payload)
+{
+    this.documentNodeId = payload.documentNodeId;
+    this.name = payload.name;
+    this.overset = payload.overset;
+    this.content = payload.content;
+    this.regions = payload.regions;
+}
+
+/**
+ * @param {CSSAgent.NamedFlow} payload
+ * @return {WebInspector.NamedFlow}
+ */
+WebInspector.NamedFlow.parsePayload = function(payload)
+{
+    return new WebInspector.NamedFlow(payload);
+}
+
+/**
+ * @constructor
+ * @param {Array.} payload
+ */
+WebInspector.NamedFlowCollection = function(payload)
+{
+    /** @type {Object.} */
+    this.namedFlowMap = {};
+
+    for (var i = 0; i < payload.length; ++i) {
+        var namedFlow = WebInspector.NamedFlow.parsePayload(payload[i]);
+        this.namedFlowMap[namedFlow.name] = namedFlow;
+    }
+}
+
+WebInspector.NamedFlowCollection.prototype = {
+    /**
+     * @param {WebInspector.NamedFlow} namedFlow
+     */
+    _appendNamedFlow: function(namedFlow)
+    {
+        this.namedFlowMap[namedFlow.name] = namedFlow;
+    },
+
+    /**
+     * @param {string} flowName
+     */
+    _removeNamedFlow: function(flowName)
+    {
+        delete this.namedFlowMap[flowName];
+    },
+
+    /**
+     * @param {string} flowName
+     * @return {WebInspector.NamedFlow}
+     */
+    flowByName: function(flowName)
+    {
+        var namedFlow = this.namedFlowMap[flowName];
+
+        if (!namedFlow)
+            return null;
+        return namedFlow;
+    }
+}
+/**
+ * @type {WebInspector.CSSStyleModel}
+ */
+WebInspector.cssModel = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleSheetMapping.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleSheetMapping.js
new file mode 100644
index 00000000..70976f09
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CSSStyleSheetMapping.js
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.CSSStyleModel} cssModel
+ * @param {WebInspector.Workspace} workspace
+ * @param {WebInspector.SimpleWorkspaceProvider} networkWorkspaceProvider
+ */
+WebInspector.CSSStyleSheetMapping = function(cssModel, workspace, networkWorkspaceProvider)
+{
+    this._cssModel = cssModel;
+    this._workspace = workspace;
+    this._stylesSourceMapping = new WebInspector.StylesSourceMapping(cssModel, workspace);
+    this._sassSourceMapping = new WebInspector.SASSSourceMapping(cssModel, workspace, networkWorkspaceProvider);
+
+    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this);
+    cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this);
+}
+
+WebInspector.CSSStyleSheetMapping.prototype = {
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _styleSheetAdded: function(event)
+    {
+        var header = /** @type {WebInspector.CSSStyleSheetHeader} */ (event.data);
+        this._stylesSourceMapping.addHeader(header);
+        this._sassSourceMapping.addHeader(header);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _styleSheetRemoved: function(event)
+    {
+        var header = /** @type {WebInspector.CSSStyleSheetHeader} */ (event.data);
+        this._stylesSourceMapping.removeHeader(header);
+        this._sassSourceMapping.removeHeader(header);
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CallStackSidebarPane.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CallStackSidebarPane.js
new file mode 100644
index 00000000..2bb8db70
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CallStackSidebarPane.js
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPane}
+ */
+WebInspector.CallStackSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, WebInspector.UIString("Call Stack"));
+    this._model = WebInspector.debuggerModel;
+
+    this.bodyElement.addEventListener("keydown", this._keyDown.bind(this), true);
+    this.bodyElement.tabIndex = 0;
+}
+
+WebInspector.CallStackSidebarPane.Events = {
+    CallFrameSelected: "CallFrameSelected"
+}
+
+WebInspector.CallStackSidebarPane.prototype = {
+    update: function(callFrames)
+    {
+        this.bodyElement.removeChildren();
+        delete this._statusMessageElement;
+        this.placards = [];
+
+        if (!callFrames) {
+            var infoElement = document.createElement("div");
+            infoElement.className = "info";
+            infoElement.textContent = WebInspector.UIString("Not Paused");
+            this.bodyElement.appendChild(infoElement);
+            return;
+        }
+
+        for (var i = 0; i < callFrames.length; ++i) {
+            var callFrame = callFrames[i];
+            var placard = new WebInspector.CallStackSidebarPane.Placard(callFrame, this);
+            placard.element.addEventListener("click", this._placardSelected.bind(this, placard), false);
+            this.placards.push(placard);
+            this.bodyElement.appendChild(placard.element);
+        }
+    },
+
+    setSelectedCallFrame: function(x)
+    {
+        for (var i = 0; i < this.placards.length; ++i) {
+            var placard = this.placards[i];
+            placard.selected = (placard._callFrame === x);
+        }
+    },
+
+    /**
+     * @param {Event=} event
+     * @return {boolean}
+     */
+    _selectNextCallFrameOnStack: function(event)
+    {
+        var index = this._selectedCallFrameIndex();
+        if (index == -1)
+            return true;
+        this._selectedPlacardByIndex(index + 1);
+        return true;
+    },
+
+    /**
+     * @param {Event=} event
+     * @return {boolean}
+     */
+    _selectPreviousCallFrameOnStack: function(event)
+    {
+        var index = this._selectedCallFrameIndex();
+        if (index == -1)
+            return true;
+        this._selectedPlacardByIndex(index - 1);
+        return true;
+    },
+
+    /**
+     * @param {number} index
+     */
+    _selectedPlacardByIndex: function(index)
+    {
+        if (index < 0 || index >= this.placards.length)
+            return;
+        this._placardSelected(this.placards[index])
+    },
+
+    /**
+     * @return {number}
+     */
+    _selectedCallFrameIndex: function()
+    {
+        if (!this._model.selectedCallFrame())
+            return -1;
+        for (var i = 0; i < this.placards.length; ++i) {
+            var placard = this.placards[i];
+            if (placard._callFrame === this._model.selectedCallFrame())
+                return i;
+        }
+        return -1;
+    },
+
+    _placardSelected: function(placard)
+    {
+        this.dispatchEventToListeners(WebInspector.CallStackSidebarPane.Events.CallFrameSelected, placard._callFrame);
+    },
+
+    _copyStackTrace: function()
+    {
+        var text = "";
+        for (var i = 0; i < this.placards.length; ++i)
+            text += this.placards[i].title + " (" + this.placards[i].subtitle + ")\n";
+        InspectorFrontendHost.copyText(text);
+    },
+
+    /**
+     * @param {function(!Array., function(Event=):boolean)} registerShortcutDelegate
+     */
+    registerShortcuts: function(registerShortcutDelegate)
+    {
+        registerShortcutDelegate(WebInspector.ScriptsPanelDescriptor.ShortcutKeys.NextCallFrame, this._selectNextCallFrameOnStack.bind(this));
+        registerShortcutDelegate(WebInspector.ScriptsPanelDescriptor.ShortcutKeys.PrevCallFrame, this._selectPreviousCallFrameOnStack.bind(this));
+    },
+
+    setStatus: function(status)
+    {
+        if (!this._statusMessageElement) {
+            this._statusMessageElement = document.createElement("div");
+            this._statusMessageElement.className = "info";
+            this.bodyElement.appendChild(this._statusMessageElement);
+        }
+        if (typeof status === "string")
+            this._statusMessageElement.textContent = status;
+        else {
+            this._statusMessageElement.removeChildren();
+            this._statusMessageElement.appendChild(status);
+        }
+    },
+
+    _keyDown: function(event)
+    {
+        if (event.altKey || event.shiftKey || event.metaKey || event.ctrlKey)
+            return;
+
+        if (event.keyIdentifier === "Up") {
+            this._selectPreviousCallFrameOnStack();
+            event.consume();
+        } else if (event.keyIdentifier === "Down") {
+            this._selectNextCallFrameOnStack();
+            event.consume();
+        }
+    },
+
+    __proto__: WebInspector.SidebarPane.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Placard}
+ * @param {WebInspector.DebuggerModel.CallFrame} callFrame
+ * @param {WebInspector.CallStackSidebarPane} pane
+ */
+WebInspector.CallStackSidebarPane.Placard = function(callFrame, pane)
+{
+    WebInspector.Placard.call(this, callFrame.functionName || WebInspector.UIString("(anonymous function)"), "");
+    callFrame.createLiveLocation(this._update.bind(this));
+    this.element.addEventListener("contextmenu", this._placardContextMenu.bind(this), true);
+    this._callFrame = callFrame;
+    this._pane = pane;
+}
+
+WebInspector.CallStackSidebarPane.Placard.prototype = {
+    _update: function(uiLocation)
+    {
+        this.subtitle = uiLocation.linkText().trimMiddle(100);
+    },
+
+    _placardContextMenu: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+
+        if (WebInspector.debuggerModel.canSetScriptSource()) {
+            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Restart frame" : "Restart Frame"), this._restartFrame.bind(this));
+            contextMenu.appendSeparator();
+        }
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy stack trace" : "Copy Stack Trace"), this._pane._copyStackTrace.bind(this._pane));
+
+        contextMenu.show();
+    },
+
+    _restartFrame: function()
+    {
+        this._callFrame.restart(undefined);
+    },
+
+    __proto__: WebInspector.Placard.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasProfileView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasProfileView.js
new file mode 100644
index 00000000..48e4bdfd
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasProfileView.js
@@ -0,0 +1,1298 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {!WebInspector.CanvasProfileHeader} profile
+ */
+WebInspector.CanvasProfileView = function(profile)
+{
+    WebInspector.View.call(this);
+    this.registerRequiredCSS("canvasProfiler.css");
+    this.element.addStyleClass("canvas-profile-view");
+    this._profile = profile;
+    this._traceLogId = profile.traceLogId();
+    this._traceLogPlayer = profile.traceLogPlayer();
+    this._linkifier = new WebInspector.Linkifier();
+
+    const defaultReplayLogWidthPercent = 0.34;
+    this._replayInfoSplitView = new WebInspector.SplitView(true, "canvasProfileViewReplaySplitLocation", defaultReplayLogWidthPercent);
+    this._replayInfoSplitView.setMainElementConstraints(defaultReplayLogWidthPercent, defaultReplayLogWidthPercent);
+    this._replayInfoSplitView.show(this.element);
+
+    this._imageSplitView = new WebInspector.SplitView(false, "canvasProfileViewSplitLocation", 300);
+    this._imageSplitView.show(this._replayInfoSplitView.firstElement());
+
+    var replayImageContainer = this._imageSplitView.firstElement();
+    replayImageContainer.id = "canvas-replay-image-container";
+    this._replayImageElement = replayImageContainer.createChild("image", "canvas-replay-image");
+    this._debugInfoElement = replayImageContainer.createChild("div", "canvas-debug-info hidden");
+    this._spinnerIcon = replayImageContainer.createChild("img", "canvas-spinner-icon hidden");
+
+    var replayLogContainer = this._imageSplitView.secondElement();
+    var controlsContainer = replayLogContainer.createChild("div", "status-bar");
+    var logGridContainer = replayLogContainer.createChild("div", "canvas-replay-log");
+
+    this._createControlButton(controlsContainer, "canvas-replay-first-step", WebInspector.UIString("First call."), this._onReplayFirstStepClick.bind(this));
+    this._createControlButton(controlsContainer, "canvas-replay-prev-step", WebInspector.UIString("Previous call."), this._onReplayStepClick.bind(this, false));
+    this._createControlButton(controlsContainer, "canvas-replay-next-step", WebInspector.UIString("Next call."), this._onReplayStepClick.bind(this, true));
+    this._createControlButton(controlsContainer, "canvas-replay-prev-draw", WebInspector.UIString("Previous drawing call."), this._onReplayDrawingCallClick.bind(this, false));
+    this._createControlButton(controlsContainer, "canvas-replay-next-draw", WebInspector.UIString("Next drawing call."), this._onReplayDrawingCallClick.bind(this, true));
+    this._createControlButton(controlsContainer, "canvas-replay-last-step", WebInspector.UIString("Last call."), this._onReplayLastStepClick.bind(this));
+
+    this._replayContextSelector = new WebInspector.StatusBarComboBox(this._onReplayContextChanged.bind(this));
+    this._replayContextSelector.createOption(WebInspector.UIString(""), WebInspector.UIString("Show screenshot of the last replayed resource."), "");
+    controlsContainer.appendChild(this._replayContextSelector.element);
+
+    this._installReplayInfoSidebarWidgets(controlsContainer);
+
+    this._replayStateView = new WebInspector.CanvasReplayStateView(this._traceLogPlayer);
+    this._replayStateView.show(this._replayInfoSplitView.secondElement());
+
+    /** @type {!Object.} */
+    this._replayContexts = {};
+
+    var columns = [
+        {title: "#", sortable: false, width: "5%"},
+        {title: WebInspector.UIString("Call"), sortable: false, width: "75%", disclosure: true},
+        {title: WebInspector.UIString("Location"), sortable: false, width: "20%"}
+    ];
+
+    this._logGrid = new WebInspector.DataGrid(columns);
+    this._logGrid.element.addStyleClass("fill");
+    this._logGrid.show(logGridContainer);
+    this._logGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, this._replayTraceLog, this);
+
+    this.element.addEventListener("mousedown", this._onMouseClick.bind(this), true);
+
+    this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._popoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), this._onHidePopover.bind(this), true);
+    this._popoverHelper.setRemoteObjectFormatter(this._hexNumbersFormatter.bind(this));
+
+    this._requestTraceLog(0);
+}
+
+/**
+ * @const
+ * @type {number}
+ */
+WebInspector.CanvasProfileView.TraceLogPollingInterval = 500;
+
+WebInspector.CanvasProfileView.prototype = {
+    dispose: function()
+    {
+        this._linkifier.reset();
+    },
+
+    get statusBarItems()
+    {
+        return [];
+    },
+
+    get profile()
+    {
+        return this._profile;
+    },
+
+    /**
+     * @override
+     * @return {Array.}
+     */
+    elementsToRestoreScrollPositionsFor: function()
+    {
+        return [this._logGrid.scrollContainer];
+    },
+
+    /**
+     * @param {!Element} controlsContainer
+     */
+    _installReplayInfoSidebarWidgets: function(controlsContainer)
+    {
+        this._replayInfoResizeWidgetElement = controlsContainer.createChild("div", "resizer-widget");
+        this._replayInfoSplitView.installResizer(this._replayInfoResizeWidgetElement);
+
+        this._toggleReplayStateSidebarButton = new WebInspector.StatusBarButton("", "right-sidebar-show-hide-button canvas-sidebar-show-hide-button", 3);
+        this._toggleReplayStateSidebarButton.addEventListener("click", clickHandler, this);
+        controlsContainer.appendChild(this._toggleReplayStateSidebarButton.element);
+        this._enableReplayInfoSidebar(false);
+
+        function clickHandler()
+        {
+            this._enableReplayInfoSidebar(this._toggleReplayStateSidebarButton.state === "left");
+        }
+    },
+
+    /**
+     * @param {boolean} show
+     */
+    _enableReplayInfoSidebar: function(show)
+    {
+        if (show) {
+            this._toggleReplayStateSidebarButton.state = "right";
+            this._toggleReplayStateSidebarButton.title = WebInspector.UIString("Hide sidebar.");
+            this._replayInfoSplitView.showBoth();
+        } else {
+            this._toggleReplayStateSidebarButton.state = "left";
+            this._toggleReplayStateSidebarButton.title = WebInspector.UIString("Show sidebar.");
+            this._replayInfoSplitView.showOnlyFirst();
+        }
+        this._replayInfoResizeWidgetElement.enableStyleClass("hidden", !show);
+    },
+
+    /**
+     * @param {Event} event
+     */
+    _onMouseClick: function(event)
+    {
+        var resourceLinkElement = event.target.enclosingNodeOrSelfWithClass("canvas-formatted-resource");
+        if (resourceLinkElement) {
+            this._enableReplayInfoSidebar(true);
+            this._replayStateView.selectResource(resourceLinkElement.__resourceId);
+            event.consume(true);
+            return;
+        }
+        if (event.target.enclosingNodeOrSelfWithClass("webkit-html-resource-link"))
+            event.consume(false);
+    },
+
+    /**
+     * @param {Element} parent
+     * @param {string} className
+     * @param {string} title
+     * @param {function(this:WebInspector.CanvasProfileView)} clickCallback
+     */
+    _createControlButton: function(parent, className, title, clickCallback)
+    {
+        var button = new WebInspector.StatusBarButton(title, className + " canvas-replay-button");
+        parent.appendChild(button.element);
+
+        button.makeLongClickEnabled();
+        button.addEventListener("click", clickCallback, this);
+        button.addEventListener("longClickDown", clickCallback, this);
+        button.addEventListener("longClickPress", clickCallback, this);
+    },
+
+    _onReplayContextChanged: function()
+    {
+        var selectedContextId = this._replayContextSelector.selectedOption().value;
+
+        /**
+         * @param {?CanvasAgent.ResourceState} resourceState
+         */
+        function didReceiveResourceState(resourceState)
+        {
+            this._enableWaitIcon(false);
+            if (selectedContextId !== this._replayContextSelector.selectedOption().value)
+                return;
+            var imageURL = (resourceState && resourceState.imageURL) || "";
+            this._replayImageElement.src = imageURL;
+            this._replayImageElement.style.visibility = imageURL ? "" : "hidden";
+        }
+
+        this._enableWaitIcon(true);
+        this._traceLogPlayer.getResourceState(selectedContextId, didReceiveResourceState.bind(this));
+    },
+
+    /**
+     * @param {boolean} forward
+     */
+    _onReplayStepClick: function(forward)
+    {
+        var selectedNode = this._logGrid.selectedNode;
+        if (!selectedNode)
+            return;
+        var nextNode = selectedNode;
+        do {
+            nextNode = forward ? nextNode.traverseNextNode(false) : nextNode.traversePreviousNode(false);
+        } while (nextNode && typeof nextNode.index !== "number");
+        (nextNode || selectedNode).revealAndSelect();
+    },
+
+    /**
+     * @param {boolean} forward
+     */
+    _onReplayDrawingCallClick: function(forward)
+    {
+        var selectedNode = this._logGrid.selectedNode;
+        if (!selectedNode)
+            return;
+        var nextNode = selectedNode;
+        while (nextNode) {
+            var sibling = forward ? nextNode.nextSibling : nextNode.previousSibling;
+            if (sibling) {
+                nextNode = sibling;
+                if (nextNode.hasChildren || nextNode.call.isDrawingCall)
+                    break;
+            } else {
+                nextNode = nextNode.parent;
+                if (!forward)
+                    break;
+            }
+        }
+        if (!nextNode && forward)
+            this._onReplayLastStepClick();
+        else
+            (nextNode || selectedNode).revealAndSelect();
+    },
+
+    _onReplayFirstStepClick: function()
+    {
+        var firstNode = this._logGrid.rootNode().children[0];
+        if (firstNode)
+            firstNode.revealAndSelect();
+    },
+
+    _onReplayLastStepClick: function()
+    {
+        var lastNode = this._logGrid.rootNode().children.peekLast();
+        if (!lastNode)
+            return;
+        while (lastNode.expanded) {
+            var lastChild = lastNode.children.peekLast();
+            if (!lastChild)
+                break;
+            lastNode = lastChild;
+        }
+        lastNode.revealAndSelect();
+    },
+
+    /**
+     * @param {boolean} enable
+     */
+    _enableWaitIcon: function(enable)
+    {
+        this._spinnerIcon.enableStyleClass("hidden", !enable);
+        this._debugInfoElement.enableStyleClass("hidden", enable);
+    },
+
+    _replayTraceLog: function()
+    {
+        if (this._pendingReplayTraceLogEvent)
+            return;
+        var index = this._selectedCallIndex();
+        if (index === -1 || index === this._lastReplayCallIndex)
+            return;
+        this._lastReplayCallIndex = index;
+        this._pendingReplayTraceLogEvent = true;
+        /**
+         * @param {CanvasAgent.ResourceState} resourceState
+         * @param {number} replayTime
+         */
+        function didReplayTraceLog(resourceState, replayTime)
+        {
+            delete this._pendingReplayTraceLogEvent;
+            this._enableWaitIcon(false);
+
+            this._debugInfoElement.textContent = "Replay time: " + Number.secondsToString(replayTime / 1000, true);
+            this._onReplayContextChanged();
+
+            if (index !== this._selectedCallIndex())
+                this._replayTraceLog();
+        }
+        this._enableWaitIcon(true);
+        this._traceLogPlayer.replayTraceLog(index, didReplayTraceLog.bind(this));
+    },
+
+    /**
+     * @param {number} offset
+     */
+    _requestTraceLog: function(offset)
+    {
+        /**
+         * @param {?CanvasAgent.TraceLog} traceLog
+         */
+        function didReceiveTraceLog(traceLog)
+        {
+            this._enableWaitIcon(false);
+            if (!traceLog)
+                return;
+            var callNodes = [];
+            var calls = traceLog.calls;
+            var index = traceLog.startOffset;
+            for (var i = 0, n = calls.length; i < n; ++i)
+                callNodes.push(this._createCallNode(index++, calls[i]));
+            var contexts = traceLog.contexts;
+            for (var i = 0, n = contexts.length; i < n; ++i) {
+                var contextId = contexts[i].resourceId || "";
+                var description = contexts[i].description || "";
+                if (this._replayContexts[contextId])
+                    continue;
+                this._replayContexts[contextId] = true;
+                this._replayContextSelector.createOption(description, WebInspector.UIString("Show screenshot of this context's canvas."), contextId);
+            }
+            this._appendCallNodes(callNodes);
+            if (traceLog.alive)
+                setTimeout(this._requestTraceLog.bind(this, index), WebInspector.CanvasProfileView.TraceLogPollingInterval);
+            else
+                this._flattenSingleFrameNode();
+            this._profile._updateCapturingStatus(traceLog);
+            this._onReplayLastStepClick(); // Automatically replay the last step.
+        }
+        this._enableWaitIcon(true);
+        this._traceLogPlayer.getTraceLog(offset, undefined, didReceiveTraceLog.bind(this));
+    },
+
+    /**
+     * @return {number}
+     */
+    _selectedCallIndex: function()
+    {
+        var node = this._logGrid.selectedNode;
+        return node ? this._peekLastRecursively(node).index : -1;
+    },
+
+    /**
+     * @param {!WebInspector.DataGridNode} node
+     * @return {!WebInspector.DataGridNode}
+     */
+    _peekLastRecursively: function(node)
+    {
+        var lastChild;
+        while ((lastChild = node.children.peekLast()))
+            node = lastChild;
+        return node;
+    },
+
+    /**
+     * @param {!Array.} callNodes
+     */
+    _appendCallNodes: function(callNodes)
+    {
+        var rootNode = this._logGrid.rootNode();
+        var frameNode = rootNode.children.peekLast();
+        if (frameNode && this._peekLastRecursively(frameNode).call.isFrameEndCall)
+            frameNode = null;
+        for (var i = 0, n = callNodes.length; i < n; ++i) {
+            if (!frameNode) {
+                var index = rootNode.children.length;
+                var data = {};
+                data[0] = "";
+                data[1] = "Frame #" + (index + 1);
+                data[2] = "";
+                frameNode = new WebInspector.DataGridNode(data);
+                frameNode.selectable = true;
+                rootNode.appendChild(frameNode);
+            }
+            var nextFrameCallIndex = i + 1;
+            while (nextFrameCallIndex < n && !callNodes[nextFrameCallIndex - 1].call.isFrameEndCall)
+                ++nextFrameCallIndex;
+            this._appendCallNodesToFrameNode(frameNode, callNodes, i, nextFrameCallIndex);
+            i = nextFrameCallIndex - 1;
+            frameNode = null;
+        }
+    },
+
+    /**
+     * @param {!WebInspector.DataGridNode} frameNode
+     * @param {!Array.} callNodes
+     * @param {number} fromIndex
+     * @param {number} toIndex not inclusive
+     */
+    _appendCallNodesToFrameNode: function(frameNode, callNodes, fromIndex, toIndex)
+    {
+        var self = this;
+        function appendDrawCallGroup()
+        {
+            var index = self._drawCallGroupsCount || 0;
+            var data = {};
+            data[0] = "";
+            data[1] = "Draw call group #" + (index + 1);
+            data[2] = "";
+            var node = new WebInspector.DataGridNode(data);
+            node.selectable = true;
+            self._drawCallGroupsCount = index + 1;
+            frameNode.appendChild(node);
+            return node;
+        }
+
+        function splitDrawCallGroup(drawCallGroup)
+        {
+            var splitIndex = 0;
+            var splitNode;
+            while ((splitNode = drawCallGroup.children[splitIndex])) {
+                if (splitNode.call.isDrawingCall)
+                    break;
+                ++splitIndex;
+            }
+            var newDrawCallGroup = appendDrawCallGroup();
+            var lastNode;
+            while ((lastNode = drawCallGroup.children[splitIndex + 1]))
+                newDrawCallGroup.appendChild(lastNode);
+            return newDrawCallGroup;
+        }
+
+        var drawCallGroup = frameNode.children.peekLast();
+        var groupHasDrawCall = false;
+        if (drawCallGroup) {
+            for (var i = 0, n = drawCallGroup.children.length; i < n; ++i) {
+                if (drawCallGroup.children[i].call.isDrawingCall) {
+                    groupHasDrawCall = true;
+                    break;
+                }
+            }
+        } else
+            drawCallGroup = appendDrawCallGroup();
+
+        for (var i = fromIndex; i < toIndex; ++i) {
+            var node = callNodes[i];
+            drawCallGroup.appendChild(node);
+            if (node.call.isDrawingCall) {
+                if (groupHasDrawCall)
+                    drawCallGroup = splitDrawCallGroup(drawCallGroup);
+                else
+                    groupHasDrawCall = true;
+            }
+        }
+    },
+
+    /**
+     * @param {number} index
+     * @param {CanvasAgent.Call} call
+     * @return {!WebInspector.DataGridNode}
+     */
+    _createCallNode: function(index, call)
+    {
+        var callViewElement = document.createElement("div");
+
+        var data = {};
+        data[0] = index + 1;
+        data[1] = callViewElement;
+        data[2] = "";
+        if (call.sourceURL) {
+            // FIXME(62725): stack trace line/column numbers are one-based.
+            var lineNumber = Math.max(0, call.lineNumber - 1) || 0;
+            var columnNumber = Math.max(0, call.columnNumber - 1) || 0;
+            data[2] = this._linkifier.linkifyLocation(call.sourceURL, lineNumber, columnNumber);
+        }
+
+        callViewElement.createChild("span", "canvas-function-name").textContent = call.functionName || "context." + call.property;
+
+        if (call.arguments) {
+            callViewElement.createTextChild("(");
+            for (var i = 0, n = call.arguments.length; i < n; ++i) {
+                var argument = /** @type {!CanvasAgent.CallArgument} */ (call.arguments[i]);
+                if (i)
+                    callViewElement.createTextChild(", ");
+                var element = WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(argument);
+                element.__argumentIndex = i;
+                callViewElement.appendChild(element);
+            }
+            callViewElement.createTextChild(")");
+        } else if (call.value) {
+            callViewElement.createTextChild(" = ");
+            callViewElement.appendChild(WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(call.value));
+        }
+
+        if (call.result) {
+            callViewElement.createTextChild(" => ");
+            callViewElement.appendChild(WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(call.result));
+        }
+
+        var node = new WebInspector.DataGridNode(data);
+        node.index = index;
+        node.selectable = true;
+        node.call = call;
+        return node;
+    },
+
+    _popoverAnchor: function(element, event)
+    {
+        var argumentElement = element.enclosingNodeOrSelfWithClass("canvas-call-argument");
+        if (!argumentElement || argumentElement.__suppressPopover)
+            return null;
+        return argumentElement;
+    },
+
+    _resolveObjectForPopover: function(argumentElement, showCallback, objectGroupName)
+    {
+        /**
+         * @param {?Protocol.Error} error
+         * @param {RuntimeAgent.RemoteObject=} result
+         * @param {CanvasAgent.ResourceState=} resourceState
+         */
+        function showObjectPopover(error, result, resourceState)
+        {
+            if (error)
+                return;
+
+            // FIXME: handle resourceState also
+            if (!result)
+                return;
+
+            this._popoverAnchorElement = argumentElement.cloneNode(true);
+            this._popoverAnchorElement.addStyleClass("canvas-popover-anchor");
+            this._popoverAnchorElement.addStyleClass("source-frame-eval-expression");
+            argumentElement.parentElement.appendChild(this._popoverAnchorElement);
+
+            var diffLeft = this._popoverAnchorElement.boxInWindow().x - argumentElement.boxInWindow().x;
+            this._popoverAnchorElement.style.left = this._popoverAnchorElement.offsetLeft - diffLeft + "px";
+
+            showCallback(WebInspector.RemoteObject.fromPayload(result), false, this._popoverAnchorElement);
+        }
+
+        var evalResult = argumentElement.__evalResult;
+        if (evalResult)
+            showObjectPopover.call(this, null, evalResult);
+        else {
+            var dataGridNode = this._logGrid.dataGridNodeFromNode(argumentElement);
+            if (!dataGridNode || typeof dataGridNode.index !== "number") {
+                this._popoverHelper.hidePopover();
+                return;
+            }
+            var callIndex = dataGridNode.index;
+            var argumentIndex = argumentElement.__argumentIndex;
+            if (typeof argumentIndex !== "number")
+                argumentIndex = -1;
+            CanvasAgent.evaluateTraceLogCallArgument(this._traceLogId, callIndex, argumentIndex, objectGroupName, showObjectPopover.bind(this));
+        }
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} object
+     * @return {string}
+     */
+    _hexNumbersFormatter: function(object)
+    {
+        if (object.type === "number") {
+            // Show enum values in hex with min length of 4 (e.g. 0x0012).
+            var str = "0000" + Number(object.description).toString(16).toUpperCase();
+            str = str.replace(/^0+(.{4,})$/, "$1");
+            return "0x" + str;
+        }
+        return object.description || "";
+    },
+
+    _onHidePopover: function()
+    {
+        if (this._popoverAnchorElement) {
+            this._popoverAnchorElement.remove()
+            delete this._popoverAnchorElement;
+        }
+    },
+
+    _flattenSingleFrameNode: function()
+    {
+        var rootNode = this._logGrid.rootNode();
+        if (rootNode.children.length !== 1)
+            return;
+        var frameNode = rootNode.children[0];
+        while (frameNode.children[0])
+            rootNode.appendChild(frameNode.children[0]);
+        rootNode.removeChild(frameNode);
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileType}
+ */
+WebInspector.CanvasProfileType = function()
+{
+    WebInspector.ProfileType.call(this, WebInspector.CanvasProfileType.TypeId, WebInspector.UIString("Capture Canvas Frame"));
+    this._nextProfileUid = 1;
+    this._recording = false;
+    this._lastProfileHeader = null;
+
+    this._capturingModeSelector = new WebInspector.StatusBarComboBox(this._dispatchViewUpdatedEvent.bind(this));
+    this._capturingModeSelector.element.title = WebInspector.UIString("Canvas capture mode.");
+    this._capturingModeSelector.createOption(WebInspector.UIString("Single Frame"), WebInspector.UIString("Capture a single canvas frame."), "");
+    this._capturingModeSelector.createOption(WebInspector.UIString("Consecutive Frames"), WebInspector.UIString("Capture consecutive canvas frames."), "1");
+
+    /** @type {!Object.} */
+    this._frameOptions = {};
+
+    /** @type {!Object.} */
+    this._framesWithCanvases = {};
+
+    this._frameSelector = new WebInspector.StatusBarComboBox(this._dispatchViewUpdatedEvent.bind(this));
+    this._frameSelector.element.title = WebInspector.UIString("Frame containing the canvases to capture.");
+    this._frameSelector.element.addStyleClass("hidden");
+    WebInspector.runtimeModel.contextLists().forEach(this._addFrame, this);
+    WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListAdded, this._frameAdded, this);
+    WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListRemoved, this._frameRemoved, this);
+
+    this._dispatcher = new WebInspector.CanvasDispatcher(this);
+    this._canvasAgentEnabled = false;
+
+    this._decorationElement = document.createElement("div");
+    this._decorationElement.className = "profile-canvas-decoration";
+    this._updateDecorationElement();
+}
+
+WebInspector.CanvasProfileType.TypeId = "CANVAS_PROFILE";
+
+WebInspector.CanvasProfileType.prototype = {
+    get statusBarItems()
+    {
+        return [this._capturingModeSelector.element, this._frameSelector.element];
+    },
+
+    get buttonTooltip()
+    {
+        if (this._isSingleFrameMode())
+            return WebInspector.UIString("Capture next canvas frame.");
+        else
+            return this._recording ? WebInspector.UIString("Stop capturing canvas frames.") : WebInspector.UIString("Start capturing canvas frames.");
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    buttonClicked: function()
+    {
+        if (!this._canvasAgentEnabled)
+            return false;
+        if (this._recording) {
+            this._recording = false;
+            this._stopFrameCapturing();
+        } else if (this._isSingleFrameMode()) {
+            this._recording = false;
+            this._runSingleFrameCapturing();
+        } else {
+            this._recording = true;
+            this._startFrameCapturing();
+        }
+        return this._recording;
+    },
+
+    _runSingleFrameCapturing: function()
+    {
+        var frameId = this._selectedFrameId();
+        CanvasAgent.captureFrame(frameId, this._didStartCapturingFrame.bind(this, frameId));
+    },
+
+    _startFrameCapturing: function()
+    {
+        var frameId = this._selectedFrameId();
+        CanvasAgent.startCapturing(frameId, this._didStartCapturingFrame.bind(this, frameId));
+    },
+
+    _stopFrameCapturing: function()
+    {
+        if (!this._lastProfileHeader)
+            return;
+        var profileHeader = this._lastProfileHeader;
+        var traceLogId = profileHeader.traceLogId();
+        this._lastProfileHeader = null;
+        function didStopCapturing()
+        {
+            profileHeader._updateCapturingStatus();
+        }
+        CanvasAgent.stopCapturing(traceLogId, didStopCapturing.bind(this));
+    },
+
+    /**
+     * @param {string|undefined} frameId
+     * @param {?Protocol.Error} error
+     * @param {CanvasAgent.TraceLogId} traceLogId
+     */
+    _didStartCapturingFrame: function(frameId, error, traceLogId)
+    {
+        if (error || this._lastProfileHeader && this._lastProfileHeader.traceLogId() === traceLogId)
+            return;
+        var profileHeader = new WebInspector.CanvasProfileHeader(this, WebInspector.UIString("Trace Log %d", this._nextProfileUid), this._nextProfileUid, traceLogId, frameId);
+        ++this._nextProfileUid;
+        this._lastProfileHeader = profileHeader;
+        this.addProfile(profileHeader);
+        profileHeader._updateCapturingStatus();
+    },
+
+    get treeItemTitle()
+    {
+        return WebInspector.UIString("CANVAS PROFILE");
+    },
+
+    get description()
+    {
+        return WebInspector.UIString("Canvas calls instrumentation");
+    },
+
+    /**
+     * @override
+     * @return {Element}
+     */
+    decorationElement: function()
+    {
+        return this._decorationElement;
+    },
+
+    /**
+     * @override
+     */
+    _reset: function()
+    {
+        WebInspector.ProfileType.prototype._reset.call(this);
+        this._nextProfileUid = 1;
+    },
+
+    /**
+     * @override
+     * @param {!WebInspector.ProfileHeader} profile
+     */
+    removeProfile: function(profile)
+    {
+        WebInspector.ProfileType.prototype.removeProfile.call(this, profile);
+        if (this._recording && profile === this._lastProfileHeader)
+            this._recording = false;
+    },
+
+    setRecordingProfile: function(isProfiling)
+    {
+        this._recording = isProfiling;
+    },
+
+    /**
+     * @override
+     * @param {string=} title
+     * @return {!WebInspector.ProfileHeader}
+     */
+    createTemporaryProfile: function(title)
+    {
+        title = title || WebInspector.UIString("Capturing\u2026");
+        return new WebInspector.CanvasProfileHeader(this, title);
+    },
+
+    /**
+     * @override
+     * @param {ProfilerAgent.ProfileHeader} profile
+     * @return {!WebInspector.ProfileHeader}
+     */
+    createProfile: function(profile)
+    {
+        return new WebInspector.CanvasProfileHeader(this, profile.title, -1);
+    },
+
+    /**
+     * @param {boolean=} forcePageReload
+     */
+    _updateDecorationElement: function(forcePageReload)
+    {
+        this._decorationElement.removeChildren();
+        this._decorationElement.createChild("div", "warning-icon-small");
+        this._decorationElement.appendChild(document.createTextNode(this._canvasAgentEnabled ? WebInspector.UIString("Canvas Profiler is enabled.") : WebInspector.UIString("Canvas Profiler is disabled.")));
+        var button = this._decorationElement.createChild("button");
+        button.type = "button";
+        button.textContent = this._canvasAgentEnabled ? WebInspector.UIString("Disable") : WebInspector.UIString("Enable");
+        button.addEventListener("click", this._onProfilerEnableButtonClick.bind(this, !this._canvasAgentEnabled), false);
+
+        if (forcePageReload) {
+            if (this._canvasAgentEnabled) {
+                /**
+                 * @param {?Protocol.Error} error
+                 * @param {boolean} result
+                 */
+                function hasUninstrumentedCanvasesCallback(error, result)
+                {
+                    if (error || result)
+                        PageAgent.reload();
+                }
+                CanvasAgent.hasUninstrumentedCanvases(hasUninstrumentedCanvasesCallback.bind(this));
+            } else {
+                for (var frameId in this._framesWithCanvases) {
+                    if (this._framesWithCanvases.hasOwnProperty(frameId)) {
+                        PageAgent.reload();
+                        break;
+                    }
+                }
+            }
+        }
+    },
+
+    /**
+     * @param {boolean} enable
+     */
+    _onProfilerEnableButtonClick: function(enable)
+    {
+        if (this._canvasAgentEnabled === enable)
+            return;
+        /**
+         * @param {?Protocol.Error} error
+         */
+        function callback(error)
+        {
+            if (error)
+                return;
+            this._canvasAgentEnabled = enable;
+            this._updateDecorationElement(true);
+            this._dispatchViewUpdatedEvent();
+        }
+        if (enable)
+            CanvasAgent.enable(callback.bind(this));
+        else
+            CanvasAgent.disable(callback.bind(this));
+    },
+
+    /**
+     * @return {boolean}
+     */
+    _isSingleFrameMode: function()
+    {
+        return !this._capturingModeSelector.selectedOption().value;
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameAdded: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        this._addFrame(contextList);
+    },
+
+    /**
+     * @param {WebInspector.FrameExecutionContextList} contextList
+     */
+    _addFrame: function(contextList)
+    {
+        var frameId = contextList.frameId;
+        var option = document.createElement("option");
+        option.text = contextList.displayName;
+        option.title = contextList.url;
+        option.value = frameId;
+
+        this._frameOptions[frameId] = option;
+
+        if (this._framesWithCanvases[frameId]) {
+            this._frameSelector.addOption(option);
+            this._dispatchViewUpdatedEvent();
+        }
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameRemoved: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        var frameId = contextList.frameId;
+        var option = this._frameOptions[frameId];
+        if (option && this._framesWithCanvases[frameId]) {
+            this._frameSelector.removeOption(option);
+            this._dispatchViewUpdatedEvent();
+        }
+        delete this._frameOptions[frameId];
+        delete this._framesWithCanvases[frameId];
+    },
+
+    /**
+     * @param {string} frameId
+     */
+    _contextCreated: function(frameId)
+    {
+        if (this._framesWithCanvases[frameId])
+            return;
+        this._framesWithCanvases[frameId] = true;
+        var option = this._frameOptions[frameId];
+        if (option) {
+            this._frameSelector.addOption(option);
+            this._dispatchViewUpdatedEvent();
+        }
+    },
+
+    /**
+     * @param {PageAgent.FrameId=} frameId
+     * @param {CanvasAgent.TraceLogId=} traceLogId
+     */
+    _traceLogsRemoved: function(frameId, traceLogId)
+    {
+        var sidebarElementsToDelete = [];
+        var sidebarElements = /** @type {!Array.} */ ((this.treeElement && this.treeElement.children) || []);
+        for (var i = 0, n = sidebarElements.length; i < n; ++i) {
+            var header = /** @type {WebInspector.CanvasProfileHeader} */ (sidebarElements[i].profile);
+            if (!header)
+                continue;
+            if (frameId && frameId !== header.frameId())
+                continue;
+            if (traceLogId && traceLogId !== header.traceLogId())
+                continue;
+            sidebarElementsToDelete.push(sidebarElements[i]);
+        }
+        for (var i = 0, n = sidebarElementsToDelete.length; i < n; ++i)
+            sidebarElementsToDelete[i].ondelete();
+    },
+
+    /**
+     * @return {string|undefined}
+     */
+    _selectedFrameId: function()
+    {
+        var option = this._frameSelector.selectedOption();
+        return option ? option.value : undefined;
+    },
+
+    _dispatchViewUpdatedEvent: function()
+    {
+        this._frameSelector.element.enableStyleClass("hidden", this._frameSelector.size() <= 1);
+        this.dispatchEventToListeners(WebInspector.ProfileType.Events.ViewUpdated);
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    isInstantProfile: function()
+    {
+        return this._isSingleFrameMode();
+    },
+
+    /**
+     * @override
+     * @return {boolean}
+     */
+    isEnabled: function()
+    {
+        return this._canvasAgentEnabled;
+    },
+
+    __proto__: WebInspector.ProfileType.prototype
+}
+
+/**
+ * @constructor
+ * @implements {CanvasAgent.Dispatcher}
+ * @param {WebInspector.CanvasProfileType} profileType
+ */
+WebInspector.CanvasDispatcher = function(profileType)
+{
+    this._profileType = profileType;
+    InspectorBackend.registerCanvasDispatcher(this);
+}
+
+WebInspector.CanvasDispatcher.prototype = {
+    /**
+     * @param {string} frameId
+     */
+    contextCreated: function(frameId)
+    {
+        this._profileType._contextCreated(frameId);
+    },
+
+    /**
+     * @param {PageAgent.FrameId=} frameId
+     * @param {CanvasAgent.TraceLogId=} traceLogId
+     */
+    traceLogsRemoved: function(frameId, traceLogId)
+    {
+        this._profileType._traceLogsRemoved(frameId, traceLogId);
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ProfileHeader}
+ * @param {!WebInspector.CanvasProfileType} type
+ * @param {string} title
+ * @param {number=} uid
+ * @param {CanvasAgent.TraceLogId=} traceLogId
+ * @param {PageAgent.FrameId=} frameId
+ */
+WebInspector.CanvasProfileHeader = function(type, title, uid, traceLogId, frameId)
+{
+    WebInspector.ProfileHeader.call(this, type, title, uid);
+    /** @type {CanvasAgent.TraceLogId} */
+    this._traceLogId = traceLogId || "";
+    this._frameId = frameId;
+    this._alive = true;
+    this._traceLogSize = 0;
+    this._traceLogPlayer = traceLogId ? new WebInspector.CanvasTraceLogPlayerProxy(traceLogId) : null;
+}
+
+WebInspector.CanvasProfileHeader.prototype = {
+    /**
+     * @return {CanvasAgent.TraceLogId}
+     */
+    traceLogId: function()
+    {
+        return this._traceLogId;
+    },
+
+    /**
+     * @return {WebInspector.CanvasTraceLogPlayerProxy}
+     */
+    traceLogPlayer: function()
+    {
+        return this._traceLogPlayer;
+    },
+
+    /**
+     * @return {PageAgent.FrameId|undefined}
+     */
+    frameId: function()
+    {
+        return this._frameId;
+    },
+
+    /**
+     * @override
+     * @return {WebInspector.ProfileSidebarTreeElement}
+     */
+    createSidebarTreeElement: function()
+    {
+        return new WebInspector.ProfileSidebarTreeElement(this, WebInspector.UIString("Trace Log %d"), "profile-sidebar-tree-item");
+    },
+
+    /**
+     * @override
+     * @param {WebInspector.ProfilesPanel} profilesPanel
+     */
+    createView: function(profilesPanel)
+    {
+        return new WebInspector.CanvasProfileView(this);
+    },
+
+    /**
+     * @override
+     */
+    dispose: function()
+    {
+        if (this._traceLogPlayer)
+            this._traceLogPlayer.dispose();
+        clearTimeout(this._requestStatusTimer);
+        this._alive = false;
+    },
+
+    /**
+     * @param {CanvasAgent.TraceLog=} traceLog
+     */
+    _updateCapturingStatus: function(traceLog)
+    {
+        if (!this.sidebarElement || !this._traceLogId)
+            return;
+
+        if (traceLog) {
+            this._alive = traceLog.alive;
+            this._traceLogSize = traceLog.totalAvailableCalls;
+        }
+
+        this.sidebarElement.subtitle = this._alive ? WebInspector.UIString("Capturing\u2026 %d calls", this._traceLogSize) : WebInspector.UIString("Captured %d calls", this._traceLogSize);
+        this.sidebarElement.wait = this._alive;
+
+        if (this._alive) {
+            clearTimeout(this._requestStatusTimer);
+            this._requestStatusTimer = setTimeout(this._requestCapturingStatus.bind(this), WebInspector.CanvasProfileView.TraceLogPollingInterval);
+        }
+    },
+
+    _requestCapturingStatus: function()
+    {
+        /**
+         * @param {?CanvasAgent.TraceLog} traceLog
+         */
+        function didReceiveTraceLog(traceLog)
+        {
+            if (!traceLog)
+                return;
+            this._alive = traceLog.alive;
+            this._traceLogSize = traceLog.totalAvailableCalls;
+            this._updateCapturingStatus();
+        }
+        this._traceLogPlayer.getTraceLog(0, 0, didReceiveTraceLog.bind(this));
+    },
+
+    __proto__: WebInspector.ProfileHeader.prototype
+}
+
+WebInspector.CanvasProfileDataGridHelper = {
+    /**
+     * @param {!CanvasAgent.CallArgument} callArgument
+     * @return {!Element}
+     */
+    createCallArgumentElement: function(callArgument)
+    {
+        if (callArgument.enumName)
+            return WebInspector.CanvasProfileDataGridHelper.createEnumValueElement(callArgument.enumName, +callArgument.description);
+        var element = document.createElement("span");
+        element.className = "canvas-call-argument";
+        var description = callArgument.description;
+        if (callArgument.type === "string") {
+            const maxStringLength = 150;
+            element.createTextChild("\"");
+            element.createChild("span", "canvas-formatted-string").textContent = description.trimMiddle(maxStringLength);
+            element.createTextChild("\"");
+            element.__suppressPopover = (description.length <= maxStringLength && !/[\r\n]/.test(description));
+            if (!element.__suppressPopover)
+                element.__evalResult = WebInspector.RemoteObject.fromPrimitiveValue(description);
+        } else {
+            var type = callArgument.subtype || callArgument.type;
+            if (type) {
+                element.addStyleClass("canvas-formatted-" + type);
+                if (["null", "undefined", "boolean", "number"].indexOf(type) >= 0)
+                    element.__suppressPopover = true;
+            }
+            element.textContent = description;
+            if (callArgument.remoteObject)
+                element.__evalResult = WebInspector.RemoteObject.fromPayload(callArgument.remoteObject);
+        }
+        if (callArgument.resourceId) {
+            element.addStyleClass("canvas-formatted-resource");
+            element.__resourceId = callArgument.resourceId;
+        }
+        return element;
+    },
+
+    /**
+     * @param {string} enumName
+     * @param {number} enumValue
+     * @return {!Element}
+     */
+    createEnumValueElement: function(enumName, enumValue)
+    {
+        var element = document.createElement("span");
+        element.className = "canvas-call-argument canvas-formatted-number";
+        element.textContent = enumName;
+        element.__evalResult = WebInspector.RemoteObject.fromPrimitiveValue(enumValue);
+        return element;
+    }
+}
+
+/**
+ * @extends {WebInspector.Object}
+ * @constructor
+ * @param {CanvasAgent.TraceLogId} traceLogId
+ */
+WebInspector.CanvasTraceLogPlayerProxy = function(traceLogId)
+{
+    this._traceLogId = traceLogId;
+    /** @type {!Object.} */
+    this._currentResourceStates = {};
+    /** @type {?CanvasAgent.ResourceId} */
+    this._defaultResourceId = null;
+}
+
+/** @enum {string} */
+WebInspector.CanvasTraceLogPlayerProxy.Events = {
+    CanvasTraceLogReceived: "CanvasTraceLogReceived",
+    CanvasReplayStateChanged: "CanvasReplayStateChanged",
+    CanvasResourceStateReceived: "CanvasResourceStateReceived",
+}
+
+WebInspector.CanvasTraceLogPlayerProxy.prototype = {
+    /**
+     * @param {number|undefined} startOffset
+     * @param {number|undefined} maxLength
+     * @param {function(?CanvasAgent.TraceLog):void} userCallback
+     */
+    getTraceLog: function(startOffset, maxLength, userCallback)
+    {
+        /**
+         * @param {?Protocol.Error} error
+         * @param {CanvasAgent.TraceLog} traceLog
+         */
+        function callback(error, traceLog)
+        {
+            if (error || !traceLog) {
+                userCallback(null);
+                return;
+            }
+            userCallback(traceLog);
+            this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasTraceLogReceived, traceLog);
+        }
+        CanvasAgent.getTraceLog(this._traceLogId, startOffset, maxLength, callback.bind(this));
+    },
+
+    dispose: function()
+    {
+        this._currentResourceStates = {};
+        CanvasAgent.dropTraceLog(this._traceLogId);
+        this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
+    },
+
+    /**
+     * @param {?CanvasAgent.ResourceId} resourceId
+     * @param {function(?CanvasAgent.ResourceState):void} userCallback
+     */
+    getResourceState: function(resourceId, userCallback)
+    {
+        resourceId = resourceId || this._defaultResourceId;
+        if (!resourceId) {
+            userCallback(null); // Has not been replayed yet.
+            return;
+        }
+        if (this._currentResourceStates[resourceId]) {
+            userCallback(this._currentResourceStates[resourceId]);
+            return;
+        }
+        /**
+         * @param {?Protocol.Error} error
+         * @param {CanvasAgent.ResourceState} resourceState
+         */
+        function callback(error, resourceState)
+        {
+            if (error || !resourceState) {
+                userCallback(null);
+                return;
+            }
+            this._currentResourceStates[resourceId] = resourceState;
+            userCallback(resourceState);
+            this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, resourceState);
+        }
+        CanvasAgent.getResourceState(this._traceLogId, resourceId, callback.bind(this));
+    },
+
+    /**
+     * @param {number} index
+     * @param {function(?CanvasAgent.ResourceState, number):void} userCallback
+     */
+    replayTraceLog: function(index, userCallback)
+    {
+        /**
+         * @param {?Protocol.Error} error
+         * @param {CanvasAgent.ResourceState} resourceState
+         * @param {number} replayTime
+         */
+        function callback(error, resourceState, replayTime)
+        {
+            this._currentResourceStates = {};
+            if (error || !resourceState) {
+                resourceState = null;
+                userCallback(null, replayTime);
+            } else {
+                this._defaultResourceId = resourceState.id;
+                this._currentResourceStates[resourceState.id] = resourceState;
+                userCallback(resourceState, replayTime);
+            }
+            this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
+            if (resourceState)
+                this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, resourceState);
+        }
+        CanvasAgent.replayTraceLog(this._traceLogId, index, callback.bind(this));
+    },
+
+    clearResourceStates: function()
+    {
+        this._currentResourceStates = {};
+        this.dispatchEventToListeners(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged);
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasReplayStateView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasReplayStateView.js
new file mode 100644
index 00000000..cebe8468
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CanvasReplayStateView.js
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {WebInspector.CanvasTraceLogPlayerProxy} traceLogPlayer
+ */
+WebInspector.CanvasReplayStateView = function(traceLogPlayer)
+{
+    WebInspector.View.call(this);
+    this.registerRequiredCSS("canvasProfiler.css");
+    this.element.addStyleClass("canvas-replay-state-view");
+    this._traceLogPlayer = traceLogPlayer;
+
+    var controlsContainer = this.element.createChild("div", "status-bar");
+    this._prevButton = this._createControlButton(controlsContainer, "canvas-replay-state-prev", WebInspector.UIString("Previous resource."), this._onResourceNavigationClick.bind(this, false));
+    this._nextButton = this._createControlButton(controlsContainer, "canvas-replay-state-next", WebInspector.UIString("Next resource."), this._onResourceNavigationClick.bind(this, true));
+    this._createControlButton(controlsContainer, "canvas-replay-state-refresh", WebInspector.UIString("Refresh."), this._onStateRefreshClick.bind(this));
+
+    this._resourceSelector = new WebInspector.StatusBarComboBox(this._onReplayResourceChanged.bind(this));
+    this._currentOption = this._resourceSelector.createOption(WebInspector.UIString(""), WebInspector.UIString("Show state of the last replayed resource."), "");
+    controlsContainer.appendChild(this._resourceSelector.element);
+
+    /** @type {!Object.} */
+    this._resourceIdToDescription = {};
+
+    /** @type {!Object.>} */
+    this._gridNodesExpandedState = {};
+    /** @type {!Object.} */
+    this._gridScrollPositions = {};
+
+    /** @type {?CanvasAgent.ResourceId} */
+    this._currentResourceId = null;
+    /** @type {!Array.} */
+    this._prevOptionsStack = [];
+    /** @type {!Array.} */
+    this._nextOptionsStack = [];
+
+    /** @type {!Array.} */
+    this._highlightedGridNodes = [];
+
+    var columns = [
+        {title: WebInspector.UIString("Name"), sortable: false, width: "50%", disclosure: true},
+        {title: WebInspector.UIString("Value"), sortable: false, width: "50%"}
+    ];
+
+    this._stateGrid = new WebInspector.DataGrid(columns);
+    this._stateGrid.element.addStyleClass("fill");
+    this._stateGrid.show(this.element);
+
+    this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasReplayStateChanged, this._onReplayResourceChanged, this);
+    this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasTraceLogReceived, this._onCanvasTraceLogReceived, this);
+    this._traceLogPlayer.addEventListener(WebInspector.CanvasTraceLogPlayerProxy.Events.CanvasResourceStateReceived, this._onCanvasResourceStateReceived, this);
+
+    this._updateButtonsEnabledState();
+}
+
+WebInspector.CanvasReplayStateView.prototype = {
+    /**
+     * @param {string} resourceId
+     */
+    selectResource: function(resourceId)
+    {
+        if (resourceId === this._resourceSelector.selectedOption().value)
+            return;
+        var option = this._resourceSelector.selectElement().firstChild;
+        for (var index = 0; option; ++index, option = option.nextSibling) {
+            if (resourceId === option.value) {
+                this._resourceSelector.setSelectedIndex(index);
+                this._onReplayResourceChanged();
+                break;
+            }
+        }
+    },
+
+    /**
+     * @param {Element} parent
+     * @param {string} className
+     * @param {string} title
+     * @param {function(this:WebInspector.CanvasProfileView)} clickCallback
+     * @return {!WebInspector.StatusBarButton}
+     */
+    _createControlButton: function(parent, className, title, clickCallback)
+    {
+        var button = new WebInspector.StatusBarButton(title, className + " canvas-replay-button");
+        parent.appendChild(button.element);
+
+        button.makeLongClickEnabled();
+        button.addEventListener("click", clickCallback, this);
+        button.addEventListener("longClickDown", clickCallback, this);
+        button.addEventListener("longClickPress", clickCallback, this);
+        return button;
+    },
+
+    /**
+     * @param {boolean} forward
+     */
+    _onResourceNavigationClick: function(forward)
+    {
+        var newOption = forward ? this._nextOptionsStack.pop() : this._prevOptionsStack.pop();
+        if (!newOption)
+            return;
+        (forward ? this._prevOptionsStack : this._nextOptionsStack).push(this._currentOption);
+        this._isNavigationButton = true;
+        this.selectResource(newOption.value);
+        delete this._isNavigationButton;
+        this._updateButtonsEnabledState();
+    },
+
+    _onStateRefreshClick: function()
+    {
+        this._traceLogPlayer.clearResourceStates();
+    },
+
+    _updateButtonsEnabledState: function()
+    {
+        this._prevButton.setEnabled(this._prevOptionsStack.length > 0);
+        this._nextButton.setEnabled(this._nextOptionsStack.length > 0);
+    },
+
+    _updateCurrentOption: function()
+    {
+        const maxStackSize = 256;
+        var selectedOption = this._resourceSelector.selectedOption();
+        if (this._currentOption === selectedOption)
+            return;
+        if (!this._isNavigationButton) {
+            this._prevOptionsStack.push(this._currentOption);
+            this._nextOptionsStack = [];
+            if (this._prevOptionsStack.length > maxStackSize)
+                this._prevOptionsStack.shift();
+            this._updateButtonsEnabledState();
+        }
+        this._currentOption = selectedOption;
+    },
+
+    /**
+     * @param {!CanvasAgent.TraceLog} traceLog
+     */
+    _collectResourcesFromTraceLog: function(traceLog)
+    {
+        /** @type {!Array.} */
+        var collectedResources = [];
+        var calls = traceLog.calls;
+        for (var i = 0, n = calls.length; i < n; ++i) {
+            var call = calls[i];
+            var args = call.arguments || [];
+            for (var j = 0; j < args.length; ++j)
+                this._collectResourceFromCallArgument(args[j], collectedResources);
+            this._collectResourceFromCallArgument(call.result, collectedResources);
+            this._collectResourceFromCallArgument(call.value, collectedResources);
+        }
+        var contexts = traceLog.contexts;
+        for (var i = 0, n = contexts.length; i < n; ++i)
+            this._collectResourceFromCallArgument(contexts[i], collectedResources);
+        this._addCollectedResourcesToSelector(collectedResources);
+    },
+
+    /**
+     * @param {!CanvasAgent.ResourceState} resourceState
+     */
+    _collectResourcesFromResourceState: function(resourceState)
+    {
+        /** @type {!Array.} */
+        var collectedResources = [];
+        this._collectResourceFromResourceStateDescriptors(resourceState.descriptors, collectedResources);
+        this._addCollectedResourcesToSelector(collectedResources);
+    },
+
+    /**
+     * @param {Array.|undefined} descriptors
+     * @param {!Array.} output
+     */
+    _collectResourceFromResourceStateDescriptors: function(descriptors, output)
+    {
+        if (!descriptors)
+            return;
+        for (var i = 0, n = descriptors.length; i < n; ++i) {
+            var descriptor = descriptors[i];
+            this._collectResourceFromCallArgument(descriptor.value, output);
+            this._collectResourceFromResourceStateDescriptors(descriptor.values, output);
+        }
+    },
+
+    /**
+     * @param {CanvasAgent.CallArgument|undefined} argument
+     * @param {!Array.} output
+     */
+    _collectResourceFromCallArgument: function(argument, output)
+    {
+        if (!argument)
+            return;
+        var resourceId = argument.resourceId;
+        if (!resourceId || this._resourceIdToDescription[resourceId])
+            return;
+        this._resourceIdToDescription[resourceId] = argument.description;
+        output.push(argument);
+    },
+
+    /**
+     * @param {!Array.} collectedResources
+     */
+    _addCollectedResourcesToSelector: function(collectedResources)
+    {
+        if (!collectedResources.length)
+            return;
+        /**
+         * @param {!CanvasAgent.CallArgument} arg1
+         * @param {!CanvasAgent.CallArgument} arg2
+         * @return {number}
+         */
+        function comparator(arg1, arg2)
+        {
+            var a = arg1.description;
+            var b = arg2.description;
+            return String.naturalOrderComparator(a, b);
+        }
+        collectedResources.sort(comparator);
+
+        var selectElement = this._resourceSelector.selectElement();
+        var currentOption = selectElement.firstChild;
+        currentOption = currentOption.nextSibling; // Skip the "" option.
+        for (var i = 0, n = collectedResources.length; i < n; ++i) {
+            var argument = collectedResources[i];
+            while (currentOption && String.naturalOrderComparator(currentOption.text, argument.description) < 0)
+                currentOption = currentOption.nextSibling;
+            var option = this._resourceSelector.createOption(argument.description, WebInspector.UIString("Show state of this resource."), argument.resourceId);
+            if (currentOption)
+                selectElement.insertBefore(option, currentOption);
+        }
+    },
+
+    _onReplayResourceChanged: function()
+    {
+        this._updateCurrentOption();
+        var selectedResourceId = this._resourceSelector.selectedOption().value;
+        /**
+         * @param {?CanvasAgent.ResourceState} resourceState
+         */
+        function didReceiveResourceState(resourceState)
+        {
+            if (selectedResourceId !== this._resourceSelector.selectedOption().value)
+                return;
+            this._showResourceState(resourceState);
+        }
+        this._traceLogPlayer.getResourceState(selectedResourceId, didReceiveResourceState.bind(this));
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _onCanvasTraceLogReceived: function(event)
+    {
+        var traceLog = /** @type {CanvasAgent.TraceLog} */ (event.data);
+        if (traceLog)
+            this._collectResourcesFromTraceLog(traceLog);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _onCanvasResourceStateReceived: function(event)
+    {
+        var resourceState = /** @type {CanvasAgent.ResourceState} */ (event.data);
+        if (resourceState)
+            this._collectResourcesFromResourceState(resourceState);
+    },
+
+    /**
+     * @param {?CanvasAgent.ResourceState} resourceState
+     */
+    _showResourceState: function(resourceState)
+    {
+        this._saveExpandedState();
+        this._saveScrollState();
+
+        var rootNode = this._stateGrid.rootNode();
+        if (!resourceState) {
+            this._currentResourceId = null;
+            this._updateDataGridHighlights([]);
+            rootNode.removeChildren();
+            return;
+        }
+
+        var nodesToHighlight = [];
+        var nameToOldGridNodes = {};
+
+        /**
+         * @param {!Object} map
+         * @param {WebInspector.DataGridNode=} node
+         */
+        function populateNameToNodesMap(map, node)
+        {
+            if (!node)
+                return;
+            for (var i = 0, child; child = node.children[i]; ++i) {
+                var item = {
+                    node: child,
+                    children: {}
+                };
+                map[child.name] = item;
+                populateNameToNodesMap(item.children, child);
+            }
+        }
+        populateNameToNodesMap(nameToOldGridNodes, rootNode);
+        rootNode.removeChildren();
+
+        /**
+         * @param {!CanvasAgent.ResourceStateDescriptor} d1
+         * @param {!CanvasAgent.ResourceStateDescriptor} d2
+         * @return {number}
+         */
+        function comparator(d1, d2)
+        {
+            var hasChildren1 = !!d1.values;
+            var hasChildren2 = !!d2.values;
+            if (hasChildren1 !== hasChildren2)
+                return hasChildren1 ? 1 : -1;
+            return String.naturalOrderComparator(d1.name, d2.name);
+        }
+        /**
+         * @param {Array.|undefined} descriptors
+         * @param {!WebInspector.DataGridNode} parent
+         * @param {Object=} nameToOldChildren
+         */
+        function appendResourceStateDescriptors(descriptors, parent, nameToOldChildren)
+        {
+            descriptors = descriptors || [];
+            descriptors.sort(comparator);
+            var oldChildren = nameToOldChildren || {};
+            for (var i = 0, n = descriptors.length; i < n; ++i) {
+                var descriptor = descriptors[i];
+                var childNode = this._createDataGridNode(descriptor);
+                parent.appendChild(childNode);
+                var oldChildrenItem = oldChildren[childNode.name] || {};
+                var oldChildNode = oldChildrenItem.node;
+                if (!oldChildNode || oldChildNode.element.textContent !== childNode.element.textContent)
+                    nodesToHighlight.push(childNode);
+                appendResourceStateDescriptors.call(this, descriptor.values, childNode, oldChildrenItem.children);
+            }
+        }
+        appendResourceStateDescriptors.call(this, resourceState.descriptors, rootNode, nameToOldGridNodes);
+
+        var shouldHighlightChanges = (this._resourceKindId(this._currentResourceId) === this._resourceKindId(resourceState.id));
+        this._currentResourceId = resourceState.id;
+        this._restoreExpandedState();
+        this._updateDataGridHighlights(shouldHighlightChanges ? nodesToHighlight : []);
+        this._restoreScrollState();
+    },
+
+    /**
+     * @param {!Array.} nodes
+     */
+    _updateDataGridHighlights: function(nodes)
+    {
+        for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i) {
+            var node = this._highlightedGridNodes[i];
+            node.element.removeStyleClass("canvas-grid-node-highlighted");
+        }
+
+        this._highlightedGridNodes = nodes;
+
+        for (var i = 0, n = this._highlightedGridNodes.length; i < n; ++i) {
+            var node = this._highlightedGridNodes[i];
+            node.element.addStyleClass("canvas-grid-node-highlighted");
+            node.reveal();
+        }
+    },
+
+    /**
+     * @param {?CanvasAgent.ResourceId} resourceId
+     * @return {string}
+     */
+    _resourceKindId: function(resourceId)
+    {
+        var description = (resourceId && this._resourceIdToDescription[resourceId]) || "";
+        return description.replace(/\d+/g, "");
+    },
+
+    /**
+     * @param {function(!WebInspector.DataGridNode, string):void} callback
+     */
+    _forEachGridNode: function(callback)
+    {
+        /**
+         * @param {!WebInspector.DataGridNode} node
+         * @param {string} key
+         */
+        function processRecursively(node, key)
+        {
+            for (var i = 0, child; child = node.children[i]; ++i) {
+                var childKey = key + "#" + child.name;
+                callback(child, childKey);
+                processRecursively(child, childKey);
+            }
+        }
+        processRecursively(this._stateGrid.rootNode(), "");
+    },
+
+    _saveExpandedState: function()
+    {
+        if (!this._currentResourceId)
+            return;
+        var expandedState = {};
+        var key = this._resourceKindId(this._currentResourceId);
+        this._gridNodesExpandedState[key] = expandedState;
+        /**
+         * @param {!WebInspector.DataGridNode} node
+         * @param {string} key
+         */
+        function callback(node, key)
+        {
+            if (node.expanded)
+                expandedState[key] = true;
+        }
+        this._forEachGridNode(callback);
+    },
+
+    _restoreExpandedState: function()
+    {
+        if (!this._currentResourceId)
+            return;
+        var key = this._resourceKindId(this._currentResourceId);
+        var expandedState = this._gridNodesExpandedState[key];
+        if (!expandedState)
+            return;
+        /**
+         * @param {!WebInspector.DataGridNode} node
+         * @param {string} key
+         */
+        function callback(node, key)
+        {
+            if (expandedState[key])
+                node.expand();
+        }
+        this._forEachGridNode(callback);
+    },
+
+    _saveScrollState: function()
+    {
+        if (!this._currentResourceId)
+            return;
+        var key = this._resourceKindId(this._currentResourceId);
+        this._gridScrollPositions[key] = {
+            scrollTop: this._stateGrid.scrollContainer.scrollTop,
+            scrollLeft: this._stateGrid.scrollContainer.scrollLeft
+        };
+    },
+
+    _restoreScrollState: function()
+    {
+        if (!this._currentResourceId)
+            return;
+        var key = this._resourceKindId(this._currentResourceId);
+        var scrollState = this._gridScrollPositions[key];
+        if (!scrollState)
+            return;
+        this._stateGrid.scrollContainer.scrollTop = scrollState.scrollTop;
+        this._stateGrid.scrollContainer.scrollLeft = scrollState.scrollLeft;
+    },
+
+    /**
+     * @param {!CanvasAgent.ResourceStateDescriptor} descriptor
+     * @return {!WebInspector.DataGridNode}
+     */
+    _createDataGridNode: function(descriptor)
+    {
+        var name = descriptor.name;
+        var callArgument = descriptor.value;
+
+        /** @type {!Element|string} */
+        var valueElement = callArgument ? WebInspector.CanvasProfileDataGridHelper.createCallArgumentElement(callArgument) : "";
+
+        /** @type {!Element|string} */
+        var nameElement = name;
+        if (typeof descriptor.enumValueForName !== "undefined")
+            nameElement = WebInspector.CanvasProfileDataGridHelper.createEnumValueElement(name, +descriptor.enumValueForName);
+
+        if (descriptor.isArray && descriptor.values) {
+            if (typeof nameElement === "string")
+                nameElement += "[" + descriptor.values.length + "]";
+            else {
+                var element = document.createElement("span");
+                element.appendChild(nameElement);
+                element.createTextChild("[" + descriptor.values.length + "]");
+                nameElement = element;
+            }
+        }
+
+        var data = {};
+        data[0] = nameElement;
+        data[1] = valueElement;
+        var node = new WebInspector.DataGridNode(data);
+        node.selectable = false;
+        node.name = name;
+        return node;
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Checkbox.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Checkbox.js
new file mode 100644
index 00000000..f71590f9
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Checkbox.js
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 Google Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {string=} tooltip
+ */
+WebInspector.Checkbox = function(label, className, tooltip)
+{
+    this.element = document.createElement('label');
+    this._inputElement = document.createElement('input');
+    this._inputElement.type = "checkbox";
+
+    this.element.className = className;
+    this.element.appendChild(this._inputElement);
+    this.element.appendChild(document.createTextNode(label));
+    if (tooltip)
+        this.element.title = tooltip;
+}
+
+WebInspector.Checkbox.prototype = {
+    set checked(checked)
+    {
+        this._inputElement.checked = checked;
+    },
+
+    get checked()
+    {
+        return this._inputElement.checked;
+    },
+
+    addEventListener: function(listener)
+    {
+        function listenerWrapper(event)
+        {
+            if (listener)
+                listener(event);
+            event.consume();
+            return true;
+        }
+
+        this._inputElement.addEventListener("click", listenerWrapper, false);
+        this.element.addEventListener("click", listenerWrapper, false);
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorTextEditor.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorTextEditor.js
new file mode 100644
index 00000000..757d3380
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorTextEditor.js
@@ -0,0 +1,1560 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+importScript("cm/codemirror.js");
+importScript("cm/css.js");
+importScript("cm/javascript.js");
+importScript("cm/xml.js");
+importScript("cm/htmlmixed.js");
+
+importScript("cm/matchbrackets.js");
+importScript("cm/closebrackets.js");
+importScript("cm/markselection.js");
+importScript("cm/comment.js");
+importScript("cm/overlay.js");
+
+importScript("cm/htmlembedded.js");
+importScript("cm/clike.js");
+importScript("cm/coffeescript.js");
+importScript("cm/php.js");
+importScript("cm/python.js");
+importScript("cm/shell.js");
+importScript("CodeMirrorUtils.js");
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @implements {WebInspector.TextEditor}
+ * @param {?string} url
+ * @param {WebInspector.TextEditorDelegate} delegate
+ */
+WebInspector.CodeMirrorTextEditor = function(url, delegate)
+{
+    WebInspector.View.call(this);
+    this._delegate = delegate;
+    this._url = url;
+
+    this.registerRequiredCSS("cm/codemirror.css");
+    this.registerRequiredCSS("cm/cmdevtools.css");
+
+    this._codeMirror = window.CodeMirror(this.element, {
+        lineNumbers: true,
+        gutters: ["CodeMirror-linenumbers"],
+        matchBrackets: true,
+        smartIndent: false,
+        styleSelectedText: true,
+        electricChars: false,
+        autoCloseBrackets: { explode: false }
+    });
+    this._codeMirror._codeMirrorTextEditor = this;
+
+    CodeMirror.keyMap["devtools-common"] = {
+        "Left": "goCharLeft",
+        "Right": "goCharRight",
+        "Up": "goLineUp",
+        "Down": "goLineDown",
+        "End": "goLineEnd",
+        "Home": "goLineStartSmart",
+        "PageUp": "goPageUp",
+        "PageDown": "goPageDown",
+        "Delete": "delCharAfter",
+        "Backspace": "delCharBefore",
+        "Tab": "defaultTab",
+        "Shift-Tab": "indentLess",
+        "Enter": "smartNewlineAndIndent",
+        "Ctrl-Space": "autocomplete"
+    };
+
+    CodeMirror.keyMap["devtools-pc"] = {
+        "Ctrl-A": "selectAll",
+        "Ctrl-Z": "undoAndReveal",
+        "Shift-Ctrl-Z": "redoAndReveal",
+        "Ctrl-Y": "redo",
+        "Ctrl-Home": "goDocStart",
+        "Ctrl-Up": "goDocStart",
+        "Ctrl-End": "goDocEnd",
+        "Ctrl-Down": "goDocEnd",
+        "Ctrl-Left": "goGroupLeft",
+        "Ctrl-Right": "goGroupRight",
+        "Alt-Left": "goLineStart",
+        "Alt-Right": "goLineEnd",
+        "Ctrl-Backspace": "delGroupBefore",
+        "Ctrl-Delete": "delGroupAfter",
+        "Ctrl-/": "toggleComment",
+        fallthrough: "devtools-common"
+    };
+
+    CodeMirror.keyMap["devtools-mac"] = {
+        "Cmd-A" : "selectAll",
+        "Cmd-Z" : "undoAndReveal",
+        "Shift-Cmd-Z": "redoAndReveal",
+        "Cmd-Up": "goDocStart",
+        "Cmd-Down": "goDocEnd",
+        "Alt-Left": "goGroupLeft",
+        "Alt-Right": "goGroupRight",
+        "Cmd-Left": "goLineStartSmart",
+        "Cmd-Right": "goLineEnd",
+        "Alt-Backspace": "delGroupBefore",
+        "Alt-Delete": "delGroupAfter",
+        "Cmd-/": "toggleComment",
+        fallthrough: "devtools-common"
+    };
+
+    WebInspector.settings.textEditorIndent.addChangeListener(this._updateEditorIndentation, this);
+    this._updateEditorIndentation();
+    WebInspector.settings.showWhitespacesInEditor.addChangeListener(this._updateCodeMirrorMode, this);
+
+    this._codeMirror.setOption("keyMap", WebInspector.isMac() ? "devtools-mac" : "devtools-pc");
+    this._codeMirror.setOption("flattenSpans", false);
+    this._codeMirror.setOption("maxHighlightLength", 1000);
+    this._codeMirror.setOption("mode", null);
+
+    this._shouldClearHistory = true;
+    this._lineSeparator = "\n";
+
+    this._tokenHighlighter = new WebInspector.CodeMirrorTextEditor.TokenHighlighter(this._codeMirror);
+    this._blockIndentController = new WebInspector.CodeMirrorTextEditor.BlockIndentController(this._codeMirror);
+    this._fixWordMovement = new WebInspector.CodeMirrorTextEditor.FixWordMovement(this._codeMirror);
+    this._autocompleteController = new WebInspector.CodeMirrorTextEditor.AutocompleteController(this, this._codeMirror);
+
+    this._codeMirror.on("change", this._change.bind(this));
+    this._codeMirror.on("beforeChange", this._beforeChange.bind(this));
+    this._codeMirror.on("gutterClick", this._gutterClick.bind(this));
+    this._codeMirror.on("cursorActivity", this._cursorActivity.bind(this));
+    this._codeMirror.on("scroll", this._scroll.bind(this));
+    this._codeMirror.on("focus", this._focus.bind(this));
+    this._codeMirror.on("blur", this._blur.bind(this));
+    this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
+
+    this.element.addStyleClass("fill");
+    this.element.style.overflow = "hidden";
+    this.element.firstChild.addStyleClass("source-code");
+    this.element.firstChild.addStyleClass("fill");
+    this._elementToWidget = new Map();
+    this._nestedUpdatesCounter = 0;
+
+    this.element.addEventListener("focus", this._handleElementFocus.bind(this), false);
+    this.element.addEventListener("keydown", this._handleKeyDown.bind(this), true);
+    this.element.tabIndex = 0;
+
+    this._setupSelectionColor();
+    this._setupWhitespaceHighlight();
+}
+
+WebInspector.CodeMirrorTextEditor.autocompleteCommand = function(codeMirror)
+{
+    codeMirror._codeMirrorTextEditor._autocompleteController.autocomplete();
+}
+CodeMirror.commands.autocomplete = WebInspector.CodeMirrorTextEditor.autocompleteCommand;
+
+CodeMirror.commands.smartNewlineAndIndent = function(codeMirror)
+{
+    codeMirror.operation(innerSmartNewlineAndIndent.bind(this, codeMirror));
+
+    function countIndent(line)
+    {
+        for(var i = 0; i < line.length; ++i) {
+            if (!WebInspector.TextUtils.isSpaceChar(line[i]))
+                return i;
+        }
+        return line.length;
+    }
+
+    function innerSmartNewlineAndIndent(codeMirror)
+    {
+        var cur = codeMirror.getCursor("start");
+        var line = codeMirror.getLine(cur.line);
+        var indent = cur.line > 0 ? countIndent(line) : 0;
+        if (cur.ch <= indent) {
+            codeMirror.replaceSelection("\n" + line.substring(0, cur.ch), "end", "+input");
+            codeMirror.setSelection(new CodeMirror.Pos(cur.line + 1, cur.ch));
+        } else
+            codeMirror.execCommand("newlineAndIndent");
+    }
+}
+
+CodeMirror.commands.undoAndReveal = function(codemirror)
+{
+    var scrollInfo = codemirror.getScrollInfo();
+    codemirror.execCommand("undo");
+    var cursor = codemirror.getCursor("start");
+    codemirror._codeMirrorTextEditor._innerRevealLine(cursor.line, scrollInfo);
+}
+
+CodeMirror.commands.redoAndReveal = function(codemirror)
+{
+    var scrollInfo = codemirror.getScrollInfo();
+    codemirror.execCommand("redo");
+    var cursor = codemirror.getCursor("start");
+    codemirror._codeMirrorTextEditor._innerRevealLine(cursor.line, scrollInfo);
+}
+
+WebInspector.CodeMirrorTextEditor.LongLineModeLineLengthThreshold = 2000;
+WebInspector.CodeMirrorTextEditor.MaximumNumberOfWhitespacesPerSingleSpan = 16;
+
+WebInspector.CodeMirrorTextEditor.prototype = {
+    wasShown: function()
+    {
+        this._codeMirror.refresh();
+    },
+
+    _guessIndentationLevel: function()
+    {
+        var tabRegex = /^\t+/;
+        var tabLines = 0;
+        var indents = {};
+        function processLine(lineHandle)
+        {
+            var text = lineHandle.text;
+            if (text.length === 0 || !WebInspector.TextUtils.isSpaceChar(text[0]))
+                return;
+            if (tabRegex.test(text)) {
+                ++tabLines;
+                return;
+            }
+            var i = 0;
+            while (i < text.length && WebInspector.TextUtils.isSpaceChar(text[i]))
+                ++i;
+            if (i % 2 !== 0)
+                return;
+            indents[i] = 1 + (indents[i] || 0);
+        }
+        this._codeMirror.eachLine(processLine);
+
+        var onePercentFilterThreshold = this.linesCount / 100;
+        if (tabLines && tabLines > onePercentFilterThreshold)
+            return "\t";
+        var minimumIndent = Infinity;
+        for (var i in indents) {
+            if (indents[i] < onePercentFilterThreshold)
+                continue;
+            var indent = parseInt(i, 10);
+            if (minimumIndent > indent)
+                minimumIndent = indent;
+        }
+        if (minimumIndent === Infinity)
+            return WebInspector.TextUtils.Indent.FourSpaces;
+        return new Array(minimumIndent + 1).join(" ");
+    },
+
+    _updateEditorIndentation: function()
+    {
+        var extraKeys = {};
+        var indent = WebInspector.settings.textEditorIndent.get();
+        if (WebInspector.settings.textEditorAutoDetectIndent.get())
+            indent = this._guessIndentationLevel();
+        if (indent === WebInspector.TextUtils.Indent.TabCharacter) {
+            this._codeMirror.setOption("indentWithTabs", true);
+            this._codeMirror.setOption("indentUnit", 4);
+        } else {
+            this._codeMirror.setOption("indentWithTabs", false);
+            this._codeMirror.setOption("indentUnit", indent.length);
+            extraKeys.Tab = function(codeMirror)
+            {
+                if (codeMirror.somethingSelected())
+                    return CodeMirror.Pass;
+                var pos = codeMirror.getCursor("head");
+                codeMirror.replaceRange(indent.substring(pos.ch % indent.length), codeMirror.getCursor());
+            }
+        }
+        this._codeMirror.setOption("extraKeys", extraKeys);
+        this._indentationLevel = indent;
+    },
+
+    /**
+     * @return {string}
+     */
+    indent: function()
+    {
+        return this._indentationLevel;
+    },
+
+    /**
+     * @param {!RegExp} regex
+     * @param {WebInspector.TextRange} range
+     */
+    highlightSearchResults: function(regex, range)
+    {
+        function innerHighlightRegex()
+        {
+            if (range) {
+                this.revealLine(range.startLine);
+                this.setSelection(WebInspector.TextRange.createFromLocation(range.startLine, range.startColumn));
+            } else {
+                // Collapse selection to end on search start so that we jump to next occurence on the first enter press.
+                this.setSelection(this.selection().collapseToEnd());
+            }
+            this._tokenHighlighter.highlightSearchResults(regex, range);
+        }
+
+        this._codeMirror.operation(innerHighlightRegex.bind(this));
+    },
+
+    cancelSearchResultsHighlight: function()
+    {
+        this._codeMirror.operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
+    },
+
+    undo: function()
+    {
+        this._codeMirror.undo();
+    },
+
+    redo: function()
+    {
+        this._codeMirror.redo();
+    },
+
+    _setupSelectionColor: function()
+    {
+        if (WebInspector.CodeMirrorTextEditor._selectionStyleInjected)
+            return;
+        WebInspector.CodeMirrorTextEditor._selectionStyleInjected = true;
+        var backgroundColor = WebInspector.getSelectionBackgroundColor();
+        var backgroundColorRule = backgroundColor ? ".CodeMirror .CodeMirror-selected { background-color: " + backgroundColor + ";}" : "";
+        var foregroundColor = WebInspector.getSelectionForegroundColor();
+        var foregroundColorRule = foregroundColor ? ".CodeMirror .CodeMirror-selectedtext:not(.CodeMirror-persist-highlight) { color: " + foregroundColor + "!important;}" : "";
+        if (!foregroundColorRule && !backgroundColorRule)
+            return;
+
+        var style = document.createElement("style");
+        style.textContent = backgroundColorRule + foregroundColorRule;
+        document.head.appendChild(style);
+    },
+
+    _setupWhitespaceHighlight: function()
+    {
+        if (WebInspector.CodeMirrorTextEditor._whitespaceStyleInjected || !WebInspector.settings.showWhitespacesInEditor.get())
+            return;
+        WebInspector.CodeMirrorTextEditor._whitespaceStyleInjected = true;
+        const classBase = ".cm-whitespace-";
+        const spaceChar = "·";
+        var spaceChars = "";
+        var rules = "";
+        for(var i = 1; i <= WebInspector.CodeMirrorTextEditor.MaximumNumberOfWhitespacesPerSingleSpan; ++i) {
+            spaceChars += spaceChar;
+            var rule = classBase + i + "::before { content: '" + spaceChars + "';}\n";
+            rules += rule;
+        }
+        rules += ".cm-tab:before { display: block !important; }\n";
+        var style = document.createElement("style");
+        style.textContent = rules;
+        document.head.appendChild(style);
+    },
+
+    _handleKeyDown: function(e)
+    {
+        if (this._autocompleteController.keyDown(e))
+            e.consume(true);
+    },
+
+    _shouldProcessWordForAutocompletion: function(word)
+    {
+        return word.length && (word[0] < '0' || word[0] > '9');
+    },
+
+    /**
+     * @param {string} text
+     */
+    _addTextToCompletionDictionary: function(text)
+    {
+        var words = WebInspector.TextUtils.textToWords(text);
+        for(var i = 0; i < words.length; ++i) {
+            if (this._shouldProcessWordForAutocompletion(words[i]))
+                this._dictionary.addWord(words[i]);
+        }
+    },
+
+    /**
+     * @param {string} text
+     */
+    _removeTextFromCompletionDictionary: function(text)
+    {
+        var words = WebInspector.TextUtils.textToWords(text);
+        for(var i = 0; i < words.length; ++i) {
+            if (this._shouldProcessWordForAutocompletion(words[i]))
+                this._dictionary.removeWord(words[i]);
+        }
+    },
+
+    /**
+     * @param {WebInspector.CompletionDictionary} dictionary
+     */
+    setCompletionDictionary: function(dictionary)
+    {
+        this._dictionary = dictionary;
+        this._addTextToCompletionDictionary(this.text());
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @return {?{x: number, y: number, height: number}}
+     */
+    cursorPositionToCoordinates: function(lineNumber, column)
+    {
+        if (lineNumber >= this._codeMirror.lineCount() || lineNumber < 0 || column < 0 || column > this._codeMirror.getLine(lineNumber).length)
+            return null;
+
+        var metrics = this._codeMirror.cursorCoords(new CodeMirror.Pos(lineNumber, column));
+
+        return {
+            x: metrics.left,
+            y: metrics.top,
+            height: metrics.bottom - metrics.top
+        };
+    },
+
+    /**
+     * @param {number} x
+     * @param {number} y
+     * @return {?WebInspector.TextRange}
+     */
+    coordinatesToCursorPosition: function(x, y)
+    {
+        var element = document.elementFromPoint(x, y);
+        if (!element || !element.isSelfOrDescendant(this._codeMirror.getWrapperElement()))
+            return null;
+        var gutterBox = this._codeMirror.getGutterElement().boxInWindow();
+        if (x >= gutterBox.x && x <= gutterBox.x + gutterBox.width &&
+            y >= gutterBox.y && y <= gutterBox.y + gutterBox.height)
+            return null;
+        var coords = this._codeMirror.coordsChar({left: x, top: y});
+        return this._toRange(coords, coords);
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @return {?{startColumn: number, endColumn: number, type: string}}
+     */
+    tokenAtTextPosition: function(lineNumber, column)
+    {
+        if (lineNumber < 0 || lineNumber >= this._codeMirror.lineCount())
+            return null;
+        var token = this._codeMirror.getTokenAt(new CodeMirror.Pos(lineNumber, (column || 0) + 1));
+        if (!token || !token.type)
+            return null;
+        var convertedType = WebInspector.CodeMirrorUtils.convertTokenType(token.type);
+        if (!convertedType)
+            return null;
+        return {
+            startColumn: token.start,
+            endColumn: token.end - 1,
+            type: convertedType
+        };
+    },
+
+    /**
+     * @param {WebInspector.TextRange} textRange
+     * @return {string}
+     */
+    copyRange: function(textRange)
+    {
+        var pos = this._toPos(textRange.normalize());
+        return this._codeMirror.getRange(pos.start, pos.end);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isClean: function()
+    {
+        return this._codeMirror.isClean();
+    },
+
+    markClean: function()
+    {
+        this._codeMirror.markClean();
+    },
+
+    _hasLongLines: function()
+    {
+        function lineIterator(lineHandle)
+        {
+            if (lineHandle.text.length > WebInspector.CodeMirrorTextEditor.LongLineModeLineLengthThreshold)
+                hasLongLines = true;
+            return hasLongLines;
+        }
+        var hasLongLines = false;
+        this._codeMirror.eachLine(lineIterator);
+        return hasLongLines;
+    },
+
+    /**
+     * @param {string} mimeType
+     * @return {string}
+     */
+    _whitespaceOverlayMode: function(mimeType)
+    {
+        var modeName = CodeMirror.mimeModes[mimeType] + "+whitespaces";
+        if (CodeMirror.modes[modeName])
+            return modeName;
+
+        function modeConstructor(config, parserConfig)
+        {
+            function nextToken(stream)
+            {
+                if (stream.peek() === " ") {
+                    var spaces = 0;
+                    while (spaces < WebInspector.CodeMirrorTextEditor.MaximumNumberOfWhitespacesPerSingleSpan && stream.peek() === " ") {
+                        ++spaces;
+                        stream.next();
+                    }
+                    return "whitespace whitespace-" + spaces;
+                }
+                while (!stream.eol() && stream.peek() !== " ")
+                    stream.next();
+                return null;
+            }
+            var whitespaceMode = {
+                token: nextToken
+            };
+            return CodeMirror.overlayMode(CodeMirror.getMode(config, mimeType), whitespaceMode, false);
+        }
+        CodeMirror.defineMode(modeName, modeConstructor);
+        return modeName;
+    },
+
+    _enableLongLinesMode: function()
+    {
+        this._codeMirror.setOption("styleSelectedText", false);
+        this._longLinesMode = true;
+    },
+
+    _disableLongLinesMode: function()
+    {
+        this._codeMirror.setOption("styleSelectedText", true);
+        this._longLinesMode = false;
+    },
+
+    _updateCodeMirrorMode: function()
+    {
+        var showWhitespaces = WebInspector.settings.showWhitespacesInEditor.get();
+        this._codeMirror.setOption("mode", showWhitespaces ? this._whitespaceOverlayMode(this._mimeType) : this._mimeType);
+    },
+
+    /**
+     * @param {string} mimeType
+     */
+    setMimeType: function(mimeType)
+    {
+        this._mimeType = mimeType;
+        if (this._hasLongLines())
+            this._enableLongLinesMode();
+        else
+            this._disableLongLinesMode();
+        this._updateCodeMirrorMode();
+    },
+
+    /**
+     * @param {boolean} readOnly
+     */
+    setReadOnly: function(readOnly)
+    {
+        this.element.enableStyleClass("CodeMirror-readonly", readOnly)
+        this._codeMirror.setOption("readOnly", readOnly);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    readOnly: function()
+    {
+        return !!this._codeMirror.getOption("readOnly");
+    },
+
+    /**
+     * @param {Object} highlightDescriptor
+     */
+    removeHighlight: function(highlightDescriptor)
+    {
+        highlightDescriptor.clear();
+    },
+
+    /**
+     * @param {WebInspector.TextRange} range
+     * @param {string} cssClass
+     * @return {Object}
+     */
+    highlightRange: function(range, cssClass)
+    {
+        cssClass = "CodeMirror-persist-highlight " + cssClass;
+        var pos = this._toPos(range);
+        ++pos.end.ch;
+        return this._codeMirror.markText(pos.start, pos.end, {
+            className: cssClass,
+            startStyle: cssClass + "-start",
+            endStyle: cssClass + "-end"
+        });
+    },
+
+    /**
+     * @param {string} regex
+     * @param {string} cssClass
+     * @return {Object}
+     */
+    highlightRegex: function(regex, cssClass) { },
+
+    /**
+     * @return {Element}
+     */
+    defaultFocusedElement: function()
+    {
+        return this.element;
+    },
+
+    focus: function()
+    {
+        this._codeMirror.focus();
+    },
+
+    _handleElementFocus: function()
+    {
+        this._codeMirror.focus();
+    },
+
+    beginUpdates: function()
+    {
+        ++this._nestedUpdatesCounter;
+    },
+
+    endUpdates: function()
+    {
+        if (!--this._nestedUpdatesCounter)
+            this._codeMirror.refresh();
+    },
+
+    /**
+     * @param {number} lineNumber
+     */
+    revealLine: function(lineNumber)
+    {
+        this._innerRevealLine(lineNumber, this._codeMirror.getScrollInfo());
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {{left: number, top: number, width: number, height: number, clientWidth: number, clientHeight: number}} scrollInfo
+     */
+    _innerRevealLine: function(lineNumber, scrollInfo)
+    {
+        var topLine = this._codeMirror.lineAtHeight(scrollInfo.top, "local");
+        var bottomLine = this._codeMirror.lineAtHeight(scrollInfo.top + scrollInfo.clientHeight, "local");
+        var linesPerScreen = bottomLine - topLine + 1;
+        if (lineNumber < topLine) {
+            var topLineToReveal = Math.max(lineNumber - (linesPerScreen / 2) + 1, 0) | 0;
+            this._codeMirror.scrollIntoView(new CodeMirror.Pos(topLineToReveal, 0));
+        } else if (lineNumber > bottomLine) {
+            var bottomLineToReveal = Math.min(lineNumber + (linesPerScreen / 2) - 1, this.linesCount - 1) | 0;
+            this._codeMirror.scrollIntoView(new CodeMirror.Pos(bottomLineToReveal, 0));
+        }
+    },
+
+    _gutterClick: function(instance, lineNumber, gutter, event)
+    {
+        this.dispatchEventToListeners(WebInspector.TextEditor.Events.GutterClick, { lineNumber: lineNumber, event: event });
+    },
+
+    _contextMenu: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        var target = event.target.enclosingNodeOrSelfWithClass("CodeMirror-gutter-elt");
+        if (target)
+            this._delegate.populateLineGutterContextMenu(contextMenu, parseInt(target.textContent, 10) - 1);
+        else
+            this._delegate.populateTextAreaContextMenu(contextMenu, 0);
+        contextMenu.show();
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {boolean} disabled
+     * @param {boolean} conditional
+     */
+    addBreakpoint: function(lineNumber, disabled, conditional)
+    {
+        if (lineNumber < 0 || lineNumber >= this._codeMirror.lineCount())
+            return;
+        var className = "cm-breakpoint" + (conditional ? " cm-breakpoint-conditional" : "") + (disabled ? " cm-breakpoint-disabled" : "");
+        this._codeMirror.addLineClass(lineNumber, "wrap", className);
+    },
+
+    /**
+     * @param {number} lineNumber
+     */
+    removeBreakpoint: function(lineNumber)
+    {
+        if (lineNumber < 0 || lineNumber >= this._codeMirror.lineCount())
+            return;
+        var wrapClasses = this._codeMirror.getLineHandle(lineNumber).wrapClass;
+        if (!wrapClasses)
+            return;
+        var classes = wrapClasses.split(" ");
+        for(var i = 0; i < classes.length; ++i) {
+            if (classes[i].startsWith("cm-breakpoint"))
+                this._codeMirror.removeLineClass(lineNumber, "wrap", classes[i]);
+        }
+    },
+
+    /**
+     * @param {number} lineNumber
+     */
+    setExecutionLine: function(lineNumber)
+    {
+        this._executionLine = this._codeMirror.getLineHandle(lineNumber);
+        this._codeMirror.addLineClass(this._executionLine, "wrap", "cm-execution-line");
+    },
+
+    clearExecutionLine: function()
+    {
+        if (this._executionLine)
+            this._codeMirror.removeLineClass(this._executionLine, "wrap", "cm-execution-line");
+        delete this._executionLine;
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {Element} element
+     */
+    addDecoration: function(lineNumber, element)
+    {
+        var widget = this._codeMirror.addLineWidget(lineNumber, element);
+        this._elementToWidget.put(element, widget);
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {Element} element
+     */
+    removeDecoration: function(lineNumber, element)
+    {
+        var widget = this._elementToWidget.remove(element);
+        if (widget)
+            this._codeMirror.removeLineWidget(widget);
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number=} columnNumber
+     */
+    highlightPosition: function(lineNumber, columnNumber)
+    {
+        if (lineNumber < 0)
+            return;
+        lineNumber = Math.min(lineNumber, this._codeMirror.lineCount() - 1);
+        if (typeof columnNumber !== "number" || columnNumber < 0 || columnNumber > this._codeMirror.getLine(lineNumber).length)
+            columnNumber = 0;
+
+        this.clearPositionHighlight();
+        this._highlightedLine = this._codeMirror.getLineHandle(lineNumber);
+        if (!this._highlightedLine)
+          return;
+        this.revealLine(lineNumber);
+        this._codeMirror.addLineClass(this._highlightedLine, null, "cm-highlight");
+        this._clearHighlightTimeout = setTimeout(this.clearPositionHighlight.bind(this), 2000);
+        if (!this.readOnly())
+            this._codeMirror.setSelection(new CodeMirror.Pos(lineNumber, columnNumber));
+    },
+
+    clearPositionHighlight: function()
+    {
+        if (this._clearHighlightTimeout)
+            clearTimeout(this._clearHighlightTimeout);
+        delete this._clearHighlightTimeout;
+
+         if (this._highlightedLine)
+            this._codeMirror.removeLineClass(this._highlightedLine, null, "cm-highlight");
+        delete this._highlightedLine;
+    },
+
+    /**
+     * @return {Array.}
+     */
+    elementsToRestoreScrollPositionsFor: function()
+    {
+        return [];
+    },
+
+    /**
+     * @param {WebInspector.TextEditor} textEditor
+     */
+    inheritScrollPositions: function(textEditor)
+    {
+    },
+
+    /**
+     * @param {number} width
+     * @param {number} height
+     */
+    _updatePaddingBottom: function(width, height)
+    {
+        var scrollInfo = this._codeMirror.getScrollInfo();
+        var newPaddingBottom;
+        var linesElement = this.element.firstChild.querySelector(".CodeMirror-lines");
+        var lineCount = this._codeMirror.lineCount();
+        if (lineCount <= 1)
+            newPaddingBottom = 0;
+        else
+            newPaddingBottom = Math.max(scrollInfo.clientHeight - this._codeMirror.getLineHandle(this._codeMirror.lastLine()).height, 0);
+        newPaddingBottom += "px";
+        linesElement.style.paddingBottom = newPaddingBottom;
+        this._codeMirror.setSize(width, height);
+    },
+
+    _resizeEditor: function()
+    {
+        var parentElement = this.element.parentElement;
+        if (!parentElement || !this.isShowing())
+            return;
+        var scrollInfo = this._codeMirror.getScrollInfo();
+        var width = parentElement.offsetWidth;
+        var height = parentElement.offsetHeight;
+        this._codeMirror.setSize(width, height);
+        this._updatePaddingBottom(width, height);
+        this._codeMirror.scrollTo(scrollInfo.left, scrollInfo.top);
+    },
+
+    onResize: function()
+    {
+        this._resizeEditor();
+    },
+
+    /**
+     * @param {WebInspector.TextRange} range
+     * @param {string} text
+     * @return {WebInspector.TextRange}
+     */
+    editRange: function(range, text)
+    {
+        var pos = this._toPos(range);
+        this._codeMirror.replaceRange(text, pos.start, pos.end);
+        var newRange = this._toRange(pos.start, this._codeMirror.posFromIndex(this._codeMirror.indexFromPos(pos.start) + text.length));
+        this._delegate.onTextChanged(range, newRange);
+        if (WebInspector.settings.textEditorAutoDetectIndent.get())
+            this._updateEditorIndentation();
+        return newRange;
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @param {number} column
+     * @param {boolean=} prefixOnly
+     * @return {?WebInspector.TextRange}
+     */
+    _wordRangeForCursorPosition: function(lineNumber, column, prefixOnly)
+    {
+        var line = this.line(lineNumber);
+        if (column === 0 || !WebInspector.TextUtils.isWordChar(line.charAt(column - 1)))
+            return null;
+        var wordStart = column - 1;
+        while(wordStart > 0 && WebInspector.TextUtils.isWordChar(line.charAt(wordStart - 1)))
+            --wordStart;
+        if (prefixOnly)
+            return new WebInspector.TextRange(lineNumber, wordStart, lineNumber, column);
+        var wordEnd = column;
+        while(wordEnd < line.length && WebInspector.TextUtils.isWordChar(line.charAt(wordEnd)))
+            ++wordEnd;
+        return new WebInspector.TextRange(lineNumber, wordStart, lineNumber, wordEnd);
+    },
+
+    _beforeChange: function(codeMirror, changeObject)
+    {
+        if (!this._dictionary)
+            return;
+        this._updatedLines = this._updatedLines || {};
+        for(var i = changeObject.from.line; i <= changeObject.to.line; ++i)
+            this._updatedLines[i] = this.line(i);
+    },
+
+    /**
+     * @param {CodeMirror} codeMirror
+     * @param {{origin: string, text: Array., removed: Array.}} changeObject
+     */
+    _change: function(codeMirror, changeObject)
+    {
+        // We do not show "scroll beyond end of file" span for one line documents, so we need to check if "document has one line" changed.
+        var hasOneLine = this._codeMirror.lineCount() === 1;
+        if (hasOneLine !== this._hasOneLine)
+            this._resizeEditor();
+        this._hasOneLine = hasOneLine;
+        var widgets = this._elementToWidget.values();
+        for (var i = 0; i < widgets.length; ++i)
+            this._codeMirror.removeLineWidget(widgets[i]);
+        this._elementToWidget.clear();
+
+        if (this._updatedLines) {
+            for(var lineNumber in this._updatedLines)
+                this._removeTextFromCompletionDictionary(this._updatedLines[lineNumber]);
+            delete this._updatedLines;
+        }
+
+        var linesToUpdate = {};
+        var singleCharInput = false;
+        do {
+            var oldRange = this._toRange(changeObject.from, changeObject.to);
+            var newRange = oldRange.clone();
+            var linesAdded = changeObject.text.length;
+            singleCharInput = (changeObject.origin === "+input" && changeObject.text.length === 1 && changeObject.text[0].length === 1) ||
+                (changeObject.origin === "+delete" && changeObject.removed.length === 1 && changeObject.removed[0].length === 1);
+            if (linesAdded === 0) {
+                newRange.endLine = newRange.startLine;
+                newRange.endColumn = newRange.startColumn;
+            } else if (linesAdded === 1) {
+                newRange.endLine = newRange.startLine;
+                newRange.endColumn = newRange.startColumn + changeObject.text[0].length;
+            } else {
+                newRange.endLine = newRange.startLine + linesAdded - 1;
+                newRange.endColumn = changeObject.text[linesAdded - 1].length;
+            }
+
+            if (!this._muteTextChangedEvent)
+                this._delegate.onTextChanged(oldRange, newRange);
+
+            for(var i = newRange.startLine; i <= newRange.endLine; ++i) {
+                linesToUpdate[i] = true;
+            }
+            if (this._dictionary) {
+                for(var i = newRange.startLine; i <= newRange.endLine; ++i)
+                    linesToUpdate[i] = this.line(i);
+            }
+        } while (changeObject = changeObject.next);
+        if (this._dictionary) {
+            for(var lineNumber in linesToUpdate)
+                this._addTextToCompletionDictionary(linesToUpdate[lineNumber]);
+        }
+        if (singleCharInput)
+            this._autocompleteController.autocomplete();
+    },
+
+    _cursorActivity: function()
+    {
+        var start = this._codeMirror.getCursor("anchor");
+        var end = this._codeMirror.getCursor("head");
+        this._delegate.selectionChanged(this._toRange(start, end));
+        if (!this._tokenHighlighter.highlightedRegex())
+            this._codeMirror.operation(this._tokenHighlighter.highlightSelectedTokens.bind(this._tokenHighlighter));
+    },
+
+    _scroll: function()
+    {
+        if (this._scrollTimer)
+            clearTimeout(this._scrollTimer);
+        var topmostLineNumber = this._codeMirror.lineAtHeight(this._codeMirror.getScrollInfo().top, "local");
+        this._scrollTimer = setTimeout(this._delegate.scrollChanged.bind(this._delegate, topmostLineNumber), 100);
+    },
+
+    _focus: function()
+    {
+        this._delegate.editorFocused();
+    },
+
+    _blur: function()
+    {
+        this._autocompleteController.finishAutocomplete();
+    },
+
+    /**
+     * @param {number} lineNumber
+     */
+    scrollToLine: function(lineNumber)
+    {
+        var pos = new CodeMirror.Pos(lineNumber, 0);
+        var coords = this._codeMirror.charCoords(pos, "local");
+        this._codeMirror.scrollTo(0, coords.top);
+    },
+
+    /**
+     * @return {number}
+     */
+    firstVisibleLine: function()
+    {
+        return this._codeMirror.lineAtHeight(this._codeMirror.getScrollInfo().top, "local");
+    },
+
+    /**
+     * @return {number}
+     */
+    lastVisibleLine: function()
+    {
+        var scrollInfo = this._codeMirror.getScrollInfo();
+        return this._codeMirror.lineAtHeight(scrollInfo.top + scrollInfo.clientHeight, "local");
+    },
+
+    /**
+     * @return {WebInspector.TextRange}
+     */
+    selection: function()
+    {
+        var start = this._codeMirror.getCursor("anchor");
+        var end = this._codeMirror.getCursor("head");
+
+        return this._toRange(start, end);
+    },
+
+    /**
+     * @return {WebInspector.TextRange?}
+     */
+    lastSelection: function()
+    {
+        return this._lastSelection;
+    },
+
+    /**
+     * @param {WebInspector.TextRange} textRange
+     */
+    setSelection: function(textRange)
+    {
+        this._lastSelection = textRange;
+        var pos = this._toPos(textRange);
+        this._codeMirror.setSelection(pos.start, pos.end);
+    },
+
+    /**
+     * @param {string} text
+     */
+    _detectLineSeparator: function(text)
+    {
+        this._lineSeparator = text.indexOf("\r\n") >= 0 ? "\r\n" : "\n";
+    },
+
+    /**
+     * @param {string} text
+     */
+    setText: function(text)
+    {
+        this._muteTextChangedEvent = true;
+        this._codeMirror.setValue(text);
+        this._updateEditorIndentation();
+        if (this._shouldClearHistory) {
+            this._codeMirror.clearHistory();
+            this._shouldClearHistory = false;
+        }
+        this._detectLineSeparator(text);
+        delete this._muteTextChangedEvent;
+    },
+
+    /**
+     * @return {string}
+     */
+    text: function()
+    {
+        return this._codeMirror.getValue().replace(/\n/g, this._lineSeparator);
+    },
+
+    /**
+     * @return {WebInspector.TextRange}
+     */
+    range: function()
+    {
+        var lineCount = this.linesCount;
+        var lastLine = this._codeMirror.getLine(lineCount - 1);
+        return this._toRange(new CodeMirror.Pos(0, 0), new CodeMirror.Pos(lineCount - 1, lastLine.length));
+    },
+
+    /**
+     * @param {number} lineNumber
+     * @return {string}
+     */
+    line: function(lineNumber)
+    {
+        return this._codeMirror.getLine(lineNumber);
+    },
+
+    /**
+     * @return {number}
+     */
+    get linesCount()
+    {
+        return this._codeMirror.lineCount();
+    },
+
+    /**
+     * @param {number} line
+     * @param {string} name
+     * @param {Object?} value
+     */
+    setAttribute: function(line, name, value)
+    {
+        if (line < 0 || line >= this._codeMirror.lineCount())
+            return;
+        var handle = this._codeMirror.getLineHandle(line);
+        if (handle.attributes === undefined) handle.attributes = {};
+        handle.attributes[name] = value;
+    },
+
+    /**
+     * @param {number} line
+     * @param {string} name
+     * @return {?Object} value
+     */
+    getAttribute: function(line, name)
+    {
+        if (line < 0 || line >= this._codeMirror.lineCount())
+            return null;
+        var handle = this._codeMirror.getLineHandle(line);
+        return handle.attributes && handle.attributes[name] !== undefined ? handle.attributes[name] : null;
+    },
+
+    /**
+     * @param {number} line
+     * @param {string} name
+     */
+    removeAttribute: function(line, name)
+    {
+        if (line < 0 || line >= this._codeMirror.lineCount())
+            return;
+        var handle = this._codeMirror.getLineHandle(line);
+        if (handle && handle.attributes)
+            delete handle.attributes[name];
+    },
+
+    /**
+     * @param {WebInspector.TextRange} range
+     * @return {{start: CodeMirror.Pos, end: CodeMirror.Pos}}
+     */
+    _toPos: function(range)
+    {
+        return {
+            start: new CodeMirror.Pos(range.startLine, range.startColumn),
+            end: new CodeMirror.Pos(range.endLine, range.endColumn)
+        }
+    },
+
+    _toRange: function(start, end)
+    {
+        return new WebInspector.TextRange(start.line, start.ch, end.line, end.ch);
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+/**
+ * @constructor
+ * @param {CodeMirror} codeMirror
+ */
+WebInspector.CodeMirrorTextEditor.TokenHighlighter = function(codeMirror)
+{
+    this._codeMirror = codeMirror;
+}
+
+WebInspector.CodeMirrorTextEditor.TokenHighlighter.prototype = {
+    /**
+     * @param {RegExp} regex
+     * @param {WebInspector.TextRange} range
+     */
+    highlightSearchResults: function(regex, range)
+    {
+        var oldRegex = this._highlightRegex;
+        this._highlightRegex = regex;
+        this._highlightRange = range;
+        if (this._searchResultMarker) {
+            this._searchResultMarker.clear();
+            delete this._searchResultMarker;
+        }
+        if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
+            this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, "wrap", "cm-line-with-selection");
+        var selectionStart = this._highlightRange ? new CodeMirror.Pos(this._highlightRange.startLine, this._highlightRange.startColumn) : null;
+        if (selectionStart)
+            this._codeMirror.addLineClass(selectionStart.line, "wrap", "cm-line-with-selection");
+        if (this._highlightRegex === oldRegex) {
+            // Do not re-add overlay mode if regex did not change for better performance.
+            if (this._highlightDescriptor)
+                this._highlightDescriptor.selectionStart = selectionStart;
+        } else {
+            this._removeHighlight();
+            this._setHighlighter(this._searchHighlighter.bind(this, this._highlightRegex, this._highlightRange), selectionStart);
+        }
+        if (selectionStart) {
+            var pos = WebInspector.CodeMirrorTextEditor.prototype._toPos(this._highlightRange);
+            this._searchResultMarker = this._codeMirror.markText(pos.start, pos.end, {className: "cm-column-with-selection"});
+        }
+    },
+
+    highlightedRegex: function()
+    {
+        return this._highlightRegex;
+    },
+
+    highlightSelectedTokens: function()
+    {
+        delete this._highlightRegex;
+        delete this._highlightRange;
+
+        if (this._highlightDescriptor && this._highlightDescriptor.selectionStart)
+            this._codeMirror.removeLineClass(this._highlightDescriptor.selectionStart.line, "wrap", "cm-line-with-selection");
+        this._removeHighlight();
+        var selectionStart = this._codeMirror.getCursor("start");
+        var selectionEnd = this._codeMirror.getCursor("end");
+        if (selectionStart.line !== selectionEnd.line)
+            return;
+        if (selectionStart.ch === selectionEnd.ch)
+            return;
+
+        var selectedText = this._codeMirror.getSelection();
+        if (this._isWord(selectedText, selectionStart.line, selectionStart.ch, selectionEnd.ch)) {
+            if (selectionStart)
+                this._codeMirror.addLineClass(selectionStart.line, "wrap", "cm-line-with-selection")
+            this._setHighlighter(this._tokenHighlighter.bind(this, selectedText, selectionStart), selectionStart);
+        }
+    },
+
+    /**
+     * @param {string} selectedText
+     * @param {number} lineNumber
+     * @param {number} startColumn
+     * @param {number} endColumn
+     */
+    _isWord: function(selectedText, lineNumber, startColumn, endColumn)
+    {
+        var line = this._codeMirror.getLine(lineNumber);
+        var leftBound = startColumn === 0 || !WebInspector.TextUtils.isWordChar(line.charAt(startColumn - 1));
+        var rightBound = endColumn === line.length || !WebInspector.TextUtils.isWordChar(line.charAt(endColumn));
+        return leftBound && rightBound && WebInspector.TextUtils.isWord(selectedText);
+    },
+
+    _removeHighlight: function()
+    {
+        if (this._highlightDescriptor) {
+            this._codeMirror.removeOverlay(this._highlightDescriptor.overlay);
+            delete this._highlightDescriptor;
+        }
+    },
+
+    /**
+     * @param {RegExp} regex
+     * @param {WebInspector.TextRange} range
+     * @param {CodeMirror.StringStream} stream
+     */
+    _searchHighlighter: function(regex, range, stream)
+    {
+        if (stream.column() === 0)
+            delete this._searchMatchLength;
+        if (this._searchMatchLength) {
+            if (this._searchMatchLength > 1) {
+                for (var i = 0; i < this._searchMatchLength - 2; ++i)
+                    stream.next();
+                this._searchMatchLength = 1;
+                return "search-highlight";
+            } else {
+                stream.next();
+                delete this._searchMatchLength;
+                return "search-highlight search-highlight-end";
+            }
+        }
+        var match = stream.match(regex, false);
+        if (match) {
+            stream.next();
+            var matchLength = match[0].length;
+            if (matchLength === 1)
+                return "search-highlight search-highlight-full";
+            this._searchMatchLength = matchLength;
+            return "search-highlight search-highlight-start";
+        }
+
+        while (!stream.match(regex, false) && stream.next()) {};
+    },
+
+    /**
+     * @param {string} token
+     * @param {CodeMirror.Pos} selectionStart
+     * @param {CodeMirror.StringStream} stream
+     */
+    _tokenHighlighter: function(token, selectionStart, stream)
+    {
+        var tokenFirstChar = token.charAt(0);
+        if (stream.match(token) && (stream.eol() || !WebInspector.TextUtils.isWordChar(stream.peek())))
+            return stream.column() === selectionStart.ch ? "token-highlight column-with-selection" : "token-highlight";
+
+        var eatenChar;
+        do {
+            eatenChar = stream.next();
+        } while (eatenChar && (WebInspector.TextUtils.isWordChar(eatenChar) || stream.peek() !== tokenFirstChar));
+    },
+
+    /**
+     * @param {function(CodeMirror.StringStream)} highlighter
+     */
+    _setHighlighter: function(highlighter, selectionStart)
+    {
+        var overlayMode = {
+            token: highlighter
+        };
+        this._codeMirror.addOverlay(overlayMode);
+        this._highlightDescriptor = {
+            overlay: overlayMode,
+            selectionStart: selectionStart
+        };
+    }
+}
+
+/**
+ * @constructor
+ * @param {CodeMirror} codeMirror
+ */
+WebInspector.CodeMirrorTextEditor.BlockIndentController = function(codeMirror)
+{
+    codeMirror.addKeyMap(this);
+}
+
+WebInspector.CodeMirrorTextEditor.BlockIndentController.prototype = {
+    name: "blockIndentKeymap",
+
+    Enter: function(codeMirror)
+    {
+        if (codeMirror.somethingSelected())
+            return CodeMirror.Pass;
+        var cursor = codeMirror.getCursor();
+        if (cursor.ch === 0)
+            return CodeMirror.Pass;
+        var line = codeMirror.getLine(cursor.line);
+        if (line.substr(cursor.ch - 1, 2) === "{}") {
+            codeMirror.execCommand("newlineAndIndent");
+            codeMirror.setCursor(cursor);
+            codeMirror.execCommand("newlineAndIndent");
+            codeMirror.execCommand("indentMore");
+        } else if (line.substr(cursor.ch - 1, 1) === "{") {
+            codeMirror.execCommand("newlineAndIndent");
+            codeMirror.execCommand("indentMore");
+        } else
+            return CodeMirror.Pass;
+    },
+
+    "'}'": function(codeMirror)
+    {
+        var cursor = codeMirror.getCursor();
+        var line = codeMirror.getLine(cursor.line);
+        for(var i = 0 ; i < line.length; ++i)
+            if (!WebInspector.TextUtils.isSpaceChar(line.charAt(i)))
+                return CodeMirror.Pass;
+
+        codeMirror.replaceRange("}", cursor);
+        var matchingBracket = codeMirror.findMatchingBracket();
+        if (!matchingBracket || !matchingBracket.match)
+            return;
+
+        line = codeMirror.getLine(matchingBracket.to.line);
+        var desiredIndentation = 0;
+        while (desiredIndentation < line.length && WebInspector.TextUtils.isSpaceChar(line.charAt(desiredIndentation)))
+            ++desiredIndentation;
+
+        codeMirror.replaceRange(line.substr(0, desiredIndentation) + "}", new CodeMirror.Pos(cursor.line, 0), new CodeMirror.Pos(cursor.line, cursor.ch + 1));
+    }
+}
+
+/**
+ * @constructor
+ * @param {CodeMirror} codeMirror
+ */
+WebInspector.CodeMirrorTextEditor.FixWordMovement = function(codeMirror)
+{
+    function moveLeft(shift, codeMirror)
+    {
+        var cursor = codeMirror.getCursor("head");
+        if (cursor.ch !== 0 || cursor.line === 0)
+            return CodeMirror.Pass;
+        codeMirror.setExtending(shift);
+        codeMirror.execCommand("goLineUp");
+        codeMirror.execCommand("goLineEnd")
+        codeMirror.setExtending(false);
+    }
+    function moveRight(shift, codeMirror)
+    {
+        var cursor = codeMirror.getCursor("head");
+        var line = codeMirror.getLine(cursor.line);
+        if (cursor.ch !== line.length || cursor.line + 1 === codeMirror.lineCount())
+            return CodeMirror.Pass;
+        codeMirror.setExtending(shift);
+        codeMirror.execCommand("goLineDown");
+        codeMirror.execCommand("goLineStart");
+        codeMirror.setExtending(false);
+    }
+    function delWordBack(codeMirror)
+    {
+        if (codeMirror.somethingSelected())
+            return CodeMirror.Pass;
+        var cursor = codeMirror.getCursor("head");
+        if (cursor.ch === 0)
+            codeMirror.execCommand("delCharBefore");
+        else
+            return CodeMirror.Pass;
+    }
+
+    var modifierKey = WebInspector.isMac() ? "Alt" : "Ctrl";
+    var leftKey = modifierKey + "-Left";
+    var rightKey = modifierKey + "-Right";
+    var keyMap = {};
+    keyMap[leftKey] = moveLeft.bind(this, false);
+    keyMap[rightKey] = moveRight.bind(this, false);
+    keyMap["Shift-" + leftKey] = moveLeft.bind(this, true);
+    keyMap["Shift-" + rightKey] = moveRight.bind(this, true);
+    keyMap[modifierKey + "-Backspace"] = delWordBack.bind(this);
+    codeMirror.addKeyMap(keyMap);
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.SuggestBoxDelegate}
+ * @param {WebInspector.CodeMirrorTextEditor} textEditor
+ * @param {CodeMirror} codeMirror
+ */
+WebInspector.CodeMirrorTextEditor.AutocompleteController = function(textEditor, codeMirror)
+{
+    this._textEditor = textEditor;
+    this._codeMirror = codeMirror;
+    this._codeMirror.on("scroll", this._onScroll.bind(this));
+    this._codeMirror.on("cursorActivity", this._onCursorActivity.bind(this));
+}
+
+WebInspector.CodeMirrorTextEditor.AutocompleteController.prototype = {
+    autocomplete: function()
+    {
+        var dictionary = this._textEditor._dictionary;
+        if (!dictionary || this._codeMirror.somethingSelected()) {
+            this.finishAutocomplete();
+            return;
+        }
+
+        var cursor = this._codeMirror.getCursor();
+        var substituteRange = this._textEditor._wordRangeForCursorPosition(cursor.line, cursor.ch, false);
+        if (!substituteRange || substituteRange.startColumn === cursor.ch) {
+            this.finishAutocomplete();
+            return;
+        }
+        var prefixRange = substituteRange.clone();
+        prefixRange.endColumn = cursor.ch;
+
+        var substituteWord = this._textEditor.copyRange(substituteRange);
+        var hasPrefixInDictionary = dictionary.hasWord(substituteWord);
+        if (hasPrefixInDictionary)
+            dictionary.removeWord(substituteWord);
+        var wordsWithPrefix = dictionary.wordsWithPrefix(this._textEditor.copyRange(prefixRange));
+        if (hasPrefixInDictionary)
+            dictionary.addWord(substituteWord);
+
+        function sortSuggestions(a, b)
+        {
+            return dictionary.wordCount(b) - dictionary.wordCount(a) || a.length - b.length;
+        }
+
+        wordsWithPrefix.sort(sortSuggestions);
+
+        if (!this._suggestBox) {
+            this._suggestBox = new WebInspector.SuggestBox(this, this._textEditor.element, "generic-suggest", 6);
+            this._anchorBox = this._anchorBoxForPosition(cursor.line, cursor.ch);
+        }
+        this._suggestBox.updateSuggestions(this._anchorBox, wordsWithPrefix, 0, true, this._textEditor.copyRange(prefixRange));
+        this._prefixRange = prefixRange;
+        if (!this._suggestBox.visible())
+            this.finishAutocomplete();
+    },
+
+    finishAutocomplete: function()
+    {
+        if (!this._suggestBox)
+            return;
+        this._suggestBox.hide();
+        this._suggestBox = null;
+        this._prefixRange = null;
+        this._anchorBox = null;
+    },
+
+    /**
+     * @param {Event} e
+     */
+    keyDown: function(e)
+    {
+        if (!this._suggestBox)
+            return false;
+        if (e.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code) {
+            this.finishAutocomplete();
+            return true;
+        }
+        if (e.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) {
+            this._suggestBox.acceptSuggestion();
+            this.finishAutocomplete();
+            return true;
+        }
+        return this._suggestBox.keyPressed(e);
+    },
+
+    /**
+     * @param {string} suggestion
+     * @param {boolean=} isIntermediateSuggestion
+     */
+    applySuggestion: function(suggestion, isIntermediateSuggestion)
+    {
+        this._currentSuggestion = suggestion;
+    },
+
+    acceptSuggestion: function()
+    {
+        if (this._prefixRange.endColumn - this._prefixRange.startColumn !== this._currentSuggestion.length) {
+            var pos = this._textEditor._toPos(this._prefixRange);
+            this._codeMirror.replaceRange(this._currentSuggestion, pos.start, pos.end, "+autocomplete");
+        }
+    },
+
+    _onScroll: function()
+    {
+        if (!this._suggestBox)
+            return;
+        var cursor = this._codeMirror.getCursor();
+        var scrollInfo = this._codeMirror.getScrollInfo();
+        var topmostLineNumber = this._codeMirror.lineAtHeight(scrollInfo.top, "local");
+        var bottomLine = this._codeMirror.lineAtHeight(scrollInfo.top + scrollInfo.clientHeight, "local");
+        if (cursor.line < topmostLineNumber || cursor.line > bottomLine)
+            this.finishAutocomplete();
+        else {
+            this._anchorBox = this._anchorBoxForPosition(cursor.line, cursor.ch);
+            this._suggestBox.setPosition(this._anchorBox);
+        }
+    },
+
+    _onCursorActivity: function()
+    {
+        if (!this._suggestBox)
+            return;
+        var cursor = this._codeMirror.getCursor();
+        if (cursor.line !== this._prefixRange.startLine || cursor.ch > this._prefixRange.endColumn || cursor.ch < this._prefixRange.startColumn)
+            this.finishAutocomplete();
+    },
+
+    /**
+     * @param {number} line
+     * @param {number} column
+     * @return {AnchorBox}
+     */
+    _anchorBoxForPosition: function(line, column)
+    {
+        var metrics = this._textEditor.cursorPositionToCoordinates(line, column);
+        return metrics ? new AnchorBox(metrics.x, metrics.y, 0, metrics.height) : null;
+    },
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorUtils.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorUtils.js
new file mode 100644
index 00000000..397865e6
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CodeMirrorUtils.js
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.CodeMirrorUtils = {
+    /**
+     * @param {string} mimeType
+     * @return {function(string, function(string, string, number, number))}
+     */
+    createTokenizer: function(mimeType)
+    {
+        var mode = CodeMirror.getMode({indentUnit: 2}, mimeType);
+        var state = CodeMirror.startState(mode);
+        function tokenize(line, callback)
+        {
+            var stream = new CodeMirror.StringStream(line);
+            while (!stream.eol()) {
+                var style = mode.token(stream, state);
+                var value = stream.current();
+                callback(value, style, stream.start, stream.start + value.length);
+                stream.start = stream.pos;
+            }
+        }
+        return tokenize;
+    },
+
+    /**
+     * @param {string} tokenType
+     */
+    convertTokenType: function(tokenType)
+    {
+        if (tokenType.startsWith("js-variable") || tokenType.startsWith("js-property") || tokenType === "js-def")
+            return "javascript-ident";
+        if (tokenType === "js-string-2")
+            return "javascript-regexp";
+        if (tokenType === "js-number" || tokenType === "js-comment" || tokenType === "js-string" || tokenType === "js-keyword")
+            return "javascript-" + tokenType.substring("js-".length);
+        return null;
+    },
+
+    /**
+     * @param {string} modeName
+     * @param {string} tokenPrefix
+     */
+    overrideModeWithPrefixedTokens: function(modeName, tokenPrefix)
+    {
+        var oldModeName = modeName + "-old";
+        if (CodeMirror.modes[oldModeName])
+            return;
+
+        CodeMirror.defineMode(oldModeName, CodeMirror.modes[modeName]);
+        CodeMirror.defineMode(modeName, modeConstructor);
+
+        function modeConstructor(config, parserConfig)
+        {
+            var innerConfig = {};
+            for (var i in parserConfig)
+                innerConfig[i] = parserConfig[i];
+            innerConfig.name = oldModeName;
+            var codeMirrorMode = CodeMirror.getMode(config, innerConfig);
+            codeMirrorMode.name = modeName;
+            codeMirrorMode.token = tokenOverride.bind(this, codeMirrorMode.token);
+            return codeMirrorMode;
+        }
+
+        function tokenOverride(superToken, stream, state)
+        {
+            var token = superToken(stream, state);
+            return token ? tokenPrefix + token : token;
+        }
+    }
+}
+
+WebInspector.CodeMirrorUtils.overrideModeWithPrefixedTokens("css-base", "css-");
+WebInspector.CodeMirrorUtils.overrideModeWithPrefixedTokens("javascript", "js-");
+WebInspector.CodeMirrorUtils.overrideModeWithPrefixedTokens("xml", "xml-");
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Color.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Color.js
new file mode 100644
index 00000000..701ee982
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Color.js
@@ -0,0 +1,611 @@
+/*
+ * Copyright (C) 2009 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @param {Array.} rgba
+ * @param {string=} format
+ * @param {string=} originalText
+ * @constructor
+ */
+WebInspector.Color = function(rgba, format, originalText)
+{
+    this._rgba = rgba;
+    this._originalText = originalText || null;
+    this._format = format || null;
+    if (typeof this._rgba[3] === "undefined")
+        this._rgba[3] = 1;
+    for (var i = 0; i < 4; ++i) {
+        if (this._rgba[i] < 0)
+            this._rgba[i] = 0;
+        if (this._rgba[i] > 1)
+            this._rgba[i] = 1;
+    }
+}
+
+/**
+ * @param {string} text
+ * @return {?WebInspector.Color}
+ */
+WebInspector.Color.parse = function(text)
+{
+    // Simple - #hex, rgb(), nickname, hsl()
+    var value = text.toLowerCase().replace(/\s+/g, "");
+    var simple = /^(?:#([0-9a-f]{3,6})|rgb\(([^)]+)\)|(\w+)|hsl\(([^)]+)\))$/i;
+    var match = value.match(simple);
+    if (match) {
+        if (match[1]) { // hex
+            var hex = match[1].toUpperCase();
+            var format;
+            if (hex.length === 3) {
+                format = WebInspector.Color.Format.ShortHEX;
+                hex = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
+            } else
+                format = WebInspector.Color.Format.HEX;
+            var r = parseInt(hex.substring(0,2), 16);
+            var g = parseInt(hex.substring(2,4), 16);
+            var b = parseInt(hex.substring(4,6), 16);
+            return new WebInspector.Color([r / 255, g / 255, b / 255, 1], format, text);
+        }
+
+        if (match[2]) { // rgb
+            var rgbString = match[2].split(/\s*,\s*/);
+            var rgba = [ WebInspector.Color._parseRgbNumeric(rgbString[0]),
+                         WebInspector.Color._parseRgbNumeric(rgbString[1]),
+                         WebInspector.Color._parseRgbNumeric(rgbString[2]), 1 ];
+            return new WebInspector.Color(rgba, WebInspector.Color.Format.RGB, text);
+        }
+
+        if (match[3]) { // nickname
+            var nickname = match[3].toLowerCase();
+            if (nickname in WebInspector.Color.Nicknames) {
+                var rgba = WebInspector.Color.Nicknames[nickname];
+                var color = WebInspector.Color.fromRGBA(rgba);
+                color._format = WebInspector.Color.Format.Nickname;
+                color._originalText = nickname;
+                return color;
+            }
+            return null;
+        }
+
+        if (match[4]) { // hsl
+            var hslString = match[4].replace(/%/g, "").split(/\s*,\s*/);
+            var hsla = [ WebInspector.Color._parseHueNumeric(hslString[0]),
+                         WebInspector.Color._parseSatLightNumeric(hslString[1]),
+                         WebInspector.Color._parseSatLightNumeric(hslString[2]), 1 ];
+            var rgba = WebInspector.Color._hsl2rgb(hsla);
+            return new WebInspector.Color(rgba, WebInspector.Color.Format.HSL, text);
+        }
+
+        return null;
+    }
+
+    // Advanced - rgba(), hsla()
+    var advanced = /^(?:rgba\(([^)]+)\)|hsla\(([^)]+)\))$/;
+    match = value.match(advanced);
+    if (match) {
+        if (match[1]) { // rgba
+            var rgbaString = match[1].split(/\s*,\s*/);
+            var rgba = [ WebInspector.Color._parseRgbNumeric(rgbaString[0]),
+                         WebInspector.Color._parseRgbNumeric(rgbaString[1]),
+                         WebInspector.Color._parseRgbNumeric(rgbaString[2]),
+                         WebInspector.Color._parseAlphaNumeric(rgbaString[3]) ];
+            return new WebInspector.Color(rgba, WebInspector.Color.Format.RGBA, text);
+        }
+
+        if (match[2]) { // hsla
+            var hslaString = match[2].replace(/%/g, "").split(/\s*,\s*/);
+            var hsla = [ WebInspector.Color._parseHueNumeric(hslaString[0]),
+                         WebInspector.Color._parseSatLightNumeric(hslaString[1]),
+                         WebInspector.Color._parseSatLightNumeric(hslaString[2]),
+                         WebInspector.Color._parseAlphaNumeric(hslaString[3]) ];
+            var rgba = WebInspector.Color._hsl2rgb(hsla);
+            return new WebInspector.Color(rgba, WebInspector.Color.Format.HSLA, text);
+        }
+    }
+
+    return null;
+}
+
+/**
+ * @param {Array.} rgba
+ * @return {WebInspector.Color}
+ */
+WebInspector.Color.fromRGBA = function(rgba)
+{
+    return new WebInspector.Color([rgba[0] / 255, rgba[1] / 255, rgba[2] / 255, rgba[3]]);
+}
+
+/**
+ * @param {Array.} hsva
+ * @return {WebInspector.Color}
+ */
+WebInspector.Color.fromHSVA = function(hsva)
+{
+    var h = hsva[0];
+    var s = hsva[1];
+    var v = hsva[2];
+
+    var t = (2 - s) * v;
+    if (v === 0 || s === 0)
+        s = 0;
+    else
+        s *= v / (t < 1 ? t : 2 - t);
+    var hsla = [h, s, t / 2, hsva[3]];
+
+    return new WebInspector.Color(WebInspector.Color._hsl2rgb(hsla), WebInspector.Color.Format.HSLA);
+}
+
+WebInspector.Color.prototype = {
+    /**
+     * @return {?string}
+     */
+    format: function()
+    {
+        return this._format;
+    },
+
+    /**
+     * @return {Array.} HSLA with components within [0..1]
+     */
+    hsla: function()
+    {
+        if (this._hsla)
+            return this._hsla;
+        var r = this._rgba[0];
+        var g = this._rgba[1];
+        var b = this._rgba[2];
+        var max = Math.max(r, g, b);
+        var min = Math.min(r, g, b);
+        var diff = max - min;
+        var add = max + min;
+
+        if (min === max)
+            var h = 0;
+        else if (r === max)
+            var h = ((1/6 * (g - b) / diff) + 1) % 1;
+        else if (g === max)
+            var h = (1/6 * (b - r) / diff) + 1/3;
+        else
+            var h = (1/6 * (r - g) / diff) + 2/3;
+
+        var l = 0.5 * add;
+
+        if (l === 0)
+            var s = 0;
+        else if (l === 1)
+            var s = 1;
+        else if (l <= 0.5)
+            var s = diff / add;
+        else
+            var s = diff / (2 - add);
+
+        this._hsla = [h, s, l, this._rgba[3]];
+        return this._hsla;
+    },
+
+    /**
+     * @return {Array.} HSVA with components within [0..1]
+     */
+    hsva: function()
+    {
+        var hsla = this.hsla();
+        var h = hsla[0];
+        var s = hsla[1];
+        var l = hsla[2];
+
+        s *= l < 0.5 ? l : 1 - l;
+        return [h, s !== 0 ? 2 * s / (l + s) : 0, (l + s), hsla[3]];
+    },
+
+    /**
+     * @return {boolean}
+     */
+    hasAlpha: function()
+    {
+        return this._rgba[3] !== 1;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    canBeShortHex: function()
+    {
+        if (this.hasAlpha())
+            return false;
+        for (var i = 0; i < 3; ++i) {
+            var c = Math.round(this._rgba[i] * 255);
+            if (c % 17)
+                return false;
+        }
+        return true;
+    },
+
+    /**
+     * @return {?string}
+     */
+    toString: function(format)
+    {
+        if (!format)
+            format = this._format;
+
+        /**
+         * @param {number} value
+         * @return {number}
+         */
+        function toRgbValue(value)
+        {
+            return Math.round(value * 255);
+        }
+
+        /**
+         * @param {number} value
+         * @return {string}
+         */
+        function toHexValue(value)
+        {
+            var hex = Math.round(value * 255).toString(16);
+            return hex.length === 1 ? "0" + hex : hex;
+        }
+
+        /**
+         * @param {number} value
+         * @return {string}
+         */
+        function toShortHexValue(value)
+        {
+            return (Math.round(value * 255) / 17).toString(16);
+        }
+
+        switch (format) {
+        case WebInspector.Color.Format.Original:
+            return this._originalText;
+        case WebInspector.Color.Format.RGB:
+            if (this.hasAlpha())
+                return null;
+            return String.sprintf("rgb(%d, %d, %d)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]));
+        case WebInspector.Color.Format.RGBA:
+            return String.sprintf("rgba(%d, %d, %d, %f)", toRgbValue(this._rgba[0]), toRgbValue(this._rgba[1]), toRgbValue(this._rgba[2]), this._rgba[3]);
+        case WebInspector.Color.Format.HSL:
+            if (this.hasAlpha())
+                return null;
+            var hsl = this.hsla();
+            return String.sprintf("hsl(%d, %d%, %d%)", Math.round(hsl[0] * 360), Math.round(hsl[1] * 100), Math.round(hsl[2] * 100));
+        case WebInspector.Color.Format.HSLA:
+            var hsla = this.hsla();
+            return String.sprintf("hsla(%d, %d%, %d%, %f)", Math.round(hsla[0] * 360), Math.round(hsla[1] * 100), Math.round(hsla[2] * 100), hsla[3]);
+        case WebInspector.Color.Format.HEX:
+            if (this.hasAlpha())
+                return null;
+            return String.sprintf("#%s%s%s", toHexValue(this._rgba[0]), toHexValue(this._rgba[1]), toHexValue(this._rgba[2])).toUpperCase();
+        case WebInspector.Color.Format.ShortHEX:
+            if (!this.canBeShortHex())
+                return null;
+            return String.sprintf("#%s%s%s", toShortHexValue(this._rgba[0]), toShortHexValue(this._rgba[1]), toShortHexValue(this._rgba[2])).toUpperCase();
+        case WebInspector.Color.Format.Nickname:
+            return this.nickname();
+        }
+
+        return this._originalText;
+    },
+
+    /**
+     * @return {Array.}
+     */
+    _canonicalRGBA: function()
+    {
+        var rgba = new Array(3);
+        for (var i = 0; i < 3; ++i)
+            rgba[i] = Math.round(this._rgba[i] * 255);
+        if (this._rgba[3] !== 1)
+            rgba.push(this._rgba[3]);
+        return rgba;
+    },
+
+    /**
+     * @return {?string} nickname
+     */
+    nickname: function()
+    {
+        if (!WebInspector.Color._rgbaToNickname) {
+            WebInspector.Color._rgbaToNickname = {};
+            for (var nickname in WebInspector.Color.Nicknames) {
+                var rgba = WebInspector.Color.Nicknames[nickname];
+                WebInspector.Color._rgbaToNickname[rgba] = nickname;
+            }
+        }
+
+        return WebInspector.Color._rgbaToNickname[this._canonicalRGBA()] || null;
+    },
+
+    /**
+     * @return {DOMAgent.RGBA}
+     */
+    toProtocolRGBA: function()
+    {
+        var rgba = this._canonicalRGBA();
+        var result = { r: rgba[0], g: rgba[1], b: rgba[2] };
+        if (rgba[3] !== 1)
+            result.a = rgba[3];
+        return result;
+    }
+}
+
+/**
+ * @param {string} value
+ * return {number}
+ */
+WebInspector.Color._parseRgbNumeric = function(value)
+{
+    var parsed = parseInt(value, 10);
+    if (value.indexOf("%") !== -1)
+        parsed /= 100;
+    else
+        parsed /= 255;
+    return parsed;
+}
+
+/**
+ * @param {string} value
+ * return {number}
+ */
+WebInspector.Color._parseHueNumeric = function(value)
+{
+    return isNaN(value) ? 0 : (parseFloat(value) / 360) % 1;
+}
+
+/**
+ * @param {string} value
+ * return {number}
+ */
+WebInspector.Color._parseSatLightNumeric = function(value)
+{
+    return parseFloat(value) / 100;
+}
+
+/**
+ * @param {string} value
+ * return {number}
+ */
+WebInspector.Color._parseAlphaNumeric = function(value)
+{
+    return isNaN(value) ? 0 : parseFloat(value);
+}
+
+/**
+ * @param {Array.} hsl
+ * @return {Array.}
+ */
+WebInspector.Color._hsl2rgb = function(hsl)
+{
+    var h = hsl[0];
+    var s = hsl[1];
+    var l = hsl[2];
+
+    function hue2rgb(p, q, h)
+    {
+        if (h < 0)
+            h += 1;
+        else if (h > 1)
+            h -= 1;
+
+        if ((h * 6) < 1)
+            return p + (q - p) * h * 6;
+        else if ((h * 2) < 1)
+            return q;
+        else if ((h * 3) < 2)
+            return p + (q - p) * ((2 / 3) - h) * 6;
+        else
+            return p;
+    }
+
+    if (s < 0)
+        s = 0;
+
+    if (l <= 0.5)
+        var q = l * (1 + s);
+    else
+        var q = l + s - (l * s);
+
+    var p = 2 * l - q;
+
+    var tr = h + (1 / 3);
+    var tg = h;
+    var tb = h - (1 / 3);
+
+    var r = hue2rgb(p, q, tr);
+    var g = hue2rgb(p, q, tg);
+    var b = hue2rgb(p, q, tb);
+    return [r, g, b, hsl[3]];
+}
+
+WebInspector.Color.Nicknames = {
+    "aliceBlue":          [240,248,255],
+    "antiqueWhite":       [250,235,215],
+    "aquamarine":         [127,255,212],
+    "azure":              [240,255,255],
+    "beige":              [245,245,220],
+    "bisque":             [255,228,196],
+    "black":              [0,0,0],
+    "blanchedAlmond":     [255,235,205],
+    "blue":               [0,0,255],
+    "blueViolet":         [138,43,226],
+    "brown":              [165,42,42],
+    "burlyWood":          [222,184,135],
+    "cadetBlue":          [95,158,160],
+    "chartreuse":         [127,255,0],
+    "chocolate":          [210,105,30],
+    "coral":              [255,127,80],
+    "cornflowerBlue":     [100,149,237],
+    "cornsilk":           [255,248,220],
+    "crimson":            [237,20,61],
+    "cyan":               [0,255,255],
+    "darkBlue":           [0,0,139],
+    "darkCyan":           [0,139,139],
+    "darkGoldenrod":      [184,134,11],
+    "darkGray":           [169,169,169],
+    "darkGreen":          [0,100,0],
+    "darkKhaki":          [189,183,107],
+    "darkMagenta":        [139,0,139],
+    "darkOliveGreen":     [85,107,47],
+    "darkOrange":         [255,140,0],
+    "darkOrchid":         [153,50,204],
+    "darkRed":            [139,0,0],
+    "darkSalmon":         [233,150,122],
+    "darkSeaGreen":       [143,188,143],
+    "darkSlateBlue":      [72,61,139],
+    "darkSlateGray":      [47,79,79],
+    "darkTurquoise":      [0,206,209],
+    "darkViolet":         [148,0,211],
+    "deepPink":           [255,20,147],
+    "deepSkyBlue":        [0,191,255],
+    "dimGray":            [105,105,105],
+    "dodgerBlue":         [30,144,255],
+    "fireBrick":          [178,34,34],
+    "floralWhite":        [255,250,240],
+    "forestGreen":        [34,139,34],
+    "gainsboro":          [220,220,220],
+    "ghostWhite":         [248,248,255],
+    "gold":               [255,215,0],
+    "goldenrod":          [218,165,32],
+    "gray":               [128,128,128],
+    "green":              [0,128,0],
+    "greenYellow":        [173,255,47],
+    "honeyDew":           [240,255,240],
+    "hotPink":            [255,105,180],
+    "indianRed":          [205,92,92],
+    "indigo":             [75,0,130],
+    "ivory":              [255,255,240],
+    "khaki":              [240,230,140],
+    "lavender":           [230,230,250],
+    "lavenderBlush":      [255,240,245],
+    "lawnGreen":          [124,252,0],
+    "lemonChiffon":       [255,250,205],
+    "lightBlue":          [173,216,230],
+    "lightCoral":         [240,128,128],
+    "lightCyan":          [224,255,255],
+    "lightGoldenrodYellow":[250,250,210],
+    "lightGreen":         [144,238,144],
+    "lightGrey":          [211,211,211],
+    "lightPink":          [255,182,193],
+    "lightSalmon":        [255,160,122],
+    "lightSeaGreen":      [32,178,170],
+    "lightSkyBlue":       [135,206,250],
+    "lightSlateGray":     [119,136,153],
+    "lightSteelBlue":     [176,196,222],
+    "lightYellow":        [255,255,224],
+    "lime":               [0,255,0],
+    "limeGreen":          [50,205,50],
+    "linen":              [250,240,230],
+    "magenta":            [255,0,255],
+    "maroon":             [128,0,0],
+    "mediumAquaMarine":   [102,205,170],
+    "mediumBlue":         [0,0,205],
+    "mediumOrchid":       [186,85,211],
+    "mediumPurple":       [147,112,219],
+    "mediumSeaGreen":     [60,179,113],
+    "mediumSlateBlue":    [123,104,238],
+    "mediumSpringGreen":  [0,250,154],
+    "mediumTurquoise":    [72,209,204],
+    "mediumVioletRed":    [199,21,133],
+    "midnightBlue":       [25,25,112],
+    "mintCream":          [245,255,250],
+    "mistyRose":          [255,228,225],
+    "moccasin":           [255,228,181],
+    "navajoWhite":        [255,222,173],
+    "navy":               [0,0,128],
+    "oldLace":            [253,245,230],
+    "olive":              [128,128,0],
+    "oliveDrab":          [107,142,35],
+    "orange":             [255,165,0],
+    "orangeRed":          [255,69,0],
+    "orchid":             [218,112,214],
+    "paleGoldenrod":      [238,232,170],
+    "paleGreen":          [152,251,152],
+    "paleTurquoise":      [175,238,238],
+    "paleVioletRed":      [219,112,147],
+    "papayaWhip":         [255,239,213],
+    "peachPuff":          [255,218,185],
+    "peru":               [205,133,63],
+    "pink":               [255,192,203],
+    "plum":               [221,160,221],
+    "powderBlue":         [176,224,230],
+    "purple":             [128,0,128],
+    "red":                [255,0,0],
+    "rosyBrown":          [188,143,143],
+    "royalBlue":          [65,105,225],
+    "saddleBrown":        [139,69,19],
+    "salmon":             [250,128,114],
+    "sandyBrown":         [244,164,96],
+    "seaGreen":           [46,139,87],
+    "seaShell":           [255,245,238],
+    "sienna":             [160,82,45],
+    "silver":             [192,192,192],
+    "skyBlue":            [135,206,235],
+    "slateBlue":          [106,90,205],
+    "slateGray":          [112,128,144],
+    "snow":               [255,250,250],
+    "springGreen":        [0,255,127],
+    "steelBlue":          [70,130,180],
+    "tan":                [210,180,140],
+    "teal":               [0,128,128],
+    "thistle":            [216,191,216],
+    "tomato":             [255,99,71],
+    "turquoise":          [64,224,208],
+    "violet":             [238,130,238],
+    "wheat":              [245,222,179],
+    "white":              [255,255,255],
+    "whiteSmoke":         [245,245,245],
+    "yellow":             [255,255,0],
+    "yellowGreen":        [154,205,50],
+    "transparent":        [0, 0, 0, 0],
+};
+
+WebInspector.Color.PageHighlight = {
+    Content: WebInspector.Color.fromRGBA([111, 168, 220, .66]),
+    ContentLight: WebInspector.Color.fromRGBA([111, 168, 220, .5]),
+    ContentOutline: WebInspector.Color.fromRGBA([9, 83, 148]),
+    Padding: WebInspector.Color.fromRGBA([147, 196, 125, .55]),
+    PaddingLight: WebInspector.Color.fromRGBA([147, 196, 125, .4]),
+    Border: WebInspector.Color.fromRGBA([255, 229, 153, .66]),
+    BorderLight: WebInspector.Color.fromRGBA([255, 229, 153, .5]),
+    Margin: WebInspector.Color.fromRGBA([246, 178, 107, .66]),
+    MarginLight: WebInspector.Color.fromRGBA([246, 178, 107, .5]),
+    EventTarget: WebInspector.Color.fromRGBA([255, 196, 196, .66])
+}
+
+WebInspector.Color.Format = {
+    Original: "original",
+    Nickname: "nickname",
+    HEX: "hex",
+    ShortHEX: "shorthex",
+    RGB: "rgb",
+    RGBA: "rgba",
+    HSL: "hsl",
+    HSLA: "hsla"
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompilerScriptMapping.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompilerScriptMapping.js
new file mode 100644
index 00000000..372d4d28
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompilerScriptMapping.js
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @implements {WebInspector.ScriptSourceMapping}
+ * @param {WebInspector.Workspace} workspace
+ * @param {WebInspector.SimpleWorkspaceProvider} networkWorkspaceProvider
+ */
+WebInspector.CompilerScriptMapping = function(workspace, networkWorkspaceProvider)
+{
+    this._workspace = workspace;
+    this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAddedToWorkspace, this);
+    this._networkWorkspaceProvider = networkWorkspaceProvider;
+    /** @type {!Object.} */
+    this._sourceMapForSourceMapURL = {};
+    /** @type {!Object.>} */
+    this._pendingSourceMapLoadingCallbacks = {};
+    /** @type {!Object.} */
+    this._sourceMapForScriptId = {};
+    /** @type {!Map.} */
+    this._scriptForSourceMap = new Map();
+    /** @type {!Object.} */
+    this._sourceMapForURL = {};
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
+}
+
+WebInspector.CompilerScriptMapping.prototype = {
+    /**
+     * @param {WebInspector.RawLocation} rawLocation
+     * @return {WebInspector.UILocation}
+     */
+    rawLocationToUILocation: function(rawLocation)
+    {
+        var debuggerModelLocation = /** @type {WebInspector.DebuggerModel.Location} */ (rawLocation);
+        var sourceMap = this._sourceMapForScriptId[debuggerModelLocation.scriptId];
+        if (!sourceMap)
+            return null;
+        var lineNumber = debuggerModelLocation.lineNumber;
+        var columnNumber = debuggerModelLocation.columnNumber || 0;
+        var entry = sourceMap.findEntry(lineNumber, columnNumber);
+        if (!entry || entry.length === 2)
+            return null;
+        var url = entry[2];
+        var uiSourceCode = this._workspace.uiSourceCodeForURL(url);
+        if (!uiSourceCode)
+            return null;
+        return new WebInspector.UILocation(uiSourceCode, entry[3], entry[4]);
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
+    {
+        if (!uiSourceCode.url)
+            return null;
+        var sourceMap = this._sourceMapForURL[uiSourceCode.url];
+        if (!sourceMap)
+            return null;
+        var entry = sourceMap.findEntryReversed(uiSourceCode.url, lineNumber);
+        return WebInspector.debuggerModel.createRawLocation(this._scriptForSourceMap.get(sourceMap) || null, entry[0], entry[1]);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isIdentity: function()
+    {
+        return false;
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     */
+    addScript: function(script)
+    {
+        script.pushSourceMapping(this);
+        this.loadSourceMapForScript(script, sourceMapLoaded.bind(this));
+
+        /**
+         * @param {?WebInspector.SourceMap} sourceMap
+         */
+        function sourceMapLoaded(sourceMap)
+        {
+            if (!sourceMap)
+                return;
+
+            if (this._scriptForSourceMap.get(sourceMap)) {
+                this._sourceMapForScriptId[script.scriptId] = sourceMap;
+                script.updateLocations();
+                return;
+            }
+
+            this._sourceMapForScriptId[script.scriptId] = sourceMap;
+            this._scriptForSourceMap.put(sourceMap, script);
+
+            var sourceURLs = sourceMap.sources();
+            for (var i = 0; i < sourceURLs.length; ++i) {
+                var sourceURL = sourceURLs[i];
+                if (this._sourceMapForURL[sourceURL])
+                    continue;
+                this._sourceMapForURL[sourceURL] = sourceMap;
+                if (!this._workspace.hasMappingForURL(sourceURL) && !this._workspace.uiSourceCodeForURL(sourceURL)) {
+                    var contentProvider = sourceMap.sourceContentProvider(sourceURL, WebInspector.resourceTypes.Script);
+                    this._networkWorkspaceProvider.addFileForURL(sourceURL, contentProvider, true);
+                }
+                var uiSourceCode = this._workspace.uiSourceCodeForURL(sourceURL);
+                if (uiSourceCode) {
+                    this._bindUISourceCode(uiSourceCode);
+                    uiSourceCode.isContentScript = script.isContentScript;
+                }
+            }
+            script.updateLocations();
+        }
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     */
+    _bindUISourceCode: function(uiSourceCode)
+    {
+        uiSourceCode.setSourceMapping(this);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _uiSourceCodeAddedToWorkspace: function(event)
+    {
+        var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.data);
+        if (!uiSourceCode.url || !this._sourceMapForURL[uiSourceCode.url])
+            return;
+        this._bindUISourceCode(uiSourceCode);
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     * @param {function(?WebInspector.SourceMap)} callback
+     */
+    loadSourceMapForScript: function(script, callback)
+    {
+        // script.sourceURL can be a random string, but is generally an absolute path -> complete it to inspected page url for
+        // relative links.
+        if (!script.sourceMapURL) {
+            callback(null);
+            return;
+        }
+        var scriptURL = WebInspector.ParsedURL.completeURL(WebInspector.inspectedPageURL, script.sourceURL);
+        if (!scriptURL) {
+            callback(null);
+            return;
+        }
+        var sourceMapURL = WebInspector.ParsedURL.completeURL(scriptURL, script.sourceMapURL);
+        if (!sourceMapURL) {
+            callback(null);
+            return;
+        }
+
+        var sourceMap = this._sourceMapForSourceMapURL[sourceMapURL];
+        if (sourceMap) {
+            callback(sourceMap);
+            return;
+        }
+
+        var pendingCallbacks = this._pendingSourceMapLoadingCallbacks[sourceMapURL];
+        if (pendingCallbacks) {
+            pendingCallbacks.push(callback);
+            return;
+        }
+
+        pendingCallbacks = [callback];
+        this._pendingSourceMapLoadingCallbacks[sourceMapURL] = pendingCallbacks;
+
+        WebInspector.SourceMap.load(sourceMapURL, scriptURL, sourceMapLoaded.bind(this));
+
+        /**
+         * @param {?WebInspector.SourceMap} sourceMap
+         */
+        function sourceMapLoaded(sourceMap)
+        {
+            var callbacks = this._pendingSourceMapLoadingCallbacks[sourceMapURL];
+            delete this._pendingSourceMapLoadingCallbacks[sourceMapURL];
+            if (!callbacks)
+                return;
+            if (sourceMap)
+                this._sourceMapForSourceMapURL[sourceMapURL] = sourceMap;
+            for (var i = 0; i < callbacks.length; ++i)
+                callbacks[i](sourceMap);
+        }
+    },
+
+    _debuggerReset: function()
+    {
+        this._sourceMapForSourceMapURL = {};
+        this._pendingSourceMapLoadingCallbacks = {};
+        this._sourceMapForScriptId = {};
+        this._scriptForSourceMap = new Map();
+        this._sourceMapForURL = {};
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompletionDictionary.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompletionDictionary.js
new file mode 100644
index 00000000..bac7cb06
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CompletionDictionary.js
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @interface
+ */
+WebInspector.CompletionDictionary = function() { }
+
+WebInspector.CompletionDictionary.prototype = {
+    /**
+     * @param {string} word
+     */
+    addWord: function(word) { },
+
+    /**
+     * @param {string} word
+     */
+    removeWord: function(word) { },
+
+    /**
+     * @param {string} word
+     * @return {boolean}
+     */
+    hasWord: function(word) { },
+
+    /**
+     * @param {string} prefix
+     * @return {Array.}
+     */
+    wordsWithPrefix: function(prefix) { },
+
+    /**
+     * @param {string} word
+     * @return {number}
+     */
+    wordCount: function(word) { }
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.CompletionDictionary}
+ */
+WebInspector.SampleCompletionDictionary = function() {
+    this._words = {};
+}
+
+WebInspector.SampleCompletionDictionary.prototype = {
+    /**
+     * @param {string} word
+     */
+    addWord: function(word)
+    {
+        if (!this._words[word])
+            this._words[word] = 1;
+        else
+            ++this._words[word];
+    },
+
+    /**
+     * @param {string} word
+     */
+    removeWord: function(word)
+    {
+        if (!this._words[word])
+            return;
+        if (this._words[word] === 1)
+            delete this._words[word];
+        else
+            --this._words[word];
+    },
+
+    /**
+     * @param {string} prefix
+     * @return {Array.}
+     */
+    wordsWithPrefix: function(prefix)
+    {
+        var words = [];
+        for(var i in this._words) {
+            if (i.startsWith(prefix))
+                words.push(i);
+        }
+        return words;
+    },
+
+    /**
+     * @param {string} word
+     * @return {boolean}
+     */
+    hasWord: function(word)
+    {
+        return !!this._words[word];
+    },
+
+    /**
+     * @param {string} word
+     * @return {number}
+     */
+    wordCount: function(word)
+    {
+        return this._words[word] ? this._words[word] : 0;
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleMessage.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleMessage.js
new file mode 100644
index 00000000..48f8c167
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleMessage.js
@@ -0,0 +1,978 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.ConsoleMessage}
+ *
+ * @param {string} source
+ * @param {string} level
+ * @param {string} message
+ * @param {WebInspector.Linkifier} linkifier
+ * @param {string=} type
+ * @param {string=} url
+ * @param {number=} line
+ * @param {number=} column
+ * @param {number=} repeatCount
+ * @param {Array.=} parameters
+ * @param {ConsoleAgent.StackTrace=} stackTrace
+ * @param {NetworkAgent.RequestId=} requestId
+ * @param {boolean=} isOutdated
+ */
+WebInspector.ConsoleMessageImpl = function(source, level, message, linkifier, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated)
+{
+    WebInspector.ConsoleMessage.call(this, source, level, url, line, column, repeatCount);
+
+    this._linkifier = linkifier;
+    this.type = type || WebInspector.ConsoleMessage.MessageType.Log;
+    this._messageText = message;
+    this._parameters = parameters;
+    this._stackTrace = stackTrace;
+    this._request = requestId ? WebInspector.networkLog.requestForId(requestId) : null;
+    this._isOutdated = isOutdated;
+    /** @type {!Array.} */
+    this._dataGrids = [];
+    /** @type {!Map.} */
+    this._dataGridParents = new Map();
+
+    this._customFormatters = {
+        "object": this._formatParameterAsObject,
+        "array":  this._formatParameterAsArray,
+        "node":   this._formatParameterAsNode,
+        "string": this._formatParameterAsString
+    };
+}
+
+WebInspector.ConsoleMessageImpl.prototype = {
+    request: function()
+    {
+        return this._request;
+    },
+
+    wasShown: function()
+    {
+        for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
+            var dataGrid = this._dataGrids[i];
+            var parentElement = this._dataGridParents.get(dataGrid) || null;
+            dataGrid.show(parentElement);
+        }
+    },
+
+    willHide: function()
+    {
+        for (var i = 0; this._dataGrids && i < this._dataGrids.length; ++i) {
+            var dataGrid = this._dataGrids[i];
+            this._dataGridParents.put(dataGrid, dataGrid.element.parentElement);
+            dataGrid.detach();
+        }
+    },
+
+    _formatMessage: function()
+    {
+        this._formattedMessage = document.createElement("span");
+        this._formattedMessage.className = "console-message-text source-code";
+
+        if (this.source === WebInspector.ConsoleMessage.MessageSource.ConsoleAPI) {
+            switch (this.type) {
+                case WebInspector.ConsoleMessage.MessageType.Trace:
+                    this._messageElement = this._format(this._parameters || ["console.trace()"]);
+                    break;
+                case WebInspector.ConsoleMessage.MessageType.Clear:
+                    this._messageElement = document.createTextNode(WebInspector.UIString("Console was cleared"));
+                    this._formattedMessage.addStyleClass("console-info");
+                    break;
+                case WebInspector.ConsoleMessage.MessageType.Assert:
+                    var args = [WebInspector.UIString("Assertion failed:")];
+                    if (this._parameters)
+                        args = args.concat(this._parameters);
+                    this._messageElement = this._format(args);
+                    break;
+                case WebInspector.ConsoleMessage.MessageType.Dir:
+                    var obj = this._parameters ? this._parameters[0] : undefined;
+                    var args = ["%O", obj];
+                    this._messageElement = this._format(args);
+                    break;
+                case WebInspector.ConsoleMessage.MessageType.Profile:
+                    var title = WebInspector.ProfilesPanelDescriptor.resolveProfileTitle(this._messageText);
+                    this._messageElement = document.createTextNode(WebInspector.UIString("Profile '%s' started.", title));
+                    break;
+                case WebInspector.ConsoleMessage.MessageType.ProfileEnd:
+                    var hashIndex = this._messageText.lastIndexOf("#");
+                    var title = WebInspector.ProfilesPanelDescriptor.resolveProfileTitle(this._messageText.substring(0, hashIndex));
+                    var uid = this._messageText.substring(hashIndex + 1);
+                    var format = WebInspector.UIString("Profile '%s' finished.", "%_");
+                    var link = WebInspector.linkifyURLAsNode("webkit-profile://CPU/" + uid, title);
+                    this._messageElement = document.createElement("span");
+                    this._formatWithSubstitutionString(format, [link], this._messageElement);
+                    break;
+                default:
+                    var args = this._parameters || [this._messageText];
+                    this._messageElement = this._format(args);
+            }
+        } else if (this.source === WebInspector.ConsoleMessage.MessageSource.Network) {
+            if (this._request) {
+                this._stackTrace = this._request.initiator.stackTrace;
+                if (this._request.initiator && this._request.initiator.url) {
+                    this.url = this._request.initiator.url;
+                    this.line = this._request.initiator.lineNumber;
+                }
+                this._messageElement = document.createElement("span");
+                if (this.level === WebInspector.ConsoleMessage.MessageLevel.Error) {
+                    this._messageElement.appendChild(document.createTextNode(this._request.requestMethod + " "));
+                    this._messageElement.appendChild(WebInspector.linkifyRequestAsNode(this._request));
+                    if (this._request.failed)
+                        this._messageElement.appendChild(document.createTextNode(" " + this._request.localizedFailDescription));
+                    else
+                        this._messageElement.appendChild(document.createTextNode(" " + this._request.statusCode + " (" + this._request.statusText + ")"));
+                } else {
+                    var fragment = WebInspector.linkifyStringAsFragmentWithCustomLinkifier(this._messageText, WebInspector.linkifyRequestAsNode.bind(null, this._request));
+                    this._messageElement.appendChild(fragment);
+                }
+            } else {
+                if (this.url) {
+                    var isExternal = !WebInspector.resourceForURL(this.url) && !WebInspector.workspace.uiSourceCodeForURL(this.url);
+                    this._anchorElement = WebInspector.linkifyURLAsNode(this.url, this.url, "console-message-url", isExternal);
+                }
+                this._messageElement = this._format([this._messageText]);
+            }
+        } else {
+            var args = this._parameters || [this._messageText];
+            this._messageElement = this._format(args);
+        }
+
+        if (this.source !== WebInspector.ConsoleMessage.MessageSource.Network || this._request) {
+            if (this._stackTrace && this._stackTrace.length && this._stackTrace[0].scriptId) {
+                this._anchorElement = this._linkifyCallFrame(this._stackTrace[0]);
+            } else if (this.url && this.url !== "undefined") {
+                this._anchorElement = this._linkifyLocation(this.url, this.line, this.column);
+            }
+        }
+
+        this._formattedMessage.appendChild(this._messageElement);
+        if (this._anchorElement) {
+            this._formattedMessage.appendChild(document.createTextNode(" "));
+            this._formattedMessage.appendChild(this._anchorElement);
+        }
+        
+        var dumpStackTrace = !!this._stackTrace && this._stackTrace.length && (this.source === WebInspector.ConsoleMessage.MessageSource.Network || this.level === WebInspector.ConsoleMessage.MessageLevel.Error || this.type === WebInspector.ConsoleMessage.MessageType.Trace);
+        if (dumpStackTrace) {
+            var ol = document.createElement("ol");
+            ol.className = "outline-disclosure";
+            var treeOutline = new TreeOutline(ol);
+
+            var content = this._formattedMessage;
+            var root = new TreeElement(content, null, true);
+            content.treeElementForTest = root;
+            treeOutline.appendChild(root);
+            if (this.type === WebInspector.ConsoleMessage.MessageType.Trace)
+                root.expand();
+
+            this._populateStackTraceTreeElement(root);
+            this._formattedMessage = ol;
+        }
+
+        // This is used for inline message bubbles in SourceFrames, or other plain-text representations.
+        this._message = this._messageElement.textContent;
+    },
+
+    /**
+     * @return {string}
+     */
+    get message()
+    {
+        // force message formatting
+        var formattedMessage = this.formattedMessage;
+        return this._message;
+    },
+
+    /**
+     * @return {Element}
+     */
+    get formattedMessage()
+    {
+        if (!this._formattedMessage)
+            this._formatMessage();
+        return this._formattedMessage;
+    },
+
+    /**
+     * @return {?WebInspector.NetworkRequest}
+     */
+    request: function()
+    {
+        return this._request;
+    },
+
+    /**
+     * @param {string} url
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {Element}
+     */
+    _linkifyLocation: function(url, lineNumber, columnNumber)
+    {
+        // FIXME(62725): stack trace line/column numbers are one-based.
+        lineNumber = lineNumber ? lineNumber - 1 : 0;
+        columnNumber = columnNumber ? columnNumber - 1 : 0;
+        return this._linkifier.linkifyLocation(url, lineNumber, columnNumber, "console-message-url");
+    },
+
+    /**
+     * @param {!ConsoleAgent.CallFrame} callFrame
+     * @return {Element}
+     */
+    _linkifyCallFrame: function(callFrame)
+    {
+        // FIXME(62725): stack trace line/column numbers are one-based.
+        var lineNumber = callFrame.lineNumber ? callFrame.lineNumber - 1 : 0;
+        var columnNumber = callFrame.columnNumber ? callFrame.columnNumber - 1 : 0;
+        var rawLocation = new WebInspector.DebuggerModel.Location(callFrame.scriptId, lineNumber, columnNumber);
+        return this._linkifier.linkifyRawLocation(rawLocation, "console-message-url");
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isErrorOrWarning: function()
+    {
+        return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
+    },
+
+    _format: function(parameters)
+    {
+        // This node is used like a Builder. Values are continually appended onto it.
+        var formattedResult = document.createElement("span");
+        if (!parameters.length)
+            return formattedResult;
+
+        // Formatting code below assumes that parameters are all wrappers whereas frontend console
+        // API allows passing arbitrary values as messages (strings, numbers, etc.). Wrap them here.
+        for (var i = 0; i < parameters.length; ++i) {
+            // FIXME: Only pass runtime wrappers here.
+            if (parameters[i] instanceof WebInspector.RemoteObject)
+                continue;
+
+            if (typeof parameters[i] === "object")
+                parameters[i] = WebInspector.RemoteObject.fromPayload(parameters[i]);
+            else
+                parameters[i] = WebInspector.RemoteObject.fromPrimitiveValue(parameters[i]);
+        }
+
+        // There can be string log and string eval result. We distinguish between them based on message type.
+        var shouldFormatMessage = WebInspector.RemoteObject.type(parameters[0]) === "string" && this.type !== WebInspector.ConsoleMessage.MessageType.Result;
+
+        // Multiple parameters with the first being a format string. Save unused substitutions.
+        if (shouldFormatMessage) {
+            // Multiple parameters with the first being a format string. Save unused substitutions.
+            var result = this._formatWithSubstitutionString(parameters[0].description, parameters.slice(1), formattedResult);
+            parameters = result.unusedSubstitutions;
+            if (parameters.length)
+                formattedResult.appendChild(document.createTextNode(" "));
+        }
+
+        if (this.type === WebInspector.ConsoleMessage.MessageType.Table) {
+            formattedResult.appendChild(this._formatParameterAsTable(parameters));
+            return formattedResult;
+        }
+
+        // Single parameter, or unused substitutions from above.
+        for (var i = 0; i < parameters.length; ++i) {
+            // Inline strings when formatting.
+            if (shouldFormatMessage && parameters[i].type === "string")
+                formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i].description));
+            else
+                formattedResult.appendChild(this._formatParameter(parameters[i], false, true));
+            if (i < parameters.length - 1)
+                formattedResult.appendChild(document.createTextNode(" "));
+        }
+        return formattedResult;
+    },
+
+    /**
+     * @param {Object} output
+     * @param {boolean=} forceObjectFormat
+     * @param {boolean=} includePreview
+     */
+    _formatParameter: function(output, forceObjectFormat, includePreview)
+    {
+        var type;
+        if (forceObjectFormat)
+            type = "object";
+        else if (output instanceof WebInspector.RemoteObject)
+            type = output.subtype || output.type;
+        else
+            type = typeof output;
+
+        var formatter = this._customFormatters[type];
+        if (!formatter) {
+            formatter = this._formatParameterAsValue;
+            output = output.description;
+        }
+
+        var span = document.createElement("span");
+        span.className = "console-formatted-" + type + " source-code";
+        formatter.call(this, output, span, includePreview);
+        return span;
+    },
+
+    _formatParameterAsValue: function(val, elem)
+    {
+        elem.appendChild(document.createTextNode(val));
+    },
+
+    _formatParameterAsObject: function(obj, elem, includePreview)
+    {
+        this._formatParameterAsArrayOrObject(obj, obj.description, elem, includePreview);
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} obj
+     * @param {string} description
+     * @param {Element} elem
+     * @param {boolean} includePreview
+     */
+    _formatParameterAsArrayOrObject: function(obj, description, elem, includePreview)
+    {
+        var titleElement = document.createElement("span");
+        if (description)
+            titleElement.createTextChild(description);
+        if (includePreview && obj.preview) {
+            titleElement.addStyleClass("console-object-preview");
+            var lossless = this._appendObjectPreview(obj, description, titleElement);
+            if (lossless) {
+                elem.appendChild(titleElement);
+                return;
+            }
+        }
+        var section = new WebInspector.ObjectPropertiesSection(obj, titleElement);
+        section.enableContextMenu();
+        elem.appendChild(section.element);
+
+        var note = section.titleElement.createChild("span", "object-info-state-note");
+        note.title = WebInspector.UIString("Object state below is captured upon first expansion");
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} obj
+     * @param {string} description
+     * @param {Element} titleElement
+     * @return {boolean} true iff preview captured all information.
+     */
+    _appendObjectPreview: function(obj, description, titleElement)
+    {
+        var preview = obj.preview;
+        var isArray = obj.subtype === "array";
+
+        if (description)
+            titleElement.createTextChild(" ");
+        titleElement.createTextChild(isArray ? "[" : "{");
+        for (var i = 0; i < preview.properties.length; ++i) {
+            if (i > 0)
+                titleElement.createTextChild(", ");
+
+            var property = preview.properties[i];
+            if (!isArray || property.name != i) {
+                titleElement.createChild("span", "name").textContent = property.name;
+                titleElement.createTextChild(": ");
+            }
+
+            titleElement.appendChild(this._renderPropertyPreview(property));
+        }
+        if (preview.overflow)
+            titleElement.createChild("span").textContent = "\u2026";
+        titleElement.createTextChild(isArray ? "]" : "}");
+        return preview.lossless;
+    },
+
+    /**
+     * @param {RuntimeAgent.PropertyPreview} property
+     * @return {Element}
+     */
+    _renderPropertyPreview: function(property)
+    {
+        var span = document.createElement("span");
+        span.className = "console-formatted-" + property.type;
+
+        if (property.type === "function") {
+            span.textContent = "function";
+            return span;
+        }
+
+        if (property.type === "object" && property.subtype === "regexp") {
+            span.addStyleClass("console-formatted-string");
+            span.textContent = property.value;
+            return span;
+        }
+
+        if (property.type === "object" && property.subtype === "node" && property.value) {
+            span.addStyleClass("console-formatted-preview-node");
+            WebInspector.DOMPresentationUtils.createSpansForNodeTitle(span, property.value);
+            return span;
+        }
+
+        if (property.type === "string") {
+            span.textContent = "\"" + property.value + "\"";
+            return span;
+        }
+
+        span.textContent = property.value;
+        return span;
+    },
+
+    _formatParameterAsNode: function(object, elem)
+    {
+        function printNode(nodeId)
+        {
+            if (!nodeId) {
+                // Sometimes DOM is loaded after the sync message is being formatted, so we get no
+                // nodeId here. So we fall back to object formatting here.
+                this._formatParameterAsObject(object, elem, false);
+                return;
+            }
+            var treeOutline = new WebInspector.ElementsTreeOutline(false, false);
+            treeOutline.setVisible(true);
+            treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId);
+            treeOutline.element.addStyleClass("outline-disclosure");
+            if (!treeOutline.children[0].hasChildren)
+                treeOutline.element.addStyleClass("single-node");
+            elem.appendChild(treeOutline.element);
+            treeOutline.element.treeElementForTest = treeOutline.children[0];
+        }
+        object.pushNodeToFrontend(printNode.bind(this));
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} array
+     * @return {boolean}
+     */
+    useArrayPreviewInFormatter: function(array)
+    {
+        return this.type !== WebInspector.ConsoleMessage.MessageType.DirXML && !!array.preview;
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} array
+     * @param {Element} elem
+     */
+    _formatParameterAsArray: function(array, elem)
+    {
+        if (this.useArrayPreviewInFormatter(array)) {
+            this._formatParameterAsArrayOrObject(array, "", elem, true);
+            return;
+        }
+
+        const maxFlatArrayLength = 100;
+        if (this._isOutdated || array.arrayLength() > maxFlatArrayLength)
+            this._formatParameterAsObject(array, elem, false);
+        else
+            array.getOwnProperties(this._printArray.bind(this, array, elem));
+    },
+
+    /**
+     * @param {Array.} parameters
+     * @return {Element}
+     */
+    _formatParameterAsTable: function(parameters)
+    {
+        var element = document.createElement("span");
+        var table = parameters[0];
+        if (!table || !table.preview)
+            return element;
+
+        var columnNames = [];
+        var preview = table.preview;
+        var rows = [];
+        for (var i = 0; i < preview.properties.length; ++i) {
+            var rowProperty = preview.properties[i];
+            var rowPreview = rowProperty.valuePreview;
+            if (!rowPreview)
+                continue;
+
+            var rowValue = {};
+            const maxColumnsToRender = 20;
+            for (var j = 0; j < rowPreview.properties.length; ++j) {
+                var cellProperty = rowPreview.properties[j];
+                var columnRendered = columnNames.indexOf(cellProperty.name) != -1;
+                if (!columnRendered) {
+                    if (columnNames.length === maxColumnsToRender)
+                        continue;
+                    columnRendered = true;
+                    columnNames.push(cellProperty.name);
+                }
+
+                if (columnRendered)
+                    rowValue[cellProperty.name] = this._renderPropertyPreview(cellProperty);
+            }
+            rows.push([rowProperty.name, rowValue]);
+        }
+
+        var flatValues = [];
+        for (var i = 0; i < rows.length; ++i) {
+            var rowName = rows[i][0];
+            var rowValue = rows[i][1];
+            flatValues.push(rowName);
+            for (var j = 0; j < columnNames.length; ++j)
+                flatValues.push(rowValue[columnNames[j]]);
+        }
+
+        if (!flatValues.length)
+            return element;
+        columnNames.unshift(WebInspector.UIString("(index)"));
+        var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, flatValues);
+        dataGrid.renderInline();
+        this._dataGrids.push(dataGrid);
+        this._dataGridParents.put(dataGrid, element);
+        return element;
+    },
+
+    _formatParameterAsString: function(output, elem)
+    {
+        var span = document.createElement("span");
+        span.className = "console-formatted-string source-code";
+        span.appendChild(WebInspector.linkifyStringAsFragment(output.description));
+
+        // Make black quotes.
+        elem.removeStyleClass("console-formatted-string");
+        elem.appendChild(document.createTextNode("\""));
+        elem.appendChild(span);
+        elem.appendChild(document.createTextNode("\""));
+    },
+
+    _printArray: function(array, elem, properties)
+    {
+        if (!properties)
+            return;
+
+        var elements = [];
+        for (var i = 0; i < properties.length; ++i) {
+            var property = properties[i];
+            var name = property.name;
+            if (!isNaN(name))
+                elements[name] = this._formatAsArrayEntry(property.value);
+        }
+
+        elem.appendChild(document.createTextNode("["));
+        var lastNonEmptyIndex = -1;
+
+        function appendUndefined(elem, index)
+        {
+            if (index - lastNonEmptyIndex <= 1)
+                return;
+            var span = elem.createChild("span", "console-formatted-undefined");
+            span.textContent = WebInspector.UIString("undefined × %d", index - lastNonEmptyIndex - 1);
+        }
+
+        var length = array.arrayLength();
+        for (var i = 0; i < length; ++i) {
+            var element = elements[i];
+            if (!element)
+                continue;
+
+            if (i - lastNonEmptyIndex > 1) {
+                appendUndefined(elem, i);
+                elem.appendChild(document.createTextNode(", "));
+            }
+
+            elem.appendChild(element);
+            lastNonEmptyIndex = i;
+            if (i < length - 1)
+                elem.appendChild(document.createTextNode(", "));
+        }
+        appendUndefined(elem, length);
+
+        elem.appendChild(document.createTextNode("]"));
+    },
+
+    _formatAsArrayEntry: function(output)
+    {
+        // Prevent infinite expansion of cross-referencing arrays.
+        return this._formatParameter(output, output.subtype && output.subtype === "array", false);
+    },
+
+    _formatWithSubstitutionString: function(format, parameters, formattedResult)
+    {
+        var formatters = {};
+
+        function parameterFormatter(force, obj)
+        {
+            return this._formatParameter(obj, force, false);
+        }
+
+        function stringFormatter(obj)
+        {
+            return obj.description;
+        }
+
+        function floatFormatter(obj)
+        {
+            if (typeof obj.value !== "number")
+                return "NaN";
+            return obj.value;
+        }
+
+        function integerFormatter(obj)
+        {
+            if (typeof obj.value !== "number")
+                return "NaN";
+            return Math.floor(obj.value);
+        }
+
+        function bypassFormatter(obj)
+        {
+            return (obj instanceof Node) ? obj : "";
+        }
+
+        var currentStyle = null;
+        function styleFormatter(obj)
+        {
+            currentStyle = {};
+            var buffer = document.createElement("span");
+            buffer.setAttribute("style", obj.description);
+            for (var i = 0; i < buffer.style.length; i++) {
+                var property = buffer.style[i];
+                if (isWhitelistedProperty(property))
+                    currentStyle[property] = buffer.style[property];
+            }
+        }
+
+        function isWhitelistedProperty(property)
+        {
+            var prefixes = ["background", "border", "color", "font", "line", "margin", "padding", "text", "-webkit-background", "-webkit-border", "-webkit-font", "-webkit-margin", "-webkit-padding", "-webkit-text"];
+            for (var i = 0; i < prefixes.length; i++) {
+                if (property.startsWith(prefixes[i]))
+                    return true;
+            }
+            return false;
+        }
+
+        // Firebug uses %o for formatting objects.
+        formatters.o = parameterFormatter.bind(this, false);
+        formatters.s = stringFormatter;
+        formatters.f = floatFormatter;
+        // Firebug allows both %i and %d for formatting integers.
+        formatters.i = integerFormatter;
+        formatters.d = integerFormatter;
+
+        // Firebug uses %c for styling the message.
+        formatters.c = styleFormatter;
+
+        // Support %O to force object formatting, instead of the type-based %o formatting.
+        formatters.O = parameterFormatter.bind(this, true);
+
+        formatters._ = bypassFormatter;
+
+        function append(a, b)
+        {
+            if (b instanceof Node)
+                a.appendChild(b);
+            else if (typeof b !== "undefined") {
+                var toAppend = WebInspector.linkifyStringAsFragment(String(b));
+                if (currentStyle) {
+                    var wrapper = document.createElement('span');
+                    for (var key in currentStyle)
+                        wrapper.style[key] = currentStyle[key];
+                    wrapper.appendChild(toAppend);
+                    toAppend = wrapper;
+                }
+                a.appendChild(toAppend);
+            }
+            return a;
+        }
+
+        // String.format does treat formattedResult like a Builder, result is an object.
+        return String.format(format, parameters, formatters, formattedResult, append);
+    },
+
+    clearHighlight: function()
+    {
+        if (!this._formattedMessage)
+            return;
+
+        var highlightedMessage = this._formattedMessage;
+        delete this._formattedMessage;
+        delete this._anchorElement;
+        delete this._messageElement;
+        this._formatMessage();
+        this._element.replaceChild(this._formattedMessage, highlightedMessage);
+    },
+
+    highlightSearchResults: function(regexObject)
+    {
+        if (!this._formattedMessage)
+            return;
+
+        this._highlightSearchResultsInElement(regexObject, this._messageElement);
+        if (this._anchorElement)
+            this._highlightSearchResultsInElement(regexObject, this._anchorElement);
+
+        this._element.scrollIntoViewIfNeeded();
+    },
+
+    _highlightSearchResultsInElement: function(regexObject, element)
+    {
+        regexObject.lastIndex = 0;
+        var text = element.textContent;
+        var match = regexObject.exec(text);
+        var matchRanges = [];
+        while (match) {
+            matchRanges.push({ offset: match.index, length: match[0].length });
+            match = regexObject.exec(text);
+        }
+        WebInspector.highlightSearchResults(element, matchRanges);
+    },
+
+    matchesRegex: function(regexObject)
+    {
+        regexObject.lastIndex = 0;
+        return regexObject.test(this.message) || (this._anchorElement && regexObject.test(this._anchorElement.textContent));
+    },
+
+    toMessageElement: function()
+    {
+        if (this._element)
+            return this._element;
+
+        var element = document.createElement("div");
+        element.message = this;
+        element.className = "console-message";
+
+        this._element = element;
+
+        switch (this.level) {
+        case WebInspector.ConsoleMessage.MessageLevel.Log:
+            element.addStyleClass("console-log-level");
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Debug:
+            element.addStyleClass("console-debug-level");
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Warning:
+            element.addStyleClass("console-warning-level");
+            break;
+        case WebInspector.ConsoleMessage.MessageLevel.Error:
+            element.addStyleClass("console-error-level");
+            break;
+        }
+
+        if (this.type === WebInspector.ConsoleMessage.MessageType.StartGroup || this.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
+            element.addStyleClass("console-group-title");
+
+        element.appendChild(this.formattedMessage);
+
+        if (this.repeatCount > 1)
+            this.updateRepeatCount();
+
+        return element;
+    },
+
+    _populateStackTraceTreeElement: function(parentTreeElement)
+    {
+        for (var i = 0; i < this._stackTrace.length; i++) {
+            var frame = this._stackTrace[i];
+
+            var content = document.createElement("div");
+            var messageTextElement = document.createElement("span");
+            messageTextElement.className = "console-message-text source-code";
+            var functionName = frame.functionName || WebInspector.UIString("(anonymous function)");
+            messageTextElement.appendChild(document.createTextNode(functionName));
+            content.appendChild(messageTextElement);
+
+            if (frame.scriptId) {
+                content.appendChild(document.createTextNode(" "));
+                var urlElement = this._linkifyCallFrame(frame);
+                if (!urlElement)
+                    continue;
+                content.appendChild(urlElement);
+            }
+
+            var treeElement = new TreeElement(content);
+            parentTreeElement.appendChild(treeElement);
+        }
+    },
+
+    updateRepeatCount: function() {
+        if (!this._element)
+            return;
+
+        if (!this.repeatCountElement) {
+            this.repeatCountElement = document.createElement("span");
+            this.repeatCountElement.className = "bubble";
+
+            this._element.insertBefore(this.repeatCountElement, this._element.firstChild);
+            this._element.addStyleClass("repeated-message");
+        }
+        this.repeatCountElement.textContent = this.repeatCount;
+    },
+
+    toString: function()
+    {
+        var sourceString;
+        switch (this.source) {
+            case WebInspector.ConsoleMessage.MessageSource.XML:
+                sourceString = "XML";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.JS:
+                sourceString = "JS";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.Network:
+                sourceString = "Network";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.ConsoleAPI:
+                sourceString = "ConsoleAPI";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.Storage:
+                sourceString = "Storage";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.AppCache:
+                sourceString = "AppCache";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.Rendering:
+                sourceString = "Rendering";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.CSS:
+                sourceString = "CSS";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.Security:
+                sourceString = "Security";
+                break;
+            case WebInspector.ConsoleMessage.MessageSource.Other:
+                sourceString = "Other";
+                break;
+        }
+
+        var typeString;
+        switch (this.type) {
+            case WebInspector.ConsoleMessage.MessageType.Log:
+                typeString = "Log";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.Dir:
+                typeString = "Dir";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.DirXML:
+                typeString = "Dir XML";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.Trace:
+                typeString = "Trace";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed:
+            case WebInspector.ConsoleMessage.MessageType.StartGroup:
+                typeString = "Start Group";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.EndGroup:
+                typeString = "End Group";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.Assert:
+                typeString = "Assert";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.Result:
+                typeString = "Result";
+                break;
+            case WebInspector.ConsoleMessage.MessageType.Profile:
+            case WebInspector.ConsoleMessage.MessageType.ProfileEnd:
+                typeString = "Profiling";
+                break;
+        }
+
+        var levelString;
+        switch (this.level) {
+            case WebInspector.ConsoleMessage.MessageLevel.Log:
+                levelString = "Log";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Warning:
+                levelString = "Warning";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Debug:
+                levelString = "Debug";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Error:
+                levelString = "Error";
+                break;
+        }
+
+        return sourceString + " " + typeString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line;
+    },
+
+    get text()
+    {
+        return this._messageText;
+    },
+
+    location: function()
+    {
+        // FIXME(62725): stack trace line/column numbers are one-based.
+        var lineNumber = this.stackTrace ? this.stackTrace[0].lineNumber - 1 : this.line - 1;
+        var columnNumber = this.stackTrace && this.stackTrace[0].columnNumber ? this.stackTrace[0].columnNumber - 1 : 0;
+        return WebInspector.debuggerModel.createRawLocationByURL(this.url, lineNumber, columnNumber);
+    },
+
+    isEqual: function(msg)
+    {
+        if (!msg)
+            return false;
+
+        if (this._stackTrace) {
+            if (!msg._stackTrace)
+                return false;
+            var l = this._stackTrace;
+            var r = msg._stackTrace;
+            if (l.length !== r.length) 
+                return false;
+            for (var i = 0; i < l.length; i++) {
+                if (l[i].url !== r[i].url ||
+                    l[i].functionName !== r[i].functionName ||
+                    l[i].lineNumber !== r[i].lineNumber ||
+                    l[i].columnNumber !== r[i].columnNumber)
+                    return false;
+            }
+        }
+
+        return (this.source === msg.source)
+            && (this.type === msg.type)
+            && (this.level === msg.level)
+            && (this.line === msg.line)
+            && (this.url === msg.url)
+            && (this.message === msg.message)
+            && (this._request === msg._request);
+    },
+
+    get stackTrace()
+    {
+        return this._stackTrace;
+    },
+
+    /**
+     * @return {WebInspector.ConsoleMessage}
+     */
+    clone: function()
+    {
+        return WebInspector.ConsoleMessage.create(this.source, this.level, this._messageText, this.type, this.url, this.line, this.column, this.repeatCount, this._parameters, this._stackTrace, this._request ? this._request.requestId : undefined, this._isOutdated);
+    },
+
+    __proto__: WebInspector.ConsoleMessage.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleModel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleModel.js
new file mode 100644
index 00000000..5054fc18
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleModel.js
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.ConsoleModel = function()
+{
+    this.messages = [];
+    this.warnings = 0;
+    this.errors = 0;
+    this._interruptRepeatCount = false;
+    InspectorBackend.registerConsoleDispatcher(new WebInspector.ConsoleDispatcher(this));
+}
+
+WebInspector.ConsoleModel.Events = {
+    ConsoleCleared: "console-cleared",
+    MessageAdded: "console-message-added",
+    RepeatCountUpdated: "repeat-count-updated"
+}
+
+WebInspector.ConsoleModel.prototype = {
+    enableAgent: function()
+    {
+        if (WebInspector.settings.monitoringXHREnabled.get())
+            ConsoleAgent.setMonitoringXHREnabled(true);
+
+        this._enablingConsole = true;
+        function callback()
+        {
+            delete this._enablingConsole;
+        }
+        ConsoleAgent.enable(callback.bind(this));
+    },
+
+    /**
+     * @return {boolean}
+     */
+    enablingConsole: function()
+    {
+        return !!this._enablingConsole;
+    },
+
+    /**
+     * @param {WebInspector.ConsoleMessage} msg
+     * @param {boolean=} isFromBackend
+     */
+    addMessage: function(msg, isFromBackend)
+    {
+        if (isFromBackend && WebInspector.SourceMap.hasSourceMapRequestHeader(msg.request()))
+            return;
+
+        msg.index = this.messages.length;
+        this.messages.push(msg);
+        this._incrementErrorWarningCount(msg);
+
+        if (isFromBackend)
+            this._previousMessage = msg;
+
+        this._interruptRepeatCount = !isFromBackend;
+
+        this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.MessageAdded, msg);
+    },
+
+    /**
+     * @param {WebInspector.ConsoleMessage} msg
+     */
+    _incrementErrorWarningCount: function(msg)
+    {
+        switch (msg.level) {
+            case WebInspector.ConsoleMessage.MessageLevel.Warning:
+                this.warnings += msg.repeatDelta;
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Error:
+                this.errors += msg.repeatDelta;
+                break;
+        }
+    },
+
+    requestClearMessages: function()
+    {
+        ConsoleAgent.clearMessages();
+        this.clearMessages();
+    },
+
+    clearMessages: function()
+    {
+        this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.ConsoleCleared);
+
+        this.messages = [];
+        delete this._previousMessage;
+
+        this.errors = 0;
+        this.warnings = 0;
+    },
+
+    /**
+     * @param {number} count
+     */
+    _messageRepeatCountUpdated: function(count)
+    {
+        var msg = this._previousMessage;
+        if (!msg)
+            return;
+
+        var prevRepeatCount = msg.totalRepeatCount;
+
+        if (!this._interruptRepeatCount) {
+            msg.repeatDelta = count - prevRepeatCount;
+            msg.repeatCount = msg.repeatCount + msg.repeatDelta;
+            msg.totalRepeatCount = count;
+            msg.updateRepeatCount();
+
+            this._incrementErrorWarningCount(msg);
+            this.dispatchEventToListeners(WebInspector.ConsoleModel.Events.RepeatCountUpdated, msg);
+        } else {
+            var msgCopy = msg.clone();
+            msgCopy.totalRepeatCount = count;
+            msgCopy.repeatCount = (count - prevRepeatCount) || 1;
+            msgCopy.repeatDelta = msgCopy.repeatCount;
+            this.addMessage(msgCopy, true);
+        }
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @param {string} source
+ * @param {string} level
+ * @param {string=} url
+ * @param {number=} line
+ * @param {number=} column
+ * @param {number=} repeatCount
+ */
+WebInspector.ConsoleMessage = function(source, level, url, line, column, repeatCount)
+{
+    this.source = source;
+    this.level = level;
+    this.url = url || null;
+    this.line = line || 0;
+    this.column = column || 0;
+    this.message = "";
+
+    repeatCount = repeatCount || 1;
+    this.repeatCount = repeatCount;
+    this.repeatDelta = repeatCount;
+    this.totalRepeatCount = repeatCount;
+}
+
+WebInspector.ConsoleMessage.prototype = {
+    /**
+     * @return {boolean}
+     */
+    isErrorOrWarning: function()
+    {
+        return (this.level === WebInspector.ConsoleMessage.MessageLevel.Warning || this.level === WebInspector.ConsoleMessage.MessageLevel.Error);
+    },
+
+    updateRepeatCount: function()
+    {
+        // Implemented by concrete instances
+    },
+
+    /**
+     * @return {WebInspector.ConsoleMessage}
+     */
+    clone: function()
+    {
+        // Implemented by concrete instances
+    },
+
+    /**
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    location: function()
+    {
+        // Implemented by concrete instances
+    }
+}
+
+/**
+ * @param {string} source
+ * @param {string} level
+ * @param {string} message
+ * @param {string=} type
+ * @param {string=} url
+ * @param {number=} line
+ * @param {number=} column
+ * @param {number=} repeatCount
+ * @param {Array.=} parameters
+ * @param {ConsoleAgent.StackTrace=} stackTrace
+ * @param {NetworkAgent.RequestId=} requestId
+ * @param {boolean=} isOutdated
+ * @return {WebInspector.ConsoleMessage}
+ */
+WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated)
+{
+}
+
+// Note: Keep these constants in sync with the ones in Console.h
+WebInspector.ConsoleMessage.MessageSource = {
+    XML: "xml",
+    JS: "javascript",
+    Network: "network",
+    ConsoleAPI: "console-api",
+    Storage: "storage",
+    AppCache: "appcache",
+    Rendering: "rendering",
+    CSS: "css",
+    Security: "security",
+    Other: "other",
+    Deprecation: "deprecation"
+}
+
+WebInspector.ConsoleMessage.MessageType = {
+    Log: "log",
+    Dir: "dir",
+    DirXML: "dirxml",
+    Table: "table",
+    Trace: "trace",
+    Clear: "clear",
+    StartGroup: "startGroup",
+    StartGroupCollapsed: "startGroupCollapsed",
+    EndGroup: "endGroup",
+    Assert: "assert",
+    Result: "result",
+    Profile: "profile",
+    ProfileEnd: "profileEnd"
+}
+
+WebInspector.ConsoleMessage.MessageLevel = {
+    Log: "log",
+    Warning: "warning",
+    Error: "error",
+    Debug: "debug"
+}
+
+
+/**
+ * @constructor
+ * @implements {ConsoleAgent.Dispatcher}
+ * @param {WebInspector.ConsoleModel} console
+ */
+WebInspector.ConsoleDispatcher = function(console)
+{
+    this._console = console;
+}
+
+WebInspector.ConsoleDispatcher.prototype = {
+    /**
+     * @param {ConsoleAgent.ConsoleMessage} payload
+     */
+    messageAdded: function(payload)
+    {
+        var consoleMessage = WebInspector.ConsoleMessage.create(
+            payload.source,
+            payload.level,
+            payload.text,
+            payload.type,
+            payload.url,
+            payload.line,
+            payload.column,
+            payload.repeatCount,
+            payload.parameters,
+            payload.stackTrace,
+            payload.networkRequestId,
+            this._console._enablingConsole);
+        this._console.addMessage(consoleMessage, true);
+    },
+
+    /**
+     * @param {number} count
+     */
+    messageRepeatCountUpdated: function(count)
+    {
+        this._console._messageRepeatCountUpdated(count);
+    },
+
+    messagesCleared: function()
+    {
+        if (!WebInspector.settings.preserveConsoleLog.get())
+            this._console.clearMessages();
+    }
+}
+
+/**
+ * @type {?WebInspector.ConsoleModel}
+ */
+WebInspector.console = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsolePanel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsolePanel.js
new file mode 100644
index 00000000..85c6df40
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsolePanel.js
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Panel}
+ */
+WebInspector.ConsolePanel = function()
+{
+    WebInspector.Panel.call(this, "console");
+
+    this._view = WebInspector.consoleView;
+}
+
+WebInspector.ConsolePanel.prototype = {
+    get statusBarItems()
+    {
+        return this._view.statusBarItems;
+    },
+
+    wasShown: function()
+    {
+        WebInspector.Panel.prototype.wasShown.call(this);
+        if (WebInspector.drawer.visible) {
+            WebInspector.drawer.hide(WebInspector.Drawer.AnimationType.Immediately);
+            this._drawerWasVisible = true;
+        }
+        this._view.show(this.element);
+    },
+
+    willHide: function()
+    {
+        if (this._drawerWasVisible) {
+            WebInspector.drawer.show(this._view, WebInspector.Drawer.AnimationType.Immediately);
+            delete this._drawerWasVisible;
+        }
+        WebInspector.Panel.prototype.willHide.call(this);
+    },
+
+    searchCanceled: function()
+    {
+        this._view.searchCanceled();
+    },
+
+    canFilter: function()
+    {
+        return this._view.canFilter();
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} shouldJump
+     */
+    performSearch: function(query, shouldJump)
+    {
+        this._view.performSearch(query, shouldJump, this);
+    },
+
+    /**
+     * @param {string} query
+     */
+    performFilter: function(query)
+    {
+        this._view.performFilter(query);
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        this._view.jumpToNextSearchResult(this);
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        this._view.jumpToPreviousSearchResult(this);
+    },
+
+    __proto__: WebInspector.Panel.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleView.js
new file mode 100644
index 00000000..9178a201
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ConsoleView.js
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @extends {WebInspector.View}
+ * @implements {WebInspector.Searchable}
+ * @constructor
+ * @param {boolean} hideContextSelector
+ */
+WebInspector.ConsoleView = function(hideContextSelector)
+{
+    WebInspector.View.call(this);
+
+    this.element.id = "console-view";
+    this._visibleMessagesIndices = [];
+    this._urlToMessageCount = {};
+
+    this._clearConsoleButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear console log."), "clear-status-bar-item");
+    this._clearConsoleButton.addEventListener("click", this._requestClearMessages, this);
+
+    this._frameSelector = new WebInspector.StatusBarComboBox(this._frameChanged.bind(this), "console-context");
+    this._contextSelector = new WebInspector.StatusBarComboBox(this._contextChanged.bind(this), "console-context");
+
+    this._filter = new WebInspector.ConsoleViewFilter();
+    this._filter.addEventListener(WebInspector.ConsoleViewFilter.Events.FilterChanged, this._updateMessageList.bind(this));
+
+    if (hideContextSelector) {
+        this._frameSelector.element.addStyleClass("hidden");
+        this._contextSelector.element.addStyleClass("hidden");
+    }
+
+    this.messagesElement = document.createElement("div");
+    this.messagesElement.id = "console-messages";
+    this.messagesElement.className = "monospace";
+    this.messagesElement.addEventListener("click", this._messagesClicked.bind(this), true);
+    this.element.appendChild(this.messagesElement);
+    this._scrolledToBottom = true;
+
+    this.promptElement = document.createElement("div");
+    this.promptElement.id = "console-prompt";
+    this.promptElement.className = "source-code";
+    this.promptElement.spellcheck = false;
+    this.messagesElement.appendChild(this.promptElement);
+    this.messagesElement.appendChild(document.createElement("br"));
+
+    this.topGroup = new WebInspector.ConsoleGroup(null);
+    this.messagesElement.insertBefore(this.topGroup.element, this.promptElement);
+    this.currentGroup = this.topGroup;
+
+    this._registerShortcuts();
+    this.registerRequiredCSS("textPrompt.css");
+
+    this.messagesElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), false);
+
+    WebInspector.settings.monitoringXHREnabled.addChangeListener(this._monitoringXHREnabledSettingChanged.bind(this));
+
+    WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.MessageAdded, this._consoleMessageAdded, this);
+    WebInspector.console.addEventListener(WebInspector.ConsoleModel.Events.ConsoleCleared, this._consoleCleared, this);
+
+    this._linkifier = new WebInspector.Linkifier();
+
+    this.prompt = new WebInspector.TextPromptWithHistory(WebInspector.runtimeModel.completionsForTextPrompt.bind(WebInspector.runtimeModel));
+    this.prompt.setSuggestBoxEnabled("generic-suggest");
+    this.prompt.renderAsBlock();
+    this.prompt.attach(this.promptElement);
+    this.prompt.proxyElement.addEventListener("keydown", this._promptKeyDown.bind(this), false);
+    this.prompt.setHistoryData(WebInspector.settings.consoleHistory.get());
+
+    WebInspector.runtimeModel.contextLists().forEach(this._addFrame, this);
+    WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListAdded, this._frameAdded, this);
+    WebInspector.runtimeModel.addEventListener(WebInspector.RuntimeModel.Events.FrameExecutionContextListRemoved, this._frameRemoved, this);
+
+    this._filterStatusMessageElement = document.createElement("div");
+    this._filterStatusMessageElement.classList.add("console-message");
+    this._filterStatusTextElement = this._filterStatusMessageElement.createChild("span", "console-info");
+    this._filterStatusMessageElement.createTextChild(" ");
+    var resetFiltersLink = this._filterStatusMessageElement.createChild("span", "console-info node-link");
+    resetFiltersLink.textContent = WebInspector.UIString("Show all messages.");
+    resetFiltersLink.addEventListener("click", this._filter.reset.bind(this._filter), true);
+
+    this.messagesElement.insertBefore(this._filterStatusMessageElement, this.topGroup.element);
+
+    this._updateFilterStatus();
+}
+
+WebInspector.ConsoleView.prototype = {
+    get statusBarItems()
+    {
+        return [this._clearConsoleButton.element, this._frameSelector.element, this._contextSelector.element, this._filter.sourceFilterButton.element, this._filter.filterBarElement];
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameAdded: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        this._addFrame(contextList);
+    },
+
+    /**
+     * @param {WebInspector.FrameExecutionContextList} contextList
+     */
+    _addFrame: function(contextList)
+    {
+        var option = this._frameSelector.createOption(contextList.displayName, contextList.url);
+        option._contextList = contextList;
+        contextList._consoleOption = option;
+        contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextsUpdated, this._frameUpdated, this);
+        contextList.addEventListener(WebInspector.FrameExecutionContextList.EventTypes.ContextAdded, this._contextAdded, this);
+        this._frameChanged();
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameRemoved: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        this._frameSelector.removeOption(contextList._consoleOption);
+        this._frameChanged();
+    },
+
+    _frameChanged: function()
+    {
+        var context = this._currentFrame();
+        if (!context) {
+            WebInspector.runtimeModel.setCurrentExecutionContext(null);
+            this._contextSelector.element.addStyleClass("hidden");
+            return;
+        }
+
+        var executionContexts = context.executionContexts();
+        if (executionContexts.length)
+            WebInspector.runtimeModel.setCurrentExecutionContext(executionContexts[0]);
+
+        if (executionContexts.length === 1) {
+            this._contextSelector.element.addStyleClass("hidden");
+            return;
+        }
+        this._contextSelector.element.removeStyleClass("hidden");
+        this._contextSelector.removeOptions();
+        for (var i = 0; i < executionContexts.length; ++i)
+            this._appendContextOption(executionContexts[i]);
+    },
+
+    /**
+     * @param {WebInspector.ExecutionContext} executionContext
+     */
+    _appendContextOption: function(executionContext)
+    {
+        if (!WebInspector.runtimeModel.currentExecutionContext())
+            WebInspector.runtimeModel.setCurrentExecutionContext(executionContext);
+        var option = this._contextSelector.createOption(executionContext.name, executionContext.id);
+        option._executionContext = executionContext;
+    },
+
+    /**
+     * @param {Event} event
+     */
+    _contextChanged: function(event)
+    {
+        var option = this._contextSelector.selectedOption();
+        WebInspector.runtimeModel.setCurrentExecutionContext(option ? option._executionContext : null);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _frameUpdated: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        var option = contextList._consoleOption;
+        option.text = contextList.displayName;
+        option.title = contextList.url;
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _contextAdded: function(event)
+    {
+        var contextList = /** @type {WebInspector.FrameExecutionContextList} */ (event.data);
+        if (contextList === this._currentFrame())
+            this._frameChanged();
+    },
+
+    /**
+     * @return {WebInspector.FrameExecutionContextList|undefined}
+     */
+    _currentFrame: function()
+    {
+        var option = this._frameSelector.selectedOption();
+        return option ? option._contextList : undefined;
+    },
+
+    willHide: function()
+    {
+        this.prompt.hideSuggestBox();
+        this.prompt.clearAutoComplete(true);
+    },
+
+    wasShown: function()
+    {
+        if (!this.prompt.isCaretInsidePrompt())
+            this.prompt.moveCaretToEndOfPrompt();
+    },
+
+    afterShow: function()
+    {
+        WebInspector.setCurrentFocusElement(this.promptElement);
+    },
+
+    storeScrollPositions: function()
+    {
+        WebInspector.View.prototype.storeScrollPositions.call(this);
+        this._scrolledToBottom = this.messagesElement.isScrolledToBottom();
+    },
+
+    restoreScrollPositions: function()
+    {
+        if (this._scrolledToBottom)
+            this._immediatelyScrollIntoView();
+        else
+            WebInspector.View.prototype.restoreScrollPositions.call(this);
+    },
+
+    onResize: function()
+    {
+        this.restoreScrollPositions();
+    },
+
+    _isScrollIntoViewScheduled: function()
+    {
+        return !!this._scrollIntoViewTimer;
+    },
+
+    _scheduleScrollIntoView: function()
+    {
+        if (this._scrollIntoViewTimer)
+            return;
+
+        function scrollIntoView()
+        {
+            delete this._scrollIntoViewTimer;
+            this.promptElement.scrollIntoView(true);
+        }
+        this._scrollIntoViewTimer = setTimeout(scrollIntoView.bind(this), 20);
+    },
+
+    _immediatelyScrollIntoView: function()
+    {
+        this.promptElement.scrollIntoView(true);
+        this._cancelScheduledScrollIntoView();
+    },
+
+    _cancelScheduledScrollIntoView: function()
+    {
+        if (!this._isScrollIntoViewScheduled())
+            return;
+
+        clearTimeout(this._scrollIntoViewTimer);
+        delete this._scrollIntoViewTimer;
+    },
+
+    /**
+     * @param {number=} count
+     */
+    _updateFilterStatus: function(count) {
+        count = (typeof count === undefined) ? (WebInspector.console.messages.length - this._visibleMessagesIndices.length) : count;
+        this._filterStatusTextElement.textContent = WebInspector.UIString(count == 1 ? "%d message is hidden by filters." : "%d messages are hidden by filters.", count);
+        this._filterStatusMessageElement.style.display = count ? "" : "none";
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _consoleMessageAdded: function(event)
+    {
+        var message = /** @type {WebInspector.ConsoleMessage} */ (event.data);
+        var index = message.index;
+
+        if (this._urlToMessageCount[message.url])
+            this._urlToMessageCount[message.url]++;
+        else
+            this._urlToMessageCount[message.url] = 1;
+
+        if (this._filter.shouldBeVisible(message))
+            this._showConsoleMessage(index);
+        else
+            this._updateFilterStatus();
+    },
+
+    _showConsoleMessage: function(index)
+    {
+        var message = WebInspector.console.messages[index];
+
+        // this.messagesElement.isScrolledToBottom() is forcing style recalculation.
+        // We just skip it if the scroll action has been scheduled.
+        if (!this._isScrollIntoViewScheduled() && ((message instanceof WebInspector.ConsoleCommandResult) || this.messagesElement.isScrolledToBottom()))
+            this._scheduleScrollIntoView();
+
+        this._visibleMessagesIndices.push(index);
+
+        if (message.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
+            var parentGroup = this.currentGroup.parentGroup;
+            if (parentGroup)
+                this.currentGroup = parentGroup;
+        } else {
+            if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
+                var group = new WebInspector.ConsoleGroup(this.currentGroup);
+                this.currentGroup.messagesElement.appendChild(group.element);
+                this.currentGroup = group;
+                message.group = group;
+            }
+            this.currentGroup.addMessage(message);
+        }
+
+        if (this._searchRegex && message.matchesRegex(this._searchRegex)) {
+            this._searchResultsIndices.push(index);
+            WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
+        }
+    },
+
+    _consoleCleared: function()
+    {
+        this._scrolledToBottom = true;
+        for (var i = 0; i < this._visibleMessagesIndices.length; ++i)
+            WebInspector.console.messages[this._visibleMessagesIndices[i]].willHide();
+        this._visibleMessagesIndices = [];
+        this._searchResultsIndices = [];
+
+        if (this._searchRegex)
+            WebInspector.searchController.updateSearchMatchesCount(0, this._searchProvider);
+
+        this.currentGroup = this.topGroup;
+        this.topGroup.messagesElement.removeChildren();
+
+        this._clearCurrentSearchResultHighlight();
+        this._updateFilterStatus(0);
+
+        this._linkifier.reset();
+    },
+
+    _handleContextMenuEvent: function(event)
+    {
+        if (!window.getSelection().isCollapsed) {
+            // If there is a selection, we want to show our normal context menu
+            // (with Copy, etc.), and not Clear Console.
+            return;
+        }
+
+        if (event.target.enclosingNodeOrSelfWithNodeName("a"))
+            return;
+
+        var contextMenu = new WebInspector.ContextMenu(event);
+
+        function monitoringXHRItemAction()
+        {
+            WebInspector.settings.monitoringXHREnabled.set(!WebInspector.settings.monitoringXHREnabled.get());
+        }
+        contextMenu.appendCheckboxItem(WebInspector.UIString("Log XMLHttpRequests"), monitoringXHRItemAction.bind(this), WebInspector.settings.monitoringXHREnabled.get());
+
+        function preserveLogItemAction()
+        {
+            WebInspector.settings.preserveConsoleLog.set(!WebInspector.settings.preserveConsoleLog.get());
+        }
+        contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Preserve log upon navigation" : "Preserve Log upon Navigation"), preserveLogItemAction.bind(this), WebInspector.settings.preserveConsoleLog.get());
+
+        var sourceElement = event.target.enclosingNodeOrSelfWithClass("console-message");
+
+        var filterSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Filter"));
+
+        if (sourceElement && sourceElement.message.url) {
+            var menuTitle = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Hide messages from %s" : "Hide Messages from %s", new WebInspector.ParsedURL(sourceElement.message.url).displayName);
+            filterSubMenu.appendItem(menuTitle, this._filter.addMessageURLFilter.bind(this._filter, sourceElement.message.url));
+        }
+
+        filterSubMenu.appendSeparator();
+        var unhideAll = filterSubMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Unhide all" : "Unhide All"), this._filter.removeMessageURLFilter.bind(this._filter));
+        filterSubMenu.appendSeparator();
+
+        var hasFilters = false;
+
+        for (var url in this._filter.messageURLFilters) {
+            filterSubMenu.appendCheckboxItem(String.sprintf("%s (%d)", new WebInspector.ParsedURL(url).displayName, this._urlToMessageCount[url]), this._filter.removeMessageURLFilter.bind(this._filter, url), true);
+            hasFilters = true;
+        }
+
+        filterSubMenu.setEnabled(hasFilters || (sourceElement && sourceElement.message.url));
+        unhideAll.setEnabled(hasFilters);
+
+        contextMenu.appendSeparator();
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear console" : "Clear Console"), this._requestClearMessages.bind(this));
+
+        var request = (sourceElement && sourceElement.message) ? sourceElement.message.request() : null;
+        if (request && request.type === WebInspector.resourceTypes.XHR) {
+            contextMenu.appendSeparator();
+            contextMenu.appendItem(WebInspector.UIString("Replay XHR"), NetworkAgent.replayXHR.bind(null, request.requestId));
+        }
+
+        contextMenu.show();
+    },
+
+    _updateMessageList: function()
+    {
+        var group = this.topGroup;
+        var sourceMessages = WebInspector.console.messages;
+        var visibleMessageIndex = 0;
+        var newVisibleMessages = [];
+
+        if (this._searchRegex)
+            this._searchResultsIndices = [];
+
+        var anchor = null;
+        for (var i = 0; i < sourceMessages.length; ++i) {
+            var sourceMessage = sourceMessages[i];
+            var visibleMessage = WebInspector.console.messages[this._visibleMessagesIndices[visibleMessageIndex]];
+
+            if (visibleMessage === sourceMessage) {
+                if (this._filter.shouldBeVisible(visibleMessage)) {
+                    newVisibleMessages.push(this._visibleMessagesIndices[visibleMessageIndex]);
+
+                    if (this._searchRegex && sourceMessage.matchesRegex(this._searchRegex))
+                        this._searchResultsIndices.push(i);
+
+                    if (sourceMessage.type === WebInspector.ConsoleMessage.MessageType.EndGroup) {
+                        anchor = group.element;
+                        group = group.parentGroup || group;
+                    } else if (sourceMessage.type === WebInspector.ConsoleMessage.MessageType.StartGroup || sourceMessage.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
+                        group = sourceMessage.group;
+                        anchor = group.messagesElement.firstChild;
+                    } else
+                        anchor = visibleMessage.toMessageElement();
+                } else {
+                    visibleMessage.willHide();
+                    visibleMessage.toMessageElement().remove();
+                }
+                ++visibleMessageIndex;
+            } else {
+                if (this._filter.shouldBeVisible(sourceMessage)) {
+
+                    if (this._searchRegex && sourceMessage.matchesRegex(this._searchRegex))
+                        this._searchResultsIndices.push(i);
+
+                    group.addMessage(sourceMessage, anchor ? anchor.nextSibling : group.messagesElement.firstChild);
+                    newVisibleMessages.push(i);
+                    anchor = sourceMessage.toMessageElement();
+                }
+            }
+        }
+
+        if (this._searchRegex)
+            WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
+
+        this._visibleMessagesIndices = newVisibleMessages;
+        this._updateFilterStatus();
+    },
+
+    _monitoringXHREnabledSettingChanged: function(event)
+    {
+        ConsoleAgent.setMonitoringXHREnabled(event.data);
+    },
+
+    _messagesClicked: function()
+    {
+        if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
+            this.prompt.moveCaretToEndOfPrompt();
+    },
+
+    _registerShortcuts: function()
+    {
+        this._shortcuts = {};
+
+        var shortcut = WebInspector.KeyboardShortcut;
+        var section = WebInspector.shortcutsScreen.section(WebInspector.UIString("Console"));
+
+        var shortcutL = shortcut.makeDescriptor("l", WebInspector.KeyboardShortcut.Modifiers.Ctrl);
+        this._shortcuts[shortcutL.key] = this._requestClearMessages.bind(this);
+        var keys = [shortcutL];
+        if (WebInspector.isMac()) {
+            var shortcutK = shortcut.makeDescriptor("k", WebInspector.KeyboardShortcut.Modifiers.Meta);
+            this._shortcuts[shortcutK.key] = this._requestClearMessages.bind(this);
+            keys.unshift(shortcutK);
+        }
+        section.addAlternateKeys(keys, WebInspector.UIString("Clear console"));
+
+        section.addKey(shortcut.makeDescriptor(shortcut.Keys.Tab), WebInspector.UIString("Autocomplete common prefix"));
+        section.addKey(shortcut.makeDescriptor(shortcut.Keys.Right), WebInspector.UIString("Accept suggestion"));
+
+        keys = [
+            shortcut.makeDescriptor(shortcut.Keys.Down),
+            shortcut.makeDescriptor(shortcut.Keys.Up)
+        ];
+        section.addRelatedKeys(keys, WebInspector.UIString("Next/previous line"));
+
+        if (WebInspector.isMac()) {
+            keys = [
+                shortcut.makeDescriptor("N", shortcut.Modifiers.Alt),
+                shortcut.makeDescriptor("P", shortcut.Modifiers.Alt)
+            ];
+            section.addRelatedKeys(keys, WebInspector.UIString("Next/previous command"));
+        }
+
+        section.addKey(shortcut.makeDescriptor(shortcut.Keys.Enter), WebInspector.UIString("Execute command"));
+    },
+
+    _requestClearMessages: function()
+    {
+        WebInspector.console.requestClearMessages();
+    },
+
+    _promptKeyDown: function(event)
+    {
+        if (isEnterKey(event)) {
+            this._enterKeyPressed(event);
+            return;
+        }
+
+        var shortcut = WebInspector.KeyboardShortcut.makeKeyFromEvent(event);
+        var handler = this._shortcuts[shortcut];
+        if (handler) {
+            handler();
+            event.preventDefault();
+        }
+    },
+
+    /**
+     * @param {string} expression
+     * @param {boolean} showResultOnly
+     */
+    evaluateUsingTextPrompt: function(expression, showResultOnly)
+    {
+        this._appendCommand(expression, this.prompt.text, false, showResultOnly);
+    },
+
+    _enterKeyPressed: function(event)
+    {
+        if (event.altKey || event.ctrlKey || event.shiftKey)
+            return;
+
+        event.consume(true);
+
+        this.prompt.clearAutoComplete(true);
+
+        var str = this.prompt.text;
+        if (!str.length)
+            return;
+        this._appendCommand(str, "", true, false);
+    },
+
+    /**
+     * @param {WebInspector.RemoteObject} result
+     * @param {boolean} wasThrown
+     * @param {WebInspector.ConsoleCommand} originatingCommand
+     */
+    _printResult: function(result, wasThrown, originatingCommand)
+    {
+        if (!result)
+            return;
+
+        /**
+         * @param {string=} url
+         * @param {number=} lineNumber
+         * @param {number=} columnNumber
+         */
+        function addMessage(url, lineNumber, columnNumber)
+        {
+            var message = new WebInspector.ConsoleCommandResult(result, wasThrown, originatingCommand, this._linkifier, url, lineNumber, columnNumber);
+            WebInspector.console.addMessage(message);
+        }
+
+        if (result.type !== "function") {
+            addMessage.call(this);
+            return;
+        }
+
+        DebuggerAgent.getFunctionDetails(result.objectId, didGetDetails.bind(this));
+
+        /**
+         * @param {?Protocol.Error} error
+         * @param {DebuggerAgent.FunctionDetails} response
+         */
+        function didGetDetails(error, response)
+        {
+            if (error) {
+                console.error(error);
+                addMessage.call(this);
+                return;
+            }
+
+            var url;
+            var lineNumber;
+            var columnNumber;
+            var script = WebInspector.debuggerModel.scriptForId(response.location.scriptId);
+            if (script && script.sourceURL) {
+                url = script.sourceURL;
+                lineNumber = response.location.lineNumber + 1;
+                columnNumber = response.location.columnNumber + 1;
+            }
+            addMessage.call(this, url, lineNumber, columnNumber);
+        }
+    },
+
+    /**
+     * @param {string} text
+     * @param {string} newPromptText
+     * @param {boolean} useCommandLineAPI
+     * @param {boolean} showResultOnly
+     */
+    _appendCommand: function(text, newPromptText, useCommandLineAPI, showResultOnly)
+    {
+        if (!showResultOnly) {
+            var commandMessage = new WebInspector.ConsoleCommand(text);
+            WebInspector.console.addMessage(commandMessage);
+        }
+        this.prompt.text = newPromptText;
+
+        /**
+         * @param {WebInspector.RemoteObject} result
+         * @param {boolean} wasThrown
+         * @param {RuntimeAgent.RemoteObject=} valueResult
+         */
+        function printResult(result, wasThrown, valueResult)
+        {
+            if (!result)
+                return;
+
+            if (!showResultOnly) {
+                this.prompt.pushHistoryItem(text);
+                WebInspector.settings.consoleHistory.set(this.prompt.historyData.slice(-30));
+            }
+
+            this._printResult(result, wasThrown, commandMessage);
+        }
+        WebInspector.runtimeModel.evaluate(text, "console", useCommandLineAPI, false, false, true, printResult.bind(this));
+
+        WebInspector.userMetrics.ConsoleEvaluated.record();
+    },
+
+    elementsToRestoreScrollPositionsFor: function()
+    {
+        return [this.messagesElement];
+    },
+
+    searchCanceled: function()
+    {
+        this._clearCurrentSearchResultHighlight();
+        delete this._searchProvider;
+        delete this._searchResultsIndices;
+        delete this._searchRegex;
+    },
+
+    canSearchAndReplace: function()
+    {
+        return false;
+    },
+
+    canFilter: function()
+    {
+        return true;
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} shouldJump
+     * @param {WebInspector.Searchable=} self
+     */
+    performSearch: function(query, shouldJump, self)
+    {
+        this.searchCanceled();
+        this._searchProvider = self || this;
+        WebInspector.searchController.updateSearchMatchesCount(0, this._searchProvider);
+        this._searchRegex = createPlainTextSearchRegex(query, "gi");
+
+        this._searchResultsIndices = [];
+        for (var i = 0; i < this._visibleMessagesIndices.length; i++) {
+            if (WebInspector.console.messages[this._visibleMessagesIndices[i]].matchesRegex(this._searchRegex))
+                this._searchResultsIndices.push(this._visibleMessagesIndices[i]);
+        }
+        WebInspector.searchController.updateSearchMatchesCount(this._searchResultsIndices.length, this._searchProvider);
+        this._currentSearchResultIndex = -1;
+        if (shouldJump && this._searchResultsIndices.length)
+            this._jumpToSearchResult(0, self);
+    },
+
+    /**
+     * @return {number}
+     */
+    minimalSearchQuerySize: function()
+    {
+        return 0;
+    },
+
+    /**
+     * @param {string} query
+     */
+    performFilter: function(query)
+    {
+        this._filter.performFilter(query);
+    },
+
+    /**
+     * @param {WebInspector.Searchable=} self
+     */
+    jumpToNextSearchResult: function(self)
+    {
+        if (!this._searchResultsIndices || !this._searchResultsIndices.length)
+            return;
+        this._jumpToSearchResult((this._currentSearchResultIndex + 1) % this._searchResultsIndices.length, self);
+    },
+
+    /**
+     * @param {WebInspector.Searchable=} self
+     */
+    jumpToPreviousSearchResult: function(self)
+    {
+        if (!this._searchResultsIndices || !this._searchResultsIndices.length)
+            return;
+        var index = this._currentSearchResultIndex - 1;
+        if (index === -1)
+            index = this._searchResultsIndices.length - 1;
+        this._jumpToSearchResult(index, self);
+    },
+
+    _clearCurrentSearchResultHighlight: function()
+    {
+        if (!this._searchResultsIndices)
+            return;
+        var highlightedMessage = WebInspector.console.messages[this._searchResultsIndices[this._currentSearchResultIndex]];
+        if (highlightedMessage)
+            highlightedMessage.clearHighlight();
+        this._currentSearchResultIndex = -1;
+    },
+
+    _jumpToSearchResult: function(index, self)
+    {
+        this._clearCurrentSearchResultHighlight();
+        this._currentSearchResultIndex = index;
+        WebInspector.searchController.updateCurrentMatchIndex(this._currentSearchResultIndex, this._searchProvider);
+        WebInspector.console.messages[this._searchResultsIndices[index]].highlightSearchResults(this._searchRegex);
+    },
+
+    __proto__: WebInspector.View.prototype
+}
+
+/**
+ * @extends {WebInspector.Object}
+ * @constructor
+ */
+WebInspector.ConsoleViewFilter = function()
+{
+    this._messageURLFilters = WebInspector.settings.messageURLFilters.get();
+    this._messageSourceFilters = WebInspector.settings.messageSourceFilters.get();
+    this._messageLevelFilters = WebInspector.settings.messageLevelFilters.get();
+
+    this._sourceToKeyMap = {};
+
+    for (var key in WebInspector.ConsoleViewFilter._messageSourceGroups) {
+        if (!WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources) {
+            console.assert(!this._otherKey);
+            this._otherKey = key;
+            continue;
+        }
+
+        for (var i = 0; i < WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources.length; ++i)
+            this._sourceToKeyMap[WebInspector.ConsoleViewFilter._messageSourceGroups[key].sources[i]] = key;
+    }
+
+    this._filterChanged = this.dispatchEventToListeners.bind(this, WebInspector.ConsoleViewFilter.Events.FilterChanged);
+
+    WebInspector.settings.messageSourceFilters.addChangeListener(this._updateSourceFilterButton.bind(this));
+    WebInspector.settings.messageLevelFilters.addChangeListener(this._updateLevelFilterBar.bind(this));
+
+    this.sourceFilterButton = new WebInspector.StatusBarButton(WebInspector.UIString("Filter"), "console-filter", 2);
+    this.sourceFilterButton.element.addEventListener("mousedown", this._handleSourceFilterButtonClick.bind(this), false);
+
+    this._filterBarElements = [];
+
+    this.filterBarElement = document.createElement("div");
+    this.filterBarElement.className = "scope-bar status-bar-item";
+
+    this._createLevelFilterBarElement("all", WebInspector.UIString("All"));
+
+    var dividerElement = document.createElement("div");
+    dividerElement.addStyleClass("scope-bar-divider");
+    this.filterBarElement.appendChild(dividerElement);
+
+    this._createLevelFilterBarElement("error", WebInspector.UIString("Errors"));
+    this._createLevelFilterBarElement("warning", WebInspector.UIString("Warnings"));
+    this._createLevelFilterBarElement("log", WebInspector.UIString("Logs"));
+    this._createLevelFilterBarElement("debug", WebInspector.UIString("Debug"));
+
+    this._updateLevelFilterBar();
+    this._updateSourceFilterButton();
+};
+
+WebInspector.ConsoleViewFilter.Events = {
+    FilterChanged: "FilterChanged"
+};
+
+WebInspector.ConsoleViewFilter._messageSourceGroups = {
+    JS: { sources: [WebInspector.ConsoleMessage.MessageSource.JS], title: "JavaScript", styleClass: "filter-type-javascript"},
+    Network: { sources: [WebInspector.ConsoleMessage.MessageSource.Network], title: "Network", styleClass: "filter-type-network"},
+    Logging: { sources: [WebInspector.ConsoleMessage.MessageSource.ConsoleAPI], title: "Logging", styleClass: "filter-type-logging"},
+    CSS: { sources: [WebInspector.ConsoleMessage.MessageSource.CSS], title: "CSS", styleClass: "filter-type-css"},
+    Other: { title: "Other", styleClass: "filter-type-other"}
+};
+
+WebInspector.ConsoleViewFilter.prototype = {
+    /**
+     * @param {string} url
+     */
+    addMessageURLFilter: function(url)
+    {
+        this._messageURLFilters[url] = true;
+        WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
+        this._filterChanged();
+    },
+
+    /**
+     * @param {string} url
+     */
+    removeMessageURLFilter: function(url)
+    {
+        if (!url)
+            this._messageURLFilters = {};
+        else
+            delete this._messageURLFilters[url];
+
+        WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
+        this._filterChanged();
+    },
+
+    /**
+     * @returns {Object}
+     */
+    get messageURLFilters()
+    {
+        return this._messageURLFilters;
+    },
+
+    /**
+     * @param {WebInspector.ConsoleMessage} message
+     * @return {boolean}
+     */
+    shouldBeVisible: function(message)
+    {
+        if ((message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed || message.type === WebInspector.ConsoleMessage.MessageType.EndGroup))
+            return true;
+
+        if (message.url && this._messageURLFilters[message.url])
+            return false;
+
+        if (message.level && this._messageLevelFilters[message.level])
+            return false;
+
+        if (this._filterRegex) {
+            this._filterRegex.lastIndex = 0;
+            if (!message.matchesRegex(this._filterRegex))
+                return false;
+        }
+
+        // We store group keys, and we have resolved group by message source
+        if (message.source) {
+            if (this._sourceToKeyMap[message.source])
+                return !this._messageSourceFilters[this._sourceToKeyMap[message.source]];
+            else
+                return !this._messageSourceFilters[this._otherKey];
+        }
+
+
+        return true;
+    },
+
+    reset: function()
+    {
+        this._messageSourceFilters = {};
+        WebInspector.settings.messageSourceFilters.set(this._messageSourceFilters);
+        this._messageURLFilters = {};
+        WebInspector.settings.messageURLFilters.set(this._messageURLFilters);
+        this._messageLevelFilters = {};
+        WebInspector.settings.messageLevelFilters.set(this._messageLevelFilters);
+        this._filterChanged();
+    },
+
+    /**
+     * @param {string} query
+     */
+    performFilter: function(query)
+    {
+        if (!query)
+            delete this._filterRegex;
+        else
+            this._filterRegex = createPlainTextSearchRegex(query, "gi");
+
+        this._filterChanged();
+    },
+
+    /**
+     * @param {string} sourceGroup
+     * @private
+     */
+    _toggleMessageSourceFilter: function(sourceGroup)
+    {
+        if (!this._messageSourceFilters[sourceGroup])
+            this._messageSourceFilters[sourceGroup] = true;
+        else
+            delete this._messageSourceFilters[sourceGroup];
+
+        WebInspector.settings.messageSourceFilters.set(this._messageSourceFilters);
+        this._filterChanged();
+    },
+
+    /**
+     * @private
+     */
+    _updateSourceFilterButton: function()
+    {
+        var hasActiveSourceFilter = false;
+        for (var sourceGroup in WebInspector.ConsoleViewFilter._messageSourceGroups) {
+            if (this._messageSourceFilters[sourceGroup]) {
+                hasActiveSourceFilter = true;
+                break;
+            }
+        }
+
+        this.sourceFilterButton.state = hasActiveSourceFilter;
+    },
+
+    /**
+     * @param {Event} event
+     * @returns {WebInspector.ContextMenu}
+     * @private
+     */
+    _createSourceFilterMenu: function(event)
+    {
+        var menu = new WebInspector.ContextMenu(event);
+
+        for (var sourceGroup in WebInspector.ConsoleViewFilter._messageSourceGroups) {
+            var filter = WebInspector.ConsoleViewFilter._messageSourceGroups[sourceGroup];
+
+            menu.appendCheckboxItem(WebInspector.UIString(WebInspector.UIString(filter.title)), this._toggleMessageSourceFilter.bind(this, sourceGroup), !this._messageSourceFilters[sourceGroup]);
+        }
+
+        return menu;
+    },
+
+    /**
+     * @param {string} level
+     * @param {string} label
+     * @private
+     */
+    _createLevelFilterBarElement: function(level, label)
+    {
+        var categoryElement = document.createElement("li");
+        categoryElement.category = level;
+        categoryElement.className = level;
+        categoryElement.textContent = label;
+        categoryElement.addEventListener("click", this._toggleLevelFilter.bind(this, level), false);
+
+        this._filterBarElements[level] = categoryElement;
+        this.filterBarElement.appendChild(categoryElement);
+    },
+
+    /**
+     * @param {string} level
+     * @param {Event} event
+     * @private
+     */
+    _toggleLevelFilter: function(level, event)
+    {
+        var isMac = WebInspector.isMac();
+        var selectMultiple = false;
+        if (isMac && event.metaKey && !event.ctrlKey && !event.altKey && !event.shiftKey)
+            selectMultiple = true;
+        if (!isMac && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey)
+            selectMultiple = true;
+
+        if (level === "all")
+            this._messageLevelFilters = {};
+        else {
+            if (!selectMultiple) {
+                this._messageLevelFilters = {error: true, warning: true, log: true, debug: true};
+                delete this._messageLevelFilters[level];
+            } else {
+                if (this._messageLevelFilters[level])
+                    delete this._messageLevelFilters[level];
+                else
+                    this._messageLevelFilters[level] = true;
+            }
+        }
+
+        WebInspector.settings.messageLevelFilters.set(this._messageLevelFilters);
+        this._filterChanged();
+    },
+
+    /**
+     * @private
+     */
+    _updateLevelFilterBar: function()
+    {
+        var all = !(this._messageLevelFilters["error"] || this._messageLevelFilters["warning"] || this._messageLevelFilters["log"] || this._messageLevelFilters["debug"]);
+
+        this._filterBarElements["all"].enableStyleClass("selected", all);
+
+        this._filterBarElements["error"].enableStyleClass("selected", !all && !this._messageLevelFilters["error"]);
+        this._filterBarElements["warning"].enableStyleClass("selected", !all && !this._messageLevelFilters["warning"]);
+        this._filterBarElements["log"].enableStyleClass("selected", !all && !this._messageLevelFilters["log"]);
+        this._filterBarElements["debug"].enableStyleClass("selected", !all && !this._messageLevelFilters["debug"]);
+    },
+
+    /**
+     * @param {Event} event
+     * @private
+     */
+    _handleSourceFilterButtonClick: function(event)
+    {
+        if (!event.button)
+            this._createSourceFilterMenu(event).showSoftMenu();
+    },
+
+    __proto__: WebInspector.Object.prototype
+};
+
+
+/**
+ * @constructor
+ * @extends WebInspector.ConsoleMessage
+ */
+WebInspector.ConsoleCommand = function(text)
+{
+    this.text = text;
+}
+
+WebInspector.ConsoleCommand.prototype = {
+    wasShown: function()
+    {
+    },
+
+    willHide: function()
+    {
+    },
+
+    clearHighlight: function()
+    {
+        var highlightedMessage = this._formattedCommand;
+        delete this._formattedCommand;
+        this._formatCommand();
+        this._element.replaceChild(this._formattedCommand, highlightedMessage);
+    },
+
+    /**
+     * @param {RegExp} regexObject
+     */
+    highlightSearchResults: function(regexObject)
+    {
+        regexObject.lastIndex = 0;
+        var match = regexObject.exec(this.text);
+        var matchRanges = [];
+        while (match) {
+            matchRanges.push({ offset: match.index, length: match[0].length });
+            match = regexObject.exec(this.text);
+        }
+        WebInspector.highlightSearchResults(this._formattedCommand, matchRanges);
+        this._element.scrollIntoViewIfNeeded();
+    },
+
+    /**
+     * @param {RegExp} regexObject
+     */
+    matchesRegex: function(regexObject)
+    {
+        regexObject.lastIndex = 0;
+        return regexObject.test(this.text);
+    },
+
+    toMessageElement: function()
+    {
+        if (!this._element) {
+            this._element = document.createElement("div");
+            this._element.command = this;
+            this._element.className = "console-user-command";
+
+            this._formatCommand();
+            this._element.appendChild(this._formattedCommand);
+        }
+        return this._element;
+    },
+
+    _formatCommand: function()
+    {
+        this._formattedCommand = document.createElement("span");
+        this._formattedCommand.className = "console-message-text source-code";
+        this._formattedCommand.textContent = this.text;
+    },
+
+    __proto__: WebInspector.ConsoleMessage.prototype
+}
+
+/**
+ * @extends {WebInspector.ConsoleMessageImpl}
+ * @constructor
+ * @param {WebInspector.RemoteObject} result
+ * @param {boolean} wasThrown
+ * @param {WebInspector.ConsoleCommand} originatingCommand
+ * @param {WebInspector.Linkifier} linkifier
+ * @param {string=} url
+ * @param {number=} lineNumber
+ * @param {number=} columnNumber
+ */
+WebInspector.ConsoleCommandResult = function(result, wasThrown, originatingCommand, linkifier, url, lineNumber, columnNumber)
+{
+    var level = (wasThrown ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log);
+    this.originatingCommand = originatingCommand;
+    WebInspector.ConsoleMessageImpl.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, "", linkifier, WebInspector.ConsoleMessage.MessageType.Result, url, lineNumber, columnNumber, undefined, [result]);
+}
+
+WebInspector.ConsoleCommandResult.prototype = {
+    /**
+     * @override
+     * @param {WebInspector.RemoteObject} array
+     * @return {boolean}
+     */
+    useArrayPreviewInFormatter: function(array)
+    {
+        return false;
+    },
+
+    toMessageElement: function()
+    {
+        var element = WebInspector.ConsoleMessageImpl.prototype.toMessageElement.call(this);
+        element.addStyleClass("console-user-command-result");
+        return element;
+    },
+
+    __proto__: WebInspector.ConsoleMessageImpl.prototype
+}
+
+/**
+ * @constructor
+ */
+WebInspector.ConsoleGroup = function(parentGroup)
+{
+    this.parentGroup = parentGroup;
+
+    var element = document.createElement("div");
+    element.className = "console-group";
+    element.group = this;
+    this.element = element;
+
+    if (parentGroup) {
+        var bracketElement = document.createElement("div");
+        bracketElement.className = "console-group-bracket";
+        element.appendChild(bracketElement);
+    }
+
+    var messagesElement = document.createElement("div");
+    messagesElement.className = "console-group-messages";
+    element.appendChild(messagesElement);
+    this.messagesElement = messagesElement;
+}
+
+WebInspector.ConsoleGroup.prototype = {
+    /**
+     * @param {WebInspector.ConsoleMessage} message
+     * @param {Node=} node
+     */
+    addMessage: function(message, node)
+    {
+        var element = message.toMessageElement();
+
+        if (message.type === WebInspector.ConsoleMessage.MessageType.StartGroup || message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed) {
+            this.messagesElement.parentNode.insertBefore(element, this.messagesElement);
+            element.addEventListener("click", this._titleClicked.bind(this), false);
+            var groupElement = element.enclosingNodeOrSelfWithClass("console-group");
+            if (groupElement && message.type === WebInspector.ConsoleMessage.MessageType.StartGroupCollapsed)
+                groupElement.addStyleClass("collapsed");
+        } else {
+            this.messagesElement.insertBefore(element, node || null);
+            message.wasShown();
+        }
+
+        if (element.previousSibling && message.originatingCommand && element.previousSibling.command === message.originatingCommand)
+            element.previousSibling.addStyleClass("console-adjacent-user-command-result");
+    },
+
+    _titleClicked: function(event)
+    {
+        var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title");
+        if (groupTitleElement) {
+            var groupElement = groupTitleElement.enclosingNodeOrSelfWithClass("console-group");
+            if (groupElement)
+                if (groupElement.hasStyleClass("collapsed"))
+                    groupElement.removeStyleClass("collapsed");
+                else
+                    groupElement.addStyleClass("collapsed");
+            groupTitleElement.scrollIntoViewIfNeeded(true);
+        }
+
+        event.consume(true);
+    }
+}
+
+/**
+ * @type {?WebInspector.ConsoleView}
+ */
+WebInspector.consoleView = null;
+
+WebInspector.ConsoleMessage.create = function(source, level, message, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated)
+{
+    return new WebInspector.ConsoleMessageImpl(source, level, message, WebInspector.consoleView._linkifier, type, url, line, column, repeatCount, parameters, stackTrace, requestId, isOutdated);
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProvider.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProvider.js
new file mode 100644
index 00000000..c731aa24
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProvider.js
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @interface
+ */
+WebInspector.ContentProvider = function() { }
+
+WebInspector.ContentProvider.prototype = {
+    /**
+     * @return {string}
+     */
+    contentURL: function() { },
+
+    /**
+     * @return {WebInspector.ResourceType}
+     */
+    contentType: function() { },
+
+    /**
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestContent: function(callback) { },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback) { }
+}
+
+/**
+ * @constructor
+ * @param {number} lineNumber
+ * @param {string} lineContent
+ */
+WebInspector.ContentProvider.SearchMatch = function(lineNumber, lineContent) {
+    this.lineNumber = lineNumber;
+    this.lineContent = lineContent;
+}
+
+/**
+ * @param {string} content
+ * @param {string} query
+ * @param {boolean} caseSensitive
+ * @param {boolean} isRegex
+ * @return {Array.}
+ */
+WebInspector.ContentProvider.performSearchInContent = function(content, query, caseSensitive, isRegex)
+{
+    var regex = createSearchRegex(query, caseSensitive, isRegex);
+
+    var result = [];
+    var lineEndings = content.lineEndings();
+    for (var i = 0; i < lineEndings.length; ++i) {
+        var lineStart = i > 0 ? lineEndings[i - 1] + 1 : 0;
+        var lineEnd = lineEndings[i];
+        var lineContent = content.substring(lineStart, lineEnd);
+        if (lineContent.length > 0 && lineContent.charAt(lineContent.length - 1) === "\r")
+            lineContent = lineContent.substring(0, lineContent.length - 1)
+
+        regex.lastIndex = 0;
+        if (regex.exec(lineContent))
+            result.push(new WebInspector.ContentProvider.SearchMatch(i, lineContent));
+    }
+    return result;
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviderBasedProjectDelegate.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviderBasedProjectDelegate.js
new file mode 100644
index 00000000..77a03d75
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviderBasedProjectDelegate.js
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+ /**
+ * @constructor
+ * @implements {WebInspector.ProjectDelegate}
+ * @extends {WebInspector.Object}
+ * @param {string} type
+ */
+WebInspector.ContentProviderBasedProjectDelegate = function(type)
+{
+    this._type = type;
+    /** @type {!Object.} */
+    this._contentProviders = {};
+    /** @type {Object.} */
+    this._isContentScriptMap = {};
+}
+
+WebInspector.ContentProviderBasedProjectDelegate.prototype = {
+    /**
+     * @return {string}
+     */
+    id: function()
+    {
+        // Overriddden by subclasses
+        return "";
+    },
+
+    /**
+     * @return {string}
+     */
+    type: function()
+    {
+        return this._type;
+    },
+
+    /**
+     * @return {string}
+     */
+    displayName: function()
+    {
+        // Overriddden by subclasses
+        return "";
+    },
+
+    /**
+     * @param {string} path
+     * @param {function(?Date, ?number)} callback
+     */
+    requestMetadata: function(path, callback)
+    {
+        callback(null, null);
+    },
+
+    /**
+     * @param {string} path
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestFileContent: function(path, callback)
+    {
+        var contentProvider = this._contentProviders[path];
+        contentProvider.requestContent(callback);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    canSetFileContent: function()
+    {
+        return false;
+    },
+
+    /**
+     * @param {string} path
+     * @param {string} newContent
+     * @param {function(?string)} callback
+     */
+    setFileContent: function(path, newContent, callback)
+    {
+        callback(null);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    canRename: function()
+    {
+        return false;
+    },
+
+    /**
+     * @param {string} path
+     * @param {string} newName
+     * @param {function(boolean, string=)} callback
+     */
+    rename: function(path, newName, callback)
+    {
+        this.performRename(path, newName, innerCallback.bind(this));
+
+        /**
+         * @param {boolean} success
+         * @param {string=} newName
+         */
+        function innerCallback(success, newName)
+        {
+            if (success)
+                this._updateName(path, newName);
+            callback(success, newName);
+        }
+    },
+
+    /**
+     * @param {string} path
+     */
+    refresh: function(path)
+    {
+    },
+
+    /**
+     * @param {string} path
+     */
+    excludeFolder: function(path)
+    {
+    },
+
+    /**
+     * @param {string} path
+     * @param {?string} name
+     * @param {function(?string)} callback
+     */
+    createFile: function(path, name, callback)
+    {
+    },
+
+    /**
+     * @param {string} path
+     */
+    deleteFile: function(path)
+    {
+    },
+
+    remove: function()
+    {
+    },
+
+    /**
+     * @param {string} path
+     * @param {string} newName
+     * @param {function(boolean, string=)} callback
+     */
+    performRename: function(path, newName, callback)
+    {
+        callback(false);
+    },
+
+    /**
+     * @param {string} path
+     * @param {string} newName
+     */
+    _updateName: function(path, newName)
+    {
+        var oldPath = path;
+        var copyOfPath = path.split("/");
+        copyOfPath[copyOfPath.length - 1] = newName;
+        var newPath = copyOfPath.join("/");
+        this._contentProviders[newPath] = this._contentProviders[oldPath];
+        delete this._contentProviders[oldPath];
+    },
+
+    /**
+     * @param {string} path
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInFileContent: function(path, query, caseSensitive, isRegex, callback)
+    {
+        var contentProvider = this._contentProviders[path];
+        contentProvider.searchInContent(query, caseSensitive, isRegex, callback);
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {WebInspector.Progress} progress
+     * @param {function(StringMap)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, progress, callback)
+    {
+        var result = new StringMap();
+
+        var paths = Object.keys(this._contentProviders);
+        var totalCount = paths.length;
+        if (totalCount === 0) {
+            // searchInContent should call back later.
+            setTimeout(doneCallback, 0);
+            return;
+        }
+
+        function filterOutContentScripts(path)
+        {
+            return !this._isContentScriptMap[path];
+        }
+
+        if (!WebInspector.settings.searchInContentScripts.get())
+            paths = paths.filter(filterOutContentScripts.bind(this));
+
+        var barrier = new CallbackBarrier();
+        progress.setTotalWork(paths.length);
+        for (var i = 0; i < paths.length; ++i)
+            this._contentProviders[paths[i]].searchInContent(query, caseSensitive, isRegex, barrier.createCallback(contentCallback.bind(this, i)));
+        barrier.callWhenDone(doneCallback);
+
+        function contentCallback(i, searchMatches)
+        {
+            result.put(paths[i], searchMatches);
+            progress.worked(1);
+        }
+
+        function doneCallback()
+        {
+            callback(result);
+            progress.done();
+        }
+    },
+
+    /**
+     * @param {WebInspector.Progress} progress
+     * @param {function()} callback
+     */
+    indexContent: function(progress, callback)
+    {
+        setTimeout(innerCallback, 0);
+
+        function innerCallback()
+        {
+            progress.done();
+            callback();
+        }
+    },
+
+    /**
+     * @param {string} parentPath
+     * @param {string} name
+     * @param {string} url
+     * @param {WebInspector.ContentProvider} contentProvider
+     * @param {boolean} isEditable
+     * @param {boolean=} isContentScript
+     * @return {string}
+     */
+    addContentProvider: function(parentPath, name, url, contentProvider, isEditable, isContentScript)
+    {
+        var path = parentPath ? parentPath + "/" + name : name;
+        var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, url, url, contentProvider.contentType(), isEditable, isContentScript);
+        this._contentProviders[path] = contentProvider;
+        this._isContentScriptMap[path] = isContentScript || false;
+        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor);
+        return path;
+    },
+
+    /**
+     * @param {string} path
+     */
+    removeFile: function(path)
+    {
+        delete this._contentProviders[path];
+        delete this._isContentScriptMap[path];
+        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path);
+    },
+
+    /**
+     * @return {Object.}
+     */
+    contentProviders: function()
+    {
+        return this._contentProviders;
+    },
+
+    reset: function()
+    {
+        this._contentProviders = {};
+        this._isContentScriptMap = {};
+        this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.Reset, null);
+    },
+    
+    __proto__: WebInspector.Object.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviders.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviders.js
new file mode 100644
index 00000000..5394c903
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContentProviders.js
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContentProvider}
+ * @param {Array.} scripts
+ */
+WebInspector.ConcatenatedScriptsContentProvider = function(scripts)
+{
+    this._mimeType = "text/html";
+    this._scripts = scripts;
+}
+
+WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag = "";
+
+WebInspector.ConcatenatedScriptsContentProvider.prototype = {
+    /**
+     * @return {Array.}
+     */
+    _sortedScripts: function()
+    {
+        if (this._sortedScriptsArray)
+            return this._sortedScriptsArray;
+
+        this._sortedScriptsArray = [];
+        
+        var scripts = this._scripts.slice();
+        scripts.sort(function(x, y) { return x.lineOffset - y.lineOffset || x.columnOffset - y.columnOffset; });
+        
+        var scriptOpenTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag.length;
+        var scriptCloseTagLength = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag.length;
+        
+        this._sortedScriptsArray.push(scripts[0]);
+        for (var i = 1; i < scripts.length; ++i) {
+            var previousScript = this._sortedScriptsArray[this._sortedScriptsArray.length - 1];
+            
+            var lineNumber = previousScript.endLine;
+            var columnNumber = previousScript.endColumn + scriptCloseTagLength + scriptOpenTagLength;
+            
+            if (lineNumber < scripts[i].lineOffset || (lineNumber === scripts[i].lineOffset && columnNumber <= scripts[i].columnOffset))
+                this._sortedScriptsArray.push(scripts[i]);
+        }
+        return this._sortedScriptsArray;
+    },
+
+    /**
+     * @return {string}
+     */
+    contentURL: function()
+    {
+        return "";
+    },
+
+    /**
+     * @return {WebInspector.ResourceType}
+     */
+    contentType: function()
+    {
+        return WebInspector.resourceTypes.Document;
+    },
+    
+    /**
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestContent: function(callback)
+    {
+        var scripts = this._sortedScripts();
+        var sources = [];
+        function didRequestSource(content, contentEncoded, mimeType)
+        {
+            sources.push(content);
+            if (sources.length == scripts.length)
+                callback(this._concatenateScriptsContent(scripts, sources), false, this._mimeType);
+        }
+        for (var i = 0; i < scripts.length; ++i)
+            scripts[i].requestContent(didRequestSource.bind(this));
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback)
+    {
+        var results = {};
+        var scripts = this._sortedScripts();
+        var scriptsLeft = scripts.length;
+
+        function maybeCallback()
+        {
+            if (scriptsLeft)
+                return;
+
+            var result = [];
+            for (var i = 0; i < scripts.length; ++i)
+                result = result.concat(results[scripts[i].scriptId]);
+            callback(result);
+        }
+
+        /**
+         * @param {WebInspector.Script} script
+         * @param {Array.} searchMatches
+         */
+        function searchCallback(script, searchMatches)
+        {
+            results[script.scriptId] = [];
+            for (var i = 0; i < searchMatches.length; ++i) {
+                var searchMatch = new WebInspector.ContentProvider.SearchMatch(searchMatches[i].lineNumber + script.lineOffset, searchMatches[i].lineContent);
+                results[script.scriptId].push(searchMatch);
+            }
+            scriptsLeft--;
+            maybeCallback.call(this);
+        }
+
+        maybeCallback();
+        for (var i = 0; i < scripts.length; ++i)
+            scripts[i].searchInContent(query, caseSensitive, isRegex, searchCallback.bind(this, scripts[i]));
+    },
+
+    /**
+     * @return {string}
+     */
+    _concatenateScriptsContent: function(scripts, sources)
+    {
+        var content = "";
+        var lineNumber = 0;
+        var columnNumber = 0;
+
+        var scriptOpenTag = WebInspector.ConcatenatedScriptsContentProvider.scriptOpenTag;
+        var scriptCloseTag = WebInspector.ConcatenatedScriptsContentProvider.scriptCloseTag;
+        for (var i = 0; i < scripts.length; ++i) {
+            // Fill the gap with whitespace characters.
+            for (var newLinesCount = scripts[i].lineOffset - lineNumber; newLinesCount > 0; --newLinesCount) {
+                columnNumber = 0;
+                content += "\n";
+            }
+            for (var spacesCount = scripts[i].columnOffset - columnNumber - scriptOpenTag.length; spacesCount > 0; --spacesCount)
+                content += " ";
+
+            // Add script tag.
+            content += scriptOpenTag;
+            content += sources[i];
+            content += scriptCloseTag;
+            lineNumber = scripts[i].endLine;
+            columnNumber = scripts[i].endColumn + scriptCloseTag.length;
+        }
+
+        return content;
+    },
+
+    __proto__: WebInspector.ContentProvider.prototype
+}
+
+/**
+ * @constructor
+ * @param {string} sourceURL
+ * @param {WebInspector.ResourceType} contentType
+ * @param {string} mimeType
+ * @implements {WebInspector.ContentProvider}
+ */
+WebInspector.CompilerSourceMappingContentProvider = function(sourceURL, contentType, mimeType)
+{
+    this._sourceURL = sourceURL;
+    this._contentType = contentType;
+    this._mimeType = mimeType;
+}
+
+WebInspector.CompilerSourceMappingContentProvider.prototype = {
+    /**
+     * @return {string}
+     */
+    contentURL: function()
+    {
+        return this._sourceURL;
+    },
+
+    /**
+     * @return {WebInspector.ResourceType}
+     */
+    contentType: function()
+    {
+        return this._contentType;
+    },
+    
+    /**
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestContent: function(callback)
+    {
+        NetworkAgent.loadResourceForFrontend(WebInspector.resourceTreeModel.mainFrame.id, this._sourceURL, undefined, contentLoaded.bind(this));
+
+        /**
+         * @param {?Protocol.Error} error
+         * @param {number} statusCode
+         * @param {NetworkAgent.Headers} headers
+         * @param {string} content
+         */
+        function contentLoaded(error, statusCode, headers, content)
+        {
+            if (error || statusCode >= 400) {
+                console.error("Could not load content for " + this._sourceURL + " : " + (error || ("HTTP status code: " + statusCode)));
+                callback(null, false, this._mimeType);
+                return;
+            }
+
+            callback(content, false, this._mimeType);
+        }
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback)
+    {
+        this.requestContent(contentLoaded);
+
+        /**
+         * @param {?string} content
+         * @param {boolean} base64Encoded
+         * @param {string} mimeType
+         */
+        function contentLoaded(content, base64Encoded, mimeType)
+        {
+            if (typeof content !== "string") {
+                callback([]);
+                return;
+            }
+
+            callback(WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex));
+        }
+    },
+
+    __proto__: WebInspector.ContentProvider.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContentProvider}
+ * @param {WebInspector.ResourceType} contentType 
+ * @param {string} content
+ * @param {string=} mimeType
+ */
+WebInspector.StaticContentProvider = function(contentType, content, mimeType)
+{
+    this._content = content;
+    this._contentType = contentType;
+    this._mimeType = mimeType;
+}
+
+WebInspector.StaticContentProvider.prototype = {
+    /**
+     * @return {string}
+     */
+    contentURL: function()
+    {
+        return "";
+    },
+
+    /**
+     * @return {WebInspector.ResourceType}
+     */
+    contentType: function()
+    {
+        return this._contentType;
+    },
+
+    /**
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestContent: function(callback)
+    {
+        callback(this._content, false, this._mimeType || this._contentType.canonicalMimeType());
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback)
+    {
+        function performSearch()
+        {
+            callback(WebInspector.ContentProvider.performSearchInContent(this._content, query, caseSensitive, isRegex));
+        }
+
+        // searchInContent should call back later.
+        window.setTimeout(performSearch.bind(this), 0);
+    },
+
+    __proto__: WebInspector.ContentProvider.prototype
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.ContentProvider}
+ * @param {WebInspector.ContentProvider} contentProvider
+ * @param {string} mimeType
+ */
+WebInspector.ContentProviderOverridingMimeType = function(contentProvider, mimeType)
+{
+    this._contentProvider = contentProvider;
+    this._mimeType = mimeType;
+}
+
+WebInspector.ContentProviderOverridingMimeType.prototype = {
+    /**
+     * @return {string}
+     */
+    contentURL: function()
+    {
+        return this._contentProvider.contentURL();
+    },
+
+    /**
+     * @return {WebInspector.ResourceType}
+     */
+    contentType: function()
+    {
+        return this._contentProvider.contentType();
+    },
+
+    /**
+     * @param {function(?string,boolean,string)} callback
+     */
+    requestContent: function(callback)
+    {
+        this._contentProvider.requestContent(innerCallback.bind(this));
+
+        function innerCallback(content, contentEncoded, mimeType)
+        {
+            callback(content, contentEncoded, this._mimeType);
+        }
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} caseSensitive
+     * @param {boolean} isRegex
+     * @param {function(Array.)} callback
+     */
+    searchInContent: function(query, caseSensitive, isRegex, callback)
+    {
+        this._contentProvider.searchInContent(query, caseSensitive, isRegex, callback);
+    },
+
+    __proto__: WebInspector.ContentProvider.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContextMenu.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContextMenu.js
new file mode 100644
index 00000000..98bf1a49
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ContextMenu.js
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.ContextSubMenuItem} topLevelMenu
+ * @param {string} type
+ * @param {string=} label
+ * @param {boolean=} disabled
+ * @param {boolean=} checked
+ */
+WebInspector.ContextMenuItem = function(topLevelMenu, type, label, disabled, checked)
+{
+    this._type = type;
+    this._label = label;
+    this._disabled = disabled;
+    this._checked = checked;
+    this._contextMenu = topLevelMenu;
+    if (type === "item" || type === "checkbox")
+        this._id = topLevelMenu.nextId();
+}
+
+WebInspector.ContextMenuItem.prototype = {
+    id: function()
+    {
+        return this._id;
+    },
+
+    type: function()
+    {
+        return this._type;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isEnabled: function()
+    {
+        return !this._disabled;
+    },
+
+    /**
+     * @param {boolean} enabled
+     */
+    setEnabled: function(enabled)
+    {
+        this._disabled = !enabled;
+    },
+
+    _buildDescriptor: function()
+    {
+        switch (this._type) {
+        case "item":
+            return { type: "item", id: this._id, label: this._label, enabled: !this._disabled };
+        case "separator":
+            return { type: "separator" };
+        case "checkbox":
+            return { type: "checkbox", id: this._id, label: this._label, checked: !!this._checked, enabled: !this._disabled };
+        }
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ContextMenuItem}
+ * @param topLevelMenu
+ * @param {string=} label
+ * @param {boolean=} disabled
+ */
+WebInspector.ContextSubMenuItem = function(topLevelMenu, label, disabled)
+{
+    WebInspector.ContextMenuItem.call(this, topLevelMenu, "subMenu", label, disabled);
+    /** @type {!Array.} */
+    this._items = [];
+}
+
+WebInspector.ContextSubMenuItem.prototype = {
+    /**
+     * @param {string} label
+     * @param {function(?)} handler
+     * @param {boolean=} disabled
+     * @return {WebInspector.ContextMenuItem}
+     */
+    appendItem: function(label, handler, disabled)
+    {
+        var item = new WebInspector.ContextMenuItem(this._contextMenu, "item", label, disabled);
+        this._pushItem(item);
+        this._contextMenu._setHandler(item.id(), handler);
+        return item;
+    },
+
+    /**
+     * @param {string} label
+     * @param {boolean=} disabled
+     * @return {WebInspector.ContextMenuItem}
+     */
+    appendSubMenuItem: function(label, disabled)
+    {
+        var item = new WebInspector.ContextSubMenuItem(this._contextMenu, label, disabled);
+        this._pushItem(item);
+        return item;
+    },
+
+    /**
+     * @param {boolean=} disabled
+     */
+    appendCheckboxItem: function(label, handler, checked, disabled)
+    {
+        var item = new WebInspector.ContextMenuItem(this._contextMenu, "checkbox", label, disabled, checked);
+        this._pushItem(item);
+        this._contextMenu._setHandler(item.id(), handler);
+        return item;
+    },
+
+    appendSeparator: function()
+    {
+        if (this._items.length)
+            this._pendingSeparator = true;
+    },
+
+    /**
+     * @param {!WebInspector.ContextMenuItem} item
+     */
+    _pushItem: function(item)
+    {
+        if (this._pendingSeparator) {
+            this._items.push(new WebInspector.ContextMenuItem(this._contextMenu, "separator"));
+            delete this._pendingSeparator;
+        }
+        this._items.push(item);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isEmpty: function()
+    {
+        return !this._items.length;
+    },
+
+    _buildDescriptor: function()
+    {
+        var result = { type: "subMenu", label: this._label, enabled: !this._disabled, subItems: [] };
+        for (var i = 0; i < this._items.length; ++i)
+            result.subItems.push(this._items[i]._buildDescriptor());
+        return result;
+    },
+
+    __proto__: WebInspector.ContextMenuItem.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ContextSubMenuItem}
+ */
+WebInspector.ContextMenu = function(event) {
+    WebInspector.ContextSubMenuItem.call(this, this, "");
+    this._event = event;
+    this._handlers = {};
+    this._id = 0;
+}
+
+WebInspector.ContextMenu.prototype = {
+    nextId: function()
+    {
+        return this._id++;
+    },
+
+    show: function()
+    {
+        var menuObject = this._buildDescriptor();
+
+        if (menuObject.length) {
+            WebInspector._contextMenu = this;
+            InspectorFrontendHost.showContextMenu(this._event, menuObject);
+            this._event.consume();
+        }
+    },
+
+    showSoftMenu: function()
+    {
+        var menuObject = this._buildDescriptor();
+
+        if (menuObject.length) {
+            WebInspector._contextMenu = this;
+            var softMenu = new WebInspector.SoftContextMenu(menuObject);
+            softMenu.show(this._event, true);
+        }
+        this._event.consume();
+    },
+
+    _setHandler: function(id, handler)
+    {
+        if (handler)
+            this._handlers[id] = handler;
+    },
+
+    _buildDescriptor: function()
+    {
+        var result = [];
+        for (var i = 0; i < this._items.length; ++i)
+            result.push(this._items[i]._buildDescriptor());
+        return result;
+    },
+
+    _itemSelected: function(id)
+    {
+        if (this._handlers[id])
+            this._handlers[id].call(this);
+    },
+
+    /**
+     * @param {Object} target
+     */
+    appendApplicableItems: function(target)
+    {
+        for (var i = 0; i < WebInspector.ContextMenu._providers.length; ++i) {
+            var provider = WebInspector.ContextMenu._providers[i];
+            this.appendSeparator();
+            provider.appendApplicableItems(this._event, this, target);
+            this.appendSeparator();
+        }
+    },
+
+    __proto__: WebInspector.ContextSubMenuItem.prototype
+}
+
+/**
+ * @interface
+ */
+WebInspector.ContextMenu.Provider = function() { 
+}
+
+WebInspector.ContextMenu.Provider.prototype = {
+    /** 
+     * @param {WebInspector.ContextMenu} contextMenu
+     * @param {Object} target
+     */
+    appendApplicableItems: function(event, contextMenu, target) { }
+}
+
+/**
+ * @param {WebInspector.ContextMenu.Provider} provider
+ */
+WebInspector.ContextMenu.registerProvider = function(provider)
+{
+    WebInspector.ContextMenu._providers.push(provider);
+}
+
+WebInspector.ContextMenu._providers = [];
+
+WebInspector.contextMenuItemSelected = function(id)
+{
+    if (WebInspector._contextMenu)
+        WebInspector._contextMenu._itemSelected(id);
+}
+
+WebInspector.contextMenuCleared = function()
+{
+    // FIXME: Unfortunately, contextMenuCleared is invoked between show and item selected
+    // so we can't delete last menu object from WebInspector. Fix the contract.
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieItemsView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieItemsView.js
new file mode 100644
index 00000000..0fddf9e6
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieItemsView.js
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2009 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.CookieItemsView = function(treeElement, cookieDomain)
+{
+    WebInspector.View.call(this);
+
+    this.element.addStyleClass("storage-view");
+
+    this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
+    this._deleteButton.visible = false;
+    this._deleteButton.addEventListener("click", this._deleteButtonClicked, this);
+
+    this._clearButton = new WebInspector.StatusBarButton(WebInspector.UIString("Clear"), "clear-storage-status-bar-item");
+    this._clearButton.visible = false;
+    this._clearButton.addEventListener("click", this._clearButtonClicked, this);
+
+    this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
+    this._refreshButton.addEventListener("click", this._refreshButtonClicked, this);
+
+    this._treeElement = treeElement;
+    this._cookieDomain = cookieDomain;
+
+    this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("This site has no cookies."));
+    this._emptyView.show(this.element);
+
+    this.element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
+}
+
+WebInspector.CookieItemsView.prototype = {
+    get statusBarItems()
+    {
+        return [this._refreshButton.element, this._clearButton.element, this._deleteButton.element];
+    },
+
+    wasShown: function()
+    {
+        this._update();
+    },
+
+    willHide: function()
+    {
+        this._deleteButton.visible = false;
+    },
+
+    _update: function()
+    {
+        WebInspector.Cookies.getCookiesAsync(this._updateWithCookies.bind(this));
+    },
+
+    /**
+     * @param {Array.} allCookies
+     */
+    _updateWithCookies: function(allCookies)
+    {
+        this._cookies = this._filterCookiesForDomain(allCookies);
+
+        if (!this._cookies.length) {
+            // Nothing to show.
+            this._emptyView.show(this.element);
+            this._clearButton.visible = false;
+            this._deleteButton.visible = false;
+            if (this._cookiesTable)
+                this._cookiesTable.detach();
+            return;
+        }
+
+        if (!this._cookiesTable)
+            this._cookiesTable = new WebInspector.CookiesTable(false, this._update.bind(this), this._showDeleteButton.bind(this));
+
+        this._cookiesTable.setCookies(this._cookies);
+        this._emptyView.detach();
+        this._cookiesTable.show(this.element);
+        this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length,
+            Number.bytesToString(this._totalSize));
+        this._clearButton.visible = true;
+        this._deleteButton.visible = !!this._cookiesTable.selectedCookie();
+    },
+
+    /**
+     * @param {Array.} allCookies
+     */
+    _filterCookiesForDomain: function(allCookies)
+    {
+        var cookies = [];
+        var resourceURLsForDocumentURL = [];
+        this._totalSize = 0;
+
+        function populateResourcesForDocuments(resource)
+        {
+            var url = resource.documentURL.asParsedURL();
+            if (url && url.host == this._cookieDomain)
+                resourceURLsForDocumentURL.push(resource.url);
+        }
+        WebInspector.forAllResources(populateResourcesForDocuments.bind(this));
+
+        for (var i = 0; i < allCookies.length; ++i) {
+            var pushed = false;
+            var size = allCookies[i].size();
+            for (var j = 0; j < resourceURLsForDocumentURL.length; ++j) {
+                var resourceURL = resourceURLsForDocumentURL[j];
+                if (WebInspector.Cookies.cookieMatchesResourceURL(allCookies[i], resourceURL)) {
+                    this._totalSize += size;
+                    if (!pushed) {
+                        pushed = true;
+                        cookies.push(allCookies[i]);
+                    }
+                }
+            }
+        }
+        return cookies;
+    },
+
+    clear: function()
+    {
+        this._cookiesTable.clear();
+        this._update();
+    },
+
+    _clearButtonClicked: function()
+    {
+        this.clear();
+    },
+
+    _showDeleteButton: function()
+    {
+        this._deleteButton.visible = true;
+    },
+
+    _deleteButtonClicked: function()
+    {
+        var selectedCookie = this._cookiesTable.selectedCookie();
+        if (selectedCookie) {
+            selectedCookie.remove();
+            this._update();
+        }
+    },
+
+    _refreshButtonClicked: function(event)
+    {
+        this._update();
+    },
+
+    _contextMenu: function(event)
+    {
+        if (!this._cookies.length) {
+            var contextMenu = new WebInspector.ContextMenu(event);
+            contextMenu.appendItem(WebInspector.UIString("Refresh"), this._update.bind(this));
+            contextMenu.show();
+        }
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieParser.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieParser.js
new file mode 100644
index 00000000..727a637c
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookieParser.js
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Ideally, we would rely on platform support for parsing a cookie, since
+// this would save us from any potential inconsistency. However, exposing
+// platform cookie parsing logic would require quite a bit of additional
+// plumbing, and at least some platforms lack support for parsing Cookie,
+// which is in a format slightly different from Set-Cookie and is normally
+// only required on the server side.
+
+/**
+ * @constructor
+ */
+WebInspector.CookieParser = function()
+{
+}
+
+/**
+ * @constructor
+ * @param {string} key
+ * @param {string|undefined} value
+ * @param {number} position
+ */
+WebInspector.CookieParser.KeyValue = function(key, value, position)
+{
+    this.key = key;
+    this.value = value;
+    this.position = position;
+}
+
+WebInspector.CookieParser.prototype = {
+    /**
+     * @return {Array.}
+     */
+    cookies: function()
+    {
+        return this._cookies;
+    },
+
+    /**
+     * @param {string|undefined} cookieHeader
+     * @return {?Array.}
+     */
+    parseCookie: function(cookieHeader)
+    {
+        if (!this._initialize(cookieHeader))
+            return null;
+
+        for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
+            if (kv.key.charAt(0) === "$" && this._lastCookie)
+                this._lastCookie.addAttribute(kv.key.slice(1), kv.value);
+            else if (kv.key.toLowerCase() !== "$version" && typeof kv.value === "string")
+                this._addCookie(kv, WebInspector.Cookie.Type.Request);
+            this._advanceAndCheckCookieDelimiter();
+        }
+        this._flushCookie();
+        return this._cookies;
+    },
+
+    /**
+     * @param {string|undefined} setCookieHeader
+     * @return {?Array.}
+     */
+    parseSetCookie: function(setCookieHeader)
+    {
+        if (!this._initialize(setCookieHeader))
+            return null;
+        for (var kv = this._extractKeyValue(); kv; kv = this._extractKeyValue()) {
+            if (this._lastCookie)
+                this._lastCookie.addAttribute(kv.key, kv.value);
+            else
+                this._addCookie(kv, WebInspector.Cookie.Type.Response);
+            if (this._advanceAndCheckCookieDelimiter())
+                this._flushCookie();
+        }
+        this._flushCookie();
+        return this._cookies;
+    },
+
+    /**
+     * @param {string|undefined} headerValue
+     * @return {boolean}
+     */
+    _initialize: function(headerValue)
+    {
+        this._input = headerValue;
+        if (typeof headerValue !== "string")
+            return false;
+        this._cookies = [];
+        this._lastCookie = null;
+        this._originalInputLength = this._input.length;
+        return true;
+    },
+
+    _flushCookie: function()
+    {
+        if (this._lastCookie)
+            this._lastCookie.setSize(this._originalInputLength - this._input.length - this._lastCookiePosition);
+        this._lastCookie = null;
+    },
+
+    /**
+     * @return {WebInspector.CookieParser.KeyValue}
+     */
+    _extractKeyValue: function()
+    {
+        if (!this._input || !this._input.length)
+            return null;
+        // Note: RFCs offer an option for quoted values that may contain commas and semicolons.
+        // Many browsers/platforms do not support this, however (see http://webkit.org/b/16699
+        // and http://crbug.com/12361). The logic below matches latest versions of IE, Firefox,
+        // Chrome and Safari on some old platforms. The latest version of Safari supports quoted
+        // cookie values, though.
+        var keyValueMatch = /^[ \t]*([^\s=;]+)[ \t]*(?:=[ \t]*([^;\n]*))?/.exec(this._input);
+        if (!keyValueMatch) {
+            console.log("Failed parsing cookie header before: " + this._input);
+            return null;
+        }
+
+        var result = new WebInspector.CookieParser.KeyValue(keyValueMatch[1], keyValueMatch[2] && keyValueMatch[2].trim(), this._originalInputLength - this._input.length);
+        this._input = this._input.slice(keyValueMatch[0].length);
+        return result;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    _advanceAndCheckCookieDelimiter: function()
+    {
+        var match = /^\s*[\n;]\s*/.exec(this._input);
+        if (!match)
+            return false;
+        this._input = this._input.slice(match[0].length);
+        return match[0].match("\n") !== null;
+    },
+
+    /**
+     * @param {!WebInspector.CookieParser.KeyValue} keyValue
+     * @param {!WebInspector.Cookie.Type} type
+     */
+    _addCookie: function(keyValue, type)
+    {
+        if (this._lastCookie)
+            this._lastCookie.setSize(keyValue.position - this._lastCookiePosition);
+        // Mozilla bug 169091: Mozilla, IE and Chrome treat single token (w/o "=") as
+        // specifying a value for a cookie with empty name.
+        this._lastCookie = typeof keyValue.value === "string" ? new WebInspector.Cookie(keyValue.key, keyValue.value, type) :
+            new WebInspector.Cookie("", keyValue.key, type);
+        this._lastCookiePosition = keyValue.position;
+        this._cookies.push(this._lastCookie);
+    }
+};
+
+/**
+ * @param {string|undefined} header
+ * @return {?Array.}
+ */
+WebInspector.CookieParser.parseCookie = function(header)
+{
+    return (new WebInspector.CookieParser()).parseCookie(header);
+}
+
+/**
+ * @param {string|undefined} header
+ * @return {?Array.}
+ */
+WebInspector.CookieParser.parseSetCookie = function(header)
+{
+    return (new WebInspector.CookieParser()).parseSetCookie(header);
+}
+
+/**
+ * @constructor
+ * @param {string} name
+ * @param {string} value
+ * @param {?WebInspector.Cookie.Type} type
+ */
+WebInspector.Cookie = function(name, value, type)
+{
+    this._name = name;
+    this._value = value;
+    this._type = type;
+    this._attributes = {};
+}
+
+WebInspector.Cookie.prototype = {
+    /**
+     * @return {string}
+     */
+    name: function()
+    {
+        return this._name;
+    },
+
+    /**
+     * @return {string}
+     */
+    value: function()
+    {
+        return this._value;
+    },
+
+    /**
+     * @return {?WebInspector.Cookie.Type}
+     */
+    type: function()
+    {
+        return this._type;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    httpOnly: function()
+    {
+        return "httponly" in this._attributes;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    secure: function()
+    {
+        return "secure" in this._attributes;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    session: function()
+    {
+        // RFC 2965 suggests using Discard attribute to mark session cookies, but this does not seem to be widely used.
+        // Check for absence of explicitly max-age or expiry date instead.
+        return !("expires" in this._attributes || "max-age" in this._attributes);
+    },
+
+    /**
+     * @return {string}
+     */
+    path: function()
+    {
+        return this._attributes["path"];
+    },
+
+    /**
+     * @return {string}
+     */
+    port: function()
+    {
+        return this._attributes["port"];
+    },
+
+    /**
+     * @return {string}
+     */
+    domain: function()
+    {
+        return this._attributes["domain"];
+    },
+
+    /**
+     * @return {string}
+     */
+    expires: function()
+    {
+        return this._attributes["expires"];
+    },
+
+    /**
+     * @return {string}
+     */
+    maxAge: function()
+    {
+        return this._attributes["max-age"];
+    },
+
+    /**
+     * @return {number}
+     */
+    size: function()
+    {
+        return this._size;
+    },
+
+    /**
+     * @param {number} size
+     */
+    setSize: function(size)
+    {
+        this._size = size;
+    },
+
+    /**
+     * @return {Date}
+     */
+    expiresDate: function(requestDate)
+    {
+        // RFC 6265 indicates that the max-age attribute takes precedence over the expires attribute
+        if (this.maxAge()) {
+            var targetDate = requestDate === null ? new Date() : requestDate;
+            return new Date(targetDate.getTime() + 1000 * this.maxAge());
+        }
+
+        if (this.expires())
+            return new Date(this.expires());
+
+        return null;
+    },
+
+    /**
+     * @return {Object}
+     */
+    attributes: function()
+    {
+        return this._attributes;
+    },
+
+    /**
+     * @param {string} key 
+     * @param {string=} value 
+     */
+    addAttribute: function(key, value)
+    {
+        this._attributes[key.toLowerCase()] = value;
+    },
+
+    /**
+     * @param {function(?Protocol.Error)=} callback
+     */
+    remove: function(callback)
+    {
+        PageAgent.deleteCookie(this.name(), (this.secure() ? "https://" : "http://") + this.domain() + this.path(), callback);
+    }
+}
+
+/**
+ * @enum {number}
+ */
+WebInspector.Cookie.Type = {
+    Request: 0,
+    Response: 1
+};
+
+WebInspector.Cookies = {}
+
+/**
+ * @param {function(!Array.)} callback
+ */
+WebInspector.Cookies.getCookiesAsync = function(callback)
+{
+    /**
+     * @param {?Protocol.Error} error 
+     * @param {Array.} cookies
+     * @param {string} cookiesString
+     */
+    function mycallback(error, cookies, cookiesString)
+    {
+        if (error)
+            return;
+        callback(cookies.map(WebInspector.Cookies.buildCookieProtocolObject));
+    }
+
+    PageAgent.getCookies(mycallback);
+}
+
+/**
+ * @param {!PageAgent.Cookie} protocolCookie
+ * @return {!WebInspector.Cookie}
+ */
+WebInspector.Cookies.buildCookieProtocolObject = function(protocolCookie)
+{
+    var cookie = new WebInspector.Cookie(protocolCookie.name, protocolCookie.value, null);
+    cookie.addAttribute("domain", protocolCookie["domain"]);
+    cookie.addAttribute("path", protocolCookie["path"]);
+    cookie.addAttribute("port", protocolCookie["port"]);
+    if (protocolCookie["expires"])
+        cookie.addAttribute("expires", protocolCookie["expires"]);
+    if (protocolCookie["httpOnly"])
+        cookie.addAttribute("httpOnly");
+    if (protocolCookie["secure"])
+        cookie.addAttribute("secure");
+    cookie.setSize(protocolCookie["size"]);
+    return cookie;
+}
+
+/**
+ * @param {WebInspector.Cookie} cookie 
+ * @param {string} resourceURL
+ */
+WebInspector.Cookies.cookieMatchesResourceURL = function(cookie, resourceURL)
+{
+    var url = resourceURL.asParsedURL();
+    if (!url || !WebInspector.Cookies.cookieDomainMatchesResourceDomain(cookie.domain(), url.host))
+        return false;
+    return (url.path.startsWith(cookie.path())
+        && (!cookie.port() || url.port == cookie.port())
+        && (!cookie.secure() || url.scheme === "https"));
+}
+
+/**
+ * @param {string} cookieDomain 
+ * @param {string} resourceDomain
+ */
+WebInspector.Cookies.cookieDomainMatchesResourceDomain = function(cookieDomain, resourceDomain)
+{
+    if (cookieDomain.charAt(0) !== '.')
+        return resourceDomain === cookieDomain;
+    return !!resourceDomain.match(new RegExp("^([^\\.]+\\.)*" + cookieDomain.substring(1).escapeForRegExp() + "$", "i"));
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookiesTable.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookiesTable.js
new file mode 100644
index 00000000..f49df311
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/CookiesTable.js
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2009 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {boolean} expandable
+ * @param {function()=} refreshCallback
+ * @param {function()=} selectedCallback
+ */
+WebInspector.CookiesTable = function(expandable, refreshCallback, selectedCallback)
+{
+    WebInspector.View.call(this);
+    this.element.className = "fill";
+
+    var readOnly = expandable;
+    this._refreshCallback = refreshCallback;
+
+    var columns = [
+        {id: "name", title: WebInspector.UIString("Name"), sortable: true, disclosure: expandable, sort: WebInspector.DataGrid.Order.Ascending, longText: true, weight: 24},
+        {id: "value", title: WebInspector.UIString("Value"), sortable: true, longText: true, weight: 34},
+        {id: "domain", title: WebInspector.UIString("Domain"), sortable: true, weight: 7},
+        {id: "path", title: WebInspector.UIString("Path"), sortable: true, weight: 7},
+        {id: "expires", title: WebInspector.UIString("Expires / Max-Age"), sortable: true, weight: 7},
+        {id: "size", title: WebInspector.UIString("Size"), sortable: true, align: WebInspector.DataGrid.Align.Right, weight: 7},
+        {id: "httpOnly", title: WebInspector.UIString("HTTP"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7},
+        {id: "secure", title: WebInspector.UIString("Secure"), sortable: true, align: WebInspector.DataGrid.Align.Center, weight: 7}
+    ];
+
+    if (readOnly)
+        this._dataGrid = new WebInspector.DataGrid(columns);
+    else
+        this._dataGrid = new WebInspector.DataGrid(columns, undefined, this._onDeleteCookie.bind(this), refreshCallback, this._onContextMenu.bind(this));
+
+    this._dataGrid.setName("cookiesTable");
+    this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._rebuildTable, this);
+
+    if (selectedCallback)
+        this._dataGrid.addEventListener(WebInspector.DataGrid.Events.SelectedNode, selectedCallback, this);
+
+    this._nextSelectedCookie = /** @type {?WebInspector.Cookie} */ (null);
+
+    this._dataGrid.show(this.element);
+    this._data = [];
+}
+
+WebInspector.CookiesTable.prototype = {
+    /**
+     * @param {?string} domain
+     */
+    _clearAndRefresh: function(domain)
+    {
+        this.clear(domain);
+        this._refresh();
+    },
+
+    /**
+     * @param {!WebInspector.ContextMenu} contextMenu
+     * @param {WebInspector.DataGridNode} node
+     */
+    _onContextMenu: function(contextMenu, node)
+    {
+        if (node === this._dataGrid.creationNode)
+            return;
+        var cookie = node.cookie;
+        var domain = cookie.domain();
+        if (domain)
+            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all from \"%s\"" : "Clear All from \"%s\"", domain), this._clearAndRefresh.bind(this, domain));
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Clear all" : "Clear All"), this._clearAndRefresh.bind(this, null));
+    },
+
+    /**
+     * @param {!Array.} cookies
+     */
+    setCookies: function(cookies)
+    {
+        this.setCookieFolders([{cookies: cookies}]);
+    },
+
+    /**
+     * @param {!Array.}>} cookieFolders
+     */
+    setCookieFolders: function(cookieFolders)
+    {
+        this._data = cookieFolders;
+        this._rebuildTable();
+    },
+
+    /**
+     * @return {?WebInspector.Cookie}
+     */
+    selectedCookie: function()
+    {
+        var node = this._dataGrid.selectedNode;
+        return node ? node.cookie : null;
+    },
+
+    /**
+     * @param {?string=} domain
+     */
+    clear: function(domain)
+    {
+        for (var i = 0, length = this._data.length; i < length; ++i) {
+            var cookies = this._data[i].cookies;
+            for (var j = 0, cookieCount = cookies.length; j < cookieCount; ++j) {
+                if (!domain || cookies[j].domain() === domain)
+                    cookies[j].remove();
+            }
+        }
+    },
+
+    _rebuildTable: function()
+    {
+        var selectedCookie = this._nextSelectedCookie || this.selectedCookie();
+        this._nextSelectedCookie = null;
+        this._dataGrid.rootNode().removeChildren();
+        for (var i = 0; i < this._data.length; ++i) {
+            var item = this._data[i];
+            if (item.folderName) {
+                var groupData = {name: item.folderName, value: "", domain: "", path: "", expires: "", size: this._totalSize(item.cookies), httpOnly: "", secure: ""};
+                var groupNode = new WebInspector.DataGridNode(groupData);
+                groupNode.selectable = true;
+                this._dataGrid.rootNode().appendChild(groupNode);
+                groupNode.element.addStyleClass("row-group");
+                this._populateNode(groupNode, item.cookies, selectedCookie);
+                groupNode.expand();
+            } else
+                this._populateNode(this._dataGrid.rootNode(), item.cookies, selectedCookie);
+        }
+    },
+
+    /**
+     * @param {!WebInspector.DataGridNode} parentNode
+     * @param {?Array.} cookies
+     * @param {?WebInspector.Cookie} selectedCookie
+     */
+    _populateNode: function(parentNode, cookies, selectedCookie)
+    {
+        parentNode.removeChildren();
+        if (!cookies)
+            return;
+
+        this._sortCookies(cookies);
+        for (var i = 0; i < cookies.length; ++i) {
+            var cookie = cookies[i];
+            var cookieNode = this._createGridNode(cookie);
+            parentNode.appendChild(cookieNode);
+            if (selectedCookie && selectedCookie.name() === cookie.name() && selectedCookie.domain() === cookie.domain() && selectedCookie.path() === cookie.path())
+                cookieNode.select();
+        }
+    },
+
+    _totalSize: function(cookies)
+    {
+        var totalSize = 0;
+        for (var i = 0; cookies && i < cookies.length; ++i)
+            totalSize += cookies[i].size();
+        return totalSize;
+    },
+
+    /**
+     * @param {!Array.} cookies
+     */
+    _sortCookies: function(cookies)
+    {
+        var sortDirection = this._dataGrid.isSortOrderAscending() ? 1 : -1;
+
+        function compareTo(getter, cookie1, cookie2)
+        {
+            return sortDirection * (getter.apply(cookie1) + "").compareTo(getter.apply(cookie2) + "")
+        }
+
+        function numberCompare(getter, cookie1, cookie2)
+        {
+            return sortDirection * (getter.apply(cookie1) - getter.apply(cookie2));
+        }
+
+        function expiresCompare(cookie1, cookie2)
+        {
+            if (cookie1.session() !== cookie2.session())
+                return sortDirection * (cookie1.session() ? 1 : -1);
+
+            if (cookie1.session())
+                return 0;
+
+            if (cookie1.maxAge() && cookie2.maxAge())
+                return sortDirection * (cookie1.maxAge() - cookie2.maxAge());
+            if (cookie1.expires() && cookie2.expires())
+                return sortDirection * (cookie1.expires() - cookie2.expires());
+            return sortDirection * (cookie1.expires() ? 1 : -1);
+        }
+
+        var comparator;
+        switch (this._dataGrid.sortColumnIdentifier()) {
+            case "name": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.name); break;
+            case "value": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.value); break;
+            case "domain": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.domain); break;
+            case "path": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.path); break;
+            case "expires": comparator = expiresCompare; break;
+            case "size": comparator = numberCompare.bind(null, WebInspector.Cookie.prototype.size); break;
+            case "httpOnly": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.httpOnly); break;
+            case "secure": comparator = compareTo.bind(null, WebInspector.Cookie.prototype.secure); break;
+            default: compareTo.bind(null, WebInspector.Cookie.prototype.name);
+        }
+
+        cookies.sort(comparator);
+    },
+
+    /**
+     * @param {!WebInspector.Cookie} cookie
+     * @return {!WebInspector.DataGridNode}
+     */
+    _createGridNode: function(cookie)
+    {
+        var data = {};
+        data.name = cookie.name();
+        data.value = cookie.value();
+        if (cookie.type() === WebInspector.Cookie.Type.Request) {
+            data.domain = WebInspector.UIString("N/A");
+            data.path = WebInspector.UIString("N/A");
+            data.expires = WebInspector.UIString("N/A");
+        } else {
+            data.domain = cookie.domain() || "";
+            data.path = cookie.path() || "";
+            if (cookie.maxAge())
+                data.expires = Number.secondsToString(parseInt(cookie.maxAge(), 10));
+            else if (cookie.expires())
+                data.expires = new Date(cookie.expires()).toGMTString();
+            else
+                data.expires = WebInspector.UIString("Session");
+        }
+        data.size = cookie.size();
+        const checkmark = "\u2713";
+        data.httpOnly = (cookie.httpOnly() ? checkmark : "");
+        data.secure = (cookie.secure() ? checkmark : "");
+
+        var node = new WebInspector.DataGridNode(data);
+        node.cookie = cookie;
+        node.selectable = true;
+        return node;
+    },
+
+    _onDeleteCookie: function(node)
+    {
+        var cookie = node.cookie;
+        var neighbour = node.traverseNextNode() || node.traversePreviousNode();
+        if (neighbour)
+            this._nextSelectedCookie = neighbour.cookie;
+        cookie.remove();
+        this._refresh();
+    },
+
+    _refresh: function()
+    {
+        if (this._refreshCallback)
+            this._refreshCallback();
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMAgent.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMAgent.js
new file mode 100644
index 00000000..8c2b5a66
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMAgent.js
@@ -0,0 +1,1633 @@
+/*
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.DOMAgent} domAgent
+ * @param {?WebInspector.DOMDocument} doc
+ * @param {boolean} isInShadowTree
+ * @param {DOMAgent.Node} payload
+ */
+WebInspector.DOMNode = function(domAgent, doc, isInShadowTree, payload) {
+    this._domAgent = domAgent;
+    this.ownerDocument = doc;
+    this._isInShadowTree = isInShadowTree;
+
+    this.id = payload.nodeId;
+    domAgent._idToDOMNode[this.id] = this;
+    this._nodeType = payload.nodeType;
+    this._nodeName = payload.nodeName;
+    this._localName = payload.localName;
+    this._nodeValue = payload.nodeValue;
+
+    this._shadowRoots = [];
+
+    this._attributes = [];
+    this._attributesMap = {};
+    if (payload.attributes)
+        this._setAttributesPayload(payload.attributes);
+
+    this._userProperties = {};
+    this._descendantUserPropertyCounters = {};
+
+    this._childNodeCount = payload.childNodeCount || 0;
+    this._children = null;
+
+    this.nextSibling = null;
+    this.previousSibling = null;
+    this.firstChild = null;
+    this.lastChild = null;
+    this.parentNode = null;
+
+    if (payload.shadowRoots) {
+        for (var i = 0; i < payload.shadowRoots.length; ++i) {
+            var root = payload.shadowRoots[i];
+            var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, true, root);
+            this._shadowRoots.push(node);
+            node.parentNode = this;
+        }
+    }
+
+    if (payload.templateContent) {
+        this._templateContent = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, true, payload.templateContent);
+        this._templateContent.parentNode = this;
+    }
+
+    if (payload.children)
+        this._setChildrenPayload(payload.children);
+
+    if (payload.contentDocument) {
+        this._contentDocument = new WebInspector.DOMDocument(domAgent, payload.contentDocument);
+        this._children = [this._contentDocument];
+        this._renumber();
+    }
+
+    if (this._nodeType === Node.ELEMENT_NODE) {
+        // HTML and BODY from internal iframes should not overwrite top-level ones.
+        if (this.ownerDocument && !this.ownerDocument.documentElement && this._nodeName === "HTML")
+            this.ownerDocument.documentElement = this;
+        if (this.ownerDocument && !this.ownerDocument.body && this._nodeName === "BODY")
+            this.ownerDocument.body = this;
+    } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) {
+        this.publicId = payload.publicId;
+        this.systemId = payload.systemId;
+        this.internalSubset = payload.internalSubset;
+    } else if (this._nodeType === Node.ATTRIBUTE_NODE) {
+        this.name = payload.name;
+        this.value = payload.value;
+    }
+}
+
+/**
+ * @constructor
+ * @param {string} value
+ * @param {boolean} optimized
+ */
+WebInspector.DOMNode.XPathStep = function(value, optimized)
+{
+    this.value = value;
+    this.optimized = optimized;
+}
+
+WebInspector.DOMNode.XPathStep.prototype = {
+    toString: function()
+    {
+        return this.value;
+    }
+}
+
+WebInspector.DOMNode.prototype = {
+    /**
+     * @return {Array.}
+     */
+    children: function()
+    {
+        return this._children ? this._children.slice() : null;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    hasAttributes: function()
+    {
+        return this._attributes.length > 0;
+    },
+
+    /**
+     * @return {number}
+     */
+    childNodeCount: function()
+    {
+        return this._childNodeCount;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    hasShadowRoots: function()
+    {
+        return !!this._shadowRoots.length;
+    },
+
+    /**
+     * @return {Array.}
+     */
+    shadowRoots: function()
+    {
+        return this._shadowRoots.slice();
+    },
+
+    /**
+     * @return {WebInspector.DOMNode}
+     */
+    templateContent: function()
+    {
+        return this._templateContent;
+    },
+
+    /**
+     * @return {number}
+     */
+    nodeType: function()
+    {
+        return this._nodeType;
+    },
+
+    /**
+     * @return {string}
+     */
+    nodeName: function()
+    {
+        return this._nodeName;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isInShadowTree: function()
+    {
+        return this._isInShadowTree;
+    },
+
+    /**
+     * @return {string}
+     */
+    nodeNameInCorrectCase: function()
+    {
+        return this.isXMLNode() ? this.nodeName() : this.nodeName().toLowerCase();
+    },
+
+    /**
+     * @param {string} name
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setNodeName: function(name, callback)
+    {
+        DOMAgent.setNodeName(this.id, name, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @return {string}
+     */
+    localName: function()
+    {
+        return this._localName;
+    },
+
+    /**
+     * @return {string}
+     */
+    nodeValue: function()
+    {
+        return this._nodeValue;
+    },
+
+    /**
+     * @param {string} value
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setNodeValue: function(value, callback)
+    {
+        DOMAgent.setNodeValue(this.id, value, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @param {string} name
+     * @return {string}
+     */
+    getAttribute: function(name)
+    {
+        var attr = this._attributesMap[name];
+        return attr ? attr.value : undefined;
+    },
+
+    /**
+     * @param {string} name
+     * @param {string} text
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setAttribute: function(name, text, callback)
+    {
+        DOMAgent.setAttributesAsText(this.id, text, name, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @param {string} name
+     * @param {string} value
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setAttributeValue: function(name, value, callback)
+    {
+        DOMAgent.setAttributeValue(this.id, name, value, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @return {Object}
+     */
+    attributes: function()
+    {
+        return this._attributes;
+    },
+
+    /**
+     * @param {string} name
+     * @param {function(?Protocol.Error)=} callback
+     */
+    removeAttribute: function(name, callback)
+    {
+        /**
+         *  @param {?Protocol.Error} error
+         */
+        function mycallback(error)
+        {
+            if (!error) {
+                delete this._attributesMap[name];
+                for (var i = 0;  i < this._attributes.length; ++i) {
+                    if (this._attributes[i].name === name) {
+                        this._attributes.splice(i, 1);
+                        break;
+                    }
+                }
+            }
+
+            WebInspector.domAgent._markRevision(this, callback)(error);
+        }
+        DOMAgent.removeAttribute(this.id, name, mycallback.bind(this));
+    },
+
+    /**
+     * @param {function(Array.)=} callback
+     */
+    getChildNodes: function(callback)
+    {
+        if (this._children) {
+            if (callback)
+                callback(this.children());
+            return;
+        }
+
+        /**
+         * @this {WebInspector.DOMNode}
+         * @param {?Protocol.Error} error
+         */
+        function mycallback(error)
+        {
+            if (!error && callback)
+                callback(this.children());
+        }
+
+        DOMAgent.requestChildNodes(this.id, undefined, mycallback.bind(this));
+    },
+
+    /**
+     * @param {number} depth
+     * @param {function(Array.)=} callback
+     */
+    getSubtree: function(depth, callback)
+    {
+        /**
+         * @this {WebInspector.DOMNode}
+         * @param {?Protocol.Error} error
+         */
+        function mycallback(error)
+        {
+            if (callback)
+                callback(error ? null : this._children);
+        }
+
+        DOMAgent.requestChildNodes(this.id, depth, mycallback.bind(this));
+    },
+
+    /**
+     * @param {function(?Protocol.Error)=} callback
+     */
+    getOuterHTML: function(callback)
+    {
+        DOMAgent.getOuterHTML(this.id, callback);
+    },
+
+    /**
+     * @param {string} html
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setOuterHTML: function(html, callback)
+    {
+        DOMAgent.setOuterHTML(this.id, html, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @param {function(?Protocol.Error, DOMAgent.NodeId=)=} callback
+     */
+    removeNode: function(callback)
+    {
+        DOMAgent.removeNode(this.id, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    copyNode: function()
+    {
+        function copy(error, text)
+        {
+            if (!error)
+                InspectorFrontendHost.copyText(text);
+        }
+        DOMAgent.getOuterHTML(this.id, copy);
+    },
+
+    /**
+     * @param {boolean} optimized
+     */
+    copyXPath: function(optimized)
+    {
+        InspectorFrontendHost.copyText(this.xPath(optimized));
+    },
+
+    /**
+     * @param {string} objectGroupId
+     * @param {function(?Protocol.Error)=} callback
+     */
+    eventListeners: function(objectGroupId, callback)
+    {
+        DOMAgent.getEventListenersForNode(this.id, objectGroupId, callback);
+    },
+
+    /**
+     * @return {string}
+     */
+    path: function()
+    {
+        var path = [];
+        var node = this;
+        while (node && "index" in node && node._nodeName.length) {
+            path.push([node.index, node._nodeName]);
+            node = node.parentNode;
+        }
+        path.reverse();
+        return path.join(",");
+    },
+
+    /**
+     * @param {boolean} justSelector
+     * @return {string}
+     */
+    appropriateSelectorFor: function(justSelector)
+    {
+        var lowerCaseName = this.localName() || this.nodeName().toLowerCase();
+
+        var id = this.getAttribute("id");
+        if (id) {
+            var selector = "#" + id;
+            return (justSelector ? selector : lowerCaseName + selector);
+        }
+
+        var className = this.getAttribute("class");
+        if (className) {
+            var selector = "." + className.trim().replace(/\s+/g, ".");
+            return (justSelector ? selector : lowerCaseName + selector);
+        }
+
+        if (lowerCaseName === "input" && this.getAttribute("type"))
+            return lowerCaseName + "[type=\"" + this.getAttribute("type") + "\"]";
+
+        return lowerCaseName;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     * @return {boolean}
+     */
+    isAncestor: function(node)
+    {
+        if (!node)
+            return false;
+
+        var currentNode = node.parentNode;
+        while (currentNode) {
+            if (this === currentNode)
+                return true;
+            currentNode = currentNode.parentNode;
+        }
+        return false;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} descendant
+     * @return {boolean}
+     */
+    isDescendant: function(descendant)
+    {
+        return descendant !== null && descendant.isAncestor(this);
+    },
+
+    /**
+     * @param {Array.} attrs
+     * @return {boolean}
+     */
+    _setAttributesPayload: function(attrs)
+    {
+        var attributesChanged = !this._attributes || attrs.length !== this._attributes.length * 2;
+        var oldAttributesMap = this._attributesMap || {};
+
+        this._attributes = [];
+        this._attributesMap = {};
+
+        for (var i = 0; i < attrs.length; i += 2) {
+            var name = attrs[i];
+            var value = attrs[i + 1];
+            this._addAttribute(name, value);
+
+            if (attributesChanged)
+                continue;
+
+            if (!oldAttributesMap[name] || oldAttributesMap[name].value !== value)
+              attributesChanged = true;
+        }
+        return attributesChanged;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} prev
+     * @param {DOMAgent.Node} payload
+     * @return {WebInspector.DOMNode}
+     */
+    _insertChild: function(prev, payload)
+    {
+        var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload);
+        this._children.splice(this._children.indexOf(prev) + 1, 0, node);
+        this._renumber();
+        return node;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     */
+    _removeChild: function(node)
+    {
+        this._children.splice(this._children.indexOf(node), 1);
+        node.parentNode = null;
+        node._updateChildUserPropertyCountsOnRemoval(this);
+        this._renumber();
+    },
+
+    /**
+     * @param {Array.} payloads
+     */
+    _setChildrenPayload: function(payloads)
+    {
+        // We set children in the constructor.
+        if (this._contentDocument)
+            return;
+
+        this._children = [];
+        for (var i = 0; i < payloads.length; ++i) {
+            var payload = payloads[i];
+            var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload);
+            this._children.push(node);
+        }
+        this._renumber();
+    },
+
+    _renumber: function()
+    {
+        this._childNodeCount = this._children.length;
+        if (this._childNodeCount == 0) {
+            this.firstChild = null;
+            this.lastChild = null;
+            return;
+        }
+        this.firstChild = this._children[0];
+        this.lastChild = this._children[this._childNodeCount - 1];
+        for (var i = 0; i < this._childNodeCount; ++i) {
+            var child = this._children[i];
+            child.index = i;
+            child.nextSibling = i + 1 < this._childNodeCount ? this._children[i + 1] : null;
+            child.previousSibling = i - 1 >= 0 ? this._children[i - 1] : null;
+            child.parentNode = this;
+        }
+    },
+
+    /**
+     * @param {string} name
+     * @param {string} value
+     */
+    _addAttribute: function(name, value)
+    {
+        var attr = {
+            name: name,
+            value: value,
+            _node: this
+        };
+        this._attributesMap[name] = attr;
+        this._attributes.push(attr);
+    },
+
+    /**
+     * @param {string} name
+     * @param {string} value
+     */
+    _setAttribute: function(name, value)
+    {
+        var attr = this._attributesMap[name];
+        if (attr)
+            attr.value = value;
+        else
+            this._addAttribute(name, value);
+    },
+
+    /**
+     * @param {string} name
+     */
+    _removeAttribute: function(name)
+    {
+        var attr = this._attributesMap[name];
+        if (attr) {
+            this._attributes.remove(attr);
+            delete this._attributesMap[name];
+        }
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} targetNode
+     * @param {?WebInspector.DOMNode} anchorNode
+     * @param {function(?Protocol.Error, DOMAgent.NodeId=)=} callback
+     */
+    moveTo: function(targetNode, anchorNode, callback)
+    {
+        DOMAgent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, WebInspector.domAgent._markRevision(this, callback));
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isXMLNode: function()
+    {
+        return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
+    },
+
+    /**
+     * @param {boolean} optimized
+     * @return {string}
+     */
+    xPath: function(optimized)
+    {
+        if (this._nodeType === Node.DOCUMENT_NODE)
+            return "/";
+
+        var steps = [];
+        var contextNode = this;
+        while (contextNode) {
+            var step = contextNode._xPathValue(optimized);
+            if (!step)
+                break; // Error - bail out early.
+            steps.push(step);
+            if (step.optimized)
+                break;
+            contextNode = contextNode.parentNode;
+        }
+
+        steps.reverse();
+        return (steps.length && steps[0].optimized ? "" : "/") + steps.join("/");
+    },
+
+    /**
+     * @param {boolean} optimized
+     * @return {WebInspector.DOMNode.XPathStep}
+     */
+    _xPathValue: function(optimized)
+    {
+        var ownValue;
+        var ownIndex = this._xPathIndex();
+        if (ownIndex === -1)
+            return null; // Error.
+
+        switch (this._nodeType) {
+        case Node.ELEMENT_NODE:
+            if (optimized && this.getAttribute("id"))
+                return new WebInspector.DOMNode.XPathStep("//*[@id=\"" + this.getAttribute("id") + "\"]", true);
+            ownValue = this._localName;
+            break;
+        case Node.ATTRIBUTE_NODE:
+            ownValue = "@" + this._nodeName;
+            break;
+        case Node.TEXT_NODE:
+        case Node.CDATA_SECTION_NODE:
+            ownValue = "text()";
+            break;
+        case Node.PROCESSING_INSTRUCTION_NODE:
+            ownValue = "processing-instruction()";
+            break;
+        case Node.COMMENT_NODE:
+            ownValue = "comment()";
+            break;
+        case Node.DOCUMENT_NODE:
+            ownValue = "";
+            break;
+        default:
+            ownValue = "";
+            break;
+        }
+
+        if (ownIndex > 0)
+            ownValue += "[" + ownIndex + "]";
+
+        return new WebInspector.DOMNode.XPathStep(ownValue, this._nodeType === Node.DOCUMENT_NODE);
+    },
+
+    /**
+     * @return {number}
+     */
+    _xPathIndex: function()
+    {
+        // Returns -1 in case of error, 0 if no siblings matching the same expression,  otherwise.
+        function areNodesSimilar(left, right)
+        {
+            if (left === right)
+                return true;
+
+            if (left._nodeType === Node.ELEMENT_NODE && right._nodeType === Node.ELEMENT_NODE)
+                return left._localName === right._localName;
+
+            if (left._nodeType === right._nodeType)
+                return true;
+
+            // XPath treats CDATA as text nodes.
+            var leftType = left._nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : left._nodeType;
+            var rightType = right._nodeType === Node.CDATA_SECTION_NODE ? Node.TEXT_NODE : right._nodeType;
+            return leftType === rightType;
+        }
+
+        var siblings = this.parentNode ? this.parentNode._children : null;
+        if (!siblings)
+            return 0; // Root node - no siblings.
+        var hasSameNamedElements;
+        for (var i = 0; i < siblings.length; ++i) {
+            if (areNodesSimilar(this, siblings[i]) && siblings[i] !== this) {
+                hasSameNamedElements = true;
+                break;
+            }
+        }
+        if (!hasSameNamedElements)
+            return 0;
+        var ownIndex = 1; // XPath indices start with 1.
+        for (var i = 0; i < siblings.length; ++i) {
+            if (areNodesSimilar(this, siblings[i])) {
+                if (siblings[i] === this)
+                    return ownIndex;
+                ++ownIndex;
+            }
+        }
+        return -1; // An error occurred: |this| not found in parent's children.
+    },
+
+    _updateChildUserPropertyCountsOnRemoval: function(parentNode)
+    {
+        var result = {};
+        if (this._userProperties) {
+            for (var name in this._userProperties)
+                result[name] = (result[name] || 0) + 1;
+        }
+
+        if (this._descendantUserPropertyCounters) {
+            for (var name in this._descendantUserPropertyCounters) {
+                var counter = this._descendantUserPropertyCounters[name];
+                result[name] = (result[name] || 0) + counter;
+            }
+        }
+
+        for (var name in result)
+            parentNode._updateDescendantUserPropertyCount(name, -result[name]);
+    },
+
+    _updateDescendantUserPropertyCount: function(name, delta)
+    {
+        if (!this._descendantUserPropertyCounters.hasOwnProperty(name))
+            this._descendantUserPropertyCounters[name] = 0;
+        this._descendantUserPropertyCounters[name] += delta;
+        if (!this._descendantUserPropertyCounters[name])
+            delete this._descendantUserPropertyCounters[name];
+        if (this.parentNode)
+            this.parentNode._updateDescendantUserPropertyCount(name, delta);
+    },
+
+    setUserProperty: function(name, value)
+    {
+        if (value === null) {
+            this.removeUserProperty(name);
+            return;
+        }
+
+        if (this.parentNode && !this._userProperties.hasOwnProperty(name))
+            this.parentNode._updateDescendantUserPropertyCount(name, 1);
+
+        this._userProperties[name] = value;
+    },
+
+    removeUserProperty: function(name)
+    {
+        if (!this._userProperties.hasOwnProperty(name))
+            return;
+
+        delete this._userProperties[name];
+        if (this.parentNode)
+            this.parentNode._updateDescendantUserPropertyCount(name, -1);
+    },
+
+    getUserProperty: function(name)
+    {
+        return this._userProperties ? this._userProperties[name] : null;
+    },
+
+    descendantUserPropertyCount: function(name)
+    {
+        return this._descendantUserPropertyCounters && this._descendantUserPropertyCounters[name] ? this._descendantUserPropertyCounters[name] : 0;
+    },
+
+    /**
+     * @param {string} url
+     * @return {?string}
+     */
+    resolveURL: function(url)
+    {
+        if (!url)
+            return url;
+        for (var frameOwnerCandidate = this; frameOwnerCandidate; frameOwnerCandidate = frameOwnerCandidate.parentNode) {
+            if (frameOwnerCandidate.baseURL)
+                return WebInspector.ParsedURL.completeURL(frameOwnerCandidate.baseURL, url);
+        }
+        return null;
+    }
+}
+
+/**
+ * @extends {WebInspector.DOMNode}
+ * @constructor
+ * @param {WebInspector.DOMAgent} domAgent
+ * @param {DOMAgent.Node} payload
+ */
+WebInspector.DOMDocument = function(domAgent, payload)
+{
+    WebInspector.DOMNode.call(this, domAgent, this, false, payload);
+    this.documentURL = payload.documentURL || "";
+    this.baseURL = /** @type {string} */ (payload.baseURL);
+    console.assert(this.baseURL);
+    this.xmlVersion = payload.xmlVersion;
+    this._listeners = {};
+}
+
+WebInspector.DOMDocument.prototype = {
+    __proto__: WebInspector.DOMNode.prototype
+}
+
+/**
+ * @extends {WebInspector.Object}
+ * @constructor
+ */
+WebInspector.DOMAgent = function() {
+    /** @type {!Object.} */
+    this._idToDOMNode = {};
+    /** @type {?WebInspector.DOMDocument} */
+    this._document = null;
+    /** @type {!Object.} */
+    this._attributeLoadNodeIds = {};
+    InspectorBackend.registerDOMDispatcher(new WebInspector.DOMDispatcher(this));
+
+    this._defaultHighlighter = new WebInspector.DefaultDOMNodeHighlighter();
+    this._highlighter = this._defaultHighlighter;
+}
+
+WebInspector.DOMAgent.Events = {
+    AttrModified: "AttrModified",
+    AttrRemoved: "AttrRemoved",
+    CharacterDataModified: "CharacterDataModified",
+    NodeInserted: "NodeInserted",
+    NodeRemoved: "NodeRemoved",
+    DocumentUpdated: "DocumentUpdated",
+    ChildNodeCountUpdated: "ChildNodeCountUpdated",
+    UndoRedoRequested: "UndoRedoRequested",
+    UndoRedoCompleted: "UndoRedoCompleted",
+    InspectNodeRequested: "InspectNodeRequested"
+}
+
+WebInspector.DOMAgent.prototype = {
+    /**
+     * @param {function(WebInspector.DOMDocument)=} callback
+     */
+    requestDocument: function(callback)
+    {
+        if (this._document) {
+            if (callback)
+                callback(this._document);
+            return;
+        }
+
+        if (this._pendingDocumentRequestCallbacks) {
+            this._pendingDocumentRequestCallbacks.push(callback);
+            return;
+        }
+
+        this._pendingDocumentRequestCallbacks = [callback];
+
+        /**
+         * @this {WebInspector.DOMAgent}
+         * @param {?Protocol.Error} error
+         * @param {DOMAgent.Node} root
+         */
+        function onDocumentAvailable(error, root)
+        {
+            if (!error)
+                this._setDocument(root);
+
+            for (var i = 0; i < this._pendingDocumentRequestCallbacks.length; ++i) {
+                var callback = this._pendingDocumentRequestCallbacks[i];
+                if (callback)
+                    callback(this._document);
+            }
+            delete this._pendingDocumentRequestCallbacks;
+        }
+
+        DOMAgent.getDocument(onDocumentAvailable.bind(this));
+    },
+
+    /**
+     * @return {WebInspector.DOMDocument?}
+     */
+    existingDocument: function()
+    {
+        return this._document;
+    },
+
+    /**
+     * @param {RuntimeAgent.RemoteObjectId} objectId
+     * @param {function(?DOMAgent.NodeId)=} callback
+     */
+    pushNodeToFrontend: function(objectId, callback)
+    {
+        this._dispatchWhenDocumentAvailable(DOMAgent.requestNode.bind(DOMAgent, objectId), callback);
+    },
+
+    /**
+     * @param {string} path
+     * @param {function(?number)=} callback
+     */
+    pushNodeByPathToFrontend: function(path, callback)
+    {
+        this._dispatchWhenDocumentAvailable(DOMAgent.pushNodeByPathToFrontend.bind(DOMAgent, path), callback);
+    },
+
+    /**
+     * @param {number} backendNodeId
+     * @param {function(?number)=} callback
+     */
+    pushNodeByBackendIdToFrontend: function(backendNodeId, callback)
+    {
+        this._dispatchWhenDocumentAvailable(DOMAgent.pushNodeByBackendIdToFrontend.bind(DOMAgent, backendNodeId), callback);
+    },
+
+    /**
+     * @param {function(T)=} callback
+     * @return {function(?Protocol.Error, T=)|undefined}
+     * @template T
+     */
+    _wrapClientCallback: function(callback)
+    {
+        if (!callback)
+            return;
+        /**
+         * @param {?Protocol.Error} error
+         * @param {*=} result
+         */
+        return function(error, result)
+        {
+            // Caller is responsible for handling the actual error.
+            callback(error ? null : result);
+        }
+    },
+
+    /**
+     * @param {function(function(?Protocol.Error, T=)=)} func
+     * @param {function(T)=} callback
+     * @template T
+     */
+    _dispatchWhenDocumentAvailable: function(func, callback)
+    {
+        var callbackWrapper = this._wrapClientCallback(callback);
+
+        function onDocumentAvailable()
+        {
+            if (this._document)
+                func(callbackWrapper);
+            else {
+                if (callbackWrapper)
+                    callbackWrapper("No document");
+            }
+        }
+        this.requestDocument(onDocumentAvailable.bind(this));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} name
+     * @param {string} value
+     */
+    _attributeModified: function(nodeId, name, value)
+    {
+        var node = this._idToDOMNode[nodeId];
+        if (!node)
+            return;
+
+        node._setAttribute(name, value);
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.AttrModified, { node: node, name: name });
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} name
+     */
+    _attributeRemoved: function(nodeId, name)
+    {
+        var node = this._idToDOMNode[nodeId];
+        if (!node)
+            return;
+        node._removeAttribute(name);
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.AttrRemoved, { node: node, name: name });
+    },
+
+    /**
+     * @param {Array.} nodeIds
+     */
+    _inlineStyleInvalidated: function(nodeIds)
+    {
+        for (var i = 0; i < nodeIds.length; ++i)
+            this._attributeLoadNodeIds[nodeIds[i]] = true;
+        if ("_loadNodeAttributesTimeout" in this)
+            return;
+        this._loadNodeAttributesTimeout = setTimeout(this._loadNodeAttributes.bind(this), 0);
+    },
+
+    _loadNodeAttributes: function()
+    {
+        /**
+         * @this {WebInspector.DOMAgent}
+         * @param {DOMAgent.NodeId} nodeId
+         * @param {?Protocol.Error} error
+         * @param {Array.} attributes
+         */
+        function callback(nodeId, error, attributes)
+        {
+            if (error) {
+                // We are calling _loadNodeAttributes asynchronously, it is ok if node is not found.
+                return;
+            }
+            var node = this._idToDOMNode[nodeId];
+            if (node) {
+                if (node._setAttributesPayload(attributes))
+                    this.dispatchEventToListeners(WebInspector.DOMAgent.Events.AttrModified, { node: node, name: "style" });
+            }
+        }
+
+        delete this._loadNodeAttributesTimeout;
+
+        for (var nodeId in this._attributeLoadNodeIds) {
+            var nodeIdAsNumber = parseInt(nodeId, 10);
+            DOMAgent.getAttributes(nodeIdAsNumber, callback.bind(this, nodeIdAsNumber));
+        }
+        this._attributeLoadNodeIds = {};
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} newValue
+     */
+    _characterDataModified: function(nodeId, newValue)
+    {
+        var node = this._idToDOMNode[nodeId];
+        node._nodeValue = newValue;
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.CharacterDataModified, node);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @return {WebInspector.DOMNode|undefined}
+     */
+    nodeForId: function(nodeId)
+    {
+        return this._idToDOMNode[nodeId];
+    },
+
+    _documentUpdated: function()
+    {
+        this._setDocument(null);
+    },
+
+    /**
+     * @param {DOMAgent.Node} payload
+     */
+    _setDocument: function(payload)
+    {
+        this._idToDOMNode = {};
+        if (payload && "nodeId" in payload)
+            this._document = new WebInspector.DOMDocument(this, payload);
+        else
+            this._document = null;
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.DocumentUpdated, this._document);
+    },
+
+    /**
+     * @param {DOMAgent.Node} payload
+     */
+    _setDetachedRoot: function(payload)
+    {
+        if (payload.nodeName === "#document")
+            new WebInspector.DOMDocument(this, payload);
+        else
+            new WebInspector.DOMNode(this, null, false, payload);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentId
+     * @param {Array.} payloads
+     */
+    _setChildNodes: function(parentId, payloads)
+    {
+        if (!parentId && payloads.length) {
+            this._setDetachedRoot(payloads[0]);
+            return;
+        }
+
+        var parent = this._idToDOMNode[parentId];
+        parent._setChildrenPayload(payloads);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {number} newValue
+     */
+    _childNodeCountUpdated: function(nodeId, newValue)
+    {
+        var node = this._idToDOMNode[nodeId];
+        node._childNodeCount = newValue;
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.ChildNodeCountUpdated, node);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentId
+     * @param {DOMAgent.NodeId} prevId
+     * @param {DOMAgent.Node} payload
+     */
+    _childNodeInserted: function(parentId, prevId, payload)
+    {
+        var parent = this._idToDOMNode[parentId];
+        var prev = this._idToDOMNode[prevId];
+        var node = parent._insertChild(prev, payload);
+        this._idToDOMNode[node.id] = node;
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeInserted, node);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentId
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    _childNodeRemoved: function(parentId, nodeId)
+    {
+        var parent = this._idToDOMNode[parentId];
+        var node = this._idToDOMNode[nodeId];
+        parent._removeChild(node);
+        this._unbind(node);
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved, {node: node, parent: parent});
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} hostId
+     * @param {DOMAgent.Node} root
+     */
+    _shadowRootPushed: function(hostId, root)
+    {
+        var host = this._idToDOMNode[hostId];
+        if (!host)
+            return;
+        var node = new WebInspector.DOMNode(this, host.ownerDocument, true, root);
+        node.parentNode = host;
+        this._idToDOMNode[node.id] = node;
+        host._shadowRoots.push(node);
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeInserted, node);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} hostId
+     * @param {DOMAgent.NodeId} rootId
+     */
+    _shadowRootPopped: function(hostId, rootId)
+    {
+        var host = this._idToDOMNode[hostId];
+        if (!host)
+            return;
+        var root = this._idToDOMNode[rootId];
+        if (!root)
+            return;
+        host._shadowRoots.remove(root);
+        this._unbind(root);
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.NodeRemoved, {node: root, parent: host});
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     */
+    _unbind: function(node)
+    {
+        delete this._idToDOMNode[node.id];
+        for (var i = 0; node._children && i < node._children.length; ++i)
+            this._unbind(node._children[i]);
+        for (var i = 0; i < node._shadowRoots.length; ++i)
+            this._unbind(node._shadowRoots[i]);
+        if (node._templateContent)
+            this._unbind(node._templateContent);
+    },
+
+    /**
+     * @param {number} nodeId
+     */
+    inspectElement: function(nodeId)
+    {
+        var node = this._idToDOMNode[nodeId];
+        if (node)
+            this.dispatchEventToListeners(WebInspector.DOMAgent.Events.InspectNodeRequested, nodeId);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    _inspectNodeRequested: function(nodeId)
+    {
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.InspectNodeRequested, nodeId);
+    },
+
+    /**
+     * @param {string} query
+     * @param {function(number)} searchCallback
+     */
+    performSearch: function(query, searchCallback)
+    {
+        this.cancelSearch();
+
+        /**
+         * @param {?Protocol.Error} error
+         * @param {string} searchId
+         * @param {number} resultsCount
+         */
+        function callback(error, searchId, resultsCount)
+        {
+            this._searchId = searchId;
+            searchCallback(resultsCount);
+        }
+        DOMAgent.performSearch(query, callback.bind(this));
+    },
+
+    /**
+     * @param {number} index
+     * @param {?function(DOMAgent.Node)} callback
+     */
+    searchResult: function(index, callback)
+    {
+        if (this._searchId) {
+            /**
+             * @param {?Protocol.Error} error
+             * @param {Array.} nodeIds
+             */
+            function mycallback(error, nodeIds)
+            {
+                if (error) {
+                    console.error(error);
+                    callback(null);
+                    return;
+                }
+                if (nodeIds.length != 1)
+                    return;
+
+                callback(this._idToDOMNode[nodeIds[0]]);
+            }
+            DOMAgent.getSearchResults(this._searchId, index, index + 1, mycallback.bind(this));
+        } else
+            callback(null);
+    },
+
+    cancelSearch: function()
+    {
+        if (this._searchId) {
+            DOMAgent.discardSearchResults(this._searchId);
+            delete this._searchId;
+        }
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} selectors
+     * @param {function(?DOMAgent.NodeId)=} callback
+     */
+    querySelector: function(nodeId, selectors, callback)
+    {
+        DOMAgent.querySelector(nodeId, selectors, this._wrapClientCallback(callback));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} selectors
+     * @param {function(?Array.)=} callback
+     */
+    querySelectorAll: function(nodeId, selectors, callback)
+    {
+        DOMAgent.querySelectorAll(nodeId, selectors, this._wrapClientCallback(callback));
+    },
+
+    /**
+     * @param {DOMAgent.NodeId=} nodeId
+     * @param {string=} mode
+     * @param {RuntimeAgent.RemoteObjectId=} objectId
+     */
+    highlightDOMNode: function(nodeId, mode, objectId)
+    {
+        if (this._hideDOMNodeHighlightTimeout) {
+            clearTimeout(this._hideDOMNodeHighlightTimeout);
+            delete this._hideDOMNodeHighlightTimeout;
+        }
+        this._highlighter.highlightDOMNode(nodeId || 0, this._buildHighlightConfig(mode), objectId);
+    },
+
+    hideDOMNodeHighlight: function()
+    {
+        this.highlightDOMNode(0);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    highlightDOMNodeForTwoSeconds: function(nodeId)
+    {
+        this.highlightDOMNode(nodeId);
+        this._hideDOMNodeHighlightTimeout = setTimeout(this.hideDOMNodeHighlight.bind(this), 2000);
+    },
+
+    /**
+     * @param {boolean} enabled
+     * @param {boolean} inspectShadowDOM
+     * @param {function(?Protocol.Error)=} callback
+     */
+    setInspectModeEnabled: function(enabled, inspectShadowDOM, callback)
+    {
+        function onDocumentAvailable()
+        {
+            this._highlighter.setInspectModeEnabled(enabled, inspectShadowDOM, this._buildHighlightConfig(), callback);
+        }
+        this.requestDocument(onDocumentAvailable.bind(this));
+    },
+
+    /**
+     * @param {string=} mode
+     * @return {DOMAgent.HighlightConfig}
+     */
+    _buildHighlightConfig: function(mode)
+    {
+        mode = mode || "all";
+        var highlightConfig = { showInfo: mode === "all", showRulers: WebInspector.settings.showMetricsRulers.get() };
+        if (mode === "all" || mode === "content")
+            highlightConfig.contentColor = WebInspector.Color.PageHighlight.Content.toProtocolRGBA();
+
+        if (mode === "all" || mode === "padding")
+            highlightConfig.paddingColor = WebInspector.Color.PageHighlight.Padding.toProtocolRGBA();
+
+        if (mode === "all" || mode === "border")
+            highlightConfig.borderColor = WebInspector.Color.PageHighlight.Border.toProtocolRGBA();
+
+        if (mode === "all" || mode === "margin")
+            highlightConfig.marginColor = WebInspector.Color.PageHighlight.Margin.toProtocolRGBA();
+
+        if (mode === "all")
+            highlightConfig.eventTargetColor = WebInspector.Color.PageHighlight.EventTarget.toProtocolRGBA();
+
+        return highlightConfig;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     * @param {function(?Protocol.Error, A=, B=)=} callback
+     * @return {function(?Protocol.Error, A=, B=)}
+     * @template A,B
+     */
+    _markRevision: function(node, callback)
+    {
+        function wrapperFunction(error)
+        {
+            if (!error)
+                this.markUndoableState();
+
+            if (callback)
+                callback.apply(this, arguments);
+        }
+        return wrapperFunction.bind(this);
+    },
+
+    /**
+     * @param {boolean} emulationEnabled
+     */
+    emulateTouchEventObjects: function(emulationEnabled)
+    {
+        const injectedFunction = function() {
+            const touchEvents = ["ontouchstart", "ontouchend", "ontouchmove", "ontouchcancel"];
+            var recepients = [window.__proto__, document.__proto__];
+            for (var i = 0; i < touchEvents.length; ++i) {
+                for (var j = 0; j < recepients.length; ++j) {
+                    if (!(touchEvents[i] in recepients[j]))
+                        Object.defineProperty(recepients[j], touchEvents[i], { value: null, writable: true, configurable: true, enumerable: true });
+                }
+            }
+        }
+
+        if (emulationEnabled && !this._addTouchEventsScriptInjecting) {
+            this._addTouchEventsScriptInjecting = true;
+            PageAgent.addScriptToEvaluateOnLoad("(" + injectedFunction.toString() + ")()", scriptAddedCallback.bind(this));
+        } else {
+            if (typeof this._addTouchEventsScriptId !== "undefined") {
+                PageAgent.removeScriptToEvaluateOnLoad(this._addTouchEventsScriptId);
+                delete this._addTouchEventsScriptId;
+            }
+        }
+
+        function scriptAddedCallback(error, scriptId)
+        {
+            delete this._addTouchEventsScriptInjecting;
+            if (error)
+                return;
+            this._addTouchEventsScriptId = scriptId;
+        }
+
+        PageAgent.setTouchEmulationEnabled(emulationEnabled);
+    },
+
+    markUndoableState: function()
+    {
+        DOMAgent.markUndoableState();
+    },
+
+    /**
+     * @param {function(?Protocol.Error)=} callback
+     */
+    undo: function(callback)
+    {
+        function mycallback(error)
+        {
+            this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoCompleted);
+            callback(error);
+        }
+
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoRequested);
+        DOMAgent.undo(callback);
+    },
+
+    /**
+     * @param {function(?Protocol.Error)=} callback
+     */
+    redo: function(callback)
+    {
+        function mycallback(error)
+        {
+            this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoCompleted);
+            callback(error);
+        }
+
+        this.dispatchEventToListeners(WebInspector.DOMAgent.Events.UndoRedoRequested);
+        DOMAgent.redo(callback);
+    },
+
+    /**
+     * @param {WebInspector.DOMNodeHighlighter} highlighter
+     */
+    setHighlighter: function(highlighter)
+    {
+        this._highlighter = highlighter || this._defaultHighlighter;
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {DOMAgent.Dispatcher}
+ * @param {WebInspector.DOMAgent} domAgent
+ */
+WebInspector.DOMDispatcher = function(domAgent)
+{
+    this._domAgent = domAgent;
+}
+
+WebInspector.DOMDispatcher.prototype = {
+    documentUpdated: function()
+    {
+        this._domAgent._documentUpdated();
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    inspectNodeRequested: function(nodeId)
+    {
+        this._domAgent._inspectNodeRequested(nodeId);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} name
+     * @param {string} value
+     */
+    attributeModified: function(nodeId, name, value)
+    {
+        this._domAgent._attributeModified(nodeId, name, value);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} name
+     */
+    attributeRemoved: function(nodeId, name)
+    {
+        this._domAgent._attributeRemoved(nodeId, name);
+    },
+
+    /**
+     * @param {Array.} nodeIds
+     */
+    inlineStyleInvalidated: function(nodeIds)
+    {
+        this._domAgent._inlineStyleInvalidated(nodeIds);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} characterData
+     */
+    characterDataModified: function(nodeId, characterData)
+    {
+        this._domAgent._characterDataModified(nodeId, characterData);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentId
+     * @param {Array.} payloads
+     */
+    setChildNodes: function(parentId, payloads)
+    {
+        this._domAgent._setChildNodes(parentId, payloads);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {number} childNodeCount
+     */
+    childNodeCountUpdated: function(nodeId, childNodeCount)
+    {
+        this._domAgent._childNodeCountUpdated(nodeId, childNodeCount);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentNodeId
+     * @param {DOMAgent.NodeId} previousNodeId
+     * @param {DOMAgent.Node} payload
+     */
+    childNodeInserted: function(parentNodeId, previousNodeId, payload)
+    {
+        this._domAgent._childNodeInserted(parentNodeId, previousNodeId, payload);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} parentNodeId
+     * @param {DOMAgent.NodeId} nodeId
+     */
+    childNodeRemoved: function(parentNodeId, nodeId)
+    {
+        this._domAgent._childNodeRemoved(parentNodeId, nodeId);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} hostId
+     * @param {DOMAgent.Node} root
+     */
+    shadowRootPushed: function(hostId, root)
+    {
+        this._domAgent._shadowRootPushed(hostId, root);
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} hostId
+     * @param {DOMAgent.NodeId} rootId
+     */
+    shadowRootPopped: function(hostId, rootId)
+    {
+        this._domAgent._shadowRootPopped(hostId, rootId);
+    }
+}
+
+/**
+ * @interface
+ */
+WebInspector.DOMNodeHighlighter = function() {
+}
+
+WebInspector.DOMNodeHighlighter.prototype = {
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {?DOMAgent.HighlightConfig} config
+     * @param {RuntimeAgent.RemoteObjectId=} objectId
+     */
+    highlightDOMNode: function(nodeId, config, objectId) {},
+
+    /**
+     * @param {boolean} enabled
+     * @param {boolean} inspectShadowDOM
+     * @param {DOMAgent.HighlightConfig} config
+     * @param {function(?Protocol.Error)} callback
+     */
+    setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback) {}
+}
+
+/**
+ * @constructor
+ * @implements {WebInspector.DOMNodeHighlighter}
+ */
+WebInspector.DefaultDOMNodeHighlighter = function() {
+}
+
+WebInspector.DefaultDOMNodeHighlighter.prototype = {
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {?DOMAgent.HighlightConfig} config
+     * @param {RuntimeAgent.RemoteObjectId=} objectId
+     */
+    highlightDOMNode: function(nodeId, config, objectId)
+    {
+        if (objectId || nodeId)
+            DOMAgent.highlightNode(config, objectId ? undefined : nodeId, objectId);
+        else
+            DOMAgent.hideHighlight();
+    },
+
+    /**
+     * @param {boolean} enabled
+     * @param {boolean} inspectShadowDOM
+     * @param {DOMAgent.HighlightConfig} config
+     * @param {function(?Protocol.Error)} callback
+     */
+    setInspectModeEnabled: function(enabled, inspectShadowDOM, config, callback)
+    {
+        DOMAgent.setInspectModeEnabled(enabled, inspectShadowDOM, config, callback);
+    }
+}
+
+/**
+ * @type {?WebInspector.DOMAgent}
+ */
+WebInspector.domAgent = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMBreakpointsSidebarPane.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMBreakpointsSidebarPane.js
new file mode 100644
index 00000000..ecda923d
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMBreakpointsSidebarPane.js
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.NativeBreakpointsSidebarPane}
+ */
+WebInspector.DOMBreakpointsSidebarPane = function()
+{
+    WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("DOM Breakpoints"));
+
+    this._breakpointElements = {};
+
+    this._breakpointTypes = {
+        SubtreeModified: "subtree-modified",
+        AttributeModified: "attribute-modified",
+        NodeRemoved: "node-removed"
+    };
+    this._breakpointTypeLabels = {};
+    this._breakpointTypeLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString("Subtree Modified");
+    this._breakpointTypeLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString("Attribute Modified");
+    this._breakpointTypeLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString("Node Removed");
+
+    this._contextMenuLabels = {};
+    this._contextMenuLabels[this._breakpointTypes.SubtreeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Subtree modifications" : "Subtree Modifications");
+    this._contextMenuLabels[this._breakpointTypes.AttributeModified] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Attributes modifications" : "Attributes Modifications");
+    this._contextMenuLabels[this._breakpointTypes.NodeRemoved] = WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Node removal" : "Node Removal");
+
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, this._inspectedURLChanged, this);
+    WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeRemoved, this._nodeRemoved, this);
+}
+
+WebInspector.DOMBreakpointsSidebarPane.prototype = {
+    _inspectedURLChanged: function(event)
+    {
+        this._breakpointElements = {};
+        this._reset();
+        var url = event.data;
+        this._inspectedURL = url.removeURLFragment();
+    },
+
+    populateNodeContextMenu: function(node, contextMenu)
+    {
+        var nodeBreakpoints = {};
+        for (var id in this._breakpointElements) {
+            var element = this._breakpointElements[id];
+            if (element._node === node)
+                nodeBreakpoints[element._type] = true;
+        }
+
+        function toggleBreakpoint(type)
+        {
+            if (!nodeBreakpoints[type])
+                this._setBreakpoint(node, type, true);
+            else
+                this._removeBreakpoint(node, type);
+            this._saveBreakpoints();
+        }
+
+        var breakPointSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Break on..."));
+        for (var key in this._breakpointTypes) {
+            var type = this._breakpointTypes[key];
+            var label = this._contextMenuLabels[type];
+            breakPointSubMenu.appendCheckboxItem(label, toggleBreakpoint.bind(this, type), nodeBreakpoints[type]);
+        }
+    },
+
+    createBreakpointHitStatusMessage: function(auxData, callback)
+    {
+        if (auxData.type === this._breakpointTypes.SubtreeModified) {
+            var targetNodeObject = WebInspector.RemoteObject.fromPayload(auxData["targetNode"]);
+            function didPushNodeToFrontend(targetNodeId)
+            {
+                if (targetNodeId)
+                    targetNodeObject.release();
+                this._doCreateBreakpointHitStatusMessage(auxData, targetNodeId, callback);
+            }
+            targetNodeObject.pushNodeToFrontend(didPushNodeToFrontend.bind(this));
+        } else
+            this._doCreateBreakpointHitStatusMessage(auxData, null, callback);
+    },
+
+    _doCreateBreakpointHitStatusMessage: function (auxData, targetNodeId, callback)
+    {
+        var message;
+        var typeLabel = this._breakpointTypeLabels[auxData.type];
+        var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeById(auxData.nodeId);
+        var substitutions = [typeLabel, linkifiedNode];
+        var targetNode = "";
+        if (targetNodeId)
+            targetNode = WebInspector.DOMPresentationUtils.linkifyNodeById(targetNodeId);
+
+        if (auxData.type === this._breakpointTypes.SubtreeModified) {
+            if (auxData.insertion) {
+                if (targetNodeId !== auxData.nodeId) {
+                    message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to its descendant %s.";
+                    substitutions.push(targetNode);
+                } else
+                    message = "Paused on a \"%s\" breakpoint set on %s, because a new child was added to that node.";
+            } else {
+                message = "Paused on a \"%s\" breakpoint set on %s, because its descendant %s was removed.";
+                substitutions.push(targetNode);
+            }
+        } else
+            message = "Paused on a \"%s\" breakpoint set on %s.";
+
+        var element = document.createElement("span");
+        var formatters = {
+            s: function(substitution)
+            {
+                return substitution;
+            }
+        };
+        function append(a, b)
+        {
+            if (typeof b === "string")
+                b = document.createTextNode(b);
+            element.appendChild(b);
+        }
+        WebInspector.formatLocalized(message, substitutions, formatters, "", append);
+
+        callback(element);
+    },
+
+    _nodeRemoved: function(event)
+    {
+        var node = event.data.node;
+        this._removeBreakpointsForNode(event.data.node);
+        var children = node.children();
+        if (!children)
+            return;
+        for (var i = 0; i < children.length; ++i)
+            this._removeBreakpointsForNode(children[i]);
+        this._saveBreakpoints();
+    },
+
+    _removeBreakpointsForNode: function(node)
+    {
+        for (var id in this._breakpointElements) {
+            var element = this._breakpointElements[id];
+            if (element._node === node)
+                this._removeBreakpoint(element._node, element._type);
+        }
+    },
+
+    _setBreakpoint: function(node, type, enabled)
+    {
+        var breakpointId = this._createBreakpointId(node.id, type);
+        if (breakpointId in this._breakpointElements)
+            return;
+
+        var element = document.createElement("li");
+        element._node = node;
+        element._type = type;
+        element.addEventListener("contextmenu", this._contextMenu.bind(this, node, type), true);
+
+        var checkboxElement = document.createElement("input");
+        checkboxElement.className = "checkbox-elem";
+        checkboxElement.type = "checkbox";
+        checkboxElement.checked = enabled;
+        checkboxElement.addEventListener("click", this._checkboxClicked.bind(this, node, type), false);
+        element._checkboxElement = checkboxElement;
+        element.appendChild(checkboxElement);
+
+        var labelElement = document.createElement("span");
+        element.appendChild(labelElement);
+
+        var linkifiedNode = WebInspector.DOMPresentationUtils.linkifyNodeById(node.id);
+        linkifiedNode.addStyleClass("monospace");
+        labelElement.appendChild(linkifiedNode);
+
+        var description = document.createElement("div");
+        description.className = "source-text";
+        description.textContent = this._breakpointTypeLabels[type];
+        labelElement.appendChild(description);
+
+        var currentElement = this.listElement.firstChild;
+        while (currentElement) {
+            if (currentElement._type && currentElement._type < element._type)
+                break;
+            currentElement = currentElement.nextSibling;
+        }
+        this._addListElement(element, currentElement);
+        this._breakpointElements[breakpointId] = element;
+        if (enabled)
+            DOMDebuggerAgent.setDOMBreakpoint(node.id, type);
+    },
+
+    _removeAllBreakpoints: function()
+    {
+        for (var id in this._breakpointElements) {
+            var element = this._breakpointElements[id];
+            this._removeBreakpoint(element._node, element._type);
+        }
+        this._saveBreakpoints();
+    },
+
+    _removeBreakpoint: function(node, type)
+    {
+        var breakpointId = this._createBreakpointId(node.id, type);
+        var element = this._breakpointElements[breakpointId];
+        if (!element)
+            return;
+
+        this._removeListElement(element);
+        delete this._breakpointElements[breakpointId];
+        if (element._checkboxElement.checked)
+            DOMDebuggerAgent.removeDOMBreakpoint(node.id, type);
+    },
+
+    _contextMenu: function(node, type, event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        function removeBreakpoint()
+        {
+            this._removeBreakpoint(node, type);
+            this._saveBreakpoints();
+        }
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove breakpoint" : "Remove Breakpoint"), removeBreakpoint.bind(this));
+        contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Remove all DOM breakpoints" : "Remove All DOM Breakpoints"), this._removeAllBreakpoints.bind(this));
+        contextMenu.show();
+    },
+
+    _checkboxClicked: function(node, type, event)
+    {
+        if (event.target.checked)
+            DOMDebuggerAgent.setDOMBreakpoint(node.id, type);
+        else
+            DOMDebuggerAgent.removeDOMBreakpoint(node.id, type);
+        this._saveBreakpoints();
+    },
+
+    highlightBreakpoint: function(auxData)
+    {
+        var breakpointId = this._createBreakpointId(auxData.nodeId, auxData.type);
+        var element = this._breakpointElements[breakpointId];
+        if (!element)
+            return;
+        this.expand();
+        element.addStyleClass("breakpoint-hit");
+        this._highlightedElement = element;
+    },
+
+    clearBreakpointHighlight: function()
+    {
+        if (this._highlightedElement) {
+            this._highlightedElement.removeStyleClass("breakpoint-hit");
+            delete this._highlightedElement;
+        }
+    },
+
+    _createBreakpointId: function(nodeId, type)
+    {
+        return nodeId + ":" + type;
+    },
+
+    _saveBreakpoints: function()
+    {
+        var breakpoints = [];
+        var storedBreakpoints = WebInspector.settings.domBreakpoints.get();
+        for (var i = 0; i < storedBreakpoints.length; ++i) {
+            var breakpoint = storedBreakpoints[i];
+            if (breakpoint.url !== this._inspectedURL)
+                breakpoints.push(breakpoint);
+        }
+        for (var id in this._breakpointElements) {
+            var element = this._breakpointElements[id];
+            breakpoints.push({ url: this._inspectedURL, path: element._node.path(), type: element._type, enabled: element._checkboxElement.checked });
+        }
+        WebInspector.settings.domBreakpoints.set(breakpoints);
+    },
+
+    restoreBreakpoints: function()
+    {
+        var pathToBreakpoints = {};
+
+        /**
+         * @param {string} path
+         * @param {?DOMAgent.NodeId} nodeId
+         */
+        function didPushNodeByPathToFrontend(path, nodeId)
+        {
+            var node = nodeId ? WebInspector.domAgent.nodeForId(nodeId) : null;
+            if (!node)
+                return;
+
+            var breakpoints = pathToBreakpoints[path];
+            for (var i = 0; i < breakpoints.length; ++i)
+                this._setBreakpoint(node, breakpoints[i].type, breakpoints[i].enabled);
+        }
+
+        var breakpoints = WebInspector.settings.domBreakpoints.get();
+        for (var i = 0; i < breakpoints.length; ++i) {
+            var breakpoint = breakpoints[i];
+            if (breakpoint.url !== this._inspectedURL)
+                continue;
+            var path = breakpoint.path;
+            if (!pathToBreakpoints[path]) {
+                pathToBreakpoints[path] = [];
+                WebInspector.domAgent.pushNodeByPathToFrontend(path, didPushNodeByPathToFrontend.bind(this, path));
+            }
+            pathToBreakpoints[path].push(breakpoint);
+        }
+    },
+
+    /**
+     * @param {WebInspector.Panel} panel
+     */
+    createProxy: function(panel)
+    {
+        var proxy = new WebInspector.DOMBreakpointsSidebarPane.Proxy(this, panel);
+        if (!this._proxies)
+            this._proxies = [];
+        this._proxies.push(proxy);
+        return proxy;
+    },
+
+    onContentReady: function()
+    {
+        for (var i = 0; i != this._proxies.length; i++)
+            this._proxies[i].onContentReady();
+    },
+
+    __proto__: WebInspector.NativeBreakpointsSidebarPane.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.SidebarPane}
+ * @param {WebInspector.DOMBreakpointsSidebarPane} pane
+ * @param {WebInspector.Panel} panel
+ */
+WebInspector.DOMBreakpointsSidebarPane.Proxy = function(pane, panel)
+{
+    WebInspector.View._assert(!pane.titleElement.firstChild, "Cannot create proxy for a sidebar pane with a toolbar");
+
+    WebInspector.SidebarPane.call(this, pane.title());
+    this.registerRequiredCSS("breakpointsList.css");
+
+    this._wrappedPane = pane;
+    this._panel = panel;
+
+    this.bodyElement.remove();
+    this.bodyElement = this._wrappedPane.bodyElement;
+}
+
+WebInspector.DOMBreakpointsSidebarPane.Proxy.prototype = {
+    expand: function()
+    {
+        this._wrappedPane.expand();
+    },
+
+    onContentReady: function()
+    {
+        if (this._panel.isShowing())
+            this._reattachBody();
+
+        WebInspector.SidebarPane.prototype.onContentReady.call(this);
+    },
+
+    wasShown: function()
+    {
+        WebInspector.SidebarPane.prototype.wasShown.call(this);
+        this._reattachBody();
+    },
+
+    _reattachBody: function()
+    {
+        if (this.bodyElement.parentNode !== this.element)
+            this.element.appendChild(this.bodyElement);
+    },
+
+    __proto__: WebInspector.SidebarPane.prototype
+}
+
+/**
+ * @type {?WebInspector.DOMBreakpointsSidebarPane}
+ */
+WebInspector.domBreakpointsSidebarPane = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMCountersGraph.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMCountersGraph.js
new file mode 100644
index 00000000..1f004a45
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMCountersGraph.js
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.MemoryStatistics}
+ * @param {WebInspector.TimelinePanel} timelinePanel
+ * @param {WebInspector.TimelineModel} model
+ * @param {number} sidebarWidth
+ */
+WebInspector.DOMCountersGraph = function(timelinePanel, model, sidebarWidth)
+{
+    WebInspector.MemoryStatistics.call(this, timelinePanel, model, sidebarWidth);
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.CounterUIBase}
+ * @param {WebInspector.DOMCountersGraph} memoryCountersPane
+ * @param {string} title
+ * @param {string} currentValueLabel
+ * @param {Array.} rgb
+ * @param {function(WebInspector.DOMCountersGraph.Counter):number} valueGetter
+ */
+WebInspector.DOMCounterUI = function(memoryCountersPane, title, currentValueLabel, rgb, valueGetter)
+{
+    var swatchColor = "rgb(" + rgb.join(",") + ")";
+    WebInspector.CounterUIBase.call(this, memoryCountersPane, title, swatchColor, valueGetter)
+    this._range = this._swatch.element.createChild("span");
+
+    this._value = memoryCountersPane._currentValuesBar.createChild("span", "memory-counter-value");
+    this._value.style.color = swatchColor;
+    this._currentValueLabel = currentValueLabel;
+
+    this.graphColor = "rgba(" + rgb.join(",") + ",0.8)";
+    this.graphYValues = [];
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.MemoryStatistics.Counter}
+ * @param {number} time
+ * @param {number} documentCount
+ * @param {number} nodeCount
+ * @param {number} listenerCount
+ */
+WebInspector.DOMCountersGraph.Counter = function(time, documentCount, nodeCount, listenerCount)
+{
+    WebInspector.MemoryStatistics.Counter.call(this, time);
+    this.documentCount = documentCount;
+    this.nodeCount = nodeCount;
+    this.listenerCount = listenerCount;
+}
+
+WebInspector.DOMCounterUI.prototype = {
+    /**
+     * @param {number} minValue
+     * @param {number} maxValue
+     */
+    setRange: function(minValue, maxValue)
+    {
+        this._range.textContent = WebInspector.UIString("[ %d - %d ]", minValue, maxValue);
+    },
+
+    updateCurrentValue: function(countersEntry)
+    {
+        this._value.textContent =  WebInspector.UIString(this._currentValueLabel, this.valueGetter(countersEntry));
+    },
+
+    clearCurrentValueAndMarker: function(ctx)
+    {
+        this._value.textContent = "";
+        this.restoreImageUnderMarker(ctx);
+    },
+
+    /**
+     * @param {CanvasRenderingContext2D} ctx
+     * @param {number} x
+     * @param {number} y
+     * @param {number} radius
+     */
+    saveImageUnderMarker: function(ctx, x, y, radius)
+    {
+        const w = radius + 1;
+        var imageData = ctx.getImageData(x - w, y - w, 2 * w, 2 * w);
+        this._imageUnderMarker = {
+            x: x - w,
+            y: y - w,
+            imageData: imageData
+        };
+    },
+
+    /**
+     * @param {CanvasRenderingContext2D} ctx
+     */
+    restoreImageUnderMarker: function(ctx)
+    {
+        if (!this.visible)
+            return;
+        if (this._imageUnderMarker)
+            ctx.putImageData(this._imageUnderMarker.imageData, this._imageUnderMarker.x, this._imageUnderMarker.y);
+        this.discardImageUnderMarker();
+    },
+
+    discardImageUnderMarker: function()
+    {
+        delete this._imageUnderMarker;
+    },
+
+    __proto__: WebInspector.CounterUIBase.prototype
+}
+
+
+WebInspector.DOMCountersGraph.prototype = {
+    _createCurrentValuesBar: function()
+    {
+        this._currentValuesBar = this._canvasContainer.createChild("div");
+        this._currentValuesBar.id = "counter-values-bar";
+        this._canvasContainer.addStyleClass("dom-counters");
+    },
+
+    /**
+     * @return {Array.}
+     */
+    _createCounterUIList: function()
+    {
+        function getDocumentCount(entry)
+        {
+            return entry.documentCount;
+        }
+        function getNodeCount(entry)
+        {
+            return entry.nodeCount;
+        }
+        function getListenerCount(entry)
+        {
+            return entry.listenerCount;
+        }
+        return [
+            new WebInspector.DOMCounterUI(this, "Document Count", "Documents: %d", [100, 0, 0], getDocumentCount),
+            new WebInspector.DOMCounterUI(this, "DOM Node Count", "Nodes: %d", [0, 100, 0], getNodeCount),
+            new WebInspector.DOMCounterUI(this, "Event Listener Count", "Listeners: %d", [0, 0, 100], getListenerCount)
+        ];
+    },
+
+    _canvasHeight: function()
+    {
+        return this._canvasContainer.offsetHeight - this._currentValuesBar.offsetHeight;
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _onRecordAdded: function(event)
+    {
+        function addStatistics(record)
+        {
+            var counters = record["counters"];
+            if (!counters)
+                return;
+            this._counters.push(new WebInspector.DOMCountersGraph.Counter(
+                record.endTime || record.startTime,
+                counters["documents"],
+                counters["nodes"],
+                counters["jsEventListeners"]
+            ));
+        }
+        WebInspector.TimelinePresentationModel.forAllRecords([event.data], null, addStatistics.bind(this));
+    },
+
+    _draw: function()
+    {
+        WebInspector.MemoryStatistics.prototype._draw.call(this);
+        for (var i = 0; i < this._counterUI.length; i++)
+            this._drawGraph(this._counterUI[i]);
+    },
+
+    /**
+     * @param {CanvasRenderingContext2D} ctx
+     */
+    _restoreImageUnderMarker: function(ctx)
+    {
+        for (var i = 0; i < this._counterUI.length; i++) {
+            var counterUI = this._counterUI[i];
+            if (!counterUI.visible)
+                continue;
+            counterUI.restoreImageUnderMarker(ctx);
+        }
+    },
+
+    /**
+     * @param {CanvasRenderingContext2D} ctx
+     * @param {number} x
+     * @param {number} index
+     */
+    _saveImageUnderMarker: function(ctx, x, index)
+    {
+        const radius = 2;
+        for (var i = 0; i < this._counterUI.length; i++) {
+            var counterUI = this._counterUI[i];
+            if (!counterUI.visible)
+                continue;
+            var y = counterUI.graphYValues[index];
+            counterUI.saveImageUnderMarker(ctx, x, y, radius);
+        }
+    },
+
+    /**
+     * @param {CanvasRenderingContext2D} ctx
+     * @param {number} x
+     * @param {number} index
+     */
+    _drawMarker: function(ctx, x, index)
+    {
+        this._saveImageUnderMarker(ctx, x, index);
+        const radius = 2;
+        for (var i = 0; i < this._counterUI.length; i++) {
+            var counterUI = this._counterUI[i];
+            if (!counterUI.visible)
+                continue;
+            var y = counterUI.graphYValues[index];
+            ctx.beginPath();
+            ctx.arc(x, y, radius, 0, Math.PI * 2, true);
+            ctx.lineWidth = 1;
+            ctx.fillStyle = counterUI.graphColor;
+            ctx.strokeStyle = counterUI.graphColor;
+            ctx.fill();
+            ctx.stroke();
+            ctx.closePath();
+        }
+    },
+
+    /**
+     * @param {WebInspector.CounterUIBase} counterUI
+     */
+    _drawGraph: function(counterUI)
+    {
+        var canvas = this._canvas;
+        var ctx = canvas.getContext("2d");
+        var width = canvas.width;
+        var height = this._clippedHeight;
+        var originY = this._originY;
+        var valueGetter = counterUI.valueGetter;
+
+        if (!this._counters.length)
+            return;
+
+        var maxValue;
+        var minValue;
+        for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+            var value = valueGetter(this._counters[i]);
+            if (minValue === undefined || value < minValue)
+                minValue = value;
+            if (maxValue === undefined || value > maxValue)
+                maxValue = value;
+        }
+
+        counterUI.setRange(minValue, maxValue);
+
+        if (!counterUI.visible)
+            return;
+
+        var yValues = counterUI.graphYValues;
+        yValues.length = this._counters.length;
+
+        var maxYRange = maxValue - minValue;
+        var yFactor = maxYRange ? height / (maxYRange) : 1;
+
+        ctx.beginPath();
+        var currentY = originY + (height - (valueGetter(this._counters[this._minimumIndex]) - minValue) * yFactor);
+        ctx.moveTo(0, currentY);
+        for (var i = this._minimumIndex; i <= this._maximumIndex; i++) {
+             var x = this._counters[i].x;
+             ctx.lineTo(x, currentY);
+             currentY = originY + (height - (valueGetter(this._counters[i]) - minValue) * yFactor);
+             ctx.lineTo(x, currentY);
+
+             yValues[i] = currentY;
+        }
+        ctx.lineTo(width, currentY);
+        ctx.lineWidth = 1;
+        ctx.strokeStyle = counterUI.graphColor;
+        ctx.stroke();
+        ctx.closePath();
+    },
+
+    _discardImageUnderMarker: function()
+    {
+        for (var i = 0; i < this._counterUI.length; i++)
+            this._counterUI[i].discardImageUnderMarker();
+    },
+
+    __proto__: WebInspector.MemoryStatistics.prototype
+}
+
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMExtension.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMExtension.js
new file mode 100644
index 00000000..158298f8
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMExtension.js
@@ -0,0 +1,613 @@
+/*
+ * Copyright (C) 2007 Apple Inc.  All rights reserved.
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Contains diff method based on Javascript Diff Algorithm By John Resig
+ * http://ejohn.org/files/jsdiff.js (released under the MIT license).
+ */
+
+/**
+ * @param {string=} direction
+ */
+Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, direction)
+{
+    var startNode;
+    var startOffset = 0;
+    var endNode;
+    var endOffset = 0;
+
+    if (!stayWithinNode)
+        stayWithinNode = this;
+
+    if (!direction || direction === "backward" || direction === "both") {
+        var node = this;
+        while (node) {
+            if (node === stayWithinNode) {
+                if (!startNode)
+                    startNode = stayWithinNode;
+                break;
+            }
+
+            if (node.nodeType === Node.TEXT_NODE) {
+                var start = (node === this ? (offset - 1) : (node.nodeValue.length - 1));
+                for (var i = start; i >= 0; --i) {
+                    if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
+                        startNode = node;
+                        startOffset = i + 1;
+                        break;
+                    }
+                }
+            }
+
+            if (startNode)
+                break;
+
+            node = node.traversePreviousNode(stayWithinNode);
+        }
+
+        if (!startNode) {
+            startNode = stayWithinNode;
+            startOffset = 0;
+        }
+    } else {
+        startNode = this;
+        startOffset = offset;
+    }
+
+    if (!direction || direction === "forward" || direction === "both") {
+        node = this;
+        while (node) {
+            if (node === stayWithinNode) {
+                if (!endNode)
+                    endNode = stayWithinNode;
+                break;
+            }
+
+            if (node.nodeType === Node.TEXT_NODE) {
+                var start = (node === this ? offset : 0);
+                for (var i = start; i < node.nodeValue.length; ++i) {
+                    if (stopCharacters.indexOf(node.nodeValue[i]) !== -1) {
+                        endNode = node;
+                        endOffset = i;
+                        break;
+                    }
+                }
+            }
+
+            if (endNode)
+                break;
+
+            node = node.traverseNextNode(stayWithinNode);
+        }
+
+        if (!endNode) {
+            endNode = stayWithinNode;
+            endOffset = stayWithinNode.nodeType === Node.TEXT_NODE ? stayWithinNode.nodeValue.length : stayWithinNode.childNodes.length;
+        }
+    } else {
+        endNode = this;
+        endOffset = offset;
+    }
+
+    var result = this.ownerDocument.createRange();
+    result.setStart(startNode, startOffset);
+    result.setEnd(endNode, endOffset);
+
+    return result;
+}
+
+Node.prototype.traverseNextTextNode = function(stayWithin)
+{
+    var node = this.traverseNextNode(stayWithin);
+    if (!node)
+        return;
+
+    while (node && node.nodeType !== Node.TEXT_NODE)
+        node = node.traverseNextNode(stayWithin);
+
+    return node;
+}
+
+Node.prototype.rangeBoundaryForOffset = function(offset)
+{
+    var node = this.traverseNextTextNode(this);
+    while (node && offset > node.nodeValue.length) {
+        offset -= node.nodeValue.length;
+        node = node.traverseNextTextNode(this);
+    }
+    if (!node)
+        return { container: this, offset: 0 };
+    return { container: node, offset: offset };
+}
+
+/**
+ * @param {string} className
+ */
+Element.prototype.removeStyleClass = function(className)
+{
+    this.classList.remove(className);
+}
+
+Element.prototype.removeMatchingStyleClasses = function(classNameRegex)
+{
+    var regex = new RegExp("(^|\\s+)" + classNameRegex + "($|\\s+)");
+    if (regex.test(this.className))
+        this.className = this.className.replace(regex, " ");
+}
+
+/**
+ * @param {string} className
+ */
+Element.prototype.addStyleClass = function(className)
+{
+    this.classList.add(className);
+}
+
+/**
+ * @param {string} className
+ * @return {boolean}
+ */
+Element.prototype.hasStyleClass = function(className)
+{
+    return this.classList.contains(className);
+}
+
+/**
+ * @param {string} className
+ * @param {*} enable
+ */
+Element.prototype.enableStyleClass = function(className, enable)
+{
+    if (enable)
+        this.addStyleClass(className);
+    else
+        this.removeStyleClass(className);
+}
+
+/**
+ * @param {number|undefined} x
+ * @param {number|undefined} y
+ */
+Element.prototype.positionAt = function(x, y)
+{
+    if (typeof x === "number")
+        this.style.setProperty("left", x + "px");
+    else
+        this.style.removeProperty("left");
+
+    if (typeof y === "number")
+        this.style.setProperty("top", y + "px");
+    else
+        this.style.removeProperty("top");
+}
+
+Element.prototype.isScrolledToBottom = function()
+{
+    // This code works only for 0-width border
+    return this.scrollTop + this.clientHeight === this.scrollHeight;
+}
+
+/**
+ * @param {Node} fromNode
+ * @param {Node} toNode
+ */
+function removeSubsequentNodes(fromNode, toNode)
+{
+    for (var node = fromNode; node && node !== toNode; ) {
+        var nodeToRemove = node;
+        node = node.nextSibling;
+        nodeToRemove.remove();
+    }
+}
+
+/**
+ * @constructor
+ * @param {number} width
+ * @param {number} height
+ */
+function Size(width, height)
+{
+    this.width = width;
+    this.height = height;
+}
+
+/**
+ * @param {Element=} containerElement
+ * @return {Size}
+ */
+Element.prototype.measurePreferredSize = function(containerElement)
+{
+    containerElement = containerElement || document.body;
+    containerElement.appendChild(this);
+    this.positionAt(0, 0);
+    var result = new Size(this.offsetWidth, this.offsetHeight);
+    this.positionAt(undefined, undefined);
+    this.remove();
+    return result;
+}
+
+Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = function(nameArray)
+{
+    for (var node = this; node && node !== this.ownerDocument; node = node.parentNode)
+        for (var i = 0; i < nameArray.length; ++i)
+            if (node.nodeName.toLowerCase() === nameArray[i].toLowerCase())
+                return node;
+    return null;
+}
+
+Node.prototype.enclosingNodeOrSelfWithNodeName = function(nodeName)
+{
+    return this.enclosingNodeOrSelfWithNodeNameInArray([nodeName]);
+}
+
+/**
+ * @param {string} className
+ * @param {Element=} stayWithin
+ */
+Node.prototype.enclosingNodeOrSelfWithClass = function(className, stayWithin)
+{
+    for (var node = this; node && node !== stayWithin && node !== this.ownerDocument; node = node.parentNode)
+        if (node.nodeType === Node.ELEMENT_NODE && node.hasStyleClass(className))
+            return node;
+    return null;
+}
+
+Element.prototype.query = function(query)
+{
+    return this.ownerDocument.evaluate(query, this, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
+}
+
+Element.prototype.removeChildren = function()
+{
+    if (this.firstChild)
+        this.textContent = "";
+}
+
+Element.prototype.isInsertionCaretInside = function()
+{
+    var selection = window.getSelection();
+    if (!selection.rangeCount || !selection.isCollapsed)
+        return false;
+    var selectionRange = selection.getRangeAt(0);
+    return selectionRange.startContainer.isSelfOrDescendant(this);
+}
+
+/**
+ * @param {string=} className
+ */
+Element.prototype.createChild = function(elementName, className)
+{
+    var element = this.ownerDocument.createElement(elementName);
+    if (className)
+        element.className = className;
+    this.appendChild(element);
+    return element;
+}
+
+DocumentFragment.prototype.createChild = Element.prototype.createChild;
+
+/**
+ * @param {string} text
+ */
+Element.prototype.createTextChild = function(text)
+{
+    var element = this.ownerDocument.createTextNode(text);
+    this.appendChild(element);
+    return element;
+}
+
+DocumentFragment.prototype.createTextChild = Element.prototype.createTextChild;
+
+/**
+ * @return {number}
+ */
+Element.prototype.totalOffsetLeft = function()
+{
+    return this.totalOffset().left;
+}
+
+/**
+ * @return {number}
+ */
+Element.prototype.totalOffsetTop = function()
+{
+    return this.totalOffset().top;
+
+}
+
+Element.prototype.totalOffset = function()
+{
+    var totalLeft = 0;
+    var totalTop = 0;
+
+    for (var element = this; element; element = element.offsetParent) {
+        totalLeft += element.offsetLeft;
+        totalTop += element.offsetTop;
+        if (this !== element) {
+            totalLeft += element.clientLeft - element.scrollLeft;
+            totalTop += element.clientTop - element.scrollTop;
+        }
+    }
+
+    return { left: totalLeft, top: totalTop };
+}
+
+Element.prototype.scrollOffset = function()
+{
+    var curLeft = 0;
+    var curTop = 0;
+    for (var element = this; element; element = element.scrollParent) {
+        curLeft += element.scrollLeft;
+        curTop += element.scrollTop;
+    }
+    return { left: curLeft, top: curTop };
+}
+
+/**
+ * @constructor
+ * @param {number=} x
+ * @param {number=} y
+ * @param {number=} width
+ * @param {number=} height
+ */
+function AnchorBox(x, y, width, height)
+{
+    this.x = x || 0;
+    this.y = y || 0;
+    this.width = width || 0;
+    this.height = height || 0;
+}
+
+/**
+ * @param {Window} targetWindow
+ * @return {AnchorBox}
+ */
+Element.prototype.offsetRelativeToWindow = function(targetWindow)
+{
+    var elementOffset = new AnchorBox();
+    var curElement = this;
+    var curWindow = this.ownerDocument.defaultView;
+    while (curWindow && curElement) {
+        elementOffset.x += curElement.totalOffsetLeft();
+        elementOffset.y += curElement.totalOffsetTop();
+        if (curWindow === targetWindow)
+            break;
+
+        curElement = curWindow.frameElement;
+        curWindow = curWindow.parent;
+    }
+
+    return elementOffset;
+}
+
+/**
+ * @param {Window} targetWindow
+ * @return {AnchorBox}
+ */
+Element.prototype.boxInWindow = function(targetWindow)
+{
+    targetWindow = targetWindow || this.ownerDocument.defaultView;
+
+    var anchorBox = this.offsetRelativeToWindow(window);
+    anchorBox.width = Math.min(this.offsetWidth, window.innerWidth - anchorBox.x);
+    anchorBox.height = Math.min(this.offsetHeight, window.innerHeight - anchorBox.y);
+
+    return anchorBox;
+}
+
+/**
+ * @param {string} text
+ */
+Element.prototype.setTextAndTitle = function(text)
+{
+    this.textContent = text;
+    this.title = text;
+}
+
+KeyboardEvent.prototype.__defineGetter__("data", function()
+{
+    // Emulate "data" attribute from DOM 3 TextInput event.
+    // See http://www.w3.org/TR/DOM-Level-3-Events/#events-Events-TextEvent-data
+    switch (this.type) {
+        case "keypress":
+            if (!this.ctrlKey && !this.metaKey)
+                return String.fromCharCode(this.charCode);
+            else
+                return "";
+        case "keydown":
+        case "keyup":
+            if (!this.ctrlKey && !this.metaKey && !this.altKey)
+                return String.fromCharCode(this.which);
+            else
+                return "";
+    }
+});
+
+/**
+ * @param {boolean=} preventDefault
+ */
+Event.prototype.consume = function(preventDefault)
+{
+    this.stopImmediatePropagation();
+    if (preventDefault)
+        this.preventDefault();
+    this.handled = true;
+}
+
+Text.prototype.select = function(start, end)
+{
+    start = start || 0;
+    end = end || this.textContent.length;
+
+    if (start < 0)
+        start = end + start;
+
+    var selection = this.ownerDocument.defaultView.getSelection();
+    selection.removeAllRanges();
+    var range = this.ownerDocument.createRange();
+    range.setStart(this, start);
+    range.setEnd(this, end);
+    selection.addRange(range);
+    return this;
+}
+
+Element.prototype.selectionLeftOffset = function()
+{
+    // Calculate selection offset relative to the current element.
+
+    var selection = window.getSelection();
+    if (!selection.containsNode(this, true))
+        return null;
+
+    var leftOffset = selection.anchorOffset;
+    var node = selection.anchorNode;
+
+    while (node !== this) {
+        while (node.previousSibling) {
+            node = node.previousSibling;
+            leftOffset += node.textContent.length;
+        }
+        node = node.parentNode;
+    }
+
+    return leftOffset;
+}
+
+Node.prototype.isAncestor = function(node)
+{
+    if (!node)
+        return false;
+
+    var currentNode = node.parentNode;
+    while (currentNode) {
+        if (this === currentNode)
+            return true;
+        currentNode = currentNode.parentNode;
+    }
+    return false;
+}
+
+Node.prototype.isDescendant = function(descendant)
+{
+    return !!descendant && descendant.isAncestor(this);
+}
+
+Node.prototype.isSelfOrAncestor = function(node)
+{
+    return !!node && (node === this || this.isAncestor(node));
+}
+
+Node.prototype.isSelfOrDescendant = function(node)
+{
+    return !!node && (node === this || this.isDescendant(node));
+}
+
+Node.prototype.traverseNextNode = function(stayWithin)
+{
+    var node = this.firstChild;
+    if (node)
+        return node;
+
+    if (stayWithin && this === stayWithin)
+        return null;
+
+    node = this.nextSibling;
+    if (node)
+        return node;
+
+    node = this;
+    while (node && !node.nextSibling && (!stayWithin || !node.parentNode || node.parentNode !== stayWithin))
+        node = node.parentNode;
+    if (!node)
+        return null;
+
+    return node.nextSibling;
+}
+
+Node.prototype.traversePreviousNode = function(stayWithin)
+{
+    if (stayWithin && this === stayWithin)
+        return null;
+    var node = this.previousSibling;
+    while (node && node.lastChild)
+        node = node.lastChild;
+    if (node)
+        return node;
+    return this.parentNode;
+}
+
+function isEnterKey(event) {
+    // Check if in IME.
+    return event.keyCode !== 229 && event.keyIdentifier === "Enter";
+}
+
+function consumeEvent(e)
+{
+    e.consume();
+}
+
+/**
+ * Mutation observers leak memory. Keep track of them and disconnect
+ * on unload.
+ * @constructor
+ * @param {function(Array.)} handler
+ */
+function NonLeakingMutationObserver(handler)
+{
+    this._observer = new WebKitMutationObserver(handler);
+    NonLeakingMutationObserver._instances.push(this);
+    if (!NonLeakingMutationObserver._unloadListener) {
+        NonLeakingMutationObserver._unloadListener = function() {
+            while (NonLeakingMutationObserver._instances.length)
+                NonLeakingMutationObserver._instances[NonLeakingMutationObserver._instances.length - 1].disconnect();
+        };
+        window.addEventListener("unload", NonLeakingMutationObserver._unloadListener, false);
+    }
+}
+
+NonLeakingMutationObserver._instances = [];
+
+NonLeakingMutationObserver.prototype = {
+    /**
+     * @param {Element} element
+     * @param {Object} config
+     */
+    observe: function(element, config)
+    {
+        if (this._observer)
+            this._observer.observe(element, config);
+    },
+
+    disconnect: function()
+    {
+        if (this._observer)
+            this._observer.disconnect();
+        NonLeakingMutationObserver._instances.remove(this);
+        delete this._observer;
+    }
+}
+
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMPresentationUtils.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMPresentationUtils.js
new file mode 100644
index 00000000..0f9f4838
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMPresentationUtils.js
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2011 Google Inc.  All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Matt Lilek 
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.DOMPresentationUtils = {}
+
+WebInspector.DOMPresentationUtils.decorateNodeLabel = function(node, parentElement)
+{
+    var title = node.nodeNameInCorrectCase();
+
+    var nameElement = document.createElement("span");
+    nameElement.textContent = title;
+    parentElement.appendChild(nameElement);
+
+    var idAttribute = node.getAttribute("id");
+    if (idAttribute) {
+        var idElement = document.createElement("span");
+        parentElement.appendChild(idElement);
+
+        var part = "#" + idAttribute;
+        title += part;
+        idElement.appendChild(document.createTextNode(part));
+
+        // Mark the name as extra, since the ID is more important.
+        nameElement.className = "extra";
+    }
+
+    var classAttribute = node.getAttribute("class");
+    if (classAttribute) {
+        var classes = classAttribute.split(/\s+/);
+        var foundClasses = {};
+
+        if (classes.length) {
+            var classesElement = document.createElement("span");
+            classesElement.className = "extra";
+            parentElement.appendChild(classesElement);
+
+            for (var i = 0; i < classes.length; ++i) {
+                var className = classes[i];
+                if (className && !(className in foundClasses)) {
+                    var part = "." + className;
+                    title += part;
+                    classesElement.appendChild(document.createTextNode(part));
+                    foundClasses[className] = true;
+                }
+            }
+        }
+    }
+    parentElement.title = title;
+}
+
+/**
+ * @param {Element} container
+ * @param {string} nodeTitle
+ */
+WebInspector.DOMPresentationUtils.createSpansForNodeTitle = function(container, nodeTitle)
+{
+    var match = nodeTitle.match(/([^#.]+)(#[^.]+)?(\..*)?/);
+    container.createChild("span", "webkit-html-tag-name").textContent = match[1];
+    if (match[2])
+        container.createChild("span", "webkit-html-attribute-value").textContent = match[2];
+    if (match[3])
+        container.createChild("span", "webkit-html-attribute-name").textContent = match[3];
+}
+
+WebInspector.DOMPresentationUtils.linkifyNodeReference = function(node)
+{
+    var link = document.createElement("span");
+    link.className = "node-link";
+    WebInspector.DOMPresentationUtils.decorateNodeLabel(node, link);
+
+    link.addEventListener("click", WebInspector.domAgent.inspectElement.bind(WebInspector.domAgent, node.id), false);
+    link.addEventListener("mouseover", WebInspector.domAgent.highlightDOMNode.bind(WebInspector.domAgent, node.id, "", undefined), false);
+    link.addEventListener("mouseout", WebInspector.domAgent.hideDOMNodeHighlight.bind(WebInspector.domAgent), false);
+
+    return link;
+}
+
+WebInspector.DOMPresentationUtils.linkifyNodeById = function(nodeId)
+{
+    var node = WebInspector.domAgent.nodeForId(nodeId);
+    if (!node)
+        return document.createTextNode(WebInspector.UIString(""));
+    return WebInspector.DOMPresentationUtils.linkifyNodeReference(node);
+}
+
+/**
+ * @param {string} imageURL
+ * @param {boolean} showDimensions
+ * @param {function(Element=)} userCallback
+ * @param {Object=} precomputedDimensions
+ */
+WebInspector.DOMPresentationUtils.buildImagePreviewContents = function(imageURL, showDimensions, userCallback, precomputedDimensions)
+{
+    var resource = WebInspector.resourceTreeModel.resourceForURL(imageURL);
+    if (!resource) {
+        userCallback();
+        return;
+    }
+
+    var imageElement = document.createElement("img");
+    imageElement.addEventListener("load", buildContent, false);
+    imageElement.addEventListener("error", errorCallback, false);
+    resource.populateImageSource(imageElement);
+
+    function errorCallback()
+    {
+        // Drop the event parameter when invoking userCallback.
+        userCallback();
+    }
+
+    function buildContent()
+    {
+        var container = document.createElement("table");
+        container.className = "image-preview-container";
+        var naturalWidth = precomputedDimensions ? precomputedDimensions.naturalWidth : imageElement.naturalWidth;
+        var naturalHeight = precomputedDimensions ? precomputedDimensions.naturalHeight : imageElement.naturalHeight;
+        var offsetWidth = precomputedDimensions ? precomputedDimensions.offsetWidth : naturalWidth;
+        var offsetHeight = precomputedDimensions ? precomputedDimensions.offsetHeight : naturalHeight;
+        var description;
+        if (showDimensions) {
+            if (offsetHeight === naturalHeight && offsetWidth === naturalWidth)
+                description = WebInspector.UIString("%d \xd7 %d pixels", offsetWidth, offsetHeight);
+            else
+                description = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)", offsetWidth, offsetHeight, naturalWidth, naturalHeight);
+        }
+
+        container.createChild("tr").createChild("td", "image-container").appendChild(imageElement);
+        if (description)
+            container.createChild("tr").createChild("td").createChild("span", "description").textContent = description;
+        userCallback(container);
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorage.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorage.js
new file mode 100644
index 00000000..3ad5ce8b
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorage.js
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2008 Nokia Inc.  All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {string} securityOrigin
+ * @param {boolean} isLocalStorage
+ */
+WebInspector.DOMStorage = function(securityOrigin, isLocalStorage)
+{
+    this._securityOrigin = securityOrigin;
+    this._isLocalStorage = isLocalStorage;
+}
+
+/**
+ * @param {string} securityOrigin
+ * @param {boolean} isLocalStorage
+ * @return {DOMStorageAgent.StorageId}
+ */
+WebInspector.DOMStorage.storageId = function(securityOrigin, isLocalStorage)
+{
+    return { securityOrigin: securityOrigin, isLocalStorage: isLocalStorage };
+}
+
+WebInspector.DOMStorage.Events = {
+    DOMStorageItemsCleared: "DOMStorageItemsCleared",
+    DOMStorageItemRemoved: "DOMStorageItemRemoved",
+    DOMStorageItemAdded: "DOMStorageItemAdded",
+    DOMStorageItemUpdated: "DOMStorageItemUpdated"
+}
+
+WebInspector.DOMStorage.prototype = {
+
+    /** @return {DOMStorageAgent.StorageId} */
+    get id()
+    {
+        return WebInspector.DOMStorage.storageId(this._securityOrigin, this._isLocalStorage);
+    },
+
+    /** @return {string} */
+    get securityOrigin()
+    {
+        return this._securityOrigin;
+    },
+
+    /** @return {boolean} */
+    get isLocalStorage()
+    {
+        return this._isLocalStorage;
+    },
+
+    /**
+     * @param {function(?Protocol.Error, Array.):void=} callback
+     */
+    getItems: function(callback)
+    {
+        DOMStorageAgent.getDOMStorageItems(this.id, callback);
+    },
+
+    /**
+     * @param {string} key
+     * @param {string} value
+     */
+    setItem: function(key, value)
+    {
+        DOMStorageAgent.setDOMStorageItem(this.id, key, value);
+    },
+
+    /**
+     * @param {string} key
+     */
+    removeItem: function(key)
+    {
+        DOMStorageAgent.removeDOMStorageItem(this.id, key);
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.DOMStorageModel = function()
+{
+    /** @type {!Object.} */
+    this._storages = {};
+    InspectorBackend.registerDOMStorageDispatcher(new WebInspector.DOMStorageDispatcher(this));
+    DOMStorageAgent.enable();
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this);
+    WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this);
+}
+
+WebInspector.DOMStorageModel.Events = {
+    DOMStorageAdded: "DOMStorageAdded",
+    DOMStorageRemoved: "DOMStorageRemoved"
+}
+
+WebInspector.DOMStorageModel.prototype = {
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _securityOriginAdded: function(event)
+    {
+        var securityOrigin = /** @type {string} */ (event.data);
+        var localStorageKey = this._storageKey(securityOrigin, true);
+        console.assert(!this._storages[localStorageKey]);
+        var localStorage = new WebInspector.DOMStorage(securityOrigin, true);
+        this._storages[localStorageKey] = localStorage;
+        this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageAdded, localStorage);
+
+        var sessionStorageKey = this._storageKey(securityOrigin, false);
+        console.assert(!this._storages[sessionStorageKey]);
+        var sessionStorage = new WebInspector.DOMStorage(securityOrigin, false);
+        this._storages[sessionStorageKey] = sessionStorage;
+        this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageAdded, sessionStorage);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _securityOriginRemoved: function(event)
+    {
+        var securityOrigin = /** @type {string} */ (event.data);
+        var localStorageKey = this._storageKey(securityOrigin, true);
+        var localStorage = this._storages[localStorageKey];
+        console.assert(localStorage);
+        delete this._storages[localStorageKey];
+        this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, localStorage);
+
+        var sessionStorageKey = this._storageKey(securityOrigin, false);
+        var sessionStorage = this._storages[sessionStorageKey];
+        console.assert(sessionStorage);
+        delete this._storages[sessionStorageKey];
+        this.dispatchEventToListeners(WebInspector.DOMStorageModel.Events.DOMStorageRemoved, sessionStorage);
+    },
+
+    /**
+     * @param {string} securityOrigin
+     * @param {boolean} isLocalStorage
+     * @return {string}
+     */
+    _storageKey: function(securityOrigin, isLocalStorage)
+    {
+        return JSON.stringify(WebInspector.DOMStorage.storageId(securityOrigin, isLocalStorage));
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     */
+    _domStorageItemsCleared: function(storageId)
+    {
+        var domStorage = this.storageForId(storageId);
+        if (!domStorage)
+            return;
+
+        var eventData = {};
+        domStorage.dispatchEventToListeners(WebInspector.DOMStorage.Events.DOMStorageItemsCleared, eventData);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     */
+    _domStorageItemRemoved: function(storageId, key)
+    {
+        var domStorage = this.storageForId(storageId);
+        if (!domStorage)
+            return;
+
+        var eventData = { key: key };
+        domStorage.dispatchEventToListeners(WebInspector.DOMStorage.Events.DOMStorageItemRemoved, eventData);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     * @param {string} value
+     */
+    _domStorageItemAdded: function(storageId, key, value)
+    {
+        var domStorage = this.storageForId(storageId);
+        if (!domStorage)
+            return;
+
+        var eventData = { key: key, value: value };
+        domStorage.dispatchEventToListeners(WebInspector.DOMStorage.Events.DOMStorageItemAdded, eventData);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     * @param {string} oldValue
+     * @param {string} value
+     */
+    _domStorageItemUpdated: function(storageId, key, oldValue, value)
+    {
+        var domStorage = this.storageForId(storageId);
+        if (!domStorage)
+            return;
+
+        var eventData = { key: key, oldValue: oldValue, value: value };
+        domStorage.dispatchEventToListeners(WebInspector.DOMStorage.Events.DOMStorageItemUpdated, eventData);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @return {WebInspector.DOMStorage}
+     */
+    storageForId: function(storageId)
+    {
+        return this._storages[JSON.stringify(storageId)];
+    },
+
+    /**
+     * @return {Array.}
+     */
+    storages: function()
+    {
+        var result = [];
+        for (var id in this._storages)
+            result.push(this._storages[id]);
+        return result;
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {DOMStorageAgent.Dispatcher}
+ * @param {WebInspector.DOMStorageModel} model
+ */
+WebInspector.DOMStorageDispatcher = function(model)
+{
+    this._model = model;
+}
+
+WebInspector.DOMStorageDispatcher.prototype = {
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     */
+    domStorageItemsCleared: function(storageId)
+    {
+        this._model._domStorageItemsCleared(storageId);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     */
+    domStorageItemRemoved: function(storageId, key)
+    {
+        this._model._domStorageItemRemoved(storageId, key);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     * @param {string} value
+     */
+    domStorageItemAdded: function(storageId, key, value)
+    {
+        this._model._domStorageItemAdded(storageId, key, value);
+    },
+
+    /**
+     * @param {DOMStorageAgent.StorageId} storageId
+     * @param {string} key
+     * @param {string} oldValue
+     * @param {string} value
+     */
+    domStorageItemUpdated: function(storageId, key, oldValue, value)
+    {
+        this._model._domStorageItemUpdated(storageId, key, oldValue, value);
+    },
+}
+
+/**
+ * @type {WebInspector.DOMStorageModel}
+ */
+WebInspector.domStorageModel = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorageItemsView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorageItemsView.js
new file mode 100644
index 00000000..c2497c58
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMStorageItemsView.js
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2008 Nokia Inc.  All rights reserved.
+ * Copyright (C) 2013 Samsung Electronics. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.DOMStorageItemsView = function(domStorage)
+{
+    WebInspector.View.call(this);
+
+    this.domStorage = domStorage;
+
+    this.element.addStyleClass("storage-view");
+    this.element.addStyleClass("table");
+
+    this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item");
+    this.deleteButton.visible = false;
+    this.deleteButton.addEventListener("click", this._deleteButtonClicked, this);
+
+    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
+    this.refreshButton.addEventListener("click", this._refreshButtonClicked, this);
+
+    this.domStorage.addEventListener(WebInspector.DOMStorage.Events.DOMStorageItemsCleared, this._domStorageItemsCleared, this);
+    this.domStorage.addEventListener(WebInspector.DOMStorage.Events.DOMStorageItemRemoved, this._domStorageItemRemoved, this);
+    this.domStorage.addEventListener(WebInspector.DOMStorage.Events.DOMStorageItemAdded, this._domStorageItemAdded, this);
+    this.domStorage.addEventListener(WebInspector.DOMStorage.Events.DOMStorageItemUpdated, this._domStorageItemUpdated, this);
+}
+
+WebInspector.DOMStorageItemsView.prototype = {
+    get statusBarItems()
+    {
+        return [this.refreshButton.element, this.deleteButton.element];
+    },
+
+    wasShown: function()
+    {
+        this._update();
+    },
+
+    willHide: function()
+    {
+        this.deleteButton.visible = false;
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _domStorageItemsCleared: function(event)
+    {
+        if (!this.isShowing() || !this._dataGrid)
+            return;
+
+        this._dataGrid.rootNode().removeChildren();
+        this._dataGrid.addCreationNode(false);
+        this.deleteButton.visible = false;
+        event.consume(true);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _domStorageItemRemoved: function(event)
+    {
+        if (!this.isShowing() || !this._dataGrid)
+            return;
+
+        var storageData = event.data;
+        var rootNode = this._dataGrid.rootNode();
+        var children = rootNode.children;
+
+        event.consume(true);
+
+        for (var i = 0; i < children.length; ++i) {
+            var childNode = children[i];
+            if (childNode.data.key === storageData.key) {
+                rootNode.removeChild(childNode);
+                this.deleteButton.visible = (children.length > 1);
+                return;
+            }
+        }
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _domStorageItemAdded: function(event)
+    {
+        if (!this.isShowing() || !this._dataGrid)
+            return;
+
+        var storageData = event.data;
+        var rootNode = this._dataGrid.rootNode();
+        var children = rootNode.children;
+
+        event.consume(true);
+        this.deleteButton.visible = true;
+
+        for (var i = 0; i < children.length; ++i)
+            if (children[i].data.key === storageData.key)
+                return;
+
+        var childNode = new WebInspector.DataGridNode({key: storageData.key, value: storageData.value}, false);
+        rootNode.insertChild(childNode, children.length - 1);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _domStorageItemUpdated: function(event)
+    {
+        if (!this.isShowing() || !this._dataGrid)
+            return;
+
+        var storageData = event.data;
+        var rootNode = this._dataGrid.rootNode();
+        var children = rootNode.children;
+
+        event.consume(true);
+
+        var keyFound = false;
+        for (var i = 0; i < children.length; ++i) {
+            var childNode = children[i];
+            if (childNode.data.key === storageData.key) {
+                if (keyFound) {
+                    rootNode.removeChild(childNode);
+                    return;
+                }
+                keyFound = true;
+                if (childNode.data.value !== storageData.value) {
+                    childNode.data.value = storageData.value;
+                    childNode.refresh();
+                    childNode.select();
+                    childNode.reveal();
+                }
+                this.deleteButton.visible = true;
+            }
+        }
+    },
+
+    _update: function()
+    {
+        this.detachChildViews();
+        this.domStorage.getItems(this._showDOMStorageItems.bind(this));
+    },
+
+    _showDOMStorageItems: function(error, items)
+    {
+        if (error)
+            return;
+
+        this._dataGrid = this._dataGridForDOMStorageItems(items);
+        this._dataGrid.show(this.element);
+        this.deleteButton.visible = (this._dataGrid.rootNode().children.length > 1);
+    },
+
+    _dataGridForDOMStorageItems: function(items)
+    {
+        var columns = [
+            {id: "key", title: WebInspector.UIString("Key"), editable: true, weight: 50},
+            {id: "value", title: WebInspector.UIString("Value"), editable: true, weight: 50}
+        ];
+
+        var nodes = [];
+
+        var keys = [];
+        var length = items.length;
+        for (var i = 0; i < items.length; i++) {
+            var key = items[i][0];
+            var value = items[i][1];
+            var node = new WebInspector.DataGridNode({key: key, value: value}, false);
+            node.selectable = true;
+            nodes.push(node);
+            keys.push(key);
+        }
+
+        var dataGrid = new WebInspector.DataGrid(columns, this._editingCallback.bind(this), this._deleteCallback.bind(this));
+        dataGrid.setName("DOMStorageItemsView");
+        length = nodes.length;
+        for (var i = 0; i < length; ++i)
+            dataGrid.rootNode().appendChild(nodes[i]);
+        dataGrid.addCreationNode(false);
+        if (length > 0)
+            nodes[0].selected = true;
+        return dataGrid;
+    },
+
+    _deleteButtonClicked: function(event)
+    {
+        if (!this._dataGrid || !this._dataGrid.selectedNode)
+            return;
+
+        this._deleteCallback(this._dataGrid.selectedNode);
+        this._dataGrid.changeNodeAfterDeletion();
+    },
+
+    _refreshButtonClicked: function(event)
+    {
+        this._update();
+    },
+
+    _editingCallback: function(editingNode, columnIdentifier, oldText, newText)
+    {
+        var domStorage = this.domStorage;
+        if ("key" === columnIdentifier) {
+            if (typeof oldText === "string")
+                domStorage.removeItem(oldText);
+            domStorage.setItem(newText, editingNode.data.value || '');
+            this._removeDupes(editingNode);
+        } else
+            domStorage.setItem(editingNode.data.key || '', newText);
+    },
+
+    /**
+     * @param {!WebInspector.DataGridNode} masterNode
+     */
+    _removeDupes: function(masterNode)
+    {
+        var rootNode = this._dataGrid.rootNode();
+        var children = rootNode.children;
+        for (var i = children.length - 1; i >= 0; --i) {
+            var childNode = children[i];
+            if ((childNode.data.key === masterNode.data.key) && (masterNode !== childNode))
+                rootNode.removeChild(childNode);
+        }
+    },
+
+    _deleteCallback: function(node)
+    {
+        if (!node || node.isCreationNode)
+            return;
+
+        if (this.domStorage)
+            this.domStorage.removeItem(node.data.key);
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMSyntaxHighlighter.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMSyntaxHighlighter.js
new file mode 100644
index 00000000..ed5af04e
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DOMSyntaxHighlighter.js
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.DOMSyntaxHighlighter = function(mimeType, stripExtraWhitespace)
+{
+    loadScript("CodeMirrorTextEditor.js");
+    this._mimeType = mimeType;
+    this._stripExtraWhitespace = stripExtraWhitespace;
+}
+
+WebInspector.DOMSyntaxHighlighter.prototype = {
+    createSpan: function(content, className)
+    {
+        var span = document.createElement("span");
+        span.className = "cm-" + className;
+        if (this._stripExtraWhitespace && className !== "whitespace")
+            content = content.replace(/^[\n\r]*/, "").replace(/\s*$/, "");
+        span.appendChild(document.createTextNode(content));
+        return span;
+    },
+
+    syntaxHighlightNode: function(node)
+    {
+        var lines = node.textContent.split("\n");
+        node.removeChildren();
+
+        var tokenize = WebInspector.CodeMirrorUtils.createTokenizer(this._mimeType);
+        for (var i = lines[0].length ? 0 : 1; i < lines.length; ++i) {
+            var line = lines[i];
+            var plainTextStart = 0;
+            function processToken(token, tokenType, column, newColumn)
+            {
+                if (tokenType) {
+                    if (column > plainTextStart) {
+                        var plainText = line.substring(plainTextStart, column);
+                        node.appendChild(document.createTextNode(plainText));
+                    }
+                    node.appendChild(this.createSpan(token, tokenType));
+                    plainTextStart = newColumn;
+                }
+            }
+            tokenize(line, processToken.bind(this));
+            if (plainTextStart < line.length) {
+                var plainText = line.substring(plainTextStart, line.length);
+                node.appendChild(document.createTextNode(plainText));
+            }
+            if (i < lines.length - 1)
+                node.appendChild(document.createElement("br"));
+        }
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DataGrid.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DataGrid.js
new file mode 100644
index 00000000..bd403671
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DataGrid.js
@@ -0,0 +1,1806 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.         IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ * @param {!Array.} columnsArray
+ * @param {function(WebInspector.DataGridNode, string, string, string)=} editCallback
+ * @param {function(WebInspector.DataGridNode)=} deleteCallback
+ * @param {function()=} refreshCallback
+ * @param {function(!WebInspector.ContextMenu, WebInspector.DataGridNode)=} contextMenuCallback
+ */
+WebInspector.DataGrid = function(columnsArray, editCallback, deleteCallback, refreshCallback, contextMenuCallback)
+{
+    WebInspector.View.call(this);
+    this.registerRequiredCSS("dataGrid.css");
+
+    this.element.className = "data-grid";
+    this.element.tabIndex = 0;
+    this.element.addEventListener("keydown", this._keyDown.bind(this), false);
+
+    this._headerTable = document.createElement("table");
+    this._headerTable.className = "header";
+    this._headerTableHeaders = {};
+
+    this._dataTable = document.createElement("table");
+    this._dataTable.className = "data";
+
+    this._dataTable.addEventListener("mousedown", this._mouseDownInDataTable.bind(this), true);
+    this._dataTable.addEventListener("click", this._clickInDataTable.bind(this), true);
+
+    this._dataTable.addEventListener("contextmenu", this._contextMenuInDataTable.bind(this), true);
+
+    // FIXME: Add a createCallback which is different from editCallback and has different
+    // behavior when creating a new node.
+    if (editCallback)
+        this._dataTable.addEventListener("dblclick", this._ondblclick.bind(this), false);
+    this._editCallback = editCallback;
+    this._deleteCallback = deleteCallback;
+    this._refreshCallback = refreshCallback;
+    this._contextMenuCallback = contextMenuCallback;
+
+    this._scrollContainer = document.createElement("div");
+    this._scrollContainer.className = "data-container";
+    this._scrollContainer.appendChild(this._dataTable);
+
+    this.element.appendChild(this._headerTable);
+    this.element.appendChild(this._scrollContainer);
+
+    var headerRow = document.createElement("tr");
+    var columnGroup = document.createElement("colgroup");
+    columnGroup.span = columnsArray.length;
+
+    var fillerRow = document.createElement("tr");
+    fillerRow.className = "filler";
+
+    this._columnsArray = columnsArray;
+    this.columns = {};
+
+    for (var i = 0; i < columnsArray.length; ++i) {
+        var column = columnsArray[i];
+        column.ordinal = i;
+        var columnIdentifier = column.identifier = column.id || i;
+        this.columns[columnIdentifier] = column;
+        if (column.disclosure)
+            this.disclosureColumnIdentifier = columnIdentifier;
+
+        var col = document.createElement("col");
+        if (column.width)
+            col.style.width = column.width;
+        column.element = col;
+        columnGroup.appendChild(col);
+
+        var cell = document.createElement("th");
+        cell.className = columnIdentifier + "-column";
+        cell.columnIdentifier = columnIdentifier;
+        this._headerTableHeaders[columnIdentifier] = cell;
+
+        var div = document.createElement("div");
+        if (column.titleDOMFragment)
+            div.appendChild(column.titleDOMFragment);
+        else
+            div.textContent = column.title;
+        cell.appendChild(div);
+
+        if (column.sort) {
+            cell.addStyleClass("sort-" + column.sort);
+            this._sortColumnCell = cell;
+        }
+
+        if (column.sortable) {
+            cell.addEventListener("click", this._clickInHeaderCell.bind(this), false);
+            cell.addStyleClass("sortable");
+        }
+
+        headerRow.appendChild(cell);
+        fillerRow.createChild("td", columnIdentifier + "-column");
+    }
+
+    headerRow.createChild("th", "corner");
+    fillerRow.createChild("td", "corner");
+    columnGroup.createChild("col", "corner");
+
+    this._headerTableColumnGroup = columnGroup;
+    this._headerTable.appendChild(this._headerTableColumnGroup);
+    this.headerTableBody.appendChild(headerRow);
+
+    this._dataTableColumnGroup = columnGroup.cloneNode(true);
+    this._dataTable.appendChild(this._dataTableColumnGroup);
+    this.dataTableBody.appendChild(fillerRow);
+
+    this.selectedNode = null;
+    this.expandNodesWhenArrowing = false;
+    this.setRootNode(new WebInspector.DataGridNode());
+    this.indentWidth = 15;
+    this.resizers = [];
+    this._columnWidthsInitialized = false;
+}
+
+/** @typedef {{id: ?string, editable: boolean, longText: ?boolean, sort: WebInspector.DataGrid.Order, sortable: boolean, align: WebInspector.DataGrid.Align}} */
+WebInspector.DataGrid.ColumnDescriptor;
+
+WebInspector.DataGrid.Events = {
+    SelectedNode: "SelectedNode",
+    DeselectedNode: "DeselectedNode",
+    SortingChanged: "SortingChanged",
+    ColumnsResized: "ColumnsResized"
+}
+
+/** @enum {string} */
+WebInspector.DataGrid.Order = {
+    Ascending: "ascending",
+    Descending: "descending"
+}
+
+/** @enum {string} */
+WebInspector.DataGrid.Align = {
+    Center: "center",
+    Right: "right"
+}
+
+/**
+ * @param {!Array.} columnNames
+ * @param {!Array.} values
+ * @return {WebInspector.DataGrid}
+ */
+WebInspector.DataGrid.createSortableDataGrid = function(columnNames, values)
+{
+    var numColumns = columnNames.length;
+    if (!numColumns)
+        return null;
+
+    var columns = [];
+    for (var i = 0; i < columnNames.length; ++i)
+        columns.push({title: columnNames[i], width: columnNames[i].length, sortable: true});
+
+    var nodes = [];
+    for (var i = 0; i < values.length / numColumns; ++i) {
+        var data = {};
+        for (var j = 0; j < columnNames.length; ++j)
+            data[j] = values[numColumns * i + j];
+
+        var node = new WebInspector.DataGridNode(data, false);
+        node.selectable = false;
+        nodes.push(node);
+    }
+
+    var dataGrid = new WebInspector.DataGrid(columns);
+    var length = nodes.length;
+    for (var i = 0; i < length; ++i)
+        dataGrid.rootNode().appendChild(nodes[i]);
+
+    dataGrid.addEventListener(WebInspector.DataGrid.Events.SortingChanged, sortDataGrid, this);
+
+    function sortDataGrid()
+    {
+        var nodes = dataGrid._rootNode.children.slice();
+        var sortColumnIdentifier = dataGrid.sortColumnIdentifier();
+        var sortDirection = dataGrid.isSortOrderAscending() ? 1 : -1;
+        var columnIsNumeric = true;
+
+        for (var i = 0; i < nodes.length; i++) {
+            var value = nodes[i].data[sortColumnIdentifier];
+            value = value instanceof Node ? Number(value.textContent) : Number(value);
+            if (isNaN(value)) {
+                columnIsNumeric = false;
+                break;
+            }
+        }
+
+        function comparator(dataGridNode1, dataGridNode2)
+        {
+            var item1 = dataGridNode1.data[sortColumnIdentifier];
+            var item2 = dataGridNode2.data[sortColumnIdentifier];
+            item1 = item1 instanceof Node ? item1.textContent : String(item1);
+            item2 = item2 instanceof Node ? item2.textContent : String(item2);
+
+            var comparison;
+            if (columnIsNumeric) {
+                // Sort numbers based on comparing their values rather than a lexicographical comparison.
+                var number1 = parseFloat(item1);
+                var number2 = parseFloat(item2);
+                comparison = number1 < number2 ? -1 : (number1 > number2 ? 1 : 0);
+            } else
+                comparison = item1 < item2 ? -1 : (item1 > item2 ? 1 : 0);
+
+            return sortDirection * comparison;
+        }
+
+        nodes.sort(comparator);
+        dataGrid.rootNode().removeChildren();
+        for (var i = 0; i < nodes.length; i++)
+            dataGrid._rootNode.appendChild(nodes[i]);
+    }
+    return dataGrid;
+}
+
+WebInspector.DataGrid.prototype = {
+    /**
+     * @param {!WebInspector.DataGridNode} rootNode
+     */
+    setRootNode: function(rootNode)
+    {
+        if (this._rootNode) {
+            this._rootNode.removeChildren();
+            this._rootNode.dataGrid = null;
+            this._rootNode._isRoot = false;
+        }
+        /** @type {!WebInspector.DataGridNode} */
+        this._rootNode = rootNode;
+        rootNode._isRoot = true;
+        rootNode.hasChildren = false;
+        rootNode._expanded = true;
+        rootNode._revealed = true;
+        rootNode.dataGrid = this;
+    },
+
+    /**
+     * @return {!WebInspector.DataGridNode}
+     */
+    rootNode: function()
+    {
+        return this._rootNode;
+    },
+
+    _ondblclick: function(event)
+    {
+        if (this._editing || this._editingNode)
+            return;
+
+        var columnIdentifier = this.columnIdentifierFromNode(event.target);
+        if (!columnIdentifier || !this.columns[columnIdentifier].editable)
+            return;
+        this._startEditing(event.target);
+    },
+
+    /**
+     * @param {!WebInspector.DataGridNode} node
+     * @param {number} columnOrdinal
+     */
+    _startEditingColumnOfDataGridNode: function(node, columnOrdinal)
+    {
+        this._editing = true;
+        /** @type {WebInspector.DataGridNode} */
+        this._editingNode = node;
+        this._editingNode.select();
+
+        var element = this._editingNode._element.children[columnOrdinal];
+        WebInspector.startEditing(element, this._startEditingConfig(element));
+        window.getSelection().setBaseAndExtent(element, 0, element, 1);
+    },
+
+    _startEditing: function(target)
+    {
+        var element = target.enclosingNodeOrSelfWithNodeName("td");
+        if (!element)
+            return;
+
+        this._editingNode = this.dataGridNodeFromNode(target);
+        if (!this._editingNode) {
+            if (!this.creationNode)
+                return;
+            this._editingNode = this.creationNode;
+        }
+
+        // Force editing the 1st column when editing the creation node
+        if (this._editingNode.isCreationNode)
+            return this._startEditingColumnOfDataGridNode(this._editingNode, this._nextEditableColumn(-1));
+
+        this._editing = true;
+        WebInspector.startEditing(element, this._startEditingConfig(element));
+
+        window.getSelection().setBaseAndExtent(element, 0, element, 1);
+    },
+
+    renderInline: function()
+    {
+        this.element.addStyleClass("inline");
+    },
+
+    _startEditingConfig: function(element)
+    {
+        return new WebInspector.EditingConfig(this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent);
+    },
+
+    _editingCommitted: function(element, newText, oldText, context, moveDirection)
+    {
+        var columnIdentifier = this.columnIdentifierFromNode(element);
+        if (!columnIdentifier) {
+            this._editingCancelled(element);
+            return;
+        }
+        var columnOrdinal = this.columns[columnIdentifier].ordinal;
+        var textBeforeEditing = this._editingNode.data[columnIdentifier];
+        var currentEditingNode = this._editingNode;
+
+        function moveToNextIfNeeded(wasChange) {
+            if (!moveDirection)
+                return;
+
+            if (moveDirection === "forward") {
+            var firstEditableColumn = this._nextEditableColumn(-1);
+                if (currentEditingNode.isCreationNode && columnOrdinal === firstEditableColumn && !wasChange)
+                    return;
+
+                var nextEditableColumn = this._nextEditableColumn(columnOrdinal);
+                if (nextEditableColumn !== -1)
+                    return this._startEditingColumnOfDataGridNode(currentEditingNode, nextEditableColumn);
+
+                var nextDataGridNode = currentEditingNode.traverseNextNode(true, null, true);
+                if (nextDataGridNode)
+                    return this._startEditingColumnOfDataGridNode(nextDataGridNode, firstEditableColumn);
+                if (currentEditingNode.isCreationNode && wasChange) {
+                    this.addCreationNode(false);
+                    return this._startEditingColumnOfDataGridNode(this.creationNode, firstEditableColumn);
+                }
+                return;
+            }
+
+            if (moveDirection === "backward") {
+                var prevEditableColumn = this._nextEditableColumn(columnOrdinal, true);
+                if (prevEditableColumn !== -1)
+                    return this._startEditingColumnOfDataGridNode(currentEditingNode, prevEditableColumn);
+
+                var lastEditableColumn = this._nextEditableColumn(this._columnsArray.length, true);
+                var nextDataGridNode = currentEditingNode.traversePreviousNode(true, true);
+                if (nextDataGridNode)
+                    return this._startEditingColumnOfDataGridNode(nextDataGridNode, lastEditableColumn);
+                return;
+            }
+        }
+
+        if (textBeforeEditing == newText) {
+            this._editingCancelled(element);
+            moveToNextIfNeeded.call(this, false);
+            return;
+        }
+
+        // Update the text in the datagrid that we typed
+        this._editingNode.data[columnIdentifier] = newText;
+
+        // Make the callback - expects an editing node (table row), the column number that is being edited,
+        // the text that used to be there, and the new text.
+        this._editCallback(this._editingNode, columnIdentifier, textBeforeEditing, newText);
+
+        if (this._editingNode.isCreationNode)
+            this.addCreationNode(false);
+
+        this._editingCancelled(element);
+        moveToNextIfNeeded.call(this, true);
+    },
+
+    _editingCancelled: function(element)
+    {
+        delete this._editing;
+        this._editingNode = null;
+    },
+
+    /**
+     * @param {number} columnOrdinal
+     * @param {boolean=} moveBackward
+     * @return {number}
+     */
+    _nextEditableColumn: function(columnOrdinal, moveBackward)
+    {
+        var increment = moveBackward ? -1 : 1;
+        var columns = this._columnsArray;
+        for (var i = columnOrdinal + increment; (i >= 0) && (i < columns.length); i += increment) {
+            if (columns[i].editable)
+                return i;
+        }
+        return -1;
+    },
+
+    /**
+     * @return {?string}
+     */
+    sortColumnIdentifier: function()
+    {
+        if (!this._sortColumnCell)
+            return null;
+        return this._sortColumnCell.columnIdentifier;
+    },
+
+    /**
+     * @return {?string}
+     */
+    sortOrder: function()
+    {
+        if (!this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending"))
+            return WebInspector.DataGrid.Order.Ascending;
+        if (this._sortColumnCell.hasStyleClass("sort-descending"))
+            return WebInspector.DataGrid.Order.Descending;
+        return null;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isSortOrderAscending: function()
+    {
+        return !this._sortColumnCell || this._sortColumnCell.hasStyleClass("sort-ascending");
+    },
+
+    get headerTableBody()
+    {
+        if ("_headerTableBody" in this)
+            return this._headerTableBody;
+
+        this._headerTableBody = this._headerTable.getElementsByTagName("tbody")[0];
+        if (!this._headerTableBody) {
+            this._headerTableBody = this.element.ownerDocument.createElement("tbody");
+            this._headerTable.insertBefore(this._headerTableBody, this._headerTable.tFoot);
+        }
+
+        return this._headerTableBody;
+    },
+
+    get dataTableBody()
+    {
+        if ("_dataTableBody" in this)
+            return this._dataTableBody;
+
+        this._dataTableBody = this._dataTable.getElementsByTagName("tbody")[0];
+        if (!this._dataTableBody) {
+            this._dataTableBody = this.element.ownerDocument.createElement("tbody");
+            this._dataTable.insertBefore(this._dataTableBody, this._dataTable.tFoot);
+        }
+
+        return this._dataTableBody;
+    },
+
+    /**
+     * @param {Array.} widths
+     * @param {number} minPercent
+     * @param {number=} maxPercent
+     */
+    _autoSizeWidths: function(widths, minPercent, maxPercent)
+    {
+        if (minPercent)
+            minPercent = Math.min(minPercent, Math.floor(100 / widths.length));
+        var totalWidth = 0;
+        for (var i = 0; i < widths.length; ++i)
+            totalWidth += widths[i];
+        var totalPercentWidth = 0;
+        for (var i = 0; i < widths.length; ++i) {
+            var width = Math.round(100 * widths[i] / totalWidth);
+            if (minPercent && width < minPercent)
+                width = minPercent;
+            else if (maxPercent && width > maxPercent)
+                width = maxPercent;
+            totalPercentWidth += width;
+            widths[i] = width;
+        }
+        var recoupPercent = totalPercentWidth - 100;
+
+        while (minPercent && recoupPercent > 0) {
+            for (var i = 0; i < widths.length; ++i) {
+                if (widths[i] > minPercent) {
+                    --widths[i];
+                    --recoupPercent;
+                    if (!recoupPercent)
+                        break;
+                }
+            }
+        }
+
+        while (maxPercent && recoupPercent < 0) {
+            for (var i = 0; i < widths.length; ++i) {
+                if (widths[i] < maxPercent) {
+                    ++widths[i];
+                    ++recoupPercent;
+                    if (!recoupPercent)
+                        break;
+                }
+            }
+        }
+
+        return widths;
+    },
+
+    /**
+     * @param {number} minPercent
+     * @param {number=} maxPercent
+     * @param {number=} maxDescentLevel
+     */
+    autoSizeColumns: function(minPercent, maxPercent, maxDescentLevel)
+    {
+        var widths = [];
+        for (var i = 0; i < this._columnsArray.length; ++i)
+            widths.push((this._columnsArray[i].title || "").length);
+
+        maxDescentLevel = maxDescentLevel || 0;
+        var children = this._enumerateChildren(this._rootNode, [], maxDescentLevel + 1);
+        for (var i = 0; i < children.length; ++i) {
+            var node = children[i];
+            for (var j = 0; j < this._columnsArray.length; ++j) {
+                var text = node.data[this._columnsArray[j].identifier] || "";
+                if (text.length > widths[j])
+                    widths[j] = text.length;
+            }
+        }
+
+        widths = this._autoSizeWidths(widths, minPercent, maxPercent);
+
+        for (var i = 0; i < this._columnsArray.length; ++i)
+            this._columnsArray[i].element.style.width = widths[i] + "%";
+        this._columnWidthsInitialized = false;
+        this.updateWidths();
+    },
+
+    _enumerateChildren: function(rootNode, result, maxLevel)
+    {
+        if (!rootNode._isRoot)
+            result.push(rootNode);
+        if (!maxLevel)
+            return;
+        for (var i = 0; i < rootNode.children.length; ++i)
+            this._enumerateChildren(rootNode.children[i], result, maxLevel - 1);
+        return result;
+    },
+
+    onResize: function()
+    {
+        this.updateWidths();
+    },
+
+    // Updates the widths of the table, including the positions of the column
+    // resizers.
+    //
+    // IMPORTANT: This function MUST be called once after the element of the
+    // DataGrid is attached to its parent element and every subsequent time the
+    // width of the parent element is changed in order to make it possible to
+    // resize the columns.
+    //
+    // If this function is not called after the DataGrid is attached to its
+    // parent element, then the DataGrid's columns will not be resizable.
+    updateWidths: function()
+    {
+        var headerTableColumns = this._headerTableColumnGroup.children;
+
+        var tableWidth = this._dataTable.offsetWidth;
+        var numColumns = headerTableColumns.length - 1; // Do not process corner column.
+
+        // Do not attempt to use offsetes if we're not attached to the document tree yet.
+        if (!this._columnWidthsInitialized && this.element.offsetWidth) {
+            // Give all the columns initial widths now so that during a resize,
+            // when the two columns that get resized get a percent value for
+            // their widths, all the other columns already have percent values
+            // for their widths.
+            for (var i = 0; i < numColumns; i++) {
+                var columnWidth = this.headerTableBody.rows[0].cells[i].offsetWidth;
+                var percentWidth = ((columnWidth / tableWidth) * 100) + "%";
+                this._headerTableColumnGroup.children[i].style.width = percentWidth;
+                this._dataTableColumnGroup.children[i].style.width = percentWidth;
+            }
+            this._columnWidthsInitialized = true;
+        }
+        this._positionResizers();
+        this.dispatchEventToListeners(WebInspector.DataGrid.Events.ColumnsResized);
+    },
+
+    /**
+     * @param {string} name
+     */
+    setName: function(name)
+    {
+        this._columnWeightsSetting = WebInspector.settings.createSetting("dataGrid-" + name + "-columnWeights", {});
+        this._loadColumnWeights();
+    },
+
+    _loadColumnWeights: function()
+    {
+        if (!this._columnWeightsSetting)
+            return;
+        var weights = this._columnWeightsSetting.get();
+        for (var i = 0; i < this._columnsArray.length; ++i) {
+            var column = this._columnsArray[i];
+            var weight = weights[column.identifier];
+            if (weight)
+                column.weight = weight;
+        }
+        this.applyColumnWeights();
+    },
+
+    _saveColumnWeights: function()
+    {
+        if (!this._columnWeightsSetting)
+            return;
+        var weights = {};
+        for (var i = 0; i < this._columnsArray.length; ++i) {
+            var column = this._columnsArray[i];
+            weights[column.identifier] = column.weight;
+        }
+        this._columnWeightsSetting.set(weights);
+    },
+
+    wasShown: function()
+    {
+       this._loadColumnWeights();
+    },
+
+    applyColumnWeights: function()
+    {
+        var sumOfWeights = 0.0;
+        for (var i = 0; i < this._columnsArray.length; ++i) {
+            var column = this._columnsArray[i];
+            if (this.isColumnVisible(column))
+                sumOfWeights += column.weight;
+        }
+        var factor = 100 / sumOfWeights;
+
+        for (var i = 0; i < this._columnsArray.length; ++i) {
+            var column = this._columnsArray[i];
+            var width = this.isColumnVisible(column) ? ((factor * column.weight) + "%"): "0%";
+            this._headerTableColumnGroup.children[i].style.width = width;
+            this._dataTableColumnGroup.children[i].style.width = width;
+        }
+
+        this._positionResizers();
+        this.dispatchEventToListeners(WebInspector.DataGrid.Events.ColumnsResized);
+    },
+
+    /**
+     * @param {!WebInspector.DataGrid.ColumnDescriptor} column
+     * @return {boolean}
+     */
+    isColumnVisible: function(column)
+    {
+        return !column.hidden;
+    },
+
+    /**
+     * @param {string} columnIdentifier
+     * @param {boolean} visible
+     */
+    setColumnVisible: function(columnIdentifier, visible)
+    {
+        if (visible === !this.columns[columnIdentifier].hidden)
+            return;
+
+        this.columns[columnIdentifier].hidden = !visible;
+        this.element.enableStyleClass("hide-" + columnIdentifier + "-column", !visible);
+    },
+
+    get scrollContainer()
+    {
+        return this._scrollContainer;
+    },
+
+    isScrolledToLastRow: function()
+    {
+        return this._scrollContainer.isScrolledToBottom();
+    },
+
+    scrollToLastRow: function()
+    {
+        this._scrollContainer.scrollTop = this._scrollContainer.scrollHeight - this._scrollContainer.offsetHeight;
+    },
+
+    _positionResizers: function()
+    {
+        var headerTableColumns = this._headerTableColumnGroup.children;
+        var numColumns = headerTableColumns.length - 1; // Do not process corner column.
+        var left = 0;
+        var previousResizer = null;
+
+        // Make n - 1 resizers for n columns.
+        for (var i = 0; i < numColumns - 1; i++) {
+            var resizer = this.resizers[i];
+
+            if (!resizer) {
+                // This is the first call to updateWidth, so the resizers need
+                // to be created.
+                resizer = document.createElement("div");
+                resizer.addStyleClass("data-grid-resizer");
+                // This resizer is associated with the column to its right.
+                WebInspector.installDragHandle(resizer, this._startResizerDragging.bind(this), this._resizerDragging.bind(this), this._endResizerDragging.bind(this), "col-resize");
+                this.element.appendChild(resizer);
+                this.resizers[i] = resizer;
+            }
+
+            // Get the width of the cell in the first (and only) row of the
+            // header table in order to determine the width of the column, since
+            // it is not possible to query a column for its width.
+            left += this.headerTableBody.rows[0].cells[i].offsetWidth;
+
+            if (!this._columnsArray[i].hidden) {
+                resizer.style.removeProperty("display");
+                if (resizer._position !== left) {
+                    resizer._position = left;
+                    resizer.style.left = left + "px";
+                }
+                resizer.leftNeighboringColumnIndex = i;
+                if (previousResizer)
+                    previousResizer.rightNeighboringColumnIndex = i;
+                previousResizer = resizer;
+            } else {
+                if (previousResizer && previousResizer._position !== left) {
+                    previousResizer._position = left;
+                    previousResizer.style.left = left + "px";
+                }
+                resizer.style.setProperty("display", "none");
+                resizer.leftNeighboringColumnIndex = 0;
+                resizer.rightNeighboringColumnIndex = 0;
+            }
+        }
+        if (previousResizer)
+            previousResizer.rightNeighboringColumnIndex = numColumns - 1;
+    },
+
+    addCreationNode: function(hasChildren)
+    {
+        if (this.creationNode)
+            this.creationNode.makeNormal();
+
+        var emptyData = {};
+        for (var column in this.columns)
+            emptyData[column] = null;
+        this.creationNode = new WebInspector.CreationDataGridNode(emptyData, hasChildren);
+        this.rootNode().appendChild(this.creationNode);
+    },
+
+    sortNodes: function(comparator, reverseMode)
+    {
+        function comparatorWrapper(a, b)
+        {
+            if (a._dataGridNode._data.summaryRow)
+                return 1;
+            if (b._dataGridNode._data.summaryRow)
+                return -1;
+
+            var aDataGirdNode = a._dataGridNode;
+            var bDataGirdNode = b._dataGridNode;
+            return reverseMode ? comparator(bDataGirdNode, aDataGirdNode) : comparator(aDataGirdNode, bDataGirdNode);
+        }
+
+        var tbody = this.dataTableBody;
+        var tbodyParent = tbody.parentElement;
+        tbodyParent.removeChild(tbody);
+
+        var childNodes = tbody.childNodes;
+        var fillerRow = childNodes[childNodes.length - 1];
+
+        var sortedRows = Array.prototype.slice.call(childNodes, 0, childNodes.length - 1);
+        sortedRows.sort(comparatorWrapper);
+        var sortedRowsLength = sortedRows.length;
+
+        tbody.removeChildren();
+        var previousSiblingNode = null;
+        for (var i = 0; i < sortedRowsLength; ++i) {
+            var row = sortedRows[i];
+            var node = row._dataGridNode;
+            node.previousSibling = previousSiblingNode;
+            if (previousSiblingNode)
+                previousSiblingNode.nextSibling = node;
+            tbody.appendChild(row);
+            previousSiblingNode = node;
+        }
+        if (previousSiblingNode)
+            previousSiblingNode.nextSibling = null;
+
+        tbody.appendChild(fillerRow);
+        tbodyParent.appendChild(tbody);
+    },
+
+    _keyDown: function(event)
+    {
+        if (!this.selectedNode || event.shiftKey || event.metaKey || event.ctrlKey || this._editing)
+            return;
+
+        var handled = false;
+        var nextSelectedNode;
+        if (event.keyIdentifier === "Up" && !event.altKey) {
+            nextSelectedNode = this.selectedNode.traversePreviousNode(true);
+            while (nextSelectedNode && !nextSelectedNode.selectable)
+                nextSelectedNode = nextSelectedNode.traversePreviousNode(true);
+            handled = nextSelectedNode ? true : false;
+        } else if (event.keyIdentifier === "Down" && !event.altKey) {
+            nextSelectedNode = this.selectedNode.traverseNextNode(true);
+            while (nextSelectedNode && !nextSelectedNode.selectable)
+                nextSelectedNode = nextSelectedNode.traverseNextNode(true);
+            handled = nextSelectedNode ? true : false;
+        } else if (event.keyIdentifier === "Left") {
+            if (this.selectedNode.expanded) {
+                if (event.altKey)
+                    this.selectedNode.collapseRecursively();
+                else
+                    this.selectedNode.collapse();
+                handled = true;
+            } else if (this.selectedNode.parent && !this.selectedNode.parent._isRoot) {
+                handled = true;
+                if (this.selectedNode.parent.selectable) {
+                    nextSelectedNode = this.selectedNode.parent;
+                    handled = nextSelectedNode ? true : false;
+                } else if (this.selectedNode.parent)
+                    this.selectedNode.parent.collapse();
+            }
+        } else if (event.keyIdentifier === "Right") {
+            if (!this.selectedNode.revealed) {
+                this.selectedNode.reveal();
+                handled = true;
+            } else if (this.selectedNode.hasChildren) {
+                handled = true;
+                if (this.selectedNode.expanded) {
+                    nextSelectedNode = this.selectedNode.children[0];
+                    handled = nextSelectedNode ? true : false;
+                } else {
+                    if (event.altKey)
+                        this.selectedNode.expandRecursively();
+                    else
+                        this.selectedNode.expand();
+                }
+            }
+        } else if (event.keyCode === 8 || event.keyCode === 46) {
+            if (this._deleteCallback) {
+                handled = true;
+                this._deleteCallback(this.selectedNode);
+                this.changeNodeAfterDeletion();
+            }
+        } else if (isEnterKey(event)) {
+            if (this._editCallback) {
+                handled = true;
+                this._startEditing(this.selectedNode._element.children[this._nextEditableColumn(-1)]);
+            }
+        }
+
+        if (nextSelectedNode) {
+            nextSelectedNode.reveal();
+            nextSelectedNode.select();
+        }
+
+        if (handled)
+            event.consume(true);
+    },
+
+    changeNodeAfterDeletion: function()
+    {
+        var nextSelectedNode = this.selectedNode.traverseNextNode(true);
+        while (nextSelectedNode && !nextSelectedNode.selectable)
+            nextSelectedNode = nextSelectedNode.traverseNextNode(true);
+
+        if (!nextSelectedNode || nextSelectedNode.isCreationNode) {
+            nextSelectedNode = this.selectedNode.traversePreviousNode(true);
+            while (nextSelectedNode && !nextSelectedNode.selectable)
+                nextSelectedNode = nextSelectedNode.traversePreviousNode(true);
+        }
+
+        if (nextSelectedNode) {
+            nextSelectedNode.reveal();
+            nextSelectedNode.select();
+        }
+    },
+
+    /**
+     * @param {!Node} target
+     * @return {?WebInspector.DataGridNode}
+     */
+    dataGridNodeFromNode: function(target)
+    {
+        var rowElement = target.enclosingNodeOrSelfWithNodeName("tr");
+        return rowElement && rowElement._dataGridNode;
+    },
+
+    /**
+     * @param {!Node} target
+     * @return {?string}
+     */
+    columnIdentifierFromNode: function(target)
+    {
+        var cellElement = target.enclosingNodeOrSelfWithNodeName("td");
+        return cellElement && cellElement.columnIdentifier_;
+    },
+
+    _clickInHeaderCell: function(event)
+    {
+        var cell = event.target.enclosingNodeOrSelfWithNodeName("th");
+        if (!cell || (typeof cell.columnIdentifier === "undefined") || !cell.hasStyleClass("sortable"))
+            return;
+
+        var sortOrder = WebInspector.DataGrid.Order.Ascending;
+        if ((cell === this._sortColumnCell) && this.isSortOrderAscending())
+            sortOrder = WebInspector.DataGrid.Order.Descending;
+
+        if (this._sortColumnCell)
+            this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+");
+        this._sortColumnCell = cell;
+
+        cell.addStyleClass("sort-" + sortOrder);
+
+        this.dispatchEventToListeners(WebInspector.DataGrid.Events.SortingChanged);
+    },
+
+    /**
+     * @param {string} columnIdentifier
+     * @param {!WebInspector.DataGrid.Order} sortOrder
+     */
+    markColumnAsSortedBy: function(columnIdentifier, sortOrder)
+    {
+        if (this._sortColumnCell)
+            this._sortColumnCell.removeMatchingStyleClasses("sort-\\w+");
+        this._sortColumnCell = this._headerTableHeaders[columnIdentifier];
+        this._sortColumnCell.addStyleClass("sort-" + sortOrder);
+    },
+
+    headerTableHeader: function(columnIdentifier)
+    {
+        return this._headerTableHeaders[columnIdentifier];
+    },
+
+    _mouseDownInDataTable: function(event)
+    {
+        var gridNode = this.dataGridNodeFromNode(event.target);
+        if (!gridNode || !gridNode.selectable)
+            return;
+
+        if (gridNode.isEventWithinDisclosureTriangle(event))
+            return;
+
+        if (event.metaKey) {
+            if (gridNode.selected)
+                gridNode.deselect();
+            else
+                gridNode.select();
+        } else
+            gridNode.select();
+    },
+
+    _contextMenuInDataTable: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+
+        var gridNode = this.dataGridNodeFromNode(event.target);
+        if (this._refreshCallback && (!gridNode || gridNode !== this.creationNode))
+            contextMenu.appendItem(WebInspector.UIString("Refresh"), this._refreshCallback.bind(this));
+
+        if (gridNode && gridNode.selectable && !gridNode.isEventWithinDisclosureTriangle(event)) {
+            // FIXME: Use the column names for Editing, instead of just "Edit".
+            if (this._editCallback) {
+                if (gridNode === this.creationNode)
+                    contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add new" : "Add New"), this._startEditing.bind(this, event.target));
+                else {
+                    var columnIdentifier = this.columnIdentifierFromNode(event.target);
+                    if (columnIdentifier && this.columns[columnIdentifier].editable)
+                        contextMenu.appendItem(WebInspector.UIString("Edit"), this._startEditing.bind(this, event.target));
+                }
+            }
+            if (this._deleteCallback && gridNode !== this.creationNode)
+                contextMenu.appendItem(WebInspector.UIString("Delete"), this._deleteCallback.bind(this, gridNode));
+            if (this._contextMenuCallback)
+                this._contextMenuCallback(contextMenu, gridNode);
+        }
+
+        contextMenu.show();
+    },
+
+    _clickInDataTable: function(event)
+    {
+        var gridNode = this.dataGridNodeFromNode(event.target);
+        if (!gridNode || !gridNode.hasChildren)
+            return;
+
+        if (!gridNode.isEventWithinDisclosureTriangle(event))
+            return;
+
+        if (gridNode.expanded) {
+            if (event.altKey)
+                gridNode.collapseRecursively();
+            else
+                gridNode.collapse();
+        } else {
+            if (event.altKey)
+                gridNode.expandRecursively();
+            else
+                gridNode.expand();
+        }
+    },
+
+    get resizeMethod()
+    {
+        if (typeof this._resizeMethod === "undefined")
+            return WebInspector.DataGrid.ResizeMethod.Nearest;
+        return this._resizeMethod;
+    },
+
+    set resizeMethod(method)
+    {
+        this._resizeMethod = method;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    _startResizerDragging: function(event)
+    {
+        this._currentResizer = event.target;
+        return !!this._currentResizer.rightNeighboringColumnIndex
+    },
+
+    _resizerDragging: function(event)
+    {
+        var resizer = this._currentResizer;
+        if (!resizer)
+            return;
+
+        var tableWidth = this._dataTable.offsetWidth; // Cache it early, before we invalidate layout.
+
+        // Constrain the dragpoint to be within the containing div of the
+        // datagrid.
+        var dragPoint = event.clientX - this.element.totalOffsetLeft();
+        // Constrain the dragpoint to be within the space made up by the
+        // column directly to the left and the column directly to the right.
+        var leftCellIndex = resizer.leftNeighboringColumnIndex;
+        var rightCellIndex = resizer.rightNeighboringColumnIndex;
+        var firstRowCells = this.headerTableBody.rows[0].cells;
+        var leftEdgeOfPreviousColumn = 0;
+        for (var i = 0; i < leftCellIndex; i++)
+            leftEdgeOfPreviousColumn += firstRowCells[i].offsetWidth;
+
+        // Differences for other resize methods
+        if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.Last) {
+            rightCellIndex = this.resizers.length;
+        } else if (this.resizeMethod == WebInspector.DataGrid.ResizeMethod.First) {
+            leftEdgeOfPreviousColumn += firstRowCells[leftCellIndex].offsetWidth - firstRowCells[0].offsetWidth;
+            leftCellIndex = 0;
+        }
+
+        var rightEdgeOfNextColumn = leftEdgeOfPreviousColumn + firstRowCells[leftCellIndex].offsetWidth + firstRowCells[rightCellIndex].offsetWidth;
+
+        // Give each column some padding so that they don't disappear.
+        var leftMinimum = leftEdgeOfPreviousColumn + this.ColumnResizePadding;
+        var rightMaximum = rightEdgeOfNextColumn - this.ColumnResizePadding;
+        if (leftMinimum > rightMaximum)
+            return;
+
+        dragPoint = Number.constrain(dragPoint, leftMinimum, rightMaximum);
+
+        resizer.style.left = (dragPoint - this.CenterResizerOverBorderAdjustment) + "px";
+
+        var percentLeftColumn = (((dragPoint - leftEdgeOfPreviousColumn) / tableWidth) * 100) + "%";
+        this._headerTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
+        this._dataTableColumnGroup.children[leftCellIndex].style.width = percentLeftColumn;
+
+        var percentRightColumn = (((rightEdgeOfNextColumn - dragPoint) / tableWidth) * 100) + "%";
+        this._headerTableColumnGroup.children[rightCellIndex].style.width =  percentRightColumn;
+        this._dataTableColumnGroup.children[rightCellIndex].style.width = percentRightColumn;
+
+        var leftColumn = this._columnsArray[leftCellIndex];
+        var rightColumn = this._columnsArray[rightCellIndex];
+        if (leftColumn.weight || rightColumn.weight) {
+            var sumOfWeights = leftColumn.weight + rightColumn.weight;
+            var delta = rightEdgeOfNextColumn - leftEdgeOfPreviousColumn;
+            leftColumn.weight = (dragPoint - leftEdgeOfPreviousColumn) * sumOfWeights / delta;
+            rightColumn.weight = (rightEdgeOfNextColumn - dragPoint) * sumOfWeights / delta;
+        }
+
+        this._positionResizers();
+        event.preventDefault();
+        this.dispatchEventToListeners(WebInspector.DataGrid.Events.ColumnsResized);
+    },
+
+    _endResizerDragging: function(event)
+    {
+        this._currentResizer = null;
+        this._saveColumnWeights();
+        this.dispatchEventToListeners(WebInspector.DataGrid.Events.ColumnsResized);
+    },
+
+    ColumnResizePadding: 24,
+
+    CenterResizerOverBorderAdjustment: 3,
+
+    __proto__: WebInspector.View.prototype
+}
+
+WebInspector.DataGrid.ResizeMethod = {
+    Nearest: "nearest",
+    First: "first",
+    Last: "last"
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ * @param {Object.=} data
+ * @param {boolean=} hasChildren
+ */
+WebInspector.DataGridNode = function(data, hasChildren)
+{
+    this._expanded = false;
+    this._selected = false;
+    this._shouldRefreshChildren = true;
+    /** @type {!Object.} */
+    this._data = data || {};
+    /** @type {boolean} */
+    this.hasChildren = hasChildren || false;
+    /** @type {!Array.} */
+    this.children = [];
+    this.dataGrid = null;
+    this.parent = null;
+    /** @type {WebInspector.DataGridNode} */
+    this.previousSibling = null;
+    /** @type {WebInspector.DataGridNode} */
+    this.nextSibling = null;
+    this.disclosureToggleWidth = 10;
+}
+
+WebInspector.DataGridNode.prototype = {
+    /** @type {boolean} */
+    selectable: true,
+
+    /** @type {boolean} */
+    _isRoot: false,
+
+    get element()
+    {
+        if (this._element)
+            return this._element;
+
+        if (!this.dataGrid)
+            return null;
+
+        this._element = document.createElement("tr");
+        this._element._dataGridNode = this;
+
+        if (this.hasChildren)
+            this._element.addStyleClass("parent");
+        if (this.expanded)
+            this._element.addStyleClass("expanded");
+        if (this.selected)
+            this._element.addStyleClass("selected");
+        if (this.revealed)
+            this._element.addStyleClass("revealed");
+
+        this.createCells();
+        this._element.createChild("td", "corner");
+
+        return this._element;
+    },
+
+    createCells: function()
+    {
+        var columnsArray = this.dataGrid._columnsArray;
+        for (var i = 0; i < columnsArray.length; ++i) {
+            var cell = this.createCell(columnsArray[i].identifier);
+            this._element.appendChild(cell);
+        }
+    },
+
+    get data()
+    {
+        return this._data;
+    },
+
+    set data(x)
+    {
+        this._data = x || {};
+        this.refresh();
+    },
+
+    get revealed()
+    {
+        if ("_revealed" in this)
+            return this._revealed;
+
+        var currentAncestor = this.parent;
+        while (currentAncestor && !currentAncestor._isRoot) {
+            if (!currentAncestor.expanded) {
+                this._revealed = false;
+                return false;
+            }
+
+            currentAncestor = currentAncestor.parent;
+        }
+
+        this._revealed = true;
+        return true;
+    },
+
+    set hasChildren(x)
+    {
+        if (this._hasChildren === x)
+            return;
+
+        this._hasChildren = x;
+
+        if (!this._element)
+            return;
+
+        this._element.enableStyleClass("parent", this._hasChildren);
+        this._element.enableStyleClass("expanded", this._hasChildren && this.expanded);
+    },
+
+    get hasChildren()
+    {
+        return this._hasChildren;
+    },
+
+    set revealed(x)
+    {
+        if (this._revealed === x)
+            return;
+
+        this._revealed = x;
+
+        if (this._element)
+            this._element.enableStyleClass("revealed", this._revealed);
+
+        for (var i = 0; i < this.children.length; ++i)
+            this.children[i].revealed = x && this.expanded;
+    },
+
+    get depth()
+    {
+        if ("_depth" in this)
+            return this._depth;
+        if (this.parent && !this.parent._isRoot)
+            this._depth = this.parent.depth + 1;
+        else
+            this._depth = 0;
+        return this._depth;
+    },
+
+    get leftPadding()
+    {
+        if (typeof this._leftPadding === "number")
+            return this._leftPadding;
+
+        this._leftPadding = this.depth * this.dataGrid.indentWidth;
+        return this._leftPadding;
+    },
+
+    get shouldRefreshChildren()
+    {
+        return this._shouldRefreshChildren;
+    },
+
+    set shouldRefreshChildren(x)
+    {
+        this._shouldRefreshChildren = x;
+        if (x && this.expanded)
+            this.expand();
+    },
+
+    get selected()
+    {
+        return this._selected;
+    },
+
+    set selected(x)
+    {
+        if (x)
+            this.select();
+        else
+            this.deselect();
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    /**
+     * @param {boolean} x
+     */
+    set expanded(x)
+    {
+        if (x)
+            this.expand();
+        else
+            this.collapse();
+    },
+
+    refresh: function()
+    {
+        if (!this._element || !this.dataGrid)
+            return;
+
+        this._element.removeChildren();
+        this.createCells();
+        this._element.createChild("td", "corner");
+    },
+
+    /**
+     * @param {string} columnIdentifier
+     * @return {!Element}
+     */
+    createTD: function(columnIdentifier)
+    {
+        var cell = document.createElement("td");
+        cell.className = columnIdentifier + "-column";
+        cell.columnIdentifier_ = columnIdentifier;
+
+        var alignment = this.dataGrid.columns[columnIdentifier].align;
+        if (alignment)
+            cell.addStyleClass(alignment);
+
+        return cell;
+    },
+
+    /**
+     * @param {string} columnIdentifier
+     * @return {!Element}
+     */
+    createCell: function(columnIdentifier)
+    {
+        var cell = this.createTD(columnIdentifier);
+
+        var data = this.data[columnIdentifier];
+        var div = document.createElement("div");
+        if (data instanceof Node)
+            div.appendChild(data);
+        else {
+            div.textContent = data;
+            if (this.dataGrid.columns[columnIdentifier].longText)
+                div.title = data;
+        }
+        cell.appendChild(div);
+
+        if (columnIdentifier === this.dataGrid.disclosureColumnIdentifier) {
+            cell.addStyleClass("disclosure");
+            if (this.leftPadding)
+                cell.style.setProperty("padding-left", this.leftPadding + "px");
+        }
+
+        return cell;
+    },
+
+    /**
+     * @return {number}
+     */
+    nodeHeight: function()
+    {
+        var rowHeight = 16;
+        if (!this.revealed)
+            return 0;
+        if (!this.expanded)
+            return rowHeight;
+        var result = rowHeight;
+        for (var i = 0; i < this.children.length; i++)
+            result += this.children[i].nodeHeight();
+        return result;
+    },
+
+    /**
+     * @param {WebInspector.DataGridNode} child
+     */
+    appendChild: function(child)
+    {
+        this.insertChild(child, this.children.length);
+    },
+
+    /**
+     * @param {WebInspector.DataGridNode} child
+     * @param {number} index
+     */
+    insertChild: function(child, index)
+    {
+        if (!child)
+            throw("insertChild: Node can't be undefined or null.");
+        if (child.parent === this)
+            throw("insertChild: Node is already a child of this node.");
+
+        if (child.parent)
+            child.parent.removeChild(child);
+
+        this.children.splice(index, 0, child);
+        this.hasChildren = true;
+
+        child.parent = this;
+        child.dataGrid = this.dataGrid;
+        child._recalculateSiblings(index);
+
+        delete child._depth;
+        delete child._revealed;
+        delete child._attached;
+        child._shouldRefreshChildren = true;
+
+        var current = child.children[0];
+        while (current) {
+            current.dataGrid = this.dataGrid;
+            delete current._depth;
+            delete current._revealed;
+            delete current._attached;
+            current._shouldRefreshChildren = true;
+            current = current.traverseNextNode(false, child, true);
+        }
+
+        if (this.expanded)
+            child._attach();
+        if (!this.revealed)
+            child.revealed = false;
+    },
+
+    /**
+     * @param {WebInspector.DataGridNode} child
+     */
+    removeChild: function(child)
+    {
+        if (!child)
+            throw("removeChild: Node can't be undefined or null.");
+        if (child.parent !== this)
+            throw("removeChild: Node is not a child of this node.");
+
+        child.deselect();
+        child._detach();
+
+        this.children.remove(child, true);
+
+        if (child.previousSibling)
+            child.previousSibling.nextSibling = child.nextSibling;
+        if (child.nextSibling)
+            child.nextSibling.previousSibling = child.previousSibling;
+
+        child.dataGrid = null;
+        child.parent = null;
+        child.nextSibling = null;
+        child.previousSibling = null;
+
+        if (this.children.length <= 0)
+            this.hasChildren = false;
+    },
+
+    removeChildren: function()
+    {
+        for (var i = 0; i < this.children.length; ++i) {
+            var child = this.children[i];
+            child.deselect();
+            child._detach();
+
+            child.dataGrid = null;
+            child.parent = null;
+            child.nextSibling = null;
+            child.previousSibling = null;
+        }
+
+        this.children = [];
+        this.hasChildren = false;
+    },
+
+    /**
+     * @param {number} myIndex
+     */
+    _recalculateSiblings: function(myIndex)
+    {
+        if (!this.parent)
+            return;
+
+        var previousChild = (myIndex > 0 ? this.parent.children[myIndex - 1] : null);
+
+        if (previousChild) {
+            previousChild.nextSibling = this;
+            this.previousSibling = previousChild;
+        } else
+            this.previousSibling = null;
+
+        var nextChild = this.parent.children[myIndex + 1];
+
+        if (nextChild) {
+            nextChild.previousSibling = this;
+            this.nextSibling = nextChild;
+        } else
+            this.nextSibling = null;
+    },
+
+    collapse: function()
+    {
+        if (this._isRoot)
+            return;
+        if (this._element)
+            this._element.removeStyleClass("expanded");
+
+        this._expanded = false;
+
+        for (var i = 0; i < this.children.length; ++i)
+            this.children[i].revealed = false;
+    },
+
+    collapseRecursively: function()
+    {
+        var item = this;
+        while (item) {
+            if (item.expanded)
+                item.collapse();
+            item = item.traverseNextNode(false, this, true);
+        }
+    },
+
+    populate: function() { },
+
+    expand: function()
+    {
+        if (!this.hasChildren || this.expanded)
+            return;
+        if (this._isRoot)
+            return;
+
+        if (this.revealed && !this._shouldRefreshChildren)
+            for (var i = 0; i < this.children.length; ++i)
+                this.children[i].revealed = true;
+
+        if (this._shouldRefreshChildren) {
+            for (var i = 0; i < this.children.length; ++i)
+                this.children[i]._detach();
+
+            this.populate();
+
+            if (this._attached) {
+                for (var i = 0; i < this.children.length; ++i) {
+                    var child = this.children[i];
+                    if (this.revealed)
+                        child.revealed = true;
+                    child._attach();
+                }
+            }
+
+            delete this._shouldRefreshChildren;
+        }
+
+        if (this._element)
+            this._element.addStyleClass("expanded");
+
+        this._expanded = true;
+    },
+
+    expandRecursively: function()
+    {
+        var item = this;
+        while (item) {
+            item.expand();
+            item = item.traverseNextNode(false, this);
+        }
+    },
+
+    reveal: function()
+    {
+        if (this._isRoot)
+            return;
+        var currentAncestor = this.parent;
+        while (currentAncestor && !currentAncestor._isRoot) {
+            if (!currentAncestor.expanded)
+                currentAncestor.expand();
+            currentAncestor = currentAncestor.parent;
+        }
+
+        this.element.scrollIntoViewIfNeeded(false);
+    },
+
+    /**
+     * @param {boolean=} supressSelectedEvent
+     */
+    select: function(supressSelectedEvent)
+    {
+        if (!this.dataGrid || !this.selectable || this.selected)
+            return;
+
+        if (this.dataGrid.selectedNode)
+            this.dataGrid.selectedNode.deselect();
+
+        this._selected = true;
+        this.dataGrid.selectedNode = this;
+
+        if (this._element)
+            this._element.addStyleClass("selected");
+
+        if (!supressSelectedEvent)
+            this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.SelectedNode);
+    },
+
+    revealAndSelect: function()
+    {
+        if (this._isRoot)
+            return;
+        this.reveal();
+        this.select();
+    },
+
+    /**
+     * @param {boolean=} supressDeselectedEvent
+     */
+    deselect: function(supressDeselectedEvent)
+    {
+        if (!this.dataGrid || this.dataGrid.selectedNode !== this || !this.selected)
+            return;
+
+        this._selected = false;
+        this.dataGrid.selectedNode = null;
+
+        if (this._element)
+            this._element.removeStyleClass("selected");
+
+        if (!supressDeselectedEvent)
+            this.dataGrid.dispatchEventToListeners(WebInspector.DataGrid.Events.DeselectedNode);
+    },
+
+    /**
+     * @param {boolean} skipHidden
+     * @param {WebInspector.DataGridNode=} stayWithin
+     * @param {boolean=} dontPopulate
+     * @param {Object=} info
+     * @return {WebInspector.DataGridNode}
+     */
+    traverseNextNode: function(skipHidden, stayWithin, dontPopulate, info)
+    {
+        if (!dontPopulate && this.hasChildren)
+            this.populate();
+
+        if (info)
+            info.depthChange = 0;
+
+        var node = (!skipHidden || this.revealed) ? this.children[0] : null;
+        if (node && (!skipHidden || this.expanded)) {
+            if (info)
+                info.depthChange = 1;
+            return node;
+        }
+
+        if (this === stayWithin)
+            return null;
+
+        node = (!skipHidden || this.revealed) ? this.nextSibling : null;
+        if (node)
+            return node;
+
+        node = this;
+        while (node && !node._isRoot && !((!skipHidden || node.revealed) ? node.nextSibling : null) && node.parent !== stayWithin) {
+            if (info)
+                info.depthChange -= 1;
+            node = node.parent;
+        }
+
+        if (!node)
+            return null;
+
+        return (!skipHidden || node.revealed) ? node.nextSibling : null;
+    },
+
+    /**
+     * @param {boolean} skipHidden
+     * @param {boolean=} dontPopulate
+     * @return {WebInspector.DataGridNode}
+     */
+    traversePreviousNode: function(skipHidden, dontPopulate)
+    {
+        var node = (!skipHidden || this.revealed) ? this.previousSibling : null;
+        if (!dontPopulate && node && node.hasChildren)
+            node.populate();
+
+        while (node && ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null)) {
+            if (!dontPopulate && node.hasChildren)
+                node.populate();
+            node = ((!skipHidden || (node.revealed && node.expanded)) ? node.children[node.children.length - 1] : null);
+        }
+
+        if (node)
+            return node;
+
+        if (!this.parent || this.parent._isRoot)
+            return null;
+
+        return this.parent;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isEventWithinDisclosureTriangle: function(event)
+    {
+        if (!this.hasChildren)
+            return false;
+        var cell = event.target.enclosingNodeOrSelfWithNodeName("td");
+        if (!cell.hasStyleClass("disclosure"))
+            return false;
+
+        var left = cell.totalOffsetLeft() + this.leftPadding;
+        return event.pageX >= left && event.pageX <= left + this.disclosureToggleWidth;
+    },
+
+    _attach: function()
+    {
+        if (!this.dataGrid || this._attached)
+            return;
+
+        this._attached = true;
+
+        var nextNode = null;
+        var previousNode = this.traversePreviousNode(true, true);
+        if (previousNode && previousNode.element.parentNode && previousNode.element.nextSibling)
+            nextNode = previousNode.element.nextSibling;
+        if (!nextNode)
+            nextNode = this.dataGrid.dataTableBody.firstChild;
+        this.dataGrid.dataTableBody.insertBefore(this.element, nextNode);
+
+        if (this.expanded)
+            for (var i = 0; i < this.children.length; ++i)
+                this.children[i]._attach();
+    },
+
+    _detach: function()
+    {
+        if (!this._attached)
+            return;
+
+        this._attached = false;
+
+        if (this._element)
+            this._element.remove();
+
+        for (var i = 0; i < this.children.length; ++i)
+            this.children[i]._detach();
+
+        this.wasDetached();
+    },
+
+    wasDetached: function()
+    {
+    },
+
+    savePosition: function()
+    {
+        if (this._savedPosition)
+            return;
+
+        if (!this.parent)
+            throw("savePosition: Node must have a parent.");
+        this._savedPosition = {
+            parent: this.parent,
+            index: this.parent.children.indexOf(this)
+        };
+    },
+
+    restorePosition: function()
+    {
+        if (!this._savedPosition)
+            return;
+
+        if (this.parent !== this._savedPosition.parent)
+            this._savedPosition.parent.insertChild(this, this._savedPosition.index);
+
+        delete this._savedPosition;
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.DataGridNode}
+ */
+WebInspector.CreationDataGridNode = function(data, hasChildren)
+{
+    WebInspector.DataGridNode.call(this, data, hasChildren);
+    this.isCreationNode = true;
+}
+
+WebInspector.CreationDataGridNode.prototype = {
+    makeNormal: function()
+    {
+        delete this.isCreationNode;
+        delete this.makeNormal;
+    },
+
+    __proto__: WebInspector.DataGridNode.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Database.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Database.js
new file mode 100644
index 00000000..9758c25a
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Database.js
@@ -0,0 +1,207 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.DatabaseModel} model
+ */
+WebInspector.Database = function(model, id, domain, name, version)
+{
+    this._model = model;
+    this._id = id;
+    this._domain = domain;
+    this._name = name;
+    this._version = version;
+}
+
+WebInspector.Database.prototype = {
+    /** @return {string} */
+    get id()
+    {
+        return this._id;
+    },
+
+    /** @return {string} */
+    get name()
+    {
+        return this._name;
+    },
+
+    set name(x)
+    {
+        this._name = x;
+    },
+
+    /** @return {string} */
+    get version()
+    {
+        return this._version;
+    },
+
+    set version(x)
+    {
+        this._version = x;
+    },
+
+    /** @return {string} */
+    get domain()
+    {
+        return this._domain;
+    },
+
+    set domain(x)
+    {
+        this._domain = x;
+    },
+
+    /**
+     * @param {function(Array.)} callback
+     */
+    getTableNames: function(callback)
+    {
+        function sortingCallback(error, names)
+        {
+            if (!error)
+                callback(names.sort());
+        }
+        DatabaseAgent.getDatabaseTableNames(this._id, sortingCallback);
+    },
+
+    /**
+     * @param {string} query
+     * @param {function(Array.=, Array.<*>=)} onSuccess
+     * @param {function(string)} onError
+     */
+    executeSql: function(query, onSuccess, onError)
+    {
+        /**
+         * @param {?Protocol.Error} error
+         * @param {Array.=} columnNames
+         * @param {Array.<*>=} values
+         * @param {DatabaseAgent.Error=} errorObj
+         */
+        function callback(error, columnNames, values, errorObj)
+        {
+            if (error) {
+                onError(error);
+                return;
+            }
+            if (errorObj) {
+                var message;
+                if (errorObj.message)
+                    message = errorObj.message;
+                else if (errorObj.code == 2)
+                    message = WebInspector.UIString("Database no longer has expected version.");
+                else
+                    message = WebInspector.UIString("An unexpected error %s occurred.", errorObj.code);
+                onError(message);
+                return;
+            }
+            onSuccess(columnNames, values);
+        }
+        DatabaseAgent.executeSQL(this._id, query, callback.bind(this));
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.DatabaseModel = function()
+{
+    this._databases = [];
+    InspectorBackend.registerDatabaseDispatcher(new WebInspector.DatabaseDispatcher(this));
+    DatabaseAgent.enable();
+}
+
+WebInspector.DatabaseModel.Events = {
+    DatabaseAdded: "DatabaseAdded"
+}
+
+WebInspector.DatabaseModel.prototype = {
+    /**
+     * @return {Array.}
+     */
+    databases: function()
+    {
+        var result = [];
+        for (var databaseId in this._databases)
+            result.push(this._databases[databaseId]);
+        return result;
+    },
+
+    /**
+     * @param {DatabaseAgent.DatabaseId} databaseId
+     * @return {WebInspector.Database}
+     */
+    databaseForId: function(databaseId)
+    {
+        return this._databases[databaseId];
+    },
+
+    /**
+     * @param {WebInspector.Database} database
+     */
+    _addDatabase: function(database)
+    {
+        this._databases.push(database);
+        this.dispatchEventToListeners(WebInspector.DatabaseModel.Events.DatabaseAdded, database);
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @constructor
+ * @implements {DatabaseAgent.Dispatcher}
+ * @param {WebInspector.DatabaseModel} model
+ */
+WebInspector.DatabaseDispatcher = function(model)
+{
+    this._model = model;
+}
+
+WebInspector.DatabaseDispatcher.prototype = {
+    /**
+     * @param {DatabaseAgent.Database} payload
+     */
+    addDatabase: function(payload)
+    {
+        this._model._addDatabase(new WebInspector.Database(
+            this._model,
+            payload.id,
+            payload.domain,
+            payload.name,
+            payload.version));
+    }
+}
+
+/**
+ * @type {WebInspector.DatabaseModel}
+ */
+WebInspector.databaseModel = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseQueryView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseQueryView.js
new file mode 100644
index 00000000..c6d12322
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseQueryView.js
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.DatabaseQueryView = function(database)
+{
+    WebInspector.View.call(this);
+
+    this.database = database;
+
+    this.element.addStyleClass("storage-view");
+    this.element.addStyleClass("query");
+    this.element.addStyleClass("monospace");
+    this.element.addEventListener("selectstart", this._selectStart.bind(this), false);
+
+    this._promptElement = document.createElement("div");
+    this._promptElement.className = "database-query-prompt";
+    this._promptElement.appendChild(document.createElement("br"));
+    this._promptElement.addEventListener("keydown", this._promptKeyDown.bind(this), true);
+    this.element.appendChild(this._promptElement);
+
+    this.prompt = new WebInspector.TextPromptWithHistory(this.completions.bind(this), " ");
+    this.prompt.attach(this._promptElement);
+
+    this.element.addEventListener("click", this._messagesClicked.bind(this), true);
+}
+
+WebInspector.DatabaseQueryView.Events = {
+    SchemaUpdated: "SchemaUpdated"
+}
+
+WebInspector.DatabaseQueryView.prototype = {
+    _messagesClicked: function()
+    {
+        if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
+            this.prompt.moveCaretToEndOfPrompt();
+    },
+    
+    /**
+     * @param {Element} proxyElement
+     * @param {Range} wordRange
+     * @param {boolean} force
+     * @param {function(!Array., number=)} completionsReadyCallback
+     */
+    completions: function(proxyElement, wordRange, force, completionsReadyCallback)
+    {
+        var prefix = wordRange.toString().toLowerCase();
+        if (!prefix)
+            return;
+        var results = [];
+
+        function accumulateMatches(textArray)
+        {
+            for (var i = 0; i < textArray.length; ++i) {
+                var text = textArray[i].toLowerCase();
+                if (text.length < prefix.length)
+                    continue;
+                if (!text.startsWith(prefix))
+                    continue;
+                results.push(textArray[i]);
+            }
+        }
+
+        function tableNamesCallback(tableNames)
+        {
+            accumulateMatches(tableNames.map(function(name) { return name + " " }));
+            accumulateMatches(["SELECT ", "FROM ", "WHERE ", "LIMIT ", "DELETE FROM ", "CREATE ", "DROP ", "TABLE ", "INDEX ", "UPDATE ", "INSERT INTO ", "VALUES ("]);
+
+            completionsReadyCallback(results);
+        }
+        this.database.getTableNames(tableNamesCallback);
+    },
+
+    _selectStart: function(event)
+    {
+        if (this._selectionTimeout)
+            clearTimeout(this._selectionTimeout);
+
+        this.prompt.clearAutoComplete();
+
+        function moveBackIfOutside()
+        {
+            delete this._selectionTimeout;
+            if (!this.prompt.isCaretInsidePrompt() && window.getSelection().isCollapsed)
+                this.prompt.moveCaretToEndOfPrompt();
+            this.prompt.autoCompleteSoon();
+        }
+
+        this._selectionTimeout = setTimeout(moveBackIfOutside.bind(this), 100);
+    },
+
+    _promptKeyDown: function(event)
+    {
+        if (isEnterKey(event)) {
+            this._enterKeyPressed(event);
+            return;
+        }
+    },
+
+    _enterKeyPressed: function(event)
+    {
+        event.consume(true);
+
+        this.prompt.clearAutoComplete(true);
+
+        var query = this.prompt.text;
+        if (!query.length)
+            return;
+
+        this.prompt.pushHistoryItem(query);
+        this.prompt.text = "";
+
+        this.database.executeSql(query, this._queryFinished.bind(this, query), this._queryError.bind(this, query));
+    },
+
+    _queryFinished: function(query, columnNames, values)
+    {
+        var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, values);
+        var trimmedQuery = query.trim();
+
+        if (dataGrid) {
+            dataGrid.renderInline();
+            this._appendViewQueryResult(trimmedQuery, dataGrid);
+            dataGrid.autoSizeColumns(5);
+        }
+
+        if (trimmedQuery.match(/^create /i) || trimmedQuery.match(/^drop table /i))
+            this.dispatchEventToListeners(WebInspector.DatabaseQueryView.Events.SchemaUpdated, this.database);
+    },
+
+    _queryError: function(query, errorMessage)
+    {
+        this._appendErrorQueryResult(query, errorMessage);
+    },
+
+    /**
+     * @param {string} query
+     * @param {WebInspector.View} view
+     */
+    _appendViewQueryResult: function(query, view)
+    {
+        var resultElement = this._appendQueryResult(query);
+        view.show(resultElement);
+
+        this._promptElement.scrollIntoView(false);
+    },
+
+    /**
+     * @param {string} query
+     * @param {string} errorText
+     */
+    _appendErrorQueryResult: function(query, errorText)
+    {
+        var resultElement = this._appendQueryResult(query);
+        resultElement.addStyleClass("error")
+        resultElement.textContent = errorText;
+
+        this._promptElement.scrollIntoView(false);
+    },
+
+    _appendQueryResult: function(query)
+    {
+        var element = document.createElement("div");
+        element.className = "database-user-query";
+        this.element.insertBefore(element, this.prompt.proxyElement);
+
+        var commandTextElement = document.createElement("span");
+        commandTextElement.className = "database-query-text";
+        commandTextElement.textContent = query;
+        element.appendChild(commandTextElement);
+
+        var resultElement = document.createElement("div");
+        resultElement.className = "database-query-result";
+        element.appendChild(resultElement);
+        return resultElement;
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseTableView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseTableView.js
new file mode 100644
index 00000000..0d5e5f83
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DatabaseTableView.js
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.View}
+ */
+WebInspector.DatabaseTableView = function(database, tableName)
+{
+    WebInspector.View.call(this);
+
+    this.database = database;
+    this.tableName = tableName;
+
+    this.element.addStyleClass("storage-view");
+    this.element.addStyleClass("table");
+
+    this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item");
+    this.refreshButton.addEventListener("click", this._refreshButtonClicked, this);
+}
+
+WebInspector.DatabaseTableView.prototype = {
+    wasShown: function()
+    {
+        this.update();
+    },
+
+    get statusBarItems()
+    {
+        return [this.refreshButton.element];
+    },
+
+    /**
+     * @param {string} tableName
+     * @return {string}
+     */
+    _escapeTableName: function(tableName)
+    {
+        return tableName.replace(/\"/g, "\"\"");
+    },
+    
+    update: function()
+    {
+        this.database.executeSql("SELECT * FROM \"" + this._escapeTableName(this.tableName) + "\"", this._queryFinished.bind(this), this._queryError.bind(this));
+    },
+
+    _queryFinished: function(columnNames, values)
+    {
+        this.detachChildViews();
+        this.element.removeChildren();
+
+        var dataGrid = WebInspector.DataGrid.createSortableDataGrid(columnNames, values);
+        if (!dataGrid) {
+            this._emptyView = new WebInspector.EmptyView(WebInspector.UIString("The “%s”\ntable is empty.", this.tableName));
+            this._emptyView.show(this.element);
+            return;
+        }
+        dataGrid.show(this.element);
+        dataGrid.autoSizeColumns(5);
+    },
+
+    _queryError: function(error)
+    {
+        this.detachChildViews();
+        this.element.removeChildren();
+
+        var errorMsgElement = document.createElement("div");
+        errorMsgElement.className = "storage-table-error";
+        errorMsgElement.textContent = WebInspector.UIString("An error occurred trying to\nread the “%s” table.", this.tableName);
+        this.element.appendChild(errorMsgElement);
+    },
+
+    _refreshButtonClicked: function(event)
+    {
+        this.update();
+    },
+
+    __proto__: WebInspector.View.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerModel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerModel.js
new file mode 100644
index 00000000..5f46f751
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerModel.js
@@ -0,0 +1,912 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.DebuggerModel = function()
+{
+    InspectorBackend.registerDebuggerDispatcher(new WebInspector.DebuggerDispatcher(this));
+
+    this._debuggerPausedDetails = null;
+    /**
+     * @type {Object.}
+     */
+    this._scripts = {};
+    /** @type {!Object.>} */
+    this._scriptsBySourceURL = {};
+
+    this._canSetScriptSource = false;
+    this._breakpointsActive = true;
+
+    WebInspector.settings.pauseOnExceptionStateString = WebInspector.settings.createSetting("pauseOnExceptionStateString", WebInspector.DebuggerModel.PauseOnExceptionsState.DontPauseOnExceptions);
+    WebInspector.settings.pauseOnExceptionStateString.addChangeListener(this._pauseOnExceptionStateChanged, this);
+
+    this.enableDebugger();
+
+    WebInspector.DebuggerModel.applySkipStackFrameSettings();
+}
+
+// Keep these in sync with WebCore::ScriptDebugServer
+WebInspector.DebuggerModel.PauseOnExceptionsState = {
+    DontPauseOnExceptions : "none",
+    PauseOnAllExceptions : "all",
+    PauseOnUncaughtExceptions: "uncaught"
+};
+
+/**
+ * @constructor
+ * @implements {WebInspector.RawLocation}
+ * @param {string} scriptId
+ * @param {number} lineNumber
+ * @param {number} columnNumber
+ */
+WebInspector.DebuggerModel.Location = function(scriptId, lineNumber, columnNumber)
+{
+    this.scriptId = scriptId;
+    this.lineNumber = lineNumber;
+    this.columnNumber = columnNumber;
+}
+
+WebInspector.DebuggerModel.Events = {
+    DebuggerWasEnabled: "DebuggerWasEnabled",
+    DebuggerWasDisabled: "DebuggerWasDisabled",
+    DebuggerPaused: "DebuggerPaused",
+    DebuggerResumed: "DebuggerResumed",
+    ParsedScriptSource: "ParsedScriptSource",
+    FailedToParseScriptSource: "FailedToParseScriptSource",
+    BreakpointResolved: "BreakpointResolved",
+    GlobalObjectCleared: "GlobalObjectCleared",
+    CallFrameSelected: "CallFrameSelected",
+    ConsoleCommandEvaluatedInSelectedCallFrame: "ConsoleCommandEvaluatedInSelectedCallFrame",
+    BreakpointsActiveStateChanged: "BreakpointsActiveStateChanged"
+}
+
+WebInspector.DebuggerModel.BreakReason = {
+    DOM: "DOM",
+    EventListener: "EventListener",
+    XHR: "XHR",
+    Exception: "exception",
+    Assert: "assert",
+    CSPViolation: "CSPViolation",
+    DebugCommand: "debugCommand"
+}
+
+WebInspector.DebuggerModel.prototype = {
+    /**
+     * @return {boolean}
+     */
+    debuggerEnabled: function()
+    {
+        return !!this._debuggerEnabled;
+    },
+
+    enableDebugger: function()
+    {
+        if (this._debuggerEnabled)
+            return;
+
+        function callback(error, result)
+        {
+            this._canSetScriptSource = result;
+        }
+        DebuggerAgent.canSetScriptSource(callback.bind(this));
+        DebuggerAgent.enable(this._debuggerWasEnabled.bind(this));
+    },
+
+    disableDebugger: function()
+    {
+        if (!this._debuggerEnabled)
+            return;
+
+        DebuggerAgent.disable(this._debuggerWasDisabled.bind(this));
+    },
+
+    /**
+     * @return {boolean}
+     */
+    canSetScriptSource: function()
+    {
+        return this._canSetScriptSource;
+    },
+
+    _debuggerWasEnabled: function()
+    {
+        this._debuggerEnabled = true;
+        this._pauseOnExceptionStateChanged();
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasEnabled);
+    },
+
+    _pauseOnExceptionStateChanged: function()
+    {
+        DebuggerAgent.setPauseOnExceptions(WebInspector.settings.pauseOnExceptionStateString.get());
+    },
+
+    _debuggerWasDisabled: function()
+    {
+        this._debuggerEnabled = false;
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerWasDisabled);
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     */
+    continueToLocation: function(rawLocation)
+    {
+        DebuggerAgent.continueToLocation(rawLocation);
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     */
+    stepIntoSelection: function(rawLocation)
+    {
+        /**
+         * @param {WebInspector.DebuggerModel.Location} requestedLocation
+         * @param {?string} error
+         */
+        function callback(requestedLocation, error)
+        {
+           if (error)
+               return;
+           this._pendingStepIntoLocation = requestedLocation;
+        };
+        DebuggerAgent.continueToLocation(rawLocation, true, callback.bind(this, rawLocation));
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     * @param {string} condition
+     * @param {function(?DebuggerAgent.BreakpointId, Array.):void=} callback
+     */
+    setBreakpointByScriptLocation: function(rawLocation, condition, callback)
+    {
+        var script = this.scriptForId(rawLocation.scriptId);
+        if (script.sourceURL)
+            this.setBreakpointByURL(script.sourceURL, rawLocation.lineNumber, rawLocation.columnNumber, condition, callback);
+        else
+            this.setBreakpointBySourceId(rawLocation, condition, callback);
+    },
+
+    /**
+     * @param {string} url
+     * @param {number} lineNumber
+     * @param {number=} columnNumber
+     * @param {string=} condition
+     * @param {function(?DebuggerAgent.BreakpointId, Array.)=} callback
+     */
+    setBreakpointByURL: function(url, lineNumber, columnNumber, condition, callback)
+    {
+        // Adjust column if needed.
+        var minColumnNumber = 0;
+        var scripts = this._scriptsBySourceURL[url] || [];
+        for (var i = 0, l = scripts.length; i < l; ++i) {
+            var script = scripts[i];
+            if (lineNumber === script.lineOffset)
+                minColumnNumber = minColumnNumber ? Math.min(minColumnNumber, script.columnOffset) : script.columnOffset;
+        }
+        columnNumber = Math.max(columnNumber, minColumnNumber);
+
+        /**
+         * @this {WebInspector.DebuggerModel}
+         * @param {?Protocol.Error} error
+         * @param {DebuggerAgent.BreakpointId} breakpointId
+         * @param {Array.} locations
+         */
+        function didSetBreakpoint(error, breakpointId, locations)
+        {
+            if (callback) {
+                var rawLocations = /** @type {Array.} */ (locations);
+                callback(error ? null : breakpointId, rawLocations);
+            }
+        }
+        DebuggerAgent.setBreakpointByUrl(lineNumber, url, undefined, columnNumber, condition, undefined, didSetBreakpoint.bind(this));
+        WebInspector.userMetrics.ScriptsBreakpointSet.record();
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     * @param {string} condition
+     * @param {function(?DebuggerAgent.BreakpointId, Array.)=} callback
+     */
+    setBreakpointBySourceId: function(rawLocation, condition, callback)
+    {
+        /**
+         * @this {WebInspector.DebuggerModel}
+         * @param {?Protocol.Error} error
+         * @param {DebuggerAgent.BreakpointId} breakpointId
+         * @param {DebuggerAgent.Location} actualLocation
+         */
+        function didSetBreakpoint(error, breakpointId, actualLocation)
+        {
+            if (callback) {
+                var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (actualLocation);
+                callback(error ? null : breakpointId, [rawLocation]);
+            }
+        }
+        DebuggerAgent.setBreakpoint(rawLocation, condition, didSetBreakpoint.bind(this));
+        WebInspector.userMetrics.ScriptsBreakpointSet.record();
+    },
+
+    /**
+     * @param {DebuggerAgent.BreakpointId} breakpointId
+     * @param {function(?Protocol.Error)=} callback
+     */
+    removeBreakpoint: function(breakpointId, callback)
+    {
+        DebuggerAgent.removeBreakpoint(breakpointId, callback);
+    },
+
+    /**
+     * @param {DebuggerAgent.BreakpointId} breakpointId
+     * @param {DebuggerAgent.Location} location
+     */
+    _breakpointResolved: function(breakpointId, location)
+    {
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointResolved, {breakpointId: breakpointId, location: location});
+    },
+
+    _globalObjectCleared: function()
+    {
+        this._setDebuggerPausedDetails(null);
+        this._reset();
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.GlobalObjectCleared);
+    },
+
+    _reset: function()
+    {
+        this._scripts = {};
+        this._scriptsBySourceURL = {};
+    },
+
+    /**
+     * @return {Object.}
+     */
+    get scripts()
+    {
+        return this._scripts;
+    },
+
+    /**
+     * @param {DebuggerAgent.ScriptId} scriptId
+     * @return {WebInspector.Script}
+     */
+    scriptForId: function(scriptId)
+    {
+        return this._scripts[scriptId] || null;
+    },
+
+    /**
+     * @return {!Array.}
+     */
+    scriptsForSourceURL: function(sourceURL)
+    {
+        if (!sourceURL)
+            return [];
+        return this._scriptsBySourceURL[sourceURL] || [];
+    },
+
+    /**
+     * @param {DebuggerAgent.ScriptId} scriptId
+     * @param {string} newSource
+     * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
+     */
+    setScriptSource: function(scriptId, newSource, callback)
+    {
+        this._scripts[scriptId].editSource(newSource, this._didEditScriptSource.bind(this, scriptId, newSource, callback));
+    },
+
+    /**
+     * @param {DebuggerAgent.ScriptId} scriptId
+     * @param {string} newSource
+     * @param {function(?Protocol.Error, DebuggerAgent.SetScriptSourceError=)} callback
+     * @param {?Protocol.Error} error
+     * @param {DebuggerAgent.SetScriptSourceError=} errorData
+     * @param {Array.=} callFrames
+     * @param {boolean=} needsStepIn
+     */
+    _didEditScriptSource: function(scriptId, newSource, callback, error, errorData, callFrames, needsStepIn)
+    {
+        callback(error, errorData);
+        if (needsStepIn)
+            DebuggerAgent.stepInto();
+        else if (!error && callFrames && callFrames.length)
+            this._pausedScript(callFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
+    },
+
+    /**
+     * @return {Array.}
+     */
+    get callFrames()
+    {
+        return this._debuggerPausedDetails ? this._debuggerPausedDetails.callFrames : null;
+    },
+
+    /**
+     * @return {?WebInspector.DebuggerPausedDetails}
+     */
+    debuggerPausedDetails: function()
+    {
+        return this._debuggerPausedDetails;
+    },
+
+    /**
+     * @param {?WebInspector.DebuggerPausedDetails} debuggerPausedDetails
+     */
+    _setDebuggerPausedDetails: function(debuggerPausedDetails)
+    {
+        if (this._debuggerPausedDetails)
+            this._debuggerPausedDetails.dispose();
+        this._debuggerPausedDetails = debuggerPausedDetails;
+        if (this._debuggerPausedDetails)
+            this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPausedDetails);
+        if (debuggerPausedDetails) {
+            this.setSelectedCallFrame(debuggerPausedDetails.callFrames[0]);
+            DebuggerAgent.setOverlayMessage(WebInspector.UIString("Paused in debugger"));
+        } else {
+            this.setSelectedCallFrame(null);
+            DebuggerAgent.setOverlayMessage();
+        }
+    },
+
+    /**
+     * @param {Array.} callFrames
+     * @param {string} reason
+     * @param {Object|undefined} auxData
+     * @param {Array.} breakpointIds
+     */
+    _pausedScript: function(callFrames, reason, auxData, breakpointIds)
+    {
+        if (this._pendingStepIntoLocation) {
+            var requestedLocation = this._pendingStepIntoLocation;
+            delete this._pendingStepIntoLocation;
+
+            if (callFrames.length > 0) {
+                var topLocation = callFrames[0].location;
+                if (topLocation.lineNumber == requestedLocation.lineNumber && topLocation.columnNumber == requestedLocation.columnNumber && topLocation.scriptId == requestedLocation.scriptId) {
+                    DebuggerAgent.stepInto();
+                    return;
+                }
+            }
+        }
+
+        this._setDebuggerPausedDetails(new WebInspector.DebuggerPausedDetails(this, callFrames, reason, auxData, breakpointIds));
+    },
+
+    _resumedScript: function()
+    {
+        this._setDebuggerPausedDetails(null);
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed);
+    },
+
+    /**
+     * @param {DebuggerAgent.ScriptId} scriptId
+     * @param {string} sourceURL
+     * @param {number} startLine
+     * @param {number} startColumn
+     * @param {number} endLine
+     * @param {number} endColumn
+     * @param {boolean} isContentScript
+     * @param {string=} sourceMapURL
+     * @param {boolean=} hasSourceURL
+     */
+    _parsedScriptSource: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
+    {
+        var script = new WebInspector.Script(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL);
+        this._registerScript(script);
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, script);
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     */
+    _registerScript: function(script)
+    {
+        this._scripts[script.scriptId] = script;
+        if (script.isAnonymousScript())
+            return;
+
+        var scripts = this._scriptsBySourceURL[script.sourceURL];
+        if (!scripts) {
+            scripts = [];
+            this._scriptsBySourceURL[script.sourceURL] = scripts;
+        }
+        scripts.push(script);
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    createRawLocation: function(script, lineNumber, columnNumber)
+    {
+        if (script.sourceURL)
+            return this.createRawLocationByURL(script.sourceURL, lineNumber, columnNumber)
+        return new WebInspector.DebuggerModel.Location(script.scriptId, lineNumber, columnNumber);
+    },
+
+    /**
+     * @param {string} sourceURL
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    createRawLocationByURL: function(sourceURL, lineNumber, columnNumber)
+    {
+        var closestScript = null;
+        var scripts = this._scriptsBySourceURL[sourceURL] || [];
+        for (var i = 0, l = scripts.length; i < l; ++i) {
+            var script = scripts[i];
+            if (!closestScript)
+                closestScript = script;
+            if (script.lineOffset > lineNumber || (script.lineOffset === lineNumber && script.columnOffset > columnNumber))
+                continue;
+            if (script.endLine < lineNumber || (script.endLine === lineNumber && script.endColumn <= columnNumber))
+                continue;
+            closestScript = script;
+            break;
+        }
+        return closestScript ? new WebInspector.DebuggerModel.Location(closestScript.scriptId, lineNumber, columnNumber) : null;
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isPaused: function()
+    {
+        return !!this.debuggerPausedDetails();
+    },
+
+    /**
+     * @param {?WebInspector.DebuggerModel.CallFrame} callFrame
+     */
+    setSelectedCallFrame: function(callFrame)
+    {
+        this._selectedCallFrame = callFrame;
+        if (!this._selectedCallFrame)
+            return;
+
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.CallFrameSelected, callFrame);
+    },
+
+    /**
+     * @return {?WebInspector.DebuggerModel.CallFrame}
+     */
+    selectedCallFrame: function()
+    {
+        return this._selectedCallFrame;
+    },
+
+    /**
+     * @param {string} code
+     * @param {string} objectGroup
+     * @param {boolean} includeCommandLineAPI
+     * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
+     * @param {boolean} returnByValue
+     * @param {boolean} generatePreview
+     * @param {function(?WebInspector.RemoteObject, boolean, RuntimeAgent.RemoteObject=)} callback
+     */
+    evaluateOnSelectedCallFrame: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
+    {
+        /**
+         * @param {?RuntimeAgent.RemoteObject} result
+         * @param {boolean=} wasThrown
+         */
+        function didEvaluate(result, wasThrown)
+        {
+            if (returnByValue)
+                callback(null, !!wasThrown, wasThrown ? null : result);
+            else
+                callback(WebInspector.RemoteObject.fromPayload(result), !!wasThrown);
+
+            if (objectGroup === "console")
+                this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ConsoleCommandEvaluatedInSelectedCallFrame);
+        }
+
+        this.selectedCallFrame().evaluate(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluate.bind(this));
+    },
+
+    /**
+     * @param {function(Object)} callback
+     */
+    getSelectedCallFrameVariables: function(callback)
+    {
+        var result = { this: true };
+
+        var selectedCallFrame = this._selectedCallFrame;
+        if (!selectedCallFrame)
+            callback(result);
+
+        var pendingRequests = 0;
+
+        function propertiesCollected(properties)
+        {
+            for (var i = 0; properties && i < properties.length; ++i)
+                result[properties[i].name] = true;
+            if (--pendingRequests == 0)
+                callback(result);
+        }
+
+        for (var i = 0; i < selectedCallFrame.scopeChain.length; ++i) {
+            var scope = selectedCallFrame.scopeChain[i];
+            var object = WebInspector.RemoteObject.fromPayload(scope.object);
+            pendingRequests++;
+            object.getAllProperties(false, propertiesCollected);
+        }
+    },
+
+    /**
+     * @param {boolean} active
+     */
+    setBreakpointsActive: function(active)
+    {
+        if (this._breakpointsActive === active)
+            return;
+        this._breakpointsActive = active;
+        DebuggerAgent.setBreakpointsActive(active);
+        this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointsActiveStateChanged, active);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    breakpointsActive: function()
+    {
+        return this._breakpointsActive;
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
+     * @return {WebInspector.Script.Location}
+     */
+    createLiveLocation: function(rawLocation, updateDelegate)
+    {
+        var script = this._scripts[rawLocation.scriptId];
+        return script.createLiveLocation(rawLocation, updateDelegate);
+    },
+
+    /**
+     * @param {WebInspector.DebuggerModel.Location} rawLocation
+     * @return {?WebInspector.UILocation}
+     */
+    rawLocationToUILocation: function(rawLocation)
+    {
+        var script = this._scripts[rawLocation.scriptId];
+        if (!script)
+            return null;
+        return script.rawLocationToUILocation(rawLocation.lineNumber, rawLocation.columnNumber);
+    },
+
+    /**
+     * Handles notification from JavaScript VM about updated stack (liveedit or frame restart action).
+     * @this {WebInspector.DebuggerModel}
+     * @param {Array.=} newCallFrames
+     * @param {Object=} details
+     */
+    callStackModified: function(newCallFrames, details)
+    {
+        // FIXME: declare this property in protocol and in JavaScript.
+        if (details && details["stack_update_needs_step_in"])
+            DebuggerAgent.stepInto();
+        else {
+            if (newCallFrames && newCallFrames.length)
+                this._pausedScript(newCallFrames, this._debuggerPausedDetails.reason, this._debuggerPausedDetails.auxData, this._debuggerPausedDetails.breakpointIds);
+
+        }
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+WebInspector.DebuggerModel.applySkipStackFrameSettings = function()
+{
+    if (!WebInspector.experimentsSettings.frameworksDebuggingSupport.isEnabled())
+        return;
+    var settings = WebInspector.settings;
+    var patternParameter = settings.skipStackFramesSwitch.get() ? settings.skipStackFramesPattern.get() : undefined;
+    DebuggerAgent.skipStackFrames(patternParameter);
+}
+
+WebInspector.DebuggerEventTypes = {
+    JavaScriptPause: 0,
+    JavaScriptBreakpoint: 1,
+    NativeBreakpoint: 2
+};
+
+/**
+ * @constructor
+ * @implements {DebuggerAgent.Dispatcher}
+ * @param {WebInspector.DebuggerModel} debuggerModel
+ */
+WebInspector.DebuggerDispatcher = function(debuggerModel)
+{
+    this._debuggerModel = debuggerModel;
+}
+
+WebInspector.DebuggerDispatcher.prototype = {
+    /**
+     * @param {Array.} callFrames
+     * @param {string} reason
+     * @param {Object=} auxData
+     * @param {Array.=} breakpointIds
+     */
+    paused: function(callFrames, reason, auxData, breakpointIds)
+    {
+        this._debuggerModel._pausedScript(callFrames, reason, auxData, breakpointIds || []);
+    },
+
+    resumed: function()
+    {
+        this._debuggerModel._resumedScript();
+    },
+
+    globalObjectCleared: function()
+    {
+        this._debuggerModel._globalObjectCleared();
+    },
+
+    /**
+     * @param {DebuggerAgent.ScriptId} scriptId
+     * @param {string} sourceURL
+     * @param {number} startLine
+     * @param {number} startColumn
+     * @param {number} endLine
+     * @param {number} endColumn
+     * @param {boolean=} isContentScript
+     * @param {string=} sourceMapURL
+     * @param {boolean=} hasSourceURL
+     */
+    scriptParsed: function(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, isContentScript, sourceMapURL, hasSourceURL)
+    {
+        this._debuggerModel._parsedScriptSource(scriptId, sourceURL, startLine, startColumn, endLine, endColumn, !!isContentScript, sourceMapURL, hasSourceURL);
+    },
+
+    /**
+     * @param {string} sourceURL
+     * @param {string} source
+     * @param {number} startingLine
+     * @param {number} errorLine
+     * @param {string} errorMessage
+     */
+    scriptFailedToParse: function(sourceURL, source, startingLine, errorLine, errorMessage)
+    {
+    },
+
+    /**
+    * @param {DebuggerAgent.BreakpointId} breakpointId
+    * @param {DebuggerAgent.Location} location
+     */
+    breakpointResolved: function(breakpointId, location)
+    {
+        this._debuggerModel._breakpointResolved(breakpointId, location);
+    }
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.Script} script
+ * @param {DebuggerAgent.CallFrame} payload
+ */
+WebInspector.DebuggerModel.CallFrame = function(script, payload)
+{
+    this._script = script;
+    this._payload = payload;
+    this._locations = [];
+}
+
+WebInspector.DebuggerModel.CallFrame.prototype = {
+    /**
+     * @return {WebInspector.Script}
+     */
+    get script()
+    {
+        return this._script;
+    },
+
+    /**
+     * @return {string}
+     */
+    get type()
+    {
+        return this._payload.type;
+    },
+
+    /**
+     * @return {string}
+     */
+    get id()
+    {
+        return this._payload.callFrameId;
+    },
+
+    /**
+     * @return {Array.}
+     */
+    get scopeChain()
+    {
+        return this._payload.scopeChain;
+    },
+
+    /**
+     * @return {RuntimeAgent.RemoteObject}
+     */
+    get this()
+    {
+        return this._payload.this;
+    },
+
+    /**
+     * @return {string}
+     */
+    get functionName()
+    {
+        return this._payload.functionName;
+    },
+
+    /**
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    get location()
+    {
+        var rawLocation = /** @type {WebInspector.DebuggerModel.Location} */ (this._payload.location);
+        return rawLocation;
+    },
+
+    /**
+     * @param {string} code
+     * @param {string} objectGroup
+     * @param {boolean} includeCommandLineAPI
+     * @param {boolean} doNotPauseOnExceptionsAndMuteConsole
+     * @param {boolean} returnByValue
+     * @param {boolean} generatePreview
+     * @param {function(?RuntimeAgent.RemoteObject, boolean=)=} callback
+     */
+    evaluate: function(code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, callback)
+    {
+        /**
+         * @this {WebInspector.DebuggerModel.CallFrame}
+         * @param {?Protocol.Error} error
+         * @param {RuntimeAgent.RemoteObject} result
+         * @param {boolean=} wasThrown
+         */
+        function didEvaluateOnCallFrame(error, result, wasThrown)
+        {
+            if (error) {
+                console.error(error);
+                callback(null, false);
+                return;
+            }
+            callback(result, wasThrown);
+        }
+        DebuggerAgent.evaluateOnCallFrame(this._payload.callFrameId, code, objectGroup, includeCommandLineAPI, doNotPauseOnExceptionsAndMuteConsole, returnByValue, generatePreview, didEvaluateOnCallFrame.bind(this));
+    },
+
+    /**
+     * @param {function(?Protocol.Error=)=} callback
+     */
+    restart: function(callback)
+    {
+        /**
+         * @this {WebInspector.DebuggerModel.CallFrame}
+         * @param {?Protocol.Error} error
+         * @param {Array.=} callFrames
+         * @param {Object=} details
+         */
+        function protocolCallback(error, callFrames, details)
+        {
+            if (!error)
+                WebInspector.debuggerModel.callStackModified(callFrames, details);
+            if (callback)
+                callback(error);
+        }
+        DebuggerAgent.restartFrame(this._payload.callFrameId, protocolCallback);
+    },
+
+    /**
+     * @param {function(Array.)} callback
+     */
+    getStepIntoLocations: function(callback)
+    {
+        if (this._stepInLocations) {
+            callback(this._stepInLocations.slice(0));
+            return;
+        }
+        /**
+         * @param {?string} error
+         * @param {Array.=} stepInPositions
+         */
+        function getStepInPositionsCallback(error, stepInPositions) {
+            if (error) {
+                return;
+            }
+            this._stepInLocations = stepInPositions;
+            callback(this._stepInLocations.slice(0));
+        }
+        DebuggerAgent.getStepInPositions(this.id, getStepInPositionsCallback.bind(this));
+    },
+
+    /**
+     * @param {function(WebInspector.UILocation):(boolean|undefined)} updateDelegate
+     */
+    createLiveLocation: function(updateDelegate)
+    {
+        var location = this._script.createLiveLocation(this.location, updateDelegate);
+        this._locations.push(location);
+        return location;
+    },
+
+    dispose: function(updateDelegate)
+    {
+        for (var i = 0; i < this._locations.length; ++i)
+            this._locations[i].dispose();
+        this._locations = [];
+    }
+}
+
+/**
+ * @constructor
+ * @param {WebInspector.DebuggerModel} model
+ * @param {Array.} callFrames
+ * @param {string} reason
+ * @param {Object|undefined} auxData
+ * @param {Array.} breakpointIds
+ */
+WebInspector.DebuggerPausedDetails = function(model, callFrames, reason, auxData, breakpointIds)
+{
+    this.callFrames = [];
+    for (var i = 0; i < callFrames.length; ++i) {
+        var callFrame = callFrames[i];
+        var script = model.scriptForId(callFrame.location.scriptId);
+        if (script)
+            this.callFrames.push(new WebInspector.DebuggerModel.CallFrame(script, callFrame));
+    }
+    this.reason = reason;
+    this.auxData = auxData;
+    this.breakpointIds = breakpointIds;
+}
+
+WebInspector.DebuggerPausedDetails.prototype = {
+    dispose: function()
+    {
+        for (var i = 0; i < this.callFrames.length; ++i) {
+            var callFrame = this.callFrames[i];
+            callFrame.dispose();
+        }
+    }
+}
+
+/**
+ * @type {?WebInspector.DebuggerModel}
+ */
+WebInspector.debuggerModel = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerScriptMapping.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerScriptMapping.js
new file mode 100644
index 00000000..f731b1f6
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DebuggerScriptMapping.js
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {WebInspector.Workspace} workspace
+ * @param {WebInspector.SimpleWorkspaceProvider} networkWorkspaceProvider
+ */
+WebInspector.DebuggerScriptMapping = function(workspace, networkWorkspaceProvider)
+{
+    this._defaultMapping = new WebInspector.DefaultScriptMapping(workspace);
+    this._resourceMapping = new WebInspector.ResourceScriptMapping(workspace);
+    this._compilerMapping = new WebInspector.CompilerScriptMapping(workspace, networkWorkspaceProvider);
+    this._snippetMapping = WebInspector.scriptSnippetModel.scriptMapping;
+
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this);
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this);
+}
+
+WebInspector.DebuggerScriptMapping.prototype = {
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _parsedScriptSource: function(event)
+    {
+        var script = /** @type {WebInspector.Script} */ (event.data);
+        this._defaultMapping.addScript(script);
+
+        if (script.isSnippet()) {
+            this._snippetMapping.addScript(script);
+            return;
+        }
+
+        this._resourceMapping.addScript(script);
+
+        if (WebInspector.settings.jsSourceMapsEnabled.get())
+            this._compilerMapping.addScript(script);
+    }
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DefaultScriptMapping.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DefaultScriptMapping.js
new file mode 100644
index 00000000..f0015e89
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DefaultScriptMapping.js
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @implements {WebInspector.ScriptSourceMapping}
+ * @param {WebInspector.Workspace} workspace
+ */
+WebInspector.DefaultScriptMapping = function(workspace)
+{
+    this._projectDelegate = new WebInspector.DebuggerProjectDelegate();
+    this._workspace = workspace;
+    this._workspace.addProject(this._projectDelegate);
+    WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.GlobalObjectCleared, this._debuggerReset, this);
+    this._debuggerReset();
+}
+
+WebInspector.DefaultScriptMapping.prototype = {
+    /**
+     * @param {WebInspector.RawLocation} rawLocation
+     * @return {WebInspector.UILocation}
+     */
+    rawLocationToUILocation: function(rawLocation)
+    {
+        var debuggerModelLocation = /** @type {WebInspector.DebuggerModel.Location} */ (rawLocation);
+        var script = WebInspector.debuggerModel.scriptForId(debuggerModelLocation.scriptId);
+        var uiSourceCode = this._uiSourceCodeForScriptId[script.scriptId];
+        var lineNumber = debuggerModelLocation.lineNumber;
+        var columnNumber = debuggerModelLocation.columnNumber || 0;
+        return new WebInspector.UILocation(uiSourceCode, lineNumber, columnNumber);
+    },
+
+    /**
+     * @param {WebInspector.UISourceCode} uiSourceCode
+     * @param {number} lineNumber
+     * @param {number} columnNumber
+     * @return {WebInspector.DebuggerModel.Location}
+     */
+    uiLocationToRawLocation: function(uiSourceCode, lineNumber, columnNumber)
+    {
+        var scriptId = this._scriptIdForUISourceCode.get(uiSourceCode);
+        var script = WebInspector.debuggerModel.scriptForId(scriptId);
+        return WebInspector.debuggerModel.createRawLocation(script, lineNumber, columnNumber);
+    },
+
+    /**
+     * @return {boolean}
+     */
+    isIdentity: function()
+    {
+        return true;
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     */
+    addScript: function(script)
+    {
+        var path = this._projectDelegate.addScript(script);
+        var uiSourceCode = this._workspace.uiSourceCode(this._projectDelegate.id(), path);
+        this._uiSourceCodeForScriptId[script.scriptId] = uiSourceCode;
+        this._scriptIdForUISourceCode.put(uiSourceCode, script.scriptId);
+        uiSourceCode.setSourceMapping(this);
+        script.pushSourceMapping(this);
+        script.addEventListener(WebInspector.Script.Events.ScriptEdited, this._scriptEdited.bind(this, script.scriptId));
+        return uiSourceCode;
+    },
+
+    /**
+     * @param {string} scriptId
+     * @param {WebInspector.Event} event
+     */
+    _scriptEdited: function(scriptId, event)
+    {
+        var content = /** @type {string} */(event.data);
+        this._uiSourceCodeForScriptId[scriptId].addRevision(content);
+    },
+
+    _debuggerReset: function()
+    {
+        /** @type {Object.} */
+        this._uiSourceCodeForScriptId = {};
+        this._scriptIdForUISourceCode = new Map();
+        this._projectDelegate.reset();
+    }
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.ContentProviderBasedProjectDelegate}
+ */
+WebInspector.DebuggerProjectDelegate = function()
+{
+    WebInspector.ContentProviderBasedProjectDelegate.call(this, WebInspector.projectTypes.Debugger);
+}
+
+WebInspector.DebuggerProjectDelegate.prototype = {
+    /**
+     * @return {string}
+     */
+    id: function()
+    {
+        return "debugger:";
+    },
+
+    /**
+     * @return {string}
+     */
+    displayName: function()
+    {
+        return "debugger";
+    },
+
+    /**
+     * @param {WebInspector.Script} script
+     * @return {string}
+     */
+    addScript: function(script)
+    {
+        var contentProvider = script.isInlineScript() ? new WebInspector.ConcatenatedScriptsContentProvider([script]) : script;
+        var splitURL = WebInspector.ParsedURL.splitURL(script.sourceURL);
+        var name = splitURL[splitURL.length - 1];
+        name = "[VM] " + name + " (" + script.scriptId + ")";
+        return this.addContentProvider("", name, script.sourceURL, contentProvider, false, script.isContentScript);
+    },
+    
+    __proto__: WebInspector.ContentProviderBasedProjectDelegate.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DevToolsExtensionAPI.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DevToolsExtensionAPI.js
new file mode 100644
index 00000000..44f7c218
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DevToolsExtensionAPI.js
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function platformExtensionAPI(coreAPI)
+{
+    function getTabId()
+    {
+        return tabId;
+    }
+    chrome = window.chrome || {};
+    // Override chrome.devtools as a workaround for a error-throwing getter being exposed
+    // in extension pages loaded into a non-extension process (only happens for remote client
+    // extensions)
+    var devtools_descriptor = Object.getOwnPropertyDescriptor(chrome, "devtools");
+    if (!devtools_descriptor || devtools_descriptor.get)
+        Object.defineProperty(chrome, "devtools", { value: {}, enumerable: true });
+    // Only expose tabId on chrome.devtools.inspectedWindow, not webInspector.inspectedWindow.
+    chrome.devtools.inspectedWindow = {};
+    chrome.devtools.inspectedWindow.__defineGetter__("tabId", getTabId);
+    chrome.devtools.inspectedWindow.__proto__ = coreAPI.inspectedWindow;
+    chrome.devtools.network = coreAPI.network;
+    chrome.devtools.panels = coreAPI.panels;
+
+    // default to expose experimental APIs for now.
+    if (extensionInfo.exposeExperimentalAPIs !== false) {
+        chrome.experimental = chrome.experimental || {};
+        chrome.experimental.devtools = chrome.experimental.devtools || {};
+
+        var properties = Object.getOwnPropertyNames(coreAPI);
+        for (var i = 0; i < properties.length; ++i) {
+            var descriptor = Object.getOwnPropertyDescriptor(coreAPI, properties[i]);
+            Object.defineProperty(chrome.experimental.devtools, properties[i], descriptor);
+        }
+        chrome.experimental.devtools.inspectedWindow = chrome.devtools.inspectedWindow;
+    }
+    if (extensionInfo.exposeWebInspectorNamespace)
+        window.webInspector = coreAPI;
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Dialog.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Dialog.js
new file mode 100644
index 00000000..19300564
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Dialog.js
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @param {Element} relativeToElement
+ * @param {WebInspector.DialogDelegate} delegate
+ */
+WebInspector.Dialog = function(relativeToElement, delegate)
+{
+    this._delegate = delegate;
+    this._relativeToElement = relativeToElement;
+
+    this._glassPane = new WebInspector.GlassPane();
+    // Install glass pane capturing events.
+    this._glassPane.element.tabIndex = 0;
+    this._glassPane.element.addEventListener("focus", this._onGlassPaneFocus.bind(this), false);
+
+    this._element = this._glassPane.element.createChild("div");
+    this._element.tabIndex = 0;
+    this._element.addEventListener("focus", this._onFocus.bind(this), false);
+    this._element.addEventListener("keydown", this._onKeyDown.bind(this), false);
+    this._closeKeys = [
+        WebInspector.KeyboardShortcut.Keys.Enter.code,
+        WebInspector.KeyboardShortcut.Keys.Esc.code,
+    ];
+
+    delegate.show(this._element);
+
+    this._position();
+    this._windowResizeHandler = this._position.bind(this);
+    window.addEventListener("resize", this._windowResizeHandler, true);
+    this._delegate.focus();
+}
+
+/**
+ * @return {WebInspector.Dialog}
+ */
+WebInspector.Dialog.currentInstance = function()
+{
+    return WebInspector.Dialog._instance;
+}
+
+/**
+ * @param {Element} relativeToElement
+ * @param {WebInspector.DialogDelegate} delegate
+ */
+WebInspector.Dialog.show = function(relativeToElement, delegate)
+{
+    if (WebInspector.Dialog._instance)
+        return;
+    WebInspector.Dialog._instance = new WebInspector.Dialog(relativeToElement, delegate);
+}
+
+WebInspector.Dialog.hide = function()
+{
+    if (!WebInspector.Dialog._instance)
+        return;
+    WebInspector.Dialog._instance._hide();
+}
+
+WebInspector.Dialog.prototype = {
+    _hide: function()
+    {
+        if (this._isHiding)
+            return;
+        this._isHiding = true;
+
+        this._delegate.willHide();
+
+        delete WebInspector.Dialog._instance;
+        this._glassPane.dispose();
+        window.removeEventListener("resize", this._windowResizeHandler, true);
+    },
+
+    _onGlassPaneFocus: function(event)
+    {
+        this._hide();
+    },
+
+    _onFocus: function(event)
+    {
+        this._delegate.focus();
+    },
+
+    _position: function()
+    {
+        this._delegate.position(this._element, this._relativeToElement);
+    },
+
+    _onKeyDown: function(event)
+    {
+        if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Tab.code) {
+            event.preventDefault();
+            return;
+        }
+
+        if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Enter.code)
+            this._delegate.onEnter();
+
+        if (this._closeKeys.indexOf(event.keyCode) >= 0) {
+            this._hide();
+            event.consume(true);
+        }
+    }
+};
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.DialogDelegate = function()
+{
+}
+
+WebInspector.DialogDelegate.prototype = {
+    /**
+     * @param {Element} element
+     */
+    show: function(element)
+    {
+        element.appendChild(this.element);
+        this.element.addStyleClass("dialog-contents");
+        element.addStyleClass("dialog");    
+    },
+
+    /**
+     * @param {Element} element
+     * @param {Element} relativeToElement
+     */
+    position: function(element, relativeToElement)
+    {
+        var offset = relativeToElement.offsetRelativeToWindow(window);
+
+        var positionX = offset.x + (relativeToElement.offsetWidth - element.offsetWidth) / 2;
+        positionX = Number.constrain(positionX, 0, window.innerWidth - element.offsetWidth);
+
+        var positionY = offset.y + (relativeToElement.offsetHeight - element.offsetHeight) / 2;
+        positionY = Number.constrain(positionY, 0, window.innerHeight - element.offsetHeight);
+
+        element.style.left = positionX + "px";
+        element.style.top = positionY + "px";
+    },
+
+    focus: function() { },
+
+    onEnter: function() { },
+
+    willHide: function() { },
+
+    __proto__: WebInspector.Object.prototype
+}
+
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DirectoryContentView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DirectoryContentView.js
new file mode 100644
index 00000000..abd969aa
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DirectoryContentView.js
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.DataGrid}
+ */
+WebInspector.DirectoryContentView = function()
+{
+    const indexes = WebInspector.DirectoryContentView.columnIndexes;
+    var columns = [
+        {id: indexes.Name, title: WebInspector.UIString("Name"), sortable: true, sort: WebInspector.DataGrid.Order.Ascending, width: "20%"},
+        {id: indexes.URL, title: WebInspector.UIString("URL"), sortable: true, width: "20%"},
+        {id: indexes.Type, title: WebInspector.UIString("Type"), sortable: true, width: "15%"},
+        {id: indexes.Size, title: WebInspector.UIString("Size"), sortable: true, width: "10%"},
+        {id: indexes.ModificationTime, title: WebInspector.UIString("Modification Time"), sortable: true, width: "25%"}
+    ];
+
+    WebInspector.DataGrid.call(this, columns);
+    this.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this._sort, this);
+}
+
+WebInspector.DirectoryContentView.columnIndexes = {
+    Name: "0",
+    URL: "1",
+    Type: "2",
+    Size: "3",
+    ModificationTime: "4"
+}
+
+WebInspector.DirectoryContentView.prototype = {
+    /**
+     * @param {Array.} entries
+     */
+    showEntries: function(entries)
+    {
+        const indexes = WebInspector.DirectoryContentView.columnIndexes;
+        this.rootNode().removeChildren();
+        for (var i = 0; i < entries.length; ++i)
+            this.rootNode().appendChild(new WebInspector.DirectoryContentView.Node(entries[i]));
+    },
+
+    _sort: function()
+    {
+        var column = /** @type {string} */ (this.sortColumnIdentifier());
+        this.sortNodes(WebInspector.DirectoryContentView.Node.comparator(column, !this.isSortOrderAscending()), false);
+    },
+
+    __proto__: WebInspector.DataGrid.prototype
+}
+
+/**
+ * @constructor
+ * @extends {WebInspector.DataGridNode}
+ * @param {WebInspector.FileSystemModel.Entry} entry
+ */
+WebInspector.DirectoryContentView.Node = function(entry)
+{
+    const indexes = WebInspector.DirectoryContentView.columnIndexes;
+    var data = {};
+    data[indexes.Name] = entry.name;
+    data[indexes.URL] = entry.url;
+    data[indexes.Type] = entry.isDirectory ? WebInspector.UIString("Directory") : entry.mimeType;
+    data[indexes.Size] = "";
+    data[indexes.ModificationTime] = "";
+
+    WebInspector.DataGridNode.call(this, data);
+    this._entry = entry;
+    this._metadata = null;
+
+    this._entry.requestMetadata(this._metadataReceived.bind(this));
+}
+
+/**
+ * @param {string} column
+ * @param {boolean} reverse
+ */
+WebInspector.DirectoryContentView.Node.comparator = function(column, reverse)
+{
+    var reverseFactor = reverse ? -1 : 1;
+    const indexes = WebInspector.DirectoryContentView.columnIndexes;
+
+    switch (column) {
+    case indexes.Name:
+    case indexes.URL:
+        return function(x, y)
+        {
+            return isDirectoryCompare(x, y) || nameCompare(x, y);
+        };
+    case indexes.Type:
+        return function(x, y)
+        {
+            return isDirectoryCompare(x ,y) || typeCompare(x, y) || nameCompare(x, y);
+        };
+    case indexes.Size:
+        return function(x, y)
+        {
+            return isDirectoryCompare(x, y) || sizeCompare(x, y) || nameCompare(x, y);
+        };
+    case indexes.ModificationTime:
+        return function(x, y)
+        {
+            return isDirectoryCompare(x, y) || modificationTimeCompare(x, y) || nameCompare(x, y);
+        };
+    }
+
+    function isDirectoryCompare(x, y)
+    {
+        if (x._entry.isDirectory != y._entry.isDirectory)
+            return y._entry.isDirectory ? 1 : -1;
+        return 0;
+    }
+
+    function nameCompare(x, y)
+    {
+        return reverseFactor * x._entry.name.compareTo(y._entry.name);
+    }
+
+    function typeCompare(x, y)
+    {
+        return reverseFactor * (x._entry.mimeType || "").compareTo(y._entry.mimeType || "");
+    }
+
+    function sizeCompare(x, y)
+    {
+        return reverseFactor * ((x._metadata ? x._metadata.size : 0) - (y._metadata ? y._metadata.size : 0));
+    }
+
+    function modificationTimeCompare(x, y)
+    {
+        return reverseFactor * ((x._metadata ? x._metadata.modificationTime : 0) - (y._metadata ? y._metadata.modificationTime : 0));
+    }
+}
+
+WebInspector.DirectoryContentView.Node.prototype = {
+    /**
+     * @param {number} errorCode
+     * @param {FileSystemAgent.Metadata} metadata
+     */
+    _metadataReceived: function(errorCode, metadata)
+    {
+        const indexes = WebInspector.DirectoryContentView.columnIndexes;
+        if (errorCode !== 0)
+            return;
+
+        this._metadata = metadata;
+        var data = this.data;
+        if (this._entry.isDirectory)
+            data[indexes.Size] = WebInspector.UIString("-");
+        else
+            data[indexes.Size] = Number.bytesToString(metadata.size);
+        data[indexes.ModificationTime] = new Date(metadata.modificationTime).toGMTString();
+        this.data = data;
+    },
+
+    __proto__: WebInspector.DataGridNode.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DockController.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DockController.js
new file mode 100644
index 00000000..24e9e3c6
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/DockController.js
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.Object}
+ */
+WebInspector.DockController = function()
+{
+    this._dockToggleButton = new WebInspector.StatusBarButton("", "dock-status-bar-item", 3);
+    this._dockToggleButtonOption = new WebInspector.StatusBarButton("", "dock-status-bar-item", 3);
+    this._dockToggleButton.addEventListener("click", this._toggleDockState, this);
+    this._dockToggleButtonOption.addEventListener("click", this._toggleDockState, this);
+    this._dockToggleButton.setLongClickOptionsEnabled(this._createDockOptions.bind(this));
+
+    this.setDockSide(WebInspector.queryParamsObject["dockSide"] || "bottom");
+}
+
+WebInspector.DockController.State = {
+    DockedToBottom: "bottom",
+    DockedToRight: "right",
+    Undocked: "undocked"
+}
+
+WebInspector.DockController.Events = {
+    DockSideChanged: "DockSideChanged"
+}
+
+WebInspector.DockController.prototype = {
+    /**
+     * @return {Element}
+     */
+    get element()
+    {
+        return this._dockToggleButton.element;
+    },
+
+    /**
+     * @return {string}
+     */
+    dockSide: function()
+    {
+        return this._dockSide;
+    },
+
+    /**
+     * @param {string} dockSide
+     */
+    setDockSide: function(dockSide)
+    {
+        if (this._dockSide === dockSide)
+            return;
+
+        if (this._dockSide)
+            WebInspector.settings.lastDockState.set(this._dockSide);
+
+        this._dockSide = dockSide;
+        if (dockSide === WebInspector.DockController.State.Undocked) 
+            WebInspector.userMetrics.WindowDocked.record();
+        else
+            WebInspector.userMetrics.WindowUndocked.record();
+        this._updateUI();
+        this.dispatchEventToListeners(WebInspector.DockController.Events.DockSideChanged, this._dockSide);
+    },
+
+    /**
+     * @param {boolean} unavailable
+     */
+    setDockingUnavailable: function(unavailable)
+    {
+        this._isDockingUnavailable = unavailable;
+        this._updateUI();
+    },
+
+    _updateUI: function()
+    {
+        var body = document.body;
+        switch (this._dockSide) {
+        case WebInspector.DockController.State.DockedToBottom:
+            body.removeStyleClass("undocked");
+            body.removeStyleClass("dock-to-right");
+            body.addStyleClass("dock-to-bottom");
+            break;
+        case WebInspector.DockController.State.DockedToRight: 
+            body.removeStyleClass("undocked");
+            body.addStyleClass("dock-to-right");
+            body.removeStyleClass("dock-to-bottom");
+            break;
+        case WebInspector.DockController.State.Undocked: 
+            body.addStyleClass("undocked");
+            body.removeStyleClass("dock-to-right");
+            body.removeStyleClass("dock-to-bottom");
+            break;
+        }
+
+        if (this._isDockingUnavailable && this._dockSide === WebInspector.DockController.State.Undocked) {
+            this._dockToggleButton.state = "undock";
+            this._dockToggleButton.setEnabled(false);
+            return;
+        }
+
+        this._dockToggleButton.setEnabled(true);
+
+        // Choose different last state based on the current one if missing or if is the same.
+        var sides = [WebInspector.DockController.State.DockedToBottom, WebInspector.DockController.State.Undocked, WebInspector.DockController.State.DockedToRight];
+        sides.remove(this._dockSide);
+        var lastState = WebInspector.settings.lastDockState.get();
+
+        sides.remove(lastState);
+        if (sides.length === 2) { // last state was not from the list of potential values
+            lastState = sides[0];
+            sides.remove(lastState);
+        }
+        this._decorateButtonForTargetState(this._dockToggleButton, lastState);
+        this._decorateButtonForTargetState(this._dockToggleButtonOption, sides[0]);
+    },
+
+    /**
+     * @param {WebInspector.StatusBarButton} button
+     * @param {string} state
+     */
+    _decorateButtonForTargetState: function(button, state)
+    {
+        switch (state) {
+        case WebInspector.DockController.State.DockedToBottom:
+            button.title = WebInspector.UIString("Dock to main window.");
+            button.state = "bottom";
+            break;
+        case WebInspector.DockController.State.DockedToRight:
+            button.title = WebInspector.UIString("Dock to main window.");
+            button.state = "right";
+            break;
+        case WebInspector.DockController.State.Undocked: 
+            button.title = WebInspector.UIString("Undock into separate window.");
+            button.state = "undock";
+            break;
+        }
+    },
+
+    _createDockOptions: function()
+    {
+        return [this._dockToggleButtonOption];
+    },
+
+    /**
+     * @param {WebInspector.Event} e
+     */
+    _toggleDockState: function(e)
+    {
+        var action;
+        switch (e.target.state) {
+        case "bottom": action = "bottom"; break;
+        case "right": action = "right"; break;
+        case "undock": action = "undocked"; break;
+        }
+        InspectorFrontendHost.requestSetDockSide(action);
+    },
+
+    __proto__: WebInspector.Object.prototype
+}
+
+/**
+ * @type {?WebInspector.DockController}
+ */
+WebInspector.dockController = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Drawer.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Drawer.js
new file mode 100644
index 00000000..5feb75e3
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/Drawer.js
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.Drawer = function()
+{
+    this.element = document.getElementById("drawer");
+    this.element.style.height = 0;
+
+    this._savedHeight = 200; // Default.
+    this._mainElement = document.getElementById("main");
+    this._toolbarElement = document.getElementById("toolbar");
+
+    this._floatingStatusBarContainer = document.getElementById("floating-status-bar-container");
+    WebInspector.installDragHandle(this._floatingStatusBarContainer, this._startStatusBarDragging.bind(this), this._statusBarDragging.bind(this), this._endStatusBarDragging.bind(this), "row-resize");
+
+    this._drawerBodyElement = this.element.createChild("div");
+    this._drawerBodyElement.id = "drawer-body";
+
+    this._drawerContentsElement = this._drawerBodyElement.createChild("div");
+    this._drawerContentsElement.id = "drawer-contents";
+
+    this._footerElementContainer = this._drawerBodyElement.createChild("div", "status-bar hidden");
+    this._footerElementContainer.id = "drawer-footer";
+
+    this._viewStatusBar = document.createElement("div");
+    this._viewStatusBar.style.opacity = 0;
+    this._bottomStatusBar = document.getElementById("bottom-status-bar-container");
+
+    var drawerIsOverlay = WebInspector.experimentsSettings.drawerOverlay.isEnabled();
+    this._elementToAdjust = drawerIsOverlay ? this._floatingStatusBarContainer : this._mainElement;
+
+    document.body.enableStyleClass("drawer-overlay", drawerIsOverlay);
+}
+
+WebInspector.Drawer.AnimationType = {
+    Immediately: 0,
+    Normal: 1,
+    Slow: 2
+}
+
+WebInspector.Drawer.prototype = {
+    get visible()
+    {
+        return !!this._view;
+    },
+
+    _constrainHeight: function(height)
+    {
+        return Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
+    },
+
+    isHiding: function()
+    {
+        return this._isHiding;
+    },
+
+    show: function(view, animationType)
+    {
+        WebInspector.searchController.cancelSearch();
+        this.immediatelyFinishAnimation();
+
+        var drawerWasVisible = this.visible;
+
+        if (this._view) {
+            this._view.detach();
+            this._drawerContentsElement.removeChildren();
+        }
+
+        this._view = view;
+
+        var statusBarItems = this._view.statusBarItems || [];
+        this._viewStatusBar.removeChildren();
+        for (var i = 0; i < statusBarItems.length; ++i)
+            this._viewStatusBar.appendChild(statusBarItems[i]);
+
+        document.body.addStyleClass("drawer-visible");
+        this._floatingStatusBarContainer.insertBefore(document.getElementById("panel-status-bar"), this._floatingStatusBarContainer.firstElementChild);
+        this._bottomStatusBar.appendChild(this._viewStatusBar);
+        this._view.detach();
+        this._view.markAsRoot();
+        this._view.show(this._drawerContentsElement);
+
+        if (drawerWasVisible)
+            return;
+
+        var height = this._constrainHeight(this._savedHeight || this.element.offsetHeight);
+        var animations = [
+            {element: this.element, end: {height: height}},
+            {element: this._floatingStatusBarContainer, start: {"padding-left": this._bottomStatusBar.offsetLeft}, end: {"padding-left": 0}},
+            {element: this._viewStatusBar, start: {opacity: 0}, end: {opacity: 1}},
+            {element: this._elementToAdjust, start: {bottom: 0}, end: {bottom: height}}
+        ];
+
+        function animationCallback(finished)
+        {
+            if (WebInspector.inspectorView.currentPanel())
+                WebInspector.inspectorView.currentPanel().doResize();
+            if (!finished)
+                return;
+            if (this._view && this._view.afterShow)
+                this._view.afterShow();
+            delete this._currentAnimation;
+        }
+
+        this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
+
+        if (animationType === WebInspector.Drawer.AnimationType.Immediately)
+            this._currentAnimation.forceComplete();
+    },
+
+    hide: function(animationType)
+    {
+        WebInspector.searchController.cancelSearch();
+        this.immediatelyFinishAnimation();
+        if (!this.visible)
+            return;
+
+        this._isHiding = true;
+        this._savedHeight = this.element.offsetHeight;
+
+        WebInspector.restoreFocusFromElement(this.element);
+
+        // Temporarily set properties and classes to mimic the post-animation values so panels
+        // like Elements in their updateStatusBarItems call will size things to fit the final location.
+        document.body.removeStyleClass("drawer-visible");
+        WebInspector.inspectorView.currentPanel().statusBarResized();
+        document.body.addStyleClass("drawer-visible");
+
+        var animations = [
+            {element: this.element, end: {height: 0}},
+            {element: this._floatingStatusBarContainer, start: {"padding-left": 0}, end: {"padding-left": this._bottomStatusBar.offsetLeft} },
+            {element: this._viewStatusBar, start: {opacity: 1}, end: {opacity: 0}},
+            {element: this._elementToAdjust, end: {bottom: 0}}
+        ];
+
+        function animationCallback(finished)
+        {
+            if (WebInspector.inspectorView.currentPanel())
+                WebInspector.inspectorView.currentPanel().doResize();
+            if (!finished)
+                return;
+            this._view.detach();
+            delete this._view;
+            this._bottomStatusBar.removeChildren();
+            this._bottomStatusBar.appendChild(document.getElementById("panel-status-bar"));
+            this._drawerContentsElement.removeChildren();
+            document.body.removeStyleClass("drawer-visible");
+            delete this._currentAnimation;
+            this._elementToAdjust.style.bottom = 0;
+            delete this._isHiding;
+        }
+
+        this._currentAnimation = WebInspector.animateStyle(animations, this._animationDuration(animationType), animationCallback.bind(this));
+
+        if (animationType === WebInspector.Drawer.AnimationType.Immediately)
+            this._currentAnimation.forceComplete();
+    },
+
+    resize: function()
+    {
+        if (!this.visible)
+            return;
+
+        this._view.storeScrollPositions();
+        var height = this._constrainHeight(parseInt(this.element.style.height, 10));
+        this._elementToAdjust.style.bottom = height + "px";
+        this.element.style.height = height + "px";
+        this._view.doResize();
+    },
+
+    immediatelyFinishAnimation: function()
+    {
+        if (this._currentAnimation)
+            this._currentAnimation.forceComplete();
+    },
+
+    _animationDuration: function(animationType)
+    {
+        switch (animationType) {
+        case WebInspector.Drawer.AnimationType.Slow:
+            return 2000;
+        case WebInspector.Drawer.AnimationType.Normal:
+            return 100;
+        default:
+            return 0;
+        }
+    },
+
+    /**
+     * @return {boolean}
+     */
+    _startStatusBarDragging: function(event)
+    {
+        if (!this.visible || event.target !== this._floatingStatusBarContainer)
+            return false;
+
+        this._view.storeScrollPositions();
+        this._statusBarDragOffset = event.pageY - this.element.totalOffsetTop();
+        return true;
+    },
+
+    _statusBarDragging: function(event)
+    {
+        var height = window.innerHeight - event.pageY + this._statusBarDragOffset;
+        height = Number.constrain(height, Preferences.minConsoleHeight, window.innerHeight - this._mainElement.totalOffsetTop() - Preferences.minConsoleHeight);
+
+        this._elementToAdjust.style.bottom = height + "px";
+        this.element.style.height = height + "px";
+        if (WebInspector.inspectorView.currentPanel())
+            WebInspector.inspectorView.currentPanel().doResize();
+        this._view.doResize();
+
+        event.consume(true);
+    },
+
+    _endStatusBarDragging: function(event)
+    {
+        this._savedHeight = this.element.offsetHeight;
+        delete this._statusBarDragOffset;
+
+        event.consume();
+    },
+
+    /**
+     * @param {Element} element
+     */
+    setFooterElement: function(element)
+    {
+        if (element) {
+            this._footerElementContainer.removeStyleClass("hidden");
+            this._footerElementContainer.appendChild(element);
+            this._drawerContentsElement.style.bottom = this._footerElementContainer.offsetHeight + "px";
+        } else {
+            this._footerElementContainer.addStyleClass("hidden");
+            this._footerElementContainer.removeChildren();
+            this._drawerContentsElement.style.bottom = 0;
+        }
+        this._view.doResize();
+    },
+
+    /**
+     * @returns {WebInspector.Searchable}
+     */
+    getSearchProvider: function()
+    {
+        if (this._view && this._view.performSearch)
+            return this._view;
+
+        return null;
+    }
+}
+
+/**
+ * @type {WebInspector.Drawer}
+ */
+WebInspector.drawer = null;
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EditFileSystemDialog.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EditFileSystemDialog.js
new file mode 100644
index 00000000..9f7a6176
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EditFileSystemDialog.js
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2013 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.DialogDelegate}
+ * @param {string} fileSystemPath
+ */
+WebInspector.EditFileSystemDialog = function(fileSystemPath)
+{
+    WebInspector.DialogDelegate.call(this);
+    this._fileSystemPath = fileSystemPath;
+
+    this.element = document.createElement("div");
+    this.element.className = "edit-file-system-dialog";
+
+    var header = this.element.createChild("div", "header");
+    var headerText = header.createChild("span");
+    headerText.textContent = "Edit file system";
+
+    var closeButton = header.createChild("div", "close-button-gray done-button");
+    closeButton.addEventListener("click", this._onDoneClick.bind(this), false);
+
+    var contents = this.element.createChild("div", "contents");
+
+    WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.FileMappingAdded, this._fileMappingAdded, this);
+    WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.FileMappingRemoved, this._fileMappingRemoved, this);
+    WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, this._excludedFolderAdded, this);
+    WebInspector.isolatedFileSystemManager.mapping().addEventListener(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, this._excludedFolderRemoved, this);
+
+    var blockHeader = contents.createChild("div", "block-header");
+    blockHeader.textContent = "Mappings";
+    this._fileMappingsSection = contents.createChild("div", "file-mappings-section");
+    this._fileMappingsListContainer = this._fileMappingsSection.createChild("div", "settings-list-container");
+    var entries = WebInspector.isolatedFileSystemManager.mapping().mappingEntries(this._fileSystemPath);
+
+    this._fileMappingsList = new WebInspector.EditableSettingsList(["url", "path"], this._fileMappingValuesProvider.bind(this), this._fileMappingValidate.bind(this), this._fileMappingEdit.bind(this));
+    this._fileMappingsList.addEventListener(WebInspector.SettingsList.Events.Removed, this._fileMappingRemovedfromList.bind(this));
+
+    this._fileMappingsList.element.addStyleClass("file-mappings-list");
+    this._fileMappingsListContainer.appendChild(this._fileMappingsList.element);
+
+    this._entries = {};
+    for (var i = 0; i < entries.length; ++i)
+        this._addMappingRow(entries[i]);
+
+    blockHeader = contents.createChild("div", "block-header");
+    blockHeader.textContent = "Excluded folders";
+    this._excludedFolderListSection = contents.createChild("div", "excluded-folders-section");
+    this._excludedFolderListContainer = this._excludedFolderListSection.createChild("div", "settings-list-container");
+    var excludedFolderEntries = WebInspector.isolatedFileSystemManager.mapping().excludedFolders(fileSystemPath);
+
+    this._excludedFolderList = new WebInspector.EditableSettingsList(["path"], this._excludedFolderValueProvider.bind(this), this._excludedFolderValidate.bind(this), this._excludedFolderEdit.bind(this));
+    this._excludedFolderList.addEventListener(WebInspector.SettingsList.Events.Removed, this._excludedFolderRemovedfromList.bind(this));
+    this._excludedFolderList.element.addStyleClass("excluded-folders-list");
+    this._excludedFolderListContainer.appendChild(this._excludedFolderList.element);
+    this._excludedFolderEntries = new StringMap();
+    for (var i = 0; i < excludedFolderEntries.length; ++i)
+        this._addExcludedFolderRow(excludedFolderEntries[i]);
+
+    this.element.tabIndex = 0;
+}
+
+WebInspector.EditFileSystemDialog.show = function(element, fileSystemPath)
+{
+    WebInspector.Dialog.show(element, new WebInspector.EditFileSystemDialog(fileSystemPath));
+    var glassPane = document.getElementById("glass-pane");
+    glassPane.addStyleClass("settings-glass-pane");
+}
+
+WebInspector.EditFileSystemDialog.prototype = {
+    /**
+     * @param {Element} element
+     */
+    show: function(element)
+    {
+        element.appendChild(this.element);
+        this.element.addStyleClass("dialog-contents");
+        element.addStyleClass("settings-dialog");
+        element.addStyleClass("settings-tab");
+        this._dialogElement = element;
+    },
+
+    _resize: function()
+    {
+        if (!this._dialogElement)
+            return;
+
+        const width = 540;
+        const minHeight = 150;
+        var maxHeight = document.body.offsetHeight - 10;
+        maxHeight = Math.max(minHeight, maxHeight);
+        this._dialogElement.style.maxHeight = maxHeight + "px";
+        this._dialogElement.style.width = width + "px";
+    },
+
+    /**
+     * @param {Element} element
+     * @param {Element} relativeToElement
+     */
+    position: function(element, relativeToElement)
+    {
+        this._resize();
+    },
+
+    willHide: function(event)
+    {
+    },
+
+    _fileMappingAdded: function(event)
+    {
+        var entry = /** @type {WebInspector.FileSystemMapping.Entry} */ (event.data);
+        this._addMappingRow(entry);
+    },
+
+    _fileMappingRemoved: function(event)
+    {
+        var entry = /** @type {WebInspector.FileSystemMapping.Entry} */ (event.data);
+        if (this._fileSystemPath !== entry.fileSystemPath)
+            return;
+        delete this._entries[entry.urlPrefix];
+        if (this._fileMappingsList.itemForId(entry.urlPrefix))
+            this._fileMappingsList.removeItem(entry.urlPrefix);
+        this._resize();
+    },
+
+    _fileMappingValuesProvider: function(itemId, columnId)
+    {
+        if (!itemId)
+            return "";
+        var entry = this._entries[itemId];
+        switch (columnId) {
+        case "url":
+            return entry.urlPrefix;
+        case "path":
+            return entry.pathPrefix;
+        default:
+            console.assert("Should not be reached.");
+        }
+        return "";
+    },
+
+    /**
+     * @param {?string} itemId
+     * @param {Object} data
+     */
+    _fileMappingValidate: function(itemId, data)
+    {
+        var oldPathPrefix = itemId ? this._entries[itemId].pathPrefix : null;
+        return this._validateMapping(data["url"], itemId, data["path"], oldPathPrefix);
+    },
+
+    /**
+     * @param {?string} itemId
+     * @param {Object} data
+     */
+    _fileMappingEdit: function(itemId, data)
+    {
+        if (itemId) {
+            var urlPrefix = itemId;
+            var pathPrefix = this._entries[itemId].pathPrefix;
+            var fileSystemPath = this._entries[itemId].fileSystemPath;
+            WebInspector.isolatedFileSystemManager.mapping().removeFileMapping(fileSystemPath, urlPrefix, pathPrefix);
+        }
+        this._addFileMapping(data["url"], data["path"]);
+    },
+
+    /**
+     * @param {string} urlPrefix
+     * @param {?string} allowedURLPrefix
+     * @param {string} path
+     * @param {?string} allowedPathPrefix
+     */
+    _validateMapping: function(urlPrefix, allowedURLPrefix, path, allowedPathPrefix)
+    {
+        var columns = [];
+        if (!this._checkURLPrefix(urlPrefix, allowedURLPrefix))
+            columns.push("url");
+        if (!this._checkPathPrefix(path, allowedPathPrefix))
+            columns.push("path");
+        return columns;
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _fileMappingRemovedfromList: function(event)
+    {
+        var urlPrefix = /** @type{?string} */ (event.data);
+        if (!urlPrefix)
+            return;
+
+        var entry = this._entries[urlPrefix];
+        WebInspector.isolatedFileSystemManager.mapping().removeFileMapping(entry.fileSystemPath, entry.urlPrefix, entry.pathPrefix);
+    },
+
+    /**
+     * @param {string} urlPrefix
+     * @param {string} pathPrefix
+     * @return {boolean}
+     */
+    _addFileMapping: function(urlPrefix, pathPrefix)
+    {
+        var normalizedURLPrefix = this._normalizePrefix(urlPrefix);
+        var normalizedPathPrefix = this._normalizePrefix(pathPrefix);
+        WebInspector.isolatedFileSystemManager.mapping().addFileMapping(this._fileSystemPath, normalizedURLPrefix, normalizedPathPrefix);
+        this._fileMappingsList.selectItem(normalizedURLPrefix);
+        return true;
+    },
+
+    /**
+     * @param {string} prefix
+     * @return {string}
+     */
+    _normalizePrefix: function(prefix)
+    {
+        if (!prefix)
+            return "";
+        return prefix + (prefix[prefix.length - 1] === "/" ? "" : "/");
+    },
+
+    _addMappingRow: function(entry)
+    {
+        var fileSystemPath = entry.fileSystemPath;
+        var urlPrefix = entry.urlPrefix;
+        if (!this._fileSystemPath || this._fileSystemPath !== fileSystemPath)
+            return;
+
+        this._entries[urlPrefix] = entry;
+        var fileMappingListItem = this._fileMappingsList.addItem(urlPrefix, null);
+        this._resize();
+    },
+
+    _excludedFolderAdded: function(event)
+    {
+        var entry = /** @type {WebInspector.FileSystemMapping.ExcludedFolderEntry} */ (event.data);
+        this._addExcludedFolderRow(entry);
+    },
+
+    _excludedFolderRemoved: function(event)
+    {
+        var entry = /** @type {WebInspector.FileSystemMapping.ExcludedFolderEntry} */ (event.data);
+        var fileSystemPath = entry.fileSystemPath;
+        if (!fileSystemPath || this._fileSystemPath !== fileSystemPath)
+            return;
+        delete this._excludedFolderEntries[entry.path];
+        if (this._excludedFolderList.itemForId(entry.path))
+            this._excludedFolderList.removeItem(entry.path);
+    },
+
+    _excludedFolderValueProvider: function(itemId, columnId)
+    {
+        return itemId;
+    },
+
+    /**
+     * @param {?string} itemId
+     * @param {Object} data
+     */
+    _excludedFolderValidate: function(itemId, data)
+    {
+        var fileSystemPath = this._fileSystemPath;
+        var columns = [];
+        if (!this._validateExcludedFolder(data["path"], itemId))
+            columns.push("path");
+        return columns;
+    },
+
+    /**
+     * @param {string} path
+     * @param {?string} allowedPath
+     * @return {boolean}
+     */
+    _validateExcludedFolder: function(path, allowedPath)
+    {
+        return !!path && (path === allowedPath || !this._excludedFolderEntries.contains(path));
+    },
+
+    /**
+     * @param {?string} itemId
+     * @param {Object} data
+     */
+    _excludedFolderEdit: function(itemId, data)
+    {
+        var fileSystemPath = this._fileSystemPath;
+        if (itemId)
+            WebInspector.isolatedFileSystemManager.mapping().removeExcludedFolder(fileSystemPath, itemId);
+        var excludedFolderPath = data["path"];
+        WebInspector.isolatedFileSystemManager.mapping().addExcludedFolder(fileSystemPath, excludedFolderPath);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _excludedFolderRemovedfromList: function(event)
+    {
+        var itemId = /** @type{?string} */ (event.data);
+        if (!itemId)
+            return;
+        WebInspector.isolatedFileSystemManager.mapping().removeExcludedFolder(this._fileSystemPath, itemId);
+    },
+
+    /**
+     * @param {WebInspector.FileSystemMapping.ExcludedFolderEntry} entry
+     */
+    _addExcludedFolderRow: function(entry)
+    {
+        var fileSystemPath = entry.fileSystemPath;
+        if (!fileSystemPath || this._fileSystemPath !== fileSystemPath)
+            return;
+        var path = entry.path;
+        this._excludedFolderEntries.put(path, entry);
+        this._excludedFolderList.addItem(path, null);
+    },
+
+    /**
+     * @param {string} value
+     * @param {?string} allowedPrefix
+     * @return {boolean}
+     */
+    _checkURLPrefix: function(value, allowedPrefix)
+    {
+        var prefix = this._normalizePrefix(value);
+        return !!prefix && (prefix === allowedPrefix || !this._entries[prefix]);
+    },
+
+    /**
+     * @param {string} value
+     * @param {?string} allowedPrefix
+     * @return {boolean}
+     */
+    _checkPathPrefix: function(value, allowedPrefix)
+    {
+        var prefix = this._normalizePrefix(value);
+        if (!prefix)
+            return false;
+        if (prefix === allowedPrefix)
+            return true;
+        for (var urlPrefix in this._entries) {
+            var entry = this._entries[urlPrefix];
+            if (urlPrefix && entry.pathPrefix === prefix)
+                return false;
+        }
+        return true;
+    },
+
+    focus: function()
+    {
+        WebInspector.setCurrentFocusElement(this.element);
+    },
+
+    _onDoneClick: function()
+    {
+        WebInspector.Dialog.hide();
+    },
+
+    onEnter: function()
+    {
+    },
+
+    __proto__: WebInspector.DialogDelegate.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanel.js
new file mode 100644
index 00000000..d1f900c5
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanel.js
@@ -0,0 +1,1266 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Matt Lilek 
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+importScript("CSSNamedFlowCollectionsView.js");
+importScript("CSSNamedFlowView.js");
+importScript("EventListenersSidebarPane.js");
+importScript("MetricsSidebarPane.js");
+importScript("PlatformFontsSidebarPane.js");
+importScript("PropertiesSidebarPane.js");
+importScript("StylesSidebarPane.js");
+
+/**
+ * @constructor
+ * @extends {WebInspector.Panel}
+ */
+WebInspector.ElementsPanel = function()
+{
+    WebInspector.Panel.call(this, "elements");
+    this.registerRequiredCSS("breadcrumbList.css");
+    this.registerRequiredCSS("elementsPanel.css");
+    this.registerRequiredCSS("textPrompt.css");
+    this.setHideOnDetach();
+
+    const initialSidebarWidth = 325;
+    const minimumContentWidthPercent = 0.34;
+    const initialSidebarHeight = 325;
+    const minimumContentHeightPercent = 0.34;
+    this.createSidebarView(this.element, WebInspector.SidebarView.SidebarPosition.End, initialSidebarWidth, initialSidebarHeight);
+    this.splitView.setSidebarElementConstraints(Preferences.minElementsSidebarWidth, Preferences.minElementsSidebarHeight);
+    this.splitView.setMainElementConstraints(minimumContentWidthPercent, minimumContentHeightPercent);
+    this.splitView.addEventListener(WebInspector.SidebarView.EventTypes.Resized, this._updateTreeOutlineVisibleWidth.bind(this));
+
+    this.contentElement = this.splitView.mainElement;
+    this.contentElement.id = "elements-content";
+    this.contentElement.addStyleClass("outline-disclosure");
+    this.contentElement.addStyleClass("source-code");
+    if (!WebInspector.settings.domWordWrap.get())
+        this.contentElement.classList.add("nowrap");
+    WebInspector.settings.domWordWrap.addChangeListener(this._domWordWrapSettingChanged.bind(this));
+
+    this.contentElement.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
+    this.splitView.sidebarElement.addEventListener("contextmenu", this._sidebarContextMenuEventFired.bind(this), false);
+
+    this.treeOutline = new WebInspector.ElementsTreeOutline(true, true, this._populateContextMenu.bind(this), this._setPseudoClassForNodeId.bind(this));
+    this.treeOutline.wireToDomAgent();
+
+    this.treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedNodeChanged, this);
+    this.treeOutline.addEventListener(WebInspector.ElementsTreeOutline.Events.ElementsTreeUpdated, this._updateBreadcrumbIfNeeded, this);
+
+    this.crumbsElement = document.createElement("div");
+    this.crumbsElement.className = "crumbs";
+    this.crumbsElement.addEventListener("mousemove", this._mouseMovedInCrumbs.bind(this), false);
+    this.crumbsElement.addEventListener("mouseout", this._mouseMovedOutOfCrumbs.bind(this), false);
+
+    this.sidebarPanes = {};
+    this.sidebarPanes.platformFonts = new WebInspector.PlatformFontsSidebarPane();
+    this.sidebarPanes.computedStyle = new WebInspector.ComputedStyleSidebarPane();
+    this.sidebarPanes.styles = new WebInspector.StylesSidebarPane(this.sidebarPanes.computedStyle, this._setPseudoClassForNodeId.bind(this));
+    this.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane();
+    this.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
+    this.sidebarPanes.domBreakpoints = WebInspector.domBreakpointsSidebarPane.createProxy(this);
+    this.sidebarPanes.eventListeners = new WebInspector.EventListenersSidebarPane();
+
+    this.sidebarPanes.styles.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateStyles.bind(this, false));
+    this.sidebarPanes.metrics.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateMetrics.bind(this));
+    this.sidebarPanes.platformFonts.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updatePlatformFonts.bind(this));
+    this.sidebarPanes.properties.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateProperties.bind(this));
+    this.sidebarPanes.eventListeners.addEventListener(WebInspector.SidebarPane.EventTypes.wasShown, this.updateEventListeners.bind(this));
+
+    this.sidebarPanes.styles.addEventListener("style edited", this._stylesPaneEdited, this);
+    this.sidebarPanes.styles.addEventListener("style property toggled", this._stylesPaneEdited, this);
+    this.sidebarPanes.metrics.addEventListener("metrics edited", this._metricsPaneEdited, this);
+
+    WebInspector.dockController.addEventListener(WebInspector.DockController.Events.DockSideChanged, this._dockSideChanged.bind(this));
+    WebInspector.settings.splitVerticallyWhenDockedToRight.addChangeListener(this._dockSideChanged.bind(this));
+    this._dockSideChanged();
+
+    this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this));
+    this._popoverHelper.setTimeout(0);
+
+    WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdatedEvent, this);
+    WebInspector.settings.showShadowDOM.addChangeListener(this._showShadowDOMChanged.bind(this));
+
+    if (WebInspector.domAgent.existingDocument())
+        this._documentUpdated(WebInspector.domAgent.existingDocument());
+}
+
+WebInspector.ElementsPanel.prototype = {
+    _updateTreeOutlineVisibleWidth: function()
+    {
+        if (!this.treeOutline)
+            return;
+
+        var width = this.splitView.element.offsetWidth;
+        if (this.splitView.isVertical())
+            width -= this.splitView.sidebarWidth();
+        this.treeOutline.setVisibleWidth(width);
+    },
+
+    get statusBarItems()
+    {
+        return [this.crumbsElement];
+    },
+
+    defaultFocusedElement: function()
+    {
+        return this.treeOutline.element;
+    },
+
+    statusBarResized: function()
+    {
+        this.updateBreadcrumbSizes();
+    },
+
+    wasShown: function()
+    {
+        // Attach heavy component lazily
+        if (this.treeOutline.element.parentElement !== this.contentElement)
+            this.contentElement.appendChild(this.treeOutline.element);
+
+        WebInspector.Panel.prototype.wasShown.call(this);
+
+        this.updateBreadcrumb();
+        this.treeOutline.updateSelection();
+        this.treeOutline.setVisible(true);
+
+        if (!this.treeOutline.rootDOMNode)
+            WebInspector.domAgent.requestDocument();
+    },
+
+    willHide: function()
+    {
+        WebInspector.domAgent.hideDOMNodeHighlight();
+        this.treeOutline.setVisible(false);
+        this._popoverHelper.hidePopover();
+
+        // Detach heavy component on hide
+        this.contentElement.removeChild(this.treeOutline.element);
+
+        WebInspector.Panel.prototype.willHide.call(this);
+    },
+
+    onResize: function()
+    {
+        this.treeOutline.updateSelection();
+        this.updateBreadcrumbSizes();
+    },
+
+    /**
+     * @param {DOMAgent.NodeId} nodeId
+     * @param {string} pseudoClass
+     * @param {boolean} enable
+     */
+    _setPseudoClassForNodeId: function(nodeId, pseudoClass, enable)
+    {
+        var node = WebInspector.domAgent.nodeForId(nodeId);
+        if (!node)
+            return;
+
+        var pseudoClasses = node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName);
+        if (enable) {
+            pseudoClasses = pseudoClasses || [];
+            if (pseudoClasses.indexOf(pseudoClass) >= 0)
+                return;
+            pseudoClasses.push(pseudoClass);
+            node.setUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName, pseudoClasses);
+        } else {
+            if (!pseudoClasses || pseudoClasses.indexOf(pseudoClass) < 0)
+                return;
+            pseudoClasses.remove(pseudoClass);
+            if (!pseudoClasses.length)
+                node.removeUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName);
+        }
+
+        this.treeOutline.updateOpenCloseTags(node);
+        WebInspector.cssModel.forcePseudoState(node.id, node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName));
+        this._metricsPaneEdited();
+        this._stylesPaneEdited();
+
+        WebInspector.notifications.dispatchEventToListeners(WebInspector.UserMetrics.UserAction, {
+            action: WebInspector.UserMetrics.UserActionNames.ForcedElementState,
+            selector: node.appropriateSelectorFor(false),
+            enabled: enable,
+            state: pseudoClass
+        });
+    },
+
+    _selectedNodeChanged: function()
+    {
+        var selectedNode = this.selectedDOMNode();
+        if (!selectedNode && this._lastValidSelectedNode)
+            this._selectedPathOnReset = this._lastValidSelectedNode.path();
+
+        this.updateBreadcrumb(false);
+
+        this._updateSidebars();
+
+        if (selectedNode) {
+            ConsoleAgent.addInspectedNode(selectedNode.id);
+            this._lastValidSelectedNode = selectedNode;
+        }
+        WebInspector.notifications.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged);
+    },
+
+    _updateSidebars: function()
+    {
+        for (var pane in this.sidebarPanes)
+           this.sidebarPanes[pane].needsUpdate = true;
+
+        this.updateStyles(true);
+        this.updateMetrics();
+        this.updatePlatformFonts();
+        this.updateProperties();
+        this.updateEventListeners();
+    },
+
+    _reset: function()
+    {
+        delete this.currentQuery;
+    },
+
+    _documentUpdatedEvent: function(event)
+    {
+        this._documentUpdated(event.data);
+    },
+
+    _documentUpdated: function(inspectedRootDocument)
+    {
+        this._reset();
+        this.searchCanceled();
+
+        this.treeOutline.rootDOMNode = inspectedRootDocument;
+
+        if (!inspectedRootDocument) {
+            if (this.isShowing())
+                WebInspector.domAgent.requestDocument();
+            return;
+        }
+
+        WebInspector.domBreakpointsSidebarPane.restoreBreakpoints();
+
+        /**
+         * @this {WebInspector.ElementsPanel}
+         * @param {WebInspector.DOMNode=} candidateFocusNode
+         */
+        function selectNode(candidateFocusNode)
+        {
+            if (!candidateFocusNode)
+                candidateFocusNode = inspectedRootDocument.body || inspectedRootDocument.documentElement;
+
+            if (!candidateFocusNode)
+                return;
+
+            this.selectDOMNode(candidateFocusNode);
+            if (this.treeOutline.selectedTreeElement)
+                this.treeOutline.selectedTreeElement.expand();
+        }
+
+        /**
+         * @param {?DOMAgent.NodeId} nodeId
+         */
+        function selectLastSelectedNode(nodeId)
+        {
+            if (this.selectedDOMNode()) {
+                // Focused node has been explicitly set while reaching out for the last selected node.
+                return;
+            }
+            var node = nodeId ? WebInspector.domAgent.nodeForId(nodeId) : null;
+            selectNode.call(this, node);
+        }
+
+        if (this._selectedPathOnReset)
+            WebInspector.domAgent.pushNodeByPathToFrontend(this._selectedPathOnReset, selectLastSelectedNode.bind(this));
+        else
+            selectNode.call(this);
+        delete this._selectedPathOnReset;
+    },
+
+    searchCanceled: function()
+    {
+        delete this._searchQuery;
+        this._hideSearchHighlights();
+
+        WebInspector.searchController.updateSearchMatchesCount(0, this);
+
+        delete this._currentSearchResultIndex;
+        delete this._searchResults;
+        WebInspector.domAgent.cancelSearch();
+    },
+
+    /**
+     * @param {string} query
+     * @param {boolean} shouldJump
+     */
+    performSearch: function(query, shouldJump)
+    {
+        // Call searchCanceled since it will reset everything we need before doing a new search.
+        this.searchCanceled();
+
+        const whitespaceTrimmedQuery = query.trim();
+        if (!whitespaceTrimmedQuery.length)
+            return;
+
+        this._searchQuery = query;
+
+        /**
+         * @param {number} resultCount
+         */
+        function resultCountCallback(resultCount)
+        {
+            WebInspector.searchController.updateSearchMatchesCount(resultCount, this);
+            if (!resultCount)
+                return;
+
+            this._searchResults = new Array(resultCount);
+            this._currentSearchResultIndex = -1;
+            if (shouldJump)
+                this.jumpToNextSearchResult();
+        }
+        WebInspector.domAgent.performSearch(whitespaceTrimmedQuery, resultCountCallback.bind(this));
+    },
+
+    _contextMenuEventFired: function(event)
+    {
+        function toggleWordWrap()
+        {
+            WebInspector.settings.domWordWrap.set(!WebInspector.settings.domWordWrap.get());
+        }
+
+        var contextMenu = new WebInspector.ContextMenu(event);
+        this.treeOutline.populateContextMenu(contextMenu, event);
+
+        if (WebInspector.experimentsSettings.cssRegions.isEnabled()) {
+            contextMenu.appendSeparator();
+            contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "CSS named flows\u2026" : "CSS Named Flows\u2026"), this._showNamedFlowCollections.bind(this));
+        }
+
+        contextMenu.appendSeparator();
+        contextMenu.appendCheckboxItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Word wrap" : "Word Wrap"), toggleWordWrap.bind(this), WebInspector.settings.domWordWrap.get());
+
+        contextMenu.show();
+    },
+
+    _showNamedFlowCollections: function()
+    {
+        if (!WebInspector.cssNamedFlowCollectionsView)
+            WebInspector.cssNamedFlowCollectionsView = new WebInspector.CSSNamedFlowCollectionsView();
+        WebInspector.cssNamedFlowCollectionsView.showInDrawer();
+    },
+
+    _domWordWrapSettingChanged: function(event)
+    {
+        if (event.data)
+            this.contentElement.removeStyleClass("nowrap");
+        else
+            this.contentElement.addStyleClass("nowrap");
+
+        var selectedNode = this.selectedDOMNode();
+        if (!selectedNode)
+            return;
+
+        var treeElement = this.treeOutline.findTreeElement(selectedNode);
+        if (treeElement)
+            treeElement.updateSelection(); // Recalculate selection highlight dimensions.
+    },
+
+    switchToAndFocus: function(node)
+    {
+        // Reset search restore.
+        WebInspector.searchController.cancelSearch();
+        WebInspector.inspectorView.setCurrentPanel(this);
+        this.selectDOMNode(node, true);
+    },
+
+    _populateContextMenu: function(contextMenu, node)
+    {
+        // Add debbuging-related actions
+        contextMenu.appendSeparator();
+        var pane = WebInspector.domBreakpointsSidebarPane;
+        pane.populateNodeContextMenu(node, contextMenu);
+    },
+
+    _getPopoverAnchor: function(element)
+    {
+        var anchor = element.enclosingNodeOrSelfWithClass("webkit-html-resource-link");
+        if (anchor) {
+            if (!anchor.href)
+                return null;
+
+            var resource = WebInspector.resourceTreeModel.resourceForURL(anchor.href);
+            if (!resource || resource.type !== WebInspector.resourceTypes.Image)
+                return null;
+
+            anchor.removeAttribute("title");
+        }
+        return anchor;
+    },
+    
+    _loadDimensionsForNode: function(treeElement, callback)
+    {
+        // We get here for CSS properties, too, so bail out early for non-DOM treeElements.
+        if (treeElement.treeOutline !== this.treeOutline) {
+            callback();
+            return;
+        }
+        
+        var node = /** @type {WebInspector.DOMNode} */ (treeElement.representedObject);
+
+        if (!node.nodeName() || node.nodeName().toLowerCase() !== "img") {
+            callback();
+            return;
+        }
+
+        WebInspector.RemoteObject.resolveNode(node, "", resolvedNode);
+
+        function resolvedNode(object)
+        {
+            if (!object) {
+                callback();
+                return;
+            }
+
+            object.callFunctionJSON(dimensions, undefined, callback);
+            object.release();
+
+            function dimensions()
+            {
+                return { offsetWidth: this.offsetWidth, offsetHeight: this.offsetHeight, naturalWidth: this.naturalWidth, naturalHeight: this.naturalHeight };
+            }
+        }
+    },
+
+    /**
+     * @param {Element} anchor
+     * @param {WebInspector.Popover} popover
+     */
+    _showPopover: function(anchor, popover)
+    {
+        var listItem = anchor.enclosingNodeOrSelfWithNodeName("li");
+        if (listItem && listItem.treeElement)
+            this._loadDimensionsForNode(listItem.treeElement, WebInspector.DOMPresentationUtils.buildImagePreviewContents.bind(WebInspector.DOMPresentationUtils, anchor.href, true, showPopover));
+        else
+            WebInspector.DOMPresentationUtils.buildImagePreviewContents(anchor.href, true, showPopover);
+
+        /**
+         * @param {Element=} contents
+         */
+        function showPopover(contents)
+        {
+            if (!contents)
+                return;
+            popover.setCanShrink(false);
+            popover.show(contents, anchor);
+        }
+    },
+
+    jumpToNextSearchResult: function()
+    {
+        if (!this._searchResults)
+            return;
+
+        this._hideSearchHighlights();
+        if (++this._currentSearchResultIndex >= this._searchResults.length)
+            this._currentSearchResultIndex = 0;
+
+        this._highlightCurrentSearchResult();
+    },
+
+    jumpToPreviousSearchResult: function()
+    {
+        if (!this._searchResults)
+            return;
+
+        this._hideSearchHighlights();
+        if (--this._currentSearchResultIndex < 0)
+            this._currentSearchResultIndex = (this._searchResults.length - 1);
+
+        this._highlightCurrentSearchResult();
+    },
+
+    _highlightCurrentSearchResult: function()
+    {
+        var index = this._currentSearchResultIndex;
+        var searchResults = this._searchResults;
+        var searchResult = searchResults[index];
+
+        if (searchResult === null) {
+            WebInspector.searchController.updateCurrentMatchIndex(index, this);
+            return;
+        }
+
+        if (typeof searchResult === "undefined") {
+            // No data for slot, request it.
+            function callback(node)
+            {
+                searchResults[index] = node || null;
+                this._highlightCurrentSearchResult();
+            }
+            WebInspector.domAgent.searchResult(index, callback.bind(this));
+            return;
+        }
+
+        WebInspector.searchController.updateCurrentMatchIndex(index, this);
+
+        var treeElement = this.treeOutline.findTreeElement(searchResult);
+        if (treeElement) {
+            treeElement.highlightSearchResults(this._searchQuery);
+            treeElement.reveal();
+            var matches = treeElement.listItemElement.getElementsByClassName("highlighted-search-result");
+            if (matches.length)
+                matches[0].scrollIntoViewIfNeeded();
+        }
+    },
+
+    _hideSearchHighlights: function()
+    {
+        if (!this._searchResults)
+            return;
+        var searchResult = this._searchResults[this._currentSearchResultIndex];
+        if (!searchResult)
+            return;
+        var treeElement = this.treeOutline.findTreeElement(searchResult);
+        if (treeElement)
+            treeElement.hideSearchHighlights();
+    },
+
+    /**
+     * @return {WebInspector.DOMNode}
+     */
+    selectedDOMNode: function()
+    {
+        return this.treeOutline.selectedDOMNode();
+    },
+
+    /**
+     * @param {boolean=} focus
+     */
+    selectDOMNode: function(node, focus)
+    {
+        this.treeOutline.selectDOMNode(node, focus);
+    },
+
+    /**
+     * @param {WebInspector.Event} event
+     */
+    _updateBreadcrumbIfNeeded: function(event)
+    {
+        var nodes = /** @type {!Array.} */ (event.data || []);
+        if (!nodes.length)
+            return;
+
+        var crumbs = this.crumbsElement;
+        for (var crumb = crumbs.firstChild; crumb; crumb = crumb.nextSibling) {
+            if (nodes.indexOf(crumb.representedObject) !== -1) {
+                this.updateBreadcrumb(true);
+                return;
+            }
+        }
+    },
+
+    _stylesPaneEdited: function()
+    {
+        // Once styles are edited, the Metrics pane should be updated.
+        this.sidebarPanes.metrics.needsUpdate = true;
+        this.updateMetrics();
+        this.sidebarPanes.platformFonts.needsUpdate = true;
+        this.updatePlatformFonts();
+    },
+
+    _metricsPaneEdited: function()
+    {
+        // Once metrics are edited, the Styles pane should be updated.
+        this.sidebarPanes.styles.needsUpdate = true;
+        this.updateStyles(true);
+    },
+
+    _mouseMovedInCrumbs: function(event)
+    {
+        var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
+        var crumbElement = nodeUnderMouse.enclosingNodeOrSelfWithClass("crumb");
+
+        WebInspector.domAgent.highlightDOMNode(crumbElement ? crumbElement.representedObject.id : 0);
+
+        if ("_mouseOutOfCrumbsTimeout" in this) {
+            clearTimeout(this._mouseOutOfCrumbsTimeout);
+            delete this._mouseOutOfCrumbsTimeout;
+        }
+    },
+
+    _mouseMovedOutOfCrumbs: function(event)
+    {
+        var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY);
+        if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.crumbsElement))
+            return;
+
+        WebInspector.domAgent.hideDOMNodeHighlight();
+
+        this._mouseOutOfCrumbsTimeout = setTimeout(this.updateBreadcrumbSizes.bind(this), 1000);
+    },
+
+    /**
+     * @param {boolean=} forceUpdate
+     */
+    updateBreadcrumb: function(forceUpdate)
+    {
+        if (!this.isShowing())
+            return;
+
+        var crumbs = this.crumbsElement;
+
+        var handled = false;
+        var crumb = crumbs.firstChild;
+        while (crumb) {
+            if (crumb.representedObject === this.selectedDOMNode()) {
+                crumb.addStyleClass("selected");
+                handled = true;
+            } else {
+                crumb.removeStyleClass("selected");
+            }
+
+            crumb = crumb.nextSibling;
+        }
+
+        if (handled && !forceUpdate) {
+            // We don't need to rebuild the crumbs, but we need to adjust sizes
+            // to reflect the new focused or root node.
+            this.updateBreadcrumbSizes();
+            return;
+        }
+
+        crumbs.removeChildren();
+
+        var panel = this;
+
+        function selectCrumbFunction(event)
+        {
+            var crumb = event.currentTarget;
+            if (crumb.hasStyleClass("collapsed")) {
+                // Clicking a collapsed crumb will expose the hidden crumbs.
+                if (crumb === panel.crumbsElement.firstChild) {
+                    // If the focused crumb is the first child, pick the farthest crumb
+                    // that is still hidden. This allows the user to expose every crumb.
+                    var currentCrumb = crumb;
+                    while (currentCrumb) {
+                        var hidden = currentCrumb.hasStyleClass("hidden");
+                        var collapsed = currentCrumb.hasStyleClass("collapsed");
+                        if (!hidden && !collapsed)
+                            break;
+                        crumb = currentCrumb;
+                        currentCrumb = currentCrumb.nextSibling;
+                    }
+                }
+
+                panel.updateBreadcrumbSizes(crumb);
+            } else
+                panel.selectDOMNode(crumb.representedObject, true);
+
+            event.preventDefault();
+        }
+
+        for (var current = this.selectedDOMNode(); current; current = current.parentNode) {
+            if (current.nodeType() === Node.DOCUMENT_NODE)
+                continue;
+
+            crumb = document.createElement("span");
+            crumb.className = "crumb";
+            crumb.representedObject = current;
+            crumb.addEventListener("mousedown", selectCrumbFunction, false);
+
+            var crumbTitle = "";
+            switch (current.nodeType()) {
+                case Node.ELEMENT_NODE:
+                    WebInspector.DOMPresentationUtils.decorateNodeLabel(current, crumb);
+                    break;
+
+                case Node.TEXT_NODE:
+                    crumbTitle = WebInspector.UIString("(text)");
+                    break;
+
+                case Node.COMMENT_NODE:
+                    crumbTitle = "";
+                    break;
+
+                case Node.DOCUMENT_TYPE_NODE:
+                    crumbTitle = "";
+                    break;
+
+                default:
+                    crumbTitle = current.nodeNameInCorrectCase();
+            }
+
+            if (!crumb.childNodes.length) {
+                var nameElement = document.createElement("span");
+                nameElement.textContent = crumbTitle;
+                crumb.appendChild(nameElement);
+                crumb.title = crumbTitle;
+            }
+
+            if (current === this.selectedDOMNode())
+                crumb.addStyleClass("selected");
+            if (!crumbs.childNodes.length)
+                crumb.addStyleClass("end");
+
+            crumbs.appendChild(crumb);
+        }
+
+        if (crumbs.hasChildNodes())
+            crumbs.lastChild.addStyleClass("start");
+
+        this.updateBreadcrumbSizes();
+    },
+
+    /**
+     * @param {Element=} focusedCrumb
+     */
+    updateBreadcrumbSizes: function(focusedCrumb)
+    {
+        if (!this.isShowing())
+            return;
+
+        if (document.body.offsetWidth <= 0) {
+            // The stylesheet hasn't loaded yet or the window is closed,
+            // so we can't calculate what is need. Return early.
+            return;
+        }
+
+        var crumbs = this.crumbsElement;
+        if (!crumbs.childNodes.length || crumbs.offsetWidth <= 0)
+            return; // No crumbs, do nothing.
+
+        // A Zero index is the right most child crumb in the breadcrumb.
+        var selectedIndex = 0;
+        var focusedIndex = 0;
+        var selectedCrumb;
+
+        var i = 0;
+        var crumb = crumbs.firstChild;
+        while (crumb) {
+            // Find the selected crumb and index.
+            if (!selectedCrumb && crumb.hasStyleClass("selected")) {
+                selectedCrumb = crumb;
+                selectedIndex = i;
+            }
+
+            // Find the focused crumb index.
+            if (crumb === focusedCrumb)
+                focusedIndex = i;
+
+            // Remove any styles that affect size before
+            // deciding to shorten any crumbs.
+            if (crumb !== crumbs.lastChild)
+                crumb.removeStyleClass("start");
+            if (crumb !== crumbs.firstChild)
+                crumb.removeStyleClass("end");
+
+            crumb.removeStyleClass("compact");
+            crumb.removeStyleClass("collapsed");
+            crumb.removeStyleClass("hidden");
+
+            crumb = crumb.nextSibling;
+            ++i;
+        }
+
+        // Restore the start and end crumb classes in case they got removed in coalesceCollapsedCrumbs().
+        // The order of the crumbs in the document is opposite of the visual order.
+        crumbs.firstChild.addStyleClass("end");
+        crumbs.lastChild.addStyleClass("start");
+
+        var rightPadding = 20;
+        var crumbsTotalOffsetLeft = crumbs.totalOffsetLeft();
+        var windowInnerWidth = window.innerWidth;
+        var errorWarningElement = document.getElementById("error-warning-count");
+        if (!WebInspector.drawer.visible) {
+            if (errorWarningElement)
+                rightPadding += errorWarningElement.offsetWidth;
+            rightPadding += WebInspector.settingsController.statusBarItem.offsetWidth;
+        }
+
+        function crumbsAreSmallerThanContainer()
+        {
+            return (crumbsTotalOffsetLeft + crumbs.offsetWidth + rightPadding) < windowInnerWidth;
+        }
+
+        if (crumbsAreSmallerThanContainer())
+            return; // No need to compact the crumbs, they all fit at full size.
+
+        var BothSides = 0;
+        var AncestorSide = -1;
+        var ChildSide = 1;
+
+        /**
+         * @param {boolean=} significantCrumb
+         */
+        function makeCrumbsSmaller(shrinkingFunction, direction, significantCrumb)
+        {
+            if (!significantCrumb)
+                significantCrumb = (focusedCrumb || selectedCrumb);
+
+            if (significantCrumb === selectedCrumb)
+                var significantIndex = selectedIndex;
+            else if (significantCrumb === focusedCrumb)
+                var significantIndex = focusedIndex;
+            else {
+                var significantIndex = 0;
+                for (var i = 0; i < crumbs.childNodes.length; ++i) {
+                    if (crumbs.childNodes[i] === significantCrumb) {
+                        significantIndex = i;
+                        break;
+                    }
+                }
+            }
+
+            function shrinkCrumbAtIndex(index)
+            {
+                var shrinkCrumb = crumbs.childNodes[index];
+                if (shrinkCrumb && shrinkCrumb !== significantCrumb)
+                    shrinkingFunction(shrinkCrumb);
+                if (crumbsAreSmallerThanContainer())
+                    return true; // No need to compact the crumbs more.
+                return false;
+            }
+
+            // Shrink crumbs one at a time by applying the shrinkingFunction until the crumbs
+            // fit in the container or we run out of crumbs to shrink.
+            if (direction) {
+                // Crumbs are shrunk on only one side (based on direction) of the signifcant crumb.
+                var index = (direction > 0 ? 0 : crumbs.childNodes.length - 1);
+                while (index !== significantIndex) {
+                    if (shrinkCrumbAtIndex(index))
+                        return true;
+                    index += (direction > 0 ? 1 : -1);
+                }
+            } else {
+                // Crumbs are shrunk in order of descending distance from the signifcant crumb,
+                // with a tie going to child crumbs.
+                var startIndex = 0;
+                var endIndex = crumbs.childNodes.length - 1;
+                while (startIndex != significantIndex || endIndex != significantIndex) {
+                    var startDistance = significantIndex - startIndex;
+                    var endDistance = endIndex - significantIndex;
+                    if (startDistance >= endDistance)
+                        var index = startIndex++;
+                    else
+                        var index = endIndex--;
+                    if (shrinkCrumbAtIndex(index))
+                        return true;
+                }
+            }
+
+            // We are not small enough yet, return false so the caller knows.
+            return false;
+        }
+
+        function coalesceCollapsedCrumbs()
+        {
+            var crumb = crumbs.firstChild;
+            var collapsedRun = false;
+            var newStartNeeded = false;
+            var newEndNeeded = false;
+            while (crumb) {
+                var hidden = crumb.hasStyleClass("hidden");
+                if (!hidden) {
+                    var collapsed = crumb.hasStyleClass("collapsed");
+                    if (collapsedRun && collapsed) {
+                        crumb.addStyleClass("hidden");
+                        crumb.removeStyleClass("compact");
+                        crumb.removeStyleClass("collapsed");
+
+                        if (crumb.hasStyleClass("start")) {
+                            crumb.removeStyleClass("start");
+                            newStartNeeded = true;
+                        }
+
+                        if (crumb.hasStyleClass("end")) {
+                            crumb.removeStyleClass("end");
+                            newEndNeeded = true;
+                        }
+
+                        continue;
+                    }
+
+                    collapsedRun = collapsed;
+
+                    if (newEndNeeded) {
+                        newEndNeeded = false;
+                        crumb.addStyleClass("end");
+                    }
+                } else
+                    collapsedRun = true;
+                crumb = crumb.nextSibling;
+            }
+
+            if (newStartNeeded) {
+                crumb = crumbs.lastChild;
+                while (crumb) {
+                    if (!crumb.hasStyleClass("hidden")) {
+                        crumb.addStyleClass("start");
+                        break;
+                    }
+                    crumb = crumb.previousSibling;
+                }
+            }
+        }
+
+        function compact(crumb)
+        {
+            if (crumb.hasStyleClass("hidden"))
+                return;
+            crumb.addStyleClass("compact");
+        }
+
+        function collapse(crumb, dontCoalesce)
+        {
+            if (crumb.hasStyleClass("hidden"))
+                return;
+            crumb.addStyleClass("collapsed");
+            crumb.removeStyleClass("compact");
+            if (!dontCoalesce)
+                coalesceCollapsedCrumbs();
+        }
+
+        if (!focusedCrumb) {
+            // When not focused on a crumb we can be biased and collapse less important
+            // crumbs that the user might not care much about.
+
+            // Compact child crumbs.
+            if (makeCrumbsSmaller(compact, ChildSide))
+                return;
+
+            // Collapse child crumbs.
+            if (makeCrumbsSmaller(collapse, ChildSide))
+                return;
+        }
+
+        // Compact ancestor crumbs, or from both sides if focused.
+        if (makeCrumbsSmaller(compact, (focusedCrumb ? BothSides : AncestorSide)))
+            return;
+
+        // Collapse ancestor crumbs, or from both sides if focused.
+        if (makeCrumbsSmaller(collapse, (focusedCrumb ? BothSides : AncestorSide)))
+            return;
+
+        if (!selectedCrumb)
+            return;
+
+        // Compact the selected crumb.
+        compact(selectedCrumb);
+        if (crumbsAreSmallerThanContainer())
+            return;
+
+        // Collapse the selected crumb as a last resort. Pass true to prevent coalescing.
+        collapse(selectedCrumb, true);
+    },
+
+    /**
+     * @param {boolean=} forceUpdate
+     */
+    updateStyles: function(forceUpdate)
+    {
+        var stylesSidebarPane = this.sidebarPanes.styles;
+        var computedStylePane = this.sidebarPanes.computedStyle;
+        if ((!stylesSidebarPane.isShowing() && !computedStylePane.isShowing()) || !stylesSidebarPane.needsUpdate)
+            return;
+
+        stylesSidebarPane.update(this.selectedDOMNode(), forceUpdate);
+        stylesSidebarPane.needsUpdate = false;
+    },
+
+    updateMetrics: function()
+    {
+        var metricsSidebarPane = this.sidebarPanes.metrics;
+        if (!metricsSidebarPane.isShowing() || !metricsSidebarPane.needsUpdate)
+            return;
+
+        metricsSidebarPane.update(this.selectedDOMNode());
+        metricsSidebarPane.needsUpdate = false;
+    },
+
+    updatePlatformFonts: function()
+    {
+        var platformFontsSidebar = this.sidebarPanes.platformFonts;
+        if (!platformFontsSidebar.isShowing() || !platformFontsSidebar.needsUpdate)
+            return;
+
+        platformFontsSidebar.update(this.selectedDOMNode());
+        platformFontsSidebar.needsUpdate = false;
+    },
+
+    updateProperties: function()
+    {
+        var propertiesSidebarPane = this.sidebarPanes.properties;
+        if (!propertiesSidebarPane.isShowing() || !propertiesSidebarPane.needsUpdate)
+            return;
+
+        propertiesSidebarPane.update(this.selectedDOMNode());
+        propertiesSidebarPane.needsUpdate = false;
+    },
+
+    updateEventListeners: function()
+    {
+        var eventListenersSidebarPane = this.sidebarPanes.eventListeners;
+        if (!eventListenersSidebarPane.isShowing() || !eventListenersSidebarPane.needsUpdate)
+            return;
+
+        eventListenersSidebarPane.update(this.selectedDOMNode());
+        eventListenersSidebarPane.needsUpdate = false;
+    },
+
+    handleShortcut: function(event)
+    {
+        function handleUndoRedo()
+        {
+            if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && !event.shiftKey && event.keyIdentifier === "U+005A") { // Z key
+                WebInspector.domAgent.undo(this._updateSidebars.bind(this));
+                event.handled = true;
+                return;
+            }
+
+            var isRedoKey = WebInspector.isMac() ? event.metaKey && event.shiftKey && event.keyIdentifier === "U+005A" : // Z key
+                                                   event.ctrlKey && event.keyIdentifier === "U+0059"; // Y key
+            if (isRedoKey) {
+                DOMAgent.redo(this._updateSidebars.bind(this));
+                event.handled = true;
+            }
+        }
+
+        if (!this.treeOutline.editing()) {
+            handleUndoRedo.call(this);
+            if (event.handled)
+                return;
+        }
+
+        this.treeOutline.handleShortcut(event);
+    },
+
+    handleCopyEvent: function(event)
+    {
+        var currentFocusElement = WebInspector.currentFocusElement();
+        if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement))
+            return;
+
+        // Don't prevent the normal copy if the user has a selection.
+        if (!window.getSelection().isCollapsed)
+            return;
+        event.clipboardData.clearData();
+        event.preventDefault();
+        this.selectedDOMNode().copyNode();
+    },
+
+    sidebarResized: function(event)
+    {
+        this.treeOutline.updateSelection();
+    },
+
+    revealAndSelectNode: function(nodeId)
+    {
+        WebInspector.inspectorView.setCurrentPanel(this);
+
+        var node = WebInspector.domAgent.nodeForId(nodeId);
+        if (!node)
+            return;
+
+        while (!WebInspector.ElementsTreeOutline.showShadowDOM() && node && node.isInShadowTree())
+            node = node.parentNode;
+
+        WebInspector.domAgent.highlightDOMNodeForTwoSeconds(nodeId);
+        this.selectDOMNode(node, true);
+    },
+
+    /** 
+     * @param {WebInspector.ContextMenu} contextMenu
+     * @param {Object} target
+     */
+    appendApplicableItems: function(event, contextMenu, target)
+    {
+        /**
+         * @param {?DOMAgent.NodeId} nodeId
+         */
+        function selectNode(nodeId)
+        {
+            if (nodeId)
+                WebInspector.domAgent.inspectElement(nodeId);
+        }
+
+        /**
+         * @param {WebInspector.RemoteObject} remoteObject
+         */
+        function revealElement(remoteObject)
+        {
+            remoteObject.pushNodeToFrontend(selectNode);
+        }
+
+        var commandCallback;
+        if (target instanceof WebInspector.RemoteObject) {
+            var remoteObject = /** @type {WebInspector.RemoteObject} */ (target);
+            if (remoteObject.subtype === "node")
+                commandCallback = revealElement.bind(this, remoteObject);
+        } else if (target instanceof WebInspector.DOMNode) {
+            var domNode = /** @type {WebInspector.DOMNode} */ (target);
+            if (domNode.id)
+                commandCallback = WebInspector.domAgent.inspectElement.bind(WebInspector.domAgent, domNode.id);
+        }
+        if (!commandCallback)
+            return;
+        // Skip adding "Reveal..." menu item for our own tree outline.
+        if (this.treeOutline.element.isAncestor(event.target))
+            return;
+        contextMenu.appendItem(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Elements panel" : "Reveal in Elements Panel", commandCallback);
+    },
+
+    _sidebarContextMenuEventFired: function(event)
+    {
+        var contextMenu = new WebInspector.ContextMenu(event);
+        contextMenu.show();
+    },
+
+    _dockSideChanged: function()
+    {
+        var dockSide = WebInspector.dockController.dockSide();
+        var vertically = dockSide === WebInspector.DockController.State.DockedToRight && WebInspector.settings.splitVerticallyWhenDockedToRight.get();
+        this._splitVertically(vertically);
+    },
+
+    _showShadowDOMChanged: function()
+    {
+        this.treeOutline.update();
+    },
+
+    /**
+     * @param {boolean} vertically
+     */
+    _splitVertically: function(vertically)
+    {
+        if (this.sidebarPaneView && vertically === !this.splitView.isVertical())
+            return;
+
+        if (this.sidebarPaneView)
+            this.sidebarPaneView.detach();
+
+        this.splitView.setVertical(!vertically);
+
+        var computedPane = new WebInspector.SidebarPane(WebInspector.UIString("Computed"));
+        computedPane.element.addStyleClass("composite");
+        computedPane.element.addStyleClass("fill");
+        var expandComputed = computedPane.expand.bind(computedPane);
+
+        computedPane.bodyElement.appendChild(this.sidebarPanes.computedStyle.titleElement);
+        computedPane.bodyElement.addStyleClass("metrics-and-computed");
+        this.sidebarPanes.computedStyle.show(computedPane.bodyElement);
+        this.sidebarPanes.computedStyle.setExpandCallback(expandComputed);
+
+        this.sidebarPanes.platformFonts.show(computedPane.bodyElement);
+
+        if (vertically) {
+            this.sidebarPanes.metrics.show(computedPane.bodyElement, this.sidebarPanes.computedStyle.element);
+            this.sidebarPanes.metrics.setExpandCallback(expandComputed);
+
+            this.sidebarPaneView = new WebInspector.SidebarTabbedPane();
+
+            var compositePane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title());
+            compositePane.element.addStyleClass("composite");
+            compositePane.element.addStyleClass("fill");
+            var expandComposite = compositePane.expand.bind(compositePane);
+
+            var splitView = new WebInspector.SplitView(true, "StylesPaneSplitRatio", 0.5);
+            splitView.show(compositePane.bodyElement);
+
+            this.sidebarPanes.styles.show(splitView.firstElement());
+            splitView.firstElement().appendChild(this.sidebarPanes.styles.titleElement);
+            this.sidebarPanes.styles.setExpandCallback(expandComposite);
+
+            computedPane.show(splitView.secondElement());
+            computedPane.setExpandCallback(expandComposite);
+
+            this.sidebarPaneView.addPane(compositePane);
+            this.sidebarPaneView.addPane(this.sidebarPanes.properties);
+            this.sidebarPaneView.addPane(this.sidebarPanes.domBreakpoints);
+            this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
+        } else {
+            this.sidebarPaneView = new WebInspector.SidebarTabbedPane();
+
+            var stylesPane = new WebInspector.SidebarPane(this.sidebarPanes.styles.title());
+            stylesPane.element.addStyleClass("composite");
+            stylesPane.element.addStyleClass("fill");
+            var expandStyles = stylesPane.expand.bind(stylesPane);
+            stylesPane.bodyElement.addStyleClass("metrics-and-styles");
+            this.sidebarPanes.styles.show(stylesPane.bodyElement);
+            this.sidebarPanes.styles.setExpandCallback(expandStyles);
+            this.sidebarPanes.metrics.setExpandCallback(expandStyles);
+            stylesPane.bodyElement.appendChild(this.sidebarPanes.styles.titleElement);
+
+            /**
+             * @param {WebInspector.SidebarPane} pane
+             * @param {Element=} beforeElement
+             */
+            function showMetrics(pane, beforeElement)
+            {
+                this.sidebarPanes.metrics.show(pane.bodyElement, beforeElement);
+            }
+
+            /**
+             * @param {WebInspector.Event} event
+             */
+            function tabSelected(event)
+            {
+                var tabId = /** @type {string} */ (event.data.tabId);
+                if (tabId === computedPane.title())
+                    showMetrics.call(this, computedPane, this.sidebarPanes.computedStyle.element);
+                if (tabId === stylesPane.title())
+                    showMetrics.call(this, stylesPane);
+            }
+
+            this.sidebarPaneView.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, tabSelected, this);
+
+            showMetrics.call(this, stylesPane);
+            this.sidebarPaneView.addPane(stylesPane);
+            this.sidebarPaneView.addPane(computedPane);
+
+            this.sidebarPaneView.addPane(this.sidebarPanes.eventListeners);
+            this.sidebarPaneView.addPane(this.sidebarPanes.domBreakpoints);
+            this.sidebarPaneView.addPane(this.sidebarPanes.properties);
+        }
+
+        this.sidebarPaneView.show(this.splitView.sidebarElement);
+        this.sidebarPanes.styles.expand();
+    },
+
+    /**
+     * @param {string} id
+     * @param {WebInspector.SidebarPane} pane
+     */
+    addExtensionSidebarPane: function(id, pane)
+    {
+        this.sidebarPanes[id] = pane;
+        this.sidebarPaneView.addPane(pane);
+    },
+
+    __proto__: WebInspector.Panel.prototype
+}
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanelDescriptor.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanelDescriptor.js
new file mode 100644
index 00000000..d08b1f5a
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsPanelDescriptor.js
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. AND ITS CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC.
+ * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {WebInspector.PanelDescriptor}
+ * @implements {WebInspector.ContextMenu.Provider}
+ */
+WebInspector.ElementsPanelDescriptor = function()
+{
+    WebInspector.PanelDescriptor.call(this, "elements", WebInspector.UIString("Elements"), "ElementsPanel", "ElementsPanel.js");
+    WebInspector.ContextMenu.registerProvider(this);
+}
+
+WebInspector.ElementsPanelDescriptor.prototype = {
+    /** 
+     * @param {WebInspector.ContextMenu} contextMenu
+     * @param {Object} target
+     */
+    appendApplicableItems: function(event, contextMenu, target)
+    {
+        if (target instanceof WebInspector.RemoteObject) {
+            var remoteObject = /** @type {WebInspector.RemoteObject} */ (target);
+            if (remoteObject.subtype !== "node")
+                return;
+        } else if (!(target instanceof WebInspector.DOMNode))
+            return;
+        this.panel().appendApplicableItems(event, contextMenu, target);
+    },
+
+    registerShortcuts: function()
+    {
+        var elementsSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Elements Panel"));
+
+        var navigate = WebInspector.ElementsPanelDescriptor.ShortcutKeys.NavigateUp.concat(WebInspector.ElementsPanelDescriptor.ShortcutKeys.NavigateDown);
+        elementsSection.addRelatedKeys(navigate, WebInspector.UIString("Navigate elements"));
+
+        var expandCollapse = WebInspector.ElementsPanelDescriptor.ShortcutKeys.Expand.concat(WebInspector.ElementsPanelDescriptor.ShortcutKeys.Collapse);
+        elementsSection.addRelatedKeys(expandCollapse, WebInspector.UIString("Expand/collapse"));
+
+        elementsSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.EditAttribute, WebInspector.UIString("Edit attribute"));
+        elementsSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.HideElement, WebInspector.UIString("Hide element"));
+        elementsSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.ToggleEditAsHTML, WebInspector.UIString("Toggle edit as HTML"));
+
+        var stylesPaneSection = WebInspector.shortcutsScreen.section(WebInspector.UIString("Styles Pane"));
+
+        var nextPreviousProperty = WebInspector.ElementsPanelDescriptor.ShortcutKeys.NextProperty.concat(WebInspector.ElementsPanelDescriptor.ShortcutKeys.PreviousProperty);
+        stylesPaneSection.addRelatedKeys(nextPreviousProperty, WebInspector.UIString("Next/previous property"));
+
+        stylesPaneSection.addRelatedKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.IncrementValue, WebInspector.UIString("Increment value"));
+        stylesPaneSection.addRelatedKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.DecrementValue, WebInspector.UIString("Decrement value"));
+
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.IncrementBy10, WebInspector.UIString("Increment by %f", 10));
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.DecrementBy10, WebInspector.UIString("Decrement by %f", 10));
+
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.IncrementBy100, WebInspector.UIString("Increment by %f", 100));
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.DecrementBy100, WebInspector.UIString("Decrement by %f", 100));
+
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.IncrementBy01, WebInspector.UIString("Increment by %f", 0.1));
+        stylesPaneSection.addAlternateKeys(WebInspector.ElementsPanelDescriptor.ShortcutKeys.DecrementBy01, WebInspector.UIString("Decrement by %f", 0.1));
+    },
+
+    __proto__: WebInspector.PanelDescriptor.prototype
+}
+
+WebInspector.ElementsPanelDescriptor.ShortcutKeys = {
+    NavigateUp: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Up)
+    ],
+
+    NavigateDown: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Down)
+    ],
+
+    Expand: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Right)
+    ],
+
+    Collapse: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Left)
+    ],
+
+    EditAttribute: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Enter)
+    ],
+
+    HideElement: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.H)
+    ],
+
+    ToggleEditAsHTML: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.F2)
+    ],
+
+    NextProperty: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Tab)
+    ],
+
+    PreviousProperty: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Tab, WebInspector.KeyboardShortcut.Modifiers.Shift)
+    ],
+
+    IncrementValue: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Up)
+    ],
+
+    DecrementValue: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Down)
+    ],
+
+    IncrementBy10: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageUp),
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Up, WebInspector.KeyboardShortcut.Modifiers.Shift)
+    ],
+
+    DecrementBy10: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageDown),
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.Down, WebInspector.KeyboardShortcut.Modifiers.Shift)
+    ],
+
+    IncrementBy100: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageUp, WebInspector.KeyboardShortcut.Modifiers.Shift)
+    ],
+
+    DecrementBy100: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageDown, WebInspector.KeyboardShortcut.Modifiers.Shift)
+    ],
+
+    IncrementBy01: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageUp, WebInspector.KeyboardShortcut.Modifiers.Alt)
+    ],
+
+    DecrementBy01: [
+        WebInspector.KeyboardShortcut.makeDescriptor(WebInspector.KeyboardShortcut.Keys.PageDown, WebInspector.KeyboardShortcut.Modifiers.Alt)
+    ]
+};
diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsTreeOutline.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsTreeOutline.js
new file mode 100644
index 00000000..4cff01df
--- /dev/null
+++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ElementsTreeOutline.js
@@ -0,0 +1,2393 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc.  All rights reserved.
+ * Copyright (C) 2008 Matt Lilek 
+ * Copyright (C) 2009 Joseph Pecoraro
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ *     its contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ * @extends {TreeOutline}
+ * @param {boolean=} omitRootDOMNode
+ * @param {boolean=} selectEnabled
+ * @param {function(WebInspector.ContextMenu, WebInspector.DOMNode)=} contextMenuCallback
+ * @param {function(DOMAgent.NodeId, string, boolean)=} setPseudoClassCallback
+ */
+WebInspector.ElementsTreeOutline = function(omitRootDOMNode, selectEnabled, contextMenuCallback, setPseudoClassCallback)
+{
+    this.element = document.createElement("ol");
+    this.element.className = "elements-tree-outline";
+    this.element.addEventListener("mousedown", this._onmousedown.bind(this), false);
+    this.element.addEventListener("mousemove", this._onmousemove.bind(this), false);
+    this.element.addEventListener("mouseout", this._onmouseout.bind(this), false);
+    this.element.addEventListener("dragstart", this._ondragstart.bind(this), false);
+    this.element.addEventListener("dragover", this._ondragover.bind(this), false);
+    this.element.addEventListener("dragleave", this._ondragleave.bind(this), false);
+    this.element.addEventListener("drop", this._ondrop.bind(this), false);
+    this.element.addEventListener("dragend", this._ondragend.bind(this), false);
+    this.element.addEventListener("keydown", this._onkeydown.bind(this), false);
+
+    TreeOutline.call(this, this.element);
+
+    this._includeRootDOMNode = !omitRootDOMNode;
+    this._selectEnabled = selectEnabled;
+    /** @type {WebInspector.DOMNode} */
+    this._rootDOMNode = null;
+    /** @type {WebInspector.DOMNode} */
+    this._selectedDOMNode = null;
+    this._eventSupport = new WebInspector.Object();
+
+    this._visible = false;
+
+    this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true);
+    this._contextMenuCallback = contextMenuCallback;
+    this._setPseudoClassCallback = setPseudoClassCallback;
+    this._createNodeDecorators();
+}
+
+/**
+ * @enum {string}
+ */
+WebInspector.ElementsTreeOutline.Events = {
+    SelectedNodeChanged: "SelectedNodeChanged",
+    ElementsTreeUpdated: "ElementsTreeUpdated"
+}
+
+/**
+ * @const
+ * @type {!Object.}
+ */
+WebInspector.ElementsTreeOutline.MappedCharToEntity = {
+    "\u00a0": "nbsp",
+    "\u2002": "ensp",
+    "\u2003": "emsp",
+    "\u2009": "thinsp",
+    "\u200a": "#8202", // Hairspace
+    "\u200b": "#8203", // ZWSP
+    "\u200c": "zwnj",
+    "\u200d": "zwj",
+    "\u200e": "lrm",
+    "\u200f": "rlm",
+    "\u202a": "#8234", // LRE
+    "\u202b": "#8235", // RLE
+    "\u202c": "#8236", // PDF
+    "\u202d": "#8237", // LRO
+    "\u202e": "#8238" // RLO
+}
+
+WebInspector.ElementsTreeOutline.prototype = {
+    /**
+     * @param {number} width
+     */
+    setVisibleWidth: function(width)
+    {
+        this._visibleWidth = width;
+        if (this._multilineEditing)
+            this._multilineEditing.setWidth(this._visibleWidth);
+    },
+
+    _createNodeDecorators: function()
+    {
+        this._nodeDecorators = [];
+        this._nodeDecorators.push(new WebInspector.ElementsTreeOutline.PseudoStateDecorator());
+    },
+
+    wireToDomAgent: function()
+    {
+        this._elementsTreeUpdater = new WebInspector.ElementsTreeUpdater(this);
+    },
+
+    /**
+     * @param {boolean} visible
+     */
+    setVisible: function(visible)
+    {
+        this._visible = visible;
+        if (!this._visible)
+            return;
+
+        this._updateModifiedNodes();
+        if (this._selectedDOMNode)
+            this._revealAndSelectNode(this._selectedDOMNode, false);
+    },
+
+    addEventListener: function(eventType, listener, thisObject)
+    {
+        this._eventSupport.addEventListener(eventType, listener, thisObject);
+    },
+
+    removeEventListener: function(eventType, listener, thisObject)
+    {
+        this._eventSupport.removeEventListener(eventType, listener, thisObject);
+    },
+
+    get rootDOMNode()
+    {
+        return this._rootDOMNode;
+    },
+
+    set rootDOMNode(x)
+    {
+        if (this._rootDOMNode === x)
+            return;
+
+        this._rootDOMNode = x;
+
+        this._isXMLMimeType = x && x.isXMLNode();
+
+        this.update();
+    },
+
+    get isXMLMimeType()
+    {
+        return this._isXMLMimeType;
+    },
+
+    /**
+     * @return {WebInspector.DOMNode}
+     */
+    selectedDOMNode: function()
+    {
+        return this._selectedDOMNode;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     * @param {boolean=} focus
+     */
+    selectDOMNode: function(node, focus)
+    {
+        if (this._selectedDOMNode === node) {
+            this._revealAndSelectNode(node, !focus);
+            return;
+        }
+
+        this._selectedDOMNode = node;
+        this._revealAndSelectNode(node, !focus);
+
+        // The _revealAndSelectNode() method might find a different element if there is inlined text,
+        // and the select() call would change the selectedDOMNode and reenter this setter. So to
+        // avoid calling _selectedNodeChanged() twice, first check if _selectedDOMNode is the same
+        // node as the one passed in.
+        if (this._selectedDOMNode === node)
+            this._selectedNodeChanged();
+    },
+
+    /**
+     * @return {boolean}
+     */
+    editing: function()
+    {
+        var node = this.selectedDOMNode();
+        if (!node)
+            return false;
+        var treeElement = this.findTreeElement(node);
+        if (!treeElement)
+            return false;
+        return treeElement._editing || false;
+    },
+
+    update: function()
+    {
+        var selectedNode = this.selectedTreeElement ? this.selectedTreeElement._node : null;
+
+        this.removeChildren();
+
+        if (!this.rootDOMNode)
+            return;
+
+        var treeElement;
+        if (this._includeRootDOMNode) {
+            treeElement = new WebInspector.ElementsTreeElement(this.rootDOMNode);
+            treeElement.selectable = this._selectEnabled;
+            this.appendChild(treeElement);
+        } else {
+            // FIXME: this could use findTreeElement to reuse a tree element if it already exists
+            var node = this.rootDOMNode.firstChild;
+            while (node) {
+                treeElement = new WebInspector.ElementsTreeElement(node);
+                treeElement.selectable = this._selectEnabled;
+                this.appendChild(treeElement);
+                node = node.nextSibling;
+            }
+        }
+
+        if (selectedNode)
+            this._revealAndSelectNode(selectedNode, true);
+    },
+
+    updateSelection: function()
+    {
+        if (!this.selectedTreeElement)
+            return;
+        var element = this.treeOutline.selectedTreeElement;
+        element.updateSelection();
+    },
+
+    /**
+     * @param {!WebInspector.DOMNode} node
+     */
+    updateOpenCloseTags: function(node)
+    {
+        var treeElement = this.findTreeElement(node);
+        if (treeElement)
+            treeElement.updateTitle();
+        var children = treeElement.children;
+        var closingTagElement = children[children.length - 1];
+        if (closingTagElement && closingTagElement._elementCloseTag)
+            closingTagElement.updateTitle();
+    },
+
+    _selectedNodeChanged: function()
+    {
+        this._eventSupport.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, this._selectedDOMNode);
+    },
+
+    /**
+     * @param {!Array.} nodes
+     */
+    _fireElementsTreeUpdated: function(nodes)
+    {
+        this._eventSupport.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.ElementsTreeUpdated, nodes);
+    },
+
+    /**
+     * @param {!WebInspector.DOMNode} node
+     * @return {TreeElement}
+     */
+    findTreeElement: function(node)
+    {
+        function isAncestorNode(ancestor, node)
+        {
+            return ancestor.isAncestor(node);
+        }
+
+        function parentNode(node)
+        {
+            return node.parentNode;
+        }
+
+        var treeElement = TreeOutline.prototype.findTreeElement.call(this, node, isAncestorNode, parentNode);
+        if (!treeElement && node.nodeType() === Node.TEXT_NODE) {
+            // The text node might have been inlined if it was short, so try to find the parent element.
+            treeElement = TreeOutline.prototype.findTreeElement.call(this, node.parentNode, isAncestorNode, parentNode);
+        }
+
+        return treeElement;
+    },
+
+    /**
+     * @param {!WebInspector.DOMNode} node
+     * @return {TreeElement}
+     */
+    createTreeElementFor: function(node)
+    {
+        var treeElement = this.findTreeElement(node);
+        if (treeElement)
+            return treeElement;
+        if (!node.parentNode)
+            return null;
+
+        treeElement = this.createTreeElementFor(node.parentNode);
+        return treeElement ? treeElement._showChild(node) : null;
+    },
+
+    set suppressRevealAndSelect(x)
+    {
+        if (this._suppressRevealAndSelect === x)
+            return;
+        this._suppressRevealAndSelect = x;
+    },
+
+    /**
+     * @param {WebInspector.DOMNode} node
+     * @param {boolean} omitFocus
+     */
+    _revealAndSelectNode: function(node, omitFocus)
+    {
+        if (this._suppressRevealAndSelect)
+            return;
+
+        if (!this._includeRootDOMNode && node === this.rootDOMNode && this.rootDOMNode)
+            node = this.rootDOMNode.firstChild;
+        if (!node)
+            return;
+        var treeElement = this.createTreeElementFor(node);
+        if (!treeElement)
+            return;
+
+        treeElement.revealAndSelect(omitFocus);
+    },
+
+    /**
+     * @return {TreeElement}
+     */
+    _treeElementFromEvent: function(event)
+    {
+        var scrollContainer = this.element.parentElement;
+
+        // We choose this X coordinate based on the knowledge that our list
+        // items extend at least to the right edge of the outer 
    container. + // In the no-word-wrap mode the outer
      may be wider than the tree container + // (and partially hidden), in which case we are left to use only its right boundary. + var x = scrollContainer.totalOffsetLeft() + scrollContainer.offsetWidth - 36; + + var y = event.pageY; + + // Our list items have 1-pixel cracks between them vertically. We avoid + // the cracks by checking slightly above and slightly below the mouse + // and seeing if we hit the same element each time. + var elementUnderMouse = this.treeElementFromPoint(x, y); + var elementAboveMouse = this.treeElementFromPoint(x, y - 2); + var element; + if (elementUnderMouse === elementAboveMouse) + element = elementUnderMouse; + else + element = this.treeElementFromPoint(x, y + 2); + + return element; + }, + + _onmousedown: function(event) + { + var element = this._treeElementFromEvent(event); + + if (!element || element.isEventWithinDisclosureTriangle(event)) + return; + + element.select(); + }, + + _onmousemove: function(event) + { + var element = this._treeElementFromEvent(event); + if (element && this._previousHoveredElement === element) + return; + + if (this._previousHoveredElement) { + this._previousHoveredElement.hovered = false; + delete this._previousHoveredElement; + } + + if (element) { + element.hovered = true; + this._previousHoveredElement = element; + } + + WebInspector.domAgent.highlightDOMNode(element && element._node ? element._node.id : 0); + }, + + _onmouseout: function(event) + { + var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); + if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.element)) + return; + + if (this._previousHoveredElement) { + this._previousHoveredElement.hovered = false; + delete this._previousHoveredElement; + } + + WebInspector.domAgent.hideDOMNodeHighlight(); + }, + + _ondragstart: function(event) + { + if (!window.getSelection().isCollapsed) + return false; + if (event.target.nodeName === "A") + return false; + + var treeElement = this._treeElementFromEvent(event); + if (!treeElement) + return false; + + if (!this._isValidDragSourceOrTarget(treeElement)) + return false; + + if (treeElement._node.nodeName() === "BODY" || treeElement._node.nodeName() === "HEAD") + return false; + + event.dataTransfer.setData("text/plain", treeElement.listItemElement.textContent); + event.dataTransfer.effectAllowed = "copyMove"; + this._treeElementBeingDragged = treeElement; + + WebInspector.domAgent.hideDOMNodeHighlight(); + + return true; + }, + + _ondragover: function(event) + { + if (!this._treeElementBeingDragged) + return false; + + var treeElement = this._treeElementFromEvent(event); + if (!this._isValidDragSourceOrTarget(treeElement)) + return false; + + var node = treeElement._node; + while (node) { + if (node === this._treeElementBeingDragged._node) + return false; + node = node.parentNode; + } + + treeElement.updateSelection(); + treeElement.listItemElement.addStyleClass("elements-drag-over"); + this._dragOverTreeElement = treeElement; + event.preventDefault(); + event.dataTransfer.dropEffect = 'move'; + return false; + }, + + _ondragleave: function(event) + { + this._clearDragOverTreeElementMarker(); + event.preventDefault(); + return false; + }, + + /** + * @param {TreeElement} treeElement + * @return {boolean} + */ + _isValidDragSourceOrTarget: function(treeElement) + { + if (!treeElement) + return false; + + var node = treeElement.representedObject; + if (!(node instanceof WebInspector.DOMNode)) + return false; + + if (!node.parentNode || node.parentNode.nodeType() !== Node.ELEMENT_NODE) + return false; + + return true; + }, + + _ondrop: function(event) + { + event.preventDefault(); + var treeElement = this._treeElementFromEvent(event); + if (treeElement) + this._doMove(treeElement); + }, + + /** + * @param {TreeElement} treeElement + */ + _doMove: function(treeElement) + { + if (!this._treeElementBeingDragged) + return; + + var parentNode; + var anchorNode; + + if (treeElement._elementCloseTag) { + // Drop onto closing tag -> insert as last child. + parentNode = treeElement._node; + } else { + var dragTargetNode = treeElement._node; + parentNode = dragTargetNode.parentNode; + anchorNode = dragTargetNode; + } + + var wasExpanded = this._treeElementBeingDragged.expanded; + this._treeElementBeingDragged._node.moveTo(parentNode, anchorNode, this._selectNodeAfterEdit.bind(this, wasExpanded)); + + delete this._treeElementBeingDragged; + }, + + _ondragend: function(event) + { + event.preventDefault(); + this._clearDragOverTreeElementMarker(); + delete this._treeElementBeingDragged; + }, + + _clearDragOverTreeElementMarker: function() + { + if (this._dragOverTreeElement) { + this._dragOverTreeElement.updateSelection(); + this._dragOverTreeElement.listItemElement.removeStyleClass("elements-drag-over"); + delete this._dragOverTreeElement; + } + }, + + /** + * @param {Event} event + */ + _onkeydown: function(event) + { + var keyboardEvent = /** @type {KeyboardEvent} */ (event); + var node = this.selectedDOMNode(); + var treeElement = this.getCachedTreeElement(node); + if (!treeElement) + return; + + if (!treeElement._editing && WebInspector.KeyboardShortcut.hasNoModifiers(keyboardEvent) && keyboardEvent.keyCode === WebInspector.KeyboardShortcut.Keys.H.code) { + this._toggleHideShortcut(node); + event.consume(true); + return; + } + }, + + _contextMenuEventFired: function(event) + { + var treeElement = this._treeElementFromEvent(event); + if (!treeElement) + return; + + var contextMenu = new WebInspector.ContextMenu(event); + contextMenu.appendApplicableItems(treeElement._node); + contextMenu.show(); + }, + + populateContextMenu: function(contextMenu, event) + { + var treeElement = this._treeElementFromEvent(event); + if (!treeElement) + return; + + var isTag = treeElement._node.nodeType() === Node.ELEMENT_NODE; + var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node"); + if (textNode && textNode.hasStyleClass("bogus")) + textNode = null; + var commentNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-comment"); + contextMenu.appendApplicableItems(event.target); + if (textNode) { + contextMenu.appendSeparator(); + treeElement._populateTextContextMenu(contextMenu, textNode); + } else if (isTag) { + contextMenu.appendSeparator(); + treeElement._populateTagContextMenu(contextMenu, event); + } else if (commentNode) { + contextMenu.appendSeparator(); + treeElement._populateNodeContextMenu(contextMenu, textNode); + } + }, + + _updateModifiedNodes: function() + { + if (this._elementsTreeUpdater) + this._elementsTreeUpdater._updateModifiedNodes(); + }, + + _populateContextMenu: function(contextMenu, node) + { + if (this._contextMenuCallback) + this._contextMenuCallback(contextMenu, node); + }, + + handleShortcut: function(event) + { + var node = this.selectedDOMNode(); + var treeElement = this.getCachedTreeElement(node); + if (!node || !treeElement) + return; + + if (event.keyIdentifier === "F2") { + this._toggleEditAsHTML(node); + event.handled = true; + return; + } + + if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(event) && node.parentNode) { + if (event.keyIdentifier === "Up" && node.previousSibling) { + node.moveTo(node.parentNode, node.previousSibling, this._selectNodeAfterEdit.bind(this, treeElement.expanded)); + event.handled = true; + return; + } + if (event.keyIdentifier === "Down" && node.nextSibling) { + node.moveTo(node.parentNode, node.nextSibling.nextSibling, this._selectNodeAfterEdit.bind(this, treeElement.expanded)); + event.handled = true; + return; + } + } + }, + + /** + * @param {WebInspector.DOMNode} node + */ + _toggleEditAsHTML: function(node) + { + var treeElement = this.getCachedTreeElement(node); + if (!treeElement) + return; + + if (treeElement._editing && treeElement._htmlEditElement && WebInspector.isBeingEdited(treeElement._htmlEditElement)) + treeElement._editing.commit(); + else + treeElement._editAsHTML(); + }, + + /** + * @param {boolean} wasExpanded + * @param {?Protocol.Error} error + * @param {DOMAgent.NodeId=} nodeId + */ + _selectNodeAfterEdit: function(wasExpanded, error, nodeId) + { + if (error) + return; + + // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date. + this._updateModifiedNodes(); + + var newNode = nodeId ? WebInspector.domAgent.nodeForId(nodeId) : null; + if (!newNode) + return; + + this.selectDOMNode(newNode, true); + + var newTreeItem = this.findTreeElement(newNode); + if (wasExpanded) { + if (newTreeItem) + newTreeItem.expand(); + } + return newTreeItem; + }, + + /** + * Runs a script on the node's remote object that toggles a class name on + * the node and injects a stylesheet into the head of the node's document + * containing a rule to set "visibility: hidden" on the class and all it's + * ancestors. + * + * @param {WebInspector.DOMNode} node + * @param {function(?WebInspector.RemoteObject)=} userCallback + */ + _toggleHideShortcut: function(node, userCallback) + { + function resolvedNode(object) + { + if (!object) + return; + + function toggleClassAndInjectStyleRule() + { + const className = "__web-inspector-hide-shortcut__"; + const styleTagId = "__web-inspector-hide-shortcut-style__"; + const styleRule = ".__web-inspector-hide-shortcut__, .__web-inspector-hide-shortcut__ * { visibility: hidden !important; }"; + + this.classList.toggle(className); + + var style = document.head.querySelector("style#" + styleTagId); + if (style) + return; + + style = document.createElement("style"); + style.id = styleTagId; + style.type = "text/css"; + style.innerHTML = styleRule; + document.head.appendChild(style); + } + + object.callFunction(toggleClassAndInjectStyleRule, undefined, userCallback); + object.release(); + } + + WebInspector.RemoteObject.resolveNode(node, "", resolvedNode); + }, + + __proto__: TreeOutline.prototype +} + +WebInspector.ElementsTreeOutline.showShadowDOM = function() +{ + return WebInspector.settings.showShadowDOM.get() || WebInspector.ElementsTreeOutline["showShadowDOMForTest"]; +} + + +/** + * @interface + */ +WebInspector.ElementsTreeOutline.ElementDecorator = function() +{ +} + +WebInspector.ElementsTreeOutline.ElementDecorator.prototype = { + /** + * @param {WebInspector.DOMNode} node + */ + decorate: function(node) + { + }, + + /** + * @param {WebInspector.DOMNode} node + */ + decorateAncestor: function(node) + { + } +} + +/** + * @constructor + * @implements {WebInspector.ElementsTreeOutline.ElementDecorator} + */ +WebInspector.ElementsTreeOutline.PseudoStateDecorator = function() +{ + WebInspector.ElementsTreeOutline.ElementDecorator.call(this); +} + +WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName = "pseudoState"; + +WebInspector.ElementsTreeOutline.PseudoStateDecorator.prototype = { + decorate: function(node) + { + if (node.nodeType() !== Node.ELEMENT_NODE) + return null; + var propertyValue = node.getUserProperty(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName); + if (!propertyValue) + return null; + return WebInspector.UIString("Element state: %s", ":" + propertyValue.join(", :")); + }, + + decorateAncestor: function(node) + { + if (node.nodeType() !== Node.ELEMENT_NODE) + return null; + + var descendantCount = node.descendantUserPropertyCount(WebInspector.ElementsTreeOutline.PseudoStateDecorator.PropertyName); + if (!descendantCount) + return null; + if (descendantCount === 1) + return WebInspector.UIString("%d descendant with forced state", descendantCount); + return WebInspector.UIString("%d descendants with forced state", descendantCount); + }, + + __proto__: WebInspector.ElementsTreeOutline.ElementDecorator.prototype +} + +/** + * @constructor + * @extends {TreeElement} + * @param {boolean=} elementCloseTag + */ +WebInspector.ElementsTreeElement = function(node, elementCloseTag) +{ + // The title will be updated in onattach. + TreeElement.call(this, "", node); + this._node = node; + + this._elementCloseTag = elementCloseTag; + this._updateHasChildren(); + + if (this._node.nodeType() == Node.ELEMENT_NODE && !elementCloseTag) + this._canAddAttributes = true; + this._searchQuery = null; + this._expandedChildrenLimit = WebInspector.ElementsTreeElement.InitialChildrenLimit; +} + +WebInspector.ElementsTreeElement.InitialChildrenLimit = 500; + +// A union of HTML4 and HTML5-Draft elements that explicitly +// or implicitly (for HTML5) forbid the closing tag. +// FIXME: Revise once HTML5 Final is published. +WebInspector.ElementsTreeElement.ForbiddenClosingTagElements = [ + "area", "base", "basefont", "br", "canvas", "col", "command", "embed", "frame", + "hr", "img", "input", "isindex", "keygen", "link", "meta", "param", "source" +].keySet(); + +// These tags we do not allow editing their tag name. +WebInspector.ElementsTreeElement.EditTagBlacklist = [ + "html", "head", "body" +].keySet(); + +WebInspector.ElementsTreeElement.prototype = { + highlightSearchResults: function(searchQuery) + { + if (this._searchQuery !== searchQuery) { + this._updateSearchHighlight(false); + delete this._highlightResult; // A new search query. + } + + this._searchQuery = searchQuery; + this._searchHighlightsVisible = true; + this.updateTitle(true); + }, + + hideSearchHighlights: function() + { + delete this._searchHighlightsVisible; + this._updateSearchHighlight(false); + }, + + _updateSearchHighlight: function(show) + { + if (!this._highlightResult) + return; + + function updateEntryShow(entry) + { + switch (entry.type) { + case "added": + entry.parent.insertBefore(entry.node, entry.nextSibling); + break; + case "changed": + entry.node.textContent = entry.newText; + break; + } + } + + function updateEntryHide(entry) + { + switch (entry.type) { + case "added": + entry.node.remove(); + break; + case "changed": + entry.node.textContent = entry.oldText; + break; + } + } + + // Preserve the semantic of node by following the order of updates for hide and show. + if (show) { + for (var i = 0, size = this._highlightResult.length; i < size; ++i) + updateEntryShow(this._highlightResult[i]); + } else { + for (var i = (this._highlightResult.length - 1); i >= 0; --i) + updateEntryHide(this._highlightResult[i]); + } + }, + + get hovered() + { + return this._hovered; + }, + + set hovered(x) + { + if (this._hovered === x) + return; + + this._hovered = x; + + if (this.listItemElement) { + if (x) { + this.updateSelection(); + this.listItemElement.addStyleClass("hovered"); + } else { + this.listItemElement.removeStyleClass("hovered"); + } + } + }, + + get expandedChildrenLimit() + { + return this._expandedChildrenLimit; + }, + + set expandedChildrenLimit(x) + { + if (this._expandedChildrenLimit === x) + return; + + this._expandedChildrenLimit = x; + if (this.treeOutline && !this._updateChildrenInProgress) + this._updateChildren(true); + }, + + get expandedChildCount() + { + var count = this.children.length; + if (count && this.children[count - 1]._elementCloseTag) + count--; + if (count && this.children[count - 1].expandAllButton) + count--; + return count; + }, + + /** + * @param {WebInspector.DOMNode} child + * @return {?WebInspector.ElementsTreeElement} + */ + _showChild: function(child) + { + if (this._elementCloseTag) + return null; + + var index = this._visibleChildren().indexOf(child); + if (index === -1) + return null; + + if (index >= this.expandedChildrenLimit) { + this._expandedChildrenLimit = index + 1; + this._updateChildren(true); + } + + // Whether index-th child is visible in the children tree + return this.expandedChildCount > index ? this.children[index] : null; + }, + + updateSelection: function() + { + var listItemElement = this.listItemElement; + if (!listItemElement) + return; + + if (!this._readyToUpdateSelection) { + if (document.body.offsetWidth > 0) + this._readyToUpdateSelection = true; + else { + // The stylesheet hasn't loaded yet or the window is closed, + // so we can't calculate what we need. Return early. + return; + } + } + + if (!this.selectionElement) { + this.selectionElement = document.createElement("div"); + this.selectionElement.className = "selection selected"; + listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild); + } + + this.selectionElement.style.height = listItemElement.offsetHeight + "px"; + }, + + onattach: function() + { + if (this._hovered) { + this.updateSelection(); + this.listItemElement.addStyleClass("hovered"); + } + + this.updateTitle(); + this._preventFollowingLinksOnDoubleClick(); + this.listItemElement.draggable = true; + }, + + _preventFollowingLinksOnDoubleClick: function() + { + var links = this.listItemElement.querySelectorAll("li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li > .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link"); + if (!links) + return; + + for (var i = 0; i < links.length; ++i) + links[i].preventFollowOnDoubleClick = true; + }, + + onpopulate: function() + { + if (this.children.length || this._showInlineText() || this._elementCloseTag) + return; + + this.updateChildren(); + }, + + /** + * @param {boolean=} fullRefresh + */ + updateChildren: function(fullRefresh) + { + if (this._elementCloseTag) + return; + this._node.getChildNodes(this._updateChildren.bind(this, fullRefresh)); + }, + + /** + * @param {boolean=} closingTag + */ + insertChildElement: function(child, index, closingTag) + { + var newElement = new WebInspector.ElementsTreeElement(child, closingTag); + newElement.selectable = this.treeOutline._selectEnabled; + this.insertChild(newElement, index); + return newElement; + }, + + moveChild: function(child, targetIndex) + { + var wasSelected = child.selected; + this.removeChild(child); + this.insertChild(child, targetIndex); + if (wasSelected) + child.select(); + }, + + /** + * @param {boolean=} fullRefresh + */ + _updateChildren: function(fullRefresh) + { + if (this._updateChildrenInProgress || !this.treeOutline._visible) + return; + + this._updateChildrenInProgress = true; + var selectedNode = this.treeOutline.selectedDOMNode(); + var originalScrollTop = 0; + if (fullRefresh) { + var treeOutlineContainerElement = this.treeOutline.element.parentNode; + originalScrollTop = treeOutlineContainerElement.scrollTop; + var selectedTreeElement = this.treeOutline.selectedTreeElement; + if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) + this.select(); + this.removeChildren(); + } + + var treeElement = this; + var treeChildIndex = 0; + var elementToSelect; + + function updateChildrenOfNode() + { + var treeOutline = treeElement.treeOutline; + var visibleChildren = this._visibleChildren(); + + for (var i = 0; i < visibleChildren.length; ++i) { + var child = visibleChildren[i]; + var currentTreeElement = treeElement.children[treeChildIndex]; + if (!currentTreeElement || currentTreeElement._node !== child) { + // Find any existing element that is later in the children list. + var existingTreeElement = null; + for (var j = (treeChildIndex + 1), size = treeElement.expandedChildCount; j < size; ++j) { + if (treeElement.children[j]._node === child) { + existingTreeElement = treeElement.children[j]; + break; + } + } + + if (existingTreeElement && existingTreeElement.parent === treeElement) { + // If an existing element was found and it has the same parent, just move it. + treeElement.moveChild(existingTreeElement, treeChildIndex); + } else { + // No existing element found, insert a new element. + if (treeChildIndex < treeElement.expandedChildrenLimit) { + var newElement = treeElement.insertChildElement(child, treeChildIndex); + if (child === selectedNode) + elementToSelect = newElement; + if (treeElement.expandedChildCount > treeElement.expandedChildrenLimit) + treeElement.expandedChildrenLimit++; + } + } + } + + ++treeChildIndex; + } + } + + // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. + for (var i = (this.children.length - 1); i >= 0; --i) { + var currentChild = this.children[i]; + var currentNode = currentChild._node; + if (!currentNode) + continue; + var currentParentNode = currentNode.parentNode; + + if (currentParentNode === this._node) + continue; + + var selectedTreeElement = this.treeOutline.selectedTreeElement; + if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) + this.select(); + + this.removeChildAtIndex(i); + } + + updateChildrenOfNode.call(this); + this._adjustCollapsedRange(); + + var lastChild = this.children[this.children.length - 1]; + if (this._node.nodeType() == Node.ELEMENT_NODE && (!lastChild || !lastChild._elementCloseTag)) + this.insertChildElement(this._node, this.children.length, true); + + // We want to restore the original selection and tree scroll position after a full refresh, if possible. + if (fullRefresh && elementToSelect) { + elementToSelect.select(); + if (treeOutlineContainerElement && originalScrollTop <= treeOutlineContainerElement.scrollHeight) + treeOutlineContainerElement.scrollTop = originalScrollTop; + } + + delete this._updateChildrenInProgress; + }, + + _adjustCollapsedRange: function() + { + var visibleChildren = this._visibleChildren(); + // Ensure precondition: only the tree elements for node children are found in the tree + // (not the Expand All button or the closing tag). + if (this.expandAllButtonElement && this.expandAllButtonElement.__treeElement.parent) + this.removeChild(this.expandAllButtonElement.__treeElement); + + const childNodeCount = visibleChildren.length; + + // In case some nodes from the expanded range were removed, pull some nodes from the collapsed range into the expanded range at the bottom. + for (var i = this.expandedChildCount, limit = Math.min(this.expandedChildrenLimit, childNodeCount); i < limit; ++i) + this.insertChildElement(visibleChildren[i], i); + + const expandedChildCount = this.expandedChildCount; + if (childNodeCount > this.expandedChildCount) { + var targetButtonIndex = expandedChildCount; + if (!this.expandAllButtonElement) { + var button = document.createElement("button"); + button.className = "show-all-nodes"; + button.value = ""; + var item = new TreeElement(button, null, false); + item.selectable = false; + item.expandAllButton = true; + this.insertChild(item, targetButtonIndex); + this.expandAllButtonElement = item.listItemElement.firstChild; + this.expandAllButtonElement.__treeElement = item; + this.expandAllButtonElement.addEventListener("click", this.handleLoadAllChildren.bind(this), false); + } else if (!this.expandAllButtonElement.__treeElement.parent) + this.insertChild(this.expandAllButtonElement.__treeElement, targetButtonIndex); + this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)", childNodeCount - expandedChildCount); + } else if (this.expandAllButtonElement) + delete this.expandAllButtonElement; + }, + + handleLoadAllChildren: function() + { + this.expandedChildrenLimit = Math.max(this._visibleChildCount(), this.expandedChildrenLimit + WebInspector.ElementsTreeElement.InitialChildrenLimit); + }, + + expandRecursively: function() + { + function callback() + { + TreeElement.prototype.expandRecursively.call(this, Number.MAX_VALUE); + } + + this._node.getSubtree(-1, callback.bind(this)); + }, + + onexpand: function() + { + if (this._elementCloseTag) + return; + + this.updateTitle(); + this.treeOutline.updateSelection(); + }, + + oncollapse: function() + { + if (this._elementCloseTag) + return; + + this.updateTitle(); + this.treeOutline.updateSelection(); + }, + + onreveal: function() + { + if (this.listItemElement) { + var tagSpans = this.listItemElement.getElementsByClassName("webkit-html-tag-name"); + if (tagSpans.length) + tagSpans[0].scrollIntoViewIfNeeded(false); + else + this.listItemElement.scrollIntoViewIfNeeded(false); + } + }, + + onselect: function(selectedByUser) + { + this.treeOutline.suppressRevealAndSelect = true; + this.treeOutline.selectDOMNode(this._node, selectedByUser); + if (selectedByUser) + WebInspector.domAgent.highlightDOMNode(this._node.id); + this.updateSelection(); + this.treeOutline.suppressRevealAndSelect = false; + return true; + }, + + ondelete: function() + { + var startTagTreeElement = this.treeOutline.findTreeElement(this._node); + startTagTreeElement ? startTagTreeElement.remove() : this.remove(); + return true; + }, + + onenter: function() + { + // On Enter or Return start editing the first attribute + // or create a new attribute on the selected element. + if (this._editing) + return false; + + this._startEditing(); + + // prevent a newline from being immediately inserted + return true; + }, + + selectOnMouseDown: function(event) + { + TreeElement.prototype.selectOnMouseDown.call(this, event); + + if (this._editing) + return; + + if (this.treeOutline._showInElementsPanelEnabled) { + WebInspector.showPanel("elements"); + this.treeOutline.selectDOMNode(this._node, true); + } + + // Prevent selecting the nearest word on double click. + if (event.detail >= 2) + event.preventDefault(); + }, + + ondblclick: function(event) + { + if (this._editing || this._elementCloseTag) + return; + + if (this._startEditingTarget(event.target)) + return; + + if (this.hasChildren && !this.expanded) + this.expand(); + }, + + _insertInLastAttributePosition: function(tag, node) + { + if (tag.getElementsByClassName("webkit-html-attribute").length > 0) + tag.insertBefore(node, tag.lastChild); + else { + var nodeName = tag.textContent.match(/^<(.*?)>$/)[1]; + tag.textContent = ''; + tag.appendChild(document.createTextNode('<'+nodeName)); + tag.appendChild(node); + tag.appendChild(document.createTextNode('>')); + } + + this.updateSelection(); + }, + + _startEditingTarget: function(eventTarget) + { + if (this.treeOutline.selectedDOMNode() != this._node) + return; + + if (this._node.nodeType() != Node.ELEMENT_NODE && this._node.nodeType() != Node.TEXT_NODE) + return false; + + var textNode = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-text-node"); + if (textNode) + return this._startEditingTextNode(textNode); + + var attribute = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-attribute"); + if (attribute) + return this._startEditingAttribute(attribute, eventTarget); + + var tagName = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-tag-name"); + if (tagName) + return this._startEditingTagName(tagName); + + var newAttribute = eventTarget.enclosingNodeOrSelfWithClass("add-attribute"); + if (newAttribute) + return this._addNewAttribute(); + + return false; + }, + + _populateTagContextMenu: function(contextMenu, event) + { + var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute"); + var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute"); + + // Add attribute-related actions. + var treeElement = this._elementCloseTag ? this.treeOutline.findTreeElement(this._node) : this; + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Add attribute" : "Add Attribute"), this._addNewAttribute.bind(treeElement)); + if (attribute && !newAttribute) + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit attribute" : "Edit Attribute"), this._startEditingAttribute.bind(this, attribute, event.target)); + contextMenu.appendSeparator(); + if (this.treeOutline._setPseudoClassCallback) { + var pseudoSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Force element state" : "Force Element State")); + this._populateForcedPseudoStateItems(pseudoSubMenu); + contextMenu.appendSeparator(); + } + + this._populateNodeContextMenu(contextMenu); + this.treeOutline._populateContextMenu(contextMenu, this._node); + + contextMenu.appendSeparator(); + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Scroll into view" : "Scroll into View"), this._scrollIntoView.bind(this)); + }, + + _populateForcedPseudoStateItems: function(subMenu) + { + const pseudoClasses = ["active", "hover", "focus", "visited"]; + var node = this._node; + var forcedPseudoState = (node ? node.getUserProperty("pseudoState") : null) || []; + for (var i = 0; i < pseudoClasses.length; ++i) { + var pseudoClassForced = forcedPseudoState.indexOf(pseudoClasses[i]) >= 0; + subMenu.appendCheckboxItem(":" + pseudoClasses[i], this.treeOutline._setPseudoClassCallback.bind(null, node.id, pseudoClasses[i], !pseudoClassForced), pseudoClassForced, false); + } + }, + + _populateTextContextMenu: function(contextMenu, textNode) + { + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Edit text" : "Edit Text"), this._startEditingTextNode.bind(this, textNode)); + this._populateNodeContextMenu(contextMenu); + }, + + _populateNodeContextMenu: function(contextMenu) + { + // Add free-form node-related actions. + var openTagElement = this.treeOutline.getCachedTreeElement(this.representedObject) || this; + contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTagElement._editAsHTML.bind(openTagElement)); + contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); + contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._copyXPath.bind(this)); + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Inspect DOM properties" : "Inspect DOM Properties"), this._inspectDOMProperties.bind(this)); + }, + + _startEditing: function() + { + if (this.treeOutline.selectedDOMNode() !== this._node) + return; + + var listItem = this._listItemNode; + + if (this._canAddAttributes) { + var attribute = listItem.getElementsByClassName("webkit-html-attribute")[0]; + if (attribute) + return this._startEditingAttribute(attribute, attribute.getElementsByClassName("webkit-html-attribute-value")[0]); + + return this._addNewAttribute(); + } + + if (this._node.nodeType() === Node.TEXT_NODE) { + var textNode = listItem.getElementsByClassName("webkit-html-text-node")[0]; + if (textNode) + return this._startEditingTextNode(textNode); + return; + } + }, + + _addNewAttribute: function() + { + // Cannot just convert the textual html into an element without + // a parent node. Use a temporary span container for the HTML. + var container = document.createElement("span"); + this._buildAttributeDOM(container, " ", ""); + var attr = container.firstChild; + attr.style.marginLeft = "2px"; // overrides the .editing margin rule + attr.style.marginRight = "2px"; // overrides the .editing margin rule + + var tag = this.listItemElement.getElementsByClassName("webkit-html-tag")[0]; + this._insertInLastAttributePosition(tag, attr); + attr.scrollIntoViewIfNeeded(true); + return this._startEditingAttribute(attr, attr); + }, + + _triggerEditAttribute: function(attributeName) + { + var attributeElements = this.listItemElement.getElementsByClassName("webkit-html-attribute-name"); + for (var i = 0, len = attributeElements.length; i < len; ++i) { + if (attributeElements[i].textContent === attributeName) { + for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) { + if (elem.nodeType !== Node.ELEMENT_NODE) + continue; + + if (elem.hasStyleClass("webkit-html-attribute-value")) + return this._startEditingAttribute(elem.parentNode, elem); + } + } + } + }, + + _startEditingAttribute: function(attribute, elementForSelection) + { + if (WebInspector.isBeingEdited(attribute)) + return true; + + var attributeNameElement = attribute.getElementsByClassName("webkit-html-attribute-name")[0]; + if (!attributeNameElement) + return false; + + var attributeName = attributeNameElement.textContent; + var attributeValueElement = attribute.getElementsByClassName("webkit-html-attribute-value")[0]; + + function removeZeroWidthSpaceRecursive(node) + { + if (node.nodeType === Node.TEXT_NODE) { + node.nodeValue = node.nodeValue.replace(/\u200B/g, ""); + return; + } + + if (node.nodeType !== Node.ELEMENT_NODE) + return; + + for (var child = node.firstChild; child; child = child.nextSibling) + removeZeroWidthSpaceRecursive(child); + } + + var domNode; + var listItemElement = attribute.enclosingNodeOrSelfWithNodeName("li"); + if (attributeName && attributeValueElement && listItemElement && listItemElement.treeElement) + domNode = listItemElement.treeElement.representedObject; + var attributeValue = domNode ? domNode.getAttribute(attributeName) : undefined; + if (typeof attributeValue !== "undefined") + attributeValueElement.textContent = attributeValue; + + // Remove zero-width spaces that were added by nodeTitleInfo. + removeZeroWidthSpaceRecursive(attribute); + + var config = new WebInspector.EditingConfig(this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName); + + function handleKeyDownEvents(event) + { + var isMetaOrCtrl = WebInspector.isMac() ? + event.metaKey && !event.shiftKey && !event.ctrlKey && !event.altKey : + event.ctrlKey && !event.shiftKey && !event.metaKey && !event.altKey; + if (isEnterKey(event) && (event.isMetaOrCtrlForTest || !config.multiline || isMetaOrCtrl)) + return "commit"; + else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Esc.code || event.keyIdentifier === "U+001B") + return "cancel"; + else if (event.keyIdentifier === "U+0009") // Tab key + return "move-" + (event.shiftKey ? "backward" : "forward"); + else { + WebInspector.handleElementValueModifications(event, attribute); + return ""; + } + } + + config.customFinishHandler = handleKeyDownEvents.bind(this); + + this._editing = WebInspector.startEditing(attribute, config); + + window.getSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1); + + return true; + }, + + /** + * @param {Element} textNodeElement + */ + _startEditingTextNode: function(textNodeElement) + { + if (WebInspector.isBeingEdited(textNodeElement)) + return true; + + var textNode = this._node; + // We only show text nodes inline in elements if the element only + // has a single child, and that child is a text node. + if (textNode.nodeType() === Node.ELEMENT_NODE && textNode.firstChild) + textNode = textNode.firstChild; + + var container = textNodeElement.enclosingNodeOrSelfWithClass("webkit-html-text-node"); + if (container) + container.textContent = textNode.nodeValue(); // Strip the CSS or JS highlighting if present. + var config = new WebInspector.EditingConfig(this._textNodeEditingCommitted.bind(this, textNode), this._editingCancelled.bind(this)); + this._editing = WebInspector.startEditing(textNodeElement, config); + window.getSelection().setBaseAndExtent(textNodeElement, 0, textNodeElement, 1); + + return true; + }, + + /** + * @param {Element=} tagNameElement + */ + _startEditingTagName: function(tagNameElement) + { + if (!tagNameElement) { + tagNameElement = this.listItemElement.getElementsByClassName("webkit-html-tag-name")[0]; + if (!tagNameElement) + return false; + } + + var tagName = tagNameElement.textContent; + if (WebInspector.ElementsTreeElement.EditTagBlacklist[tagName.toLowerCase()]) + return false; + + if (WebInspector.isBeingEdited(tagNameElement)) + return true; + + var closingTagElement = this._distinctClosingTagElement(); + + function keyupListener(event) + { + if (closingTagElement) + closingTagElement.textContent = ""; + } + + function editingComitted(element, newTagName) + { + tagNameElement.removeEventListener('keyup', keyupListener, false); + this._tagNameEditingCommitted.apply(this, arguments); + } + + function editingCancelled() + { + tagNameElement.removeEventListener('keyup', keyupListener, false); + this._editingCancelled.apply(this, arguments); + } + + tagNameElement.addEventListener('keyup', keyupListener, false); + + var config = new WebInspector.EditingConfig(editingComitted.bind(this), editingCancelled.bind(this), tagName); + this._editing = WebInspector.startEditing(tagNameElement, config); + window.getSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1); + return true; + }, + + _startEditingAsHTML: function(commitCallback, error, initialValue) + { + if (error) + return; + if (this._editing) + return; + + function consume(event) + { + if (event.eventPhase === Event.AT_TARGET) + event.consume(true); + } + + initialValue = this._convertWhitespaceToEntities(initialValue); + + this._htmlEditElement = document.createElement("div"); + this._htmlEditElement.className = "source-code elements-tree-editor"; + + // Hide header items. + var child = this.listItemElement.firstChild; + while (child) { + child.style.display = "none"; + child = child.nextSibling; + } + // Hide children item. + if (this._childrenListNode) + this._childrenListNode.style.display = "none"; + // Append editor. + this.listItemElement.appendChild(this._htmlEditElement); + this.treeOutline.childrenListElement.parentElement.addEventListener("mousedown", consume, false); + + this.updateSelection(); + + /** + * @param {Element} element + * @param {string} newValue + */ + function commit(element, newValue) + { + commitCallback(initialValue, newValue); + dispose.call(this); + } + + function dispose() + { + delete this._editing; + delete this.treeOutline._multilineEditing; + + // Remove editor. + this.listItemElement.removeChild(this._htmlEditElement); + delete this._htmlEditElement; + // Unhide children item. + if (this._childrenListNode) + this._childrenListNode.style.removeProperty("display"); + // Unhide header items. + var child = this.listItemElement.firstChild; + while (child) { + child.style.removeProperty("display"); + child = child.nextSibling; + } + + this.treeOutline.childrenListElement.parentElement.removeEventListener("mousedown", consume, false); + this.updateSelection(); + this.treeOutline.element.focus(); + } + + var config = new WebInspector.EditingConfig(commit.bind(this), dispose.bind(this)); + config.setMultilineOptions(initialValue, { name: "xml", htmlMode: true }, "web-inspector-html", WebInspector.settings.domWordWrap.get(), true); + this._editing = WebInspector.startEditing(this._htmlEditElement, config); + this._editing.setWidth(this.treeOutline._visibleWidth); + this.treeOutline._multilineEditing = this._editing; + }, + + _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection) + { + delete this._editing; + + var treeOutline = this.treeOutline; + /** + * @param {Protocol.Error=} error + */ + function moveToNextAttributeIfNeeded(error) + { + if (error) + this._editingCancelled(element, attributeName); + + if (!moveDirection) + return; + + treeOutline._updateModifiedNodes(); + + // Search for the attribute's position, and then decide where to move to. + var attributes = this._node.attributes(); + for (var i = 0; i < attributes.length; ++i) { + if (attributes[i].name !== attributeName) + continue; + + if (moveDirection === "backward") { + if (i === 0) + this._startEditingTagName(); + else + this._triggerEditAttribute(attributes[i - 1].name); + } else { + if (i === attributes.length - 1) + this._addNewAttribute(); + else + this._triggerEditAttribute(attributes[i + 1].name); + } + return; + } + + // Moving From the "New Attribute" position. + if (moveDirection === "backward") { + if (newText === " ") { + // Moving from "New Attribute" that was not edited + if (attributes.length > 0) + this._triggerEditAttribute(attributes[attributes.length - 1].name); + } else { + // Moving from "New Attribute" that holds new value + if (attributes.length > 1) + this._triggerEditAttribute(attributes[attributes.length - 2].name); + } + } else if (moveDirection === "forward") { + if (!/^\s*$/.test(newText)) + this._addNewAttribute(); + else + this._startEditingTagName(); + } + } + + if (!attributeName.trim() && !newText.trim()) { + element.remove(); + moveToNextAttributeIfNeeded.call(this); + return; + } + + if (oldText !== newText) { + this._node.setAttribute(attributeName, newText, moveToNextAttributeIfNeeded.bind(this)); + return; + } + + this.updateTitle(); + moveToNextAttributeIfNeeded.call(this); + }, + + _tagNameEditingCommitted: function(element, newText, oldText, tagName, moveDirection) + { + delete this._editing; + var self = this; + + function cancel() + { + var closingTagElement = self._distinctClosingTagElement(); + if (closingTagElement) + closingTagElement.textContent = ""; + + self._editingCancelled(element, tagName); + moveToNextAttributeIfNeeded.call(self); + } + + function moveToNextAttributeIfNeeded() + { + if (moveDirection !== "forward") { + this._addNewAttribute(); + return; + } + + var attributes = this._node.attributes(); + if (attributes.length > 0) + this._triggerEditAttribute(attributes[0].name); + else + this._addNewAttribute(); + } + + newText = newText.trim(); + if (newText === oldText) { + cancel(); + return; + } + + var treeOutline = this.treeOutline; + var wasExpanded = this.expanded; + + function changeTagNameCallback(error, nodeId) + { + if (error || !nodeId) { + cancel(); + return; + } + var newTreeItem = treeOutline._selectNodeAfterEdit(wasExpanded, error, nodeId); + moveToNextAttributeIfNeeded.call(newTreeItem); + } + + this._node.setNodeName(newText, changeTagNameCallback); + }, + + /** + * @param {WebInspector.DOMNode} textNode + * @param {Element} element + * @param {string} newText + */ + _textNodeEditingCommitted: function(textNode, element, newText) + { + delete this._editing; + + function callback() + { + this.updateTitle(); + } + textNode.setNodeValue(newText, callback.bind(this)); + }, + + /** + * @param {Element} element + * @param {*} context + */ + _editingCancelled: function(element, context) + { + delete this._editing; + + // Need to restore attributes structure. + this.updateTitle(); + }, + + _distinctClosingTagElement: function() + { + // FIXME: Improve the Tree Element / Outline Abstraction to prevent crawling the DOM + + // For an expanded element, it will be the last element with class "close" + // in the child element list. + if (this.expanded) { + var closers = this._childrenListNode.querySelectorAll(".close"); + return closers[closers.length-1]; + } + + // Remaining cases are single line non-expanded elements with a closing + // tag, or HTML elements without a closing tag (such as
      ). Return + // null in the case where there isn't a closing tag. + var tags = this.listItemElement.getElementsByClassName("webkit-html-tag"); + return (tags.length === 1 ? null : tags[tags.length-1]); + }, + + /** + * @param {boolean=} onlySearchQueryChanged + */ + updateTitle: function(onlySearchQueryChanged) + { + // If we are editing, return early to prevent canceling the edit. + // After editing is committed updateTitle will be called. + if (this._editing) + return; + + if (onlySearchQueryChanged) { + if (this._highlightResult) + this._updateSearchHighlight(false); + } else { + var highlightElement = document.createElement("span"); + highlightElement.className = "highlight"; + highlightElement.appendChild(this._nodeTitleInfo(WebInspector.linkifyURLAsNode).titleDOM); + this.title = highlightElement; + this._updateDecorations(); + delete this._highlightResult; + } + + delete this.selectionElement; + if (this.selected) + this.updateSelection(); + this._preventFollowingLinksOnDoubleClick(); + this._highlightSearchResults(); + }, + + _createDecoratorElement: function() + { + var node = this._node; + var decoratorMessages = []; + var parentDecoratorMessages = []; + for (var i = 0; i < this.treeOutline._nodeDecorators.length; ++i) { + var decorator = this.treeOutline._nodeDecorators[i]; + var message = decorator.decorate(node); + if (message) { + decoratorMessages.push(message); + continue; + } + + if (this.expanded || this._elementCloseTag) + continue; + + message = decorator.decorateAncestor(node); + if (message) + parentDecoratorMessages.push(message) + } + if (!decoratorMessages.length && !parentDecoratorMessages.length) + return null; + + var decoratorElement = document.createElement("div"); + decoratorElement.addStyleClass("elements-gutter-decoration"); + if (!decoratorMessages.length) + decoratorElement.addStyleClass("elements-has-decorated-children"); + decoratorElement.title = decoratorMessages.concat(parentDecoratorMessages).join("\n"); + return decoratorElement; + }, + + _updateDecorations: function() + { + if (this._decoratorElement) + this._decoratorElement.remove(); + this._decoratorElement = this._createDecoratorElement(); + if (this._decoratorElement && this.listItemElement) + this.listItemElement.insertBefore(this._decoratorElement, this.listItemElement.firstChild); + }, + + /** + * @param {WebInspector.DOMNode=} node + * @param {function(string, string, string, boolean=, string=)=} linkify + */ + _buildAttributeDOM: function(parentElement, name, value, node, linkify) + { + var hasText = (value.length > 0); + var attrSpanElement = parentElement.createChild("span", "webkit-html-attribute"); + var attrNameElement = attrSpanElement.createChild("span", "webkit-html-attribute-name"); + attrNameElement.textContent = name; + + if (hasText) + attrSpanElement.appendChild(document.createTextNode("=\u200B\"")); + + if (linkify && (name === "src" || name === "href")) { + var rewrittenHref = node.resolveURL(value); + value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B"); + if (rewrittenHref === null) { + var attrValueElement = attrSpanElement.createChild("span", "webkit-html-attribute-value"); + attrValueElement.textContent = value; + } else { + if (value.startsWith("data:")) + value = value.trimMiddle(60); + attrSpanElement.appendChild(linkify(rewrittenHref, value, "webkit-html-attribute-value", node.nodeName().toLowerCase() === "a")); + } + } else { + value = value.replace(/([\/;:\)\]\}])/g, "$1\u200B"); + var attrValueElement = attrSpanElement.createChild("span", "webkit-html-attribute-value"); + attrValueElement.textContent = value; + } + + if (hasText) + attrSpanElement.appendChild(document.createTextNode("\"")); + }, + + /** + * @param {function(string, string, string, boolean=, string=)=} linkify + */ + _buildTagDOM: function(parentElement, tagName, isClosingTag, isDistinctTreeElement, linkify) + { + var node = this._node; + var classes = [ "webkit-html-tag" ]; + if (isClosingTag && isDistinctTreeElement) + classes.push("close"); + if (node.isInShadowTree()) + classes.push("shadow"); + var tagElement = parentElement.createChild("span", classes.join(" ")); + tagElement.appendChild(document.createTextNode("<")); + var tagNameElement = tagElement.createChild("span", isClosingTag ? "" : "webkit-html-tag-name"); + tagNameElement.textContent = (isClosingTag ? "/" : "") + tagName; + if (!isClosingTag && node.hasAttributes()) { + var attributes = node.attributes(); + for (var i = 0; i < attributes.length; ++i) { + var attr = attributes[i]; + tagElement.appendChild(document.createTextNode(" ")); + this._buildAttributeDOM(tagElement, attr.name, attr.value, node, linkify); + } + } + tagElement.appendChild(document.createTextNode(">")); + parentElement.appendChild(document.createTextNode("\u200B")); + }, + + _convertWhitespaceToEntities: function(text) + { + var result = ""; + var lastIndexAfterEntity = 0; + var charToEntity = WebInspector.ElementsTreeOutline.MappedCharToEntity; + for (var i = 0, size = text.length; i < size; ++i) { + var char = text.charAt(i); + if (charToEntity[char]) { + result += text.substring(lastIndexAfterEntity, i) + "&" + charToEntity[char] + ";"; + lastIndexAfterEntity = i + 1; + } + } + if (result) { + result += text.substring(lastIndexAfterEntity); + return result; + } + return text; + }, + + _nodeTitleInfo: function(linkify) + { + var node = this._node; + var info = {titleDOM: document.createDocumentFragment(), hasChildren: this.hasChildren}; + + switch (node.nodeType()) { + case Node.ATTRIBUTE_NODE: + var value = node.value || "\u200B"; // Zero width space to force showing an empty value. + this._buildAttributeDOM(info.titleDOM, node.name, value); + break; + + case Node.ELEMENT_NODE: + var tagName = node.nodeNameInCorrectCase(); + if (this._elementCloseTag) { + this._buildTagDOM(info.titleDOM, tagName, true, true); + info.hasChildren = false; + break; + } + + this._buildTagDOM(info.titleDOM, tagName, false, false, linkify); + + var showInlineText = this._showInlineText() && !this.hasChildren; + if (!this.expanded && (!showInlineText && (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements[tagName]))) { + if (this.hasChildren) { + var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node bogus"); + textNodeElement.textContent = "\u2026"; + info.titleDOM.appendChild(document.createTextNode("\u200B")); + } + this._buildTagDOM(info.titleDOM, tagName, true, false); + } + + // If this element only has a single child that is a text node, + // just show that text and the closing tag inline rather than + // create a subtree for them + if (showInlineText) { + var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node"); + textNodeElement.textContent = this._convertWhitespaceToEntities(node.firstChild.nodeValue()); + info.titleDOM.appendChild(document.createTextNode("\u200B")); + this._buildTagDOM(info.titleDOM, tagName, true, false); + info.hasChildren = false; + } + break; + + case Node.TEXT_NODE: + if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "script") { + var newNode = info.titleDOM.createChild("span", "webkit-html-text-node webkit-html-js-node"); + newNode.textContent = node.nodeValue(); + + var javascriptSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/javascript", true); + javascriptSyntaxHighlighter.syntaxHighlightNode(newNode); + } else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "style") { + var newNode = info.titleDOM.createChild("span", "webkit-html-text-node webkit-html-css-node"); + newNode.textContent = node.nodeValue(); + + var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/css", true); + cssSyntaxHighlighter.syntaxHighlightNode(newNode); + } else { + info.titleDOM.appendChild(document.createTextNode("\"")); + var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node"); + textNodeElement.textContent = this._convertWhitespaceToEntities(node.nodeValue()); + info.titleDOM.appendChild(document.createTextNode("\"")); + } + break; + + case Node.COMMENT_NODE: + var commentElement = info.titleDOM.createChild("span", "webkit-html-comment"); + commentElement.appendChild(document.createTextNode("")); + break; + + case Node.DOCUMENT_TYPE_NODE: + var docTypeElement = info.titleDOM.createChild("span", "webkit-html-doctype"); + docTypeElement.appendChild(document.createTextNode("")); + break; + + case Node.CDATA_SECTION_NODE: + var cdataElement = info.titleDOM.createChild("span", "webkit-html-text-node"); + cdataElement.appendChild(document.createTextNode("")); + break; + case Node.DOCUMENT_FRAGMENT_NODE: + var fragmentElement = info.titleDOM.createChild("span", "webkit-html-fragment"); + fragmentElement.textContent = node.nodeNameInCorrectCase().collapseWhitespace(); + if (node.isInShadowTree()) + fragmentElement.addStyleClass("shadow"); + break; + default: + info.titleDOM.appendChild(document.createTextNode(node.nodeNameInCorrectCase().collapseWhitespace())); + } + return info; + }, + + _showInlineText: function() + { + if (this._node.templateContent() || (WebInspector.ElementsTreeOutline.showShadowDOM() && this._node.hasShadowRoots())) + return false; + if (this._node.nodeType() !== Node.ELEMENT_NODE) + return false; + if (!this._node.firstChild || this._node.firstChild !== this._node.lastChild || this._node.firstChild.nodeType() !== Node.TEXT_NODE) + return false; + var textChild = this._node.firstChild; + if (textChild.nodeValue().length < Preferences.maxInlineTextChildLength) + return true; + return false; + }, + + remove: function() + { + var parentElement = this.parent; + if (!parentElement) + return; + + var self = this; + function removeNodeCallback(error, removedNodeId) + { + if (error) + return; + + parentElement.removeChild(self); + parentElement._adjustCollapsedRange(); + } + + if (!this._node.parentNode || this._node.parentNode.nodeType() === Node.DOCUMENT_NODE) + return; + this._node.removeNode(removeNodeCallback); + }, + + _editAsHTML: function() + { + var treeOutline = this.treeOutline; + var node = this._node; + var parentNode = node.parentNode; + var index = node.index; + var wasExpanded = this.expanded; + + function selectNode(error, nodeId) + { + if (error) + return; + + // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date. + treeOutline._updateModifiedNodes(); + + var newNode = parentNode ? parentNode.children()[index] || parentNode : null; + if (!newNode) + return; + + treeOutline.selectDOMNode(newNode, true); + + if (wasExpanded) { + var newTreeItem = treeOutline.findTreeElement(newNode); + if (newTreeItem) + newTreeItem.expand(); + } + } + + function commitChange(initialValue, value) + { + if (initialValue !== value) + node.setOuterHTML(value, selectNode); + else + return; + } + + node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); + }, + + _copyHTML: function() + { + this._node.copyNode(); + }, + + _copyXPath: function() + { + this._node.copyXPath(true); + }, + + _inspectDOMProperties: function() + { + WebInspector.RemoteObject.resolveNode(this._node, "console", callback); + + /** + * @param {WebInspector.RemoteObject} nodeObject + */ + function callback(nodeObject) + { + if (!nodeObject) + return; + + var message = WebInspector.ConsoleMessage.create(WebInspector.ConsoleMessage.MessageSource.ConsoleAPI, WebInspector.ConsoleMessage.MessageLevel.Log, "", WebInspector.ConsoleMessage.MessageType.Dir, undefined, undefined, undefined, undefined, [nodeObject]); + WebInspector.console.addMessage(message); + WebInspector.showConsole(); + } + }, + + _highlightSearchResults: function() + { + if (!this._searchQuery || !this._searchHighlightsVisible) + return; + if (this._highlightResult) { + this._updateSearchHighlight(true); + return; + } + + var text = this.listItemElement.textContent; + var regexObject = createPlainTextSearchRegex(this._searchQuery, "gi"); + + var offset = 0; + var match = regexObject.exec(text); + var matchRanges = []; + while (match) { + matchRanges.push({ offset: match.index, length: match[0].length }); + match = regexObject.exec(text); + } + + // Fall back for XPath, etc. matches. + if (!matchRanges.length) + matchRanges.push({ offset: 0, length: text.length }); + + this._highlightResult = []; + WebInspector.highlightSearchResults(this.listItemElement, matchRanges, this._highlightResult); + }, + + _scrollIntoView: function() + { + function scrollIntoViewCallback(object) + { + function scrollIntoView() + { + this.scrollIntoViewIfNeeded(true); + } + + if (object) + object.callFunction(scrollIntoView); + } + + WebInspector.RemoteObject.resolveNode(this._node, "", scrollIntoViewCallback); + }, + + /** + * @return {Array.} visibleChildren + */ + _visibleChildren: function() + { + var visibleChildren = WebInspector.ElementsTreeOutline.showShadowDOM() ? this._node.shadowRoots() : []; + if (this._node.templateContent()) + visibleChildren.push(this._node.templateContent()); + if (this._node.childNodeCount()) + visibleChildren = visibleChildren.concat(this._node.children()); + return visibleChildren; + }, + + /** + * @return {Array.} visibleChildren + */ + _visibleChildCount: function() + { + var childCount = this._node.childNodeCount(); + if (this._node.templateContent()) + childCount++; + if (WebInspector.ElementsTreeOutline.showShadowDOM()) + childCount += this._node.shadowRoots().length; + return childCount; + }, + + _updateHasChildren: function() + { + this.hasChildren = !this._elementCloseTag && !this._showInlineText() && this._visibleChildCount() > 0; + }, + + __proto__: TreeElement.prototype +} + +/** + * @constructor + * @param {!WebInspector.ElementsTreeOutline} treeOutline + */ +WebInspector.ElementsTreeUpdater = function(treeOutline) +{ + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeInserted, this._nodeInserted, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.NodeRemoved, this._nodeRemoved, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.AttrModified, this._attributesUpdated, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.AttrRemoved, this._attributesUpdated, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.CharacterDataModified, this._characterDataModified, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.DocumentUpdated, this._documentUpdated, this); + WebInspector.domAgent.addEventListener(WebInspector.DOMAgent.Events.ChildNodeCountUpdated, this._childNodeCountUpdated, this); + + this._treeOutline = treeOutline; + /** @type {!Map.} */ + this._recentlyModifiedNodes = new Map(); +} + +WebInspector.ElementsTreeUpdater.prototype = { + /** + * @param {!WebInspector.DOMNode} node + * @param {boolean} isUpdated + * @param {WebInspector.DOMNode=} parentNode + */ + _nodeModified: function(node, isUpdated, parentNode) + { + if (this._treeOutline._visible) + this._updateModifiedNodesSoon(); + + var entry = this._recentlyModifiedNodes.get(node); + if (!entry) { + entry = new WebInspector.ElementsTreeUpdater.UpdateEntry(isUpdated, parentNode); + this._recentlyModifiedNodes.put(node, entry); + return; + } + + entry.isUpdated |= isUpdated; + if (parentNode) + entry.parent = parentNode; + }, + + _documentUpdated: function(event) + { + var inspectedRootDocument = event.data; + + this._reset(); + + if (!inspectedRootDocument) + return; + + this._treeOutline.rootDOMNode = inspectedRootDocument; + }, + + _attributesUpdated: function(event) + { + this._nodeModified(event.data.node, true); + }, + + _characterDataModified: function(event) + { + this._nodeModified(event.data, true); + }, + + _nodeInserted: function(event) + { + this._nodeModified(event.data, false, event.data.parentNode); + }, + + _nodeRemoved: function(event) + { + this._nodeModified(event.data.node, false, event.data.parent); + }, + + _childNodeCountUpdated: function(event) + { + var treeElement = this._treeOutline.findTreeElement(event.data); + if (treeElement) + treeElement._updateHasChildren(); + }, + + _updateModifiedNodesSoon: function() + { + if (this._updateModifiedNodesTimeout) + return; + this._updateModifiedNodesTimeout = setTimeout(this._updateModifiedNodes.bind(this), 50); + }, + + _updateModifiedNodes: function() + { + if (this._updateModifiedNodesTimeout) { + clearTimeout(this._updateModifiedNodesTimeout); + delete this._updateModifiedNodesTimeout; + } + + var updatedParentTreeElements = []; + + var hidePanelWhileUpdating = this._recentlyModifiedNodes.size() > 10; + if (hidePanelWhileUpdating) { + var treeOutlineContainerElement = this._treeOutline.element.parentNode; + this._treeOutline.element.addStyleClass("hidden"); + var originalScrollTop = treeOutlineContainerElement ? treeOutlineContainerElement.scrollTop : 0; + } + + var nodes = this._recentlyModifiedNodes.keys(); + for (var i = 0, size = nodes.length; i < size; ++i) { + var node = nodes[i]; + var entry = this._recentlyModifiedNodes.get(node); + var parent = entry.parent; + + if (parent === this._treeOutline._rootDOMNode) { + // Document's children have changed, perform total update. + this._treeOutline.update(); + this._treeOutline.element.removeStyleClass("hidden"); + return; + } + + if (entry.isUpdated) { + var nodeItem = this._treeOutline.findTreeElement(node); + if (nodeItem) + nodeItem.updateTitle(); + } + + var parentNodeItem = parent ? this._treeOutline.findTreeElement(parent) : null; + if (parentNodeItem && !parentNodeItem.alreadyUpdatedChildren) { + parentNodeItem.updateChildren(); + parentNodeItem.alreadyUpdatedChildren = true; + updatedParentTreeElements.push(parentNodeItem); + } + } + + for (var i = 0; i < updatedParentTreeElements.length; ++i) + delete updatedParentTreeElements[i].alreadyUpdatedChildren; + + if (hidePanelWhileUpdating) { + this._treeOutline.element.removeStyleClass("hidden"); + if (originalScrollTop) + treeOutlineContainerElement.scrollTop = originalScrollTop; + this._treeOutline.updateSelection(); + } + this._recentlyModifiedNodes.clear(); + + this._treeOutline._fireElementsTreeUpdated(nodes); + }, + + _reset: function() + { + this._treeOutline.rootDOMNode = null; + this._treeOutline.selectDOMNode(null, false); + WebInspector.domAgent.hideDOMNodeHighlight(); + this._recentlyModifiedNodes.clear(); + } +} + +/** + * @constructor + * @param {boolean} isUpdated + * @param {WebInspector.DOMNode=} parent + */ +WebInspector.ElementsTreeUpdater.UpdateEntry = function(isUpdated, parent) +{ + this.isUpdated = isUpdated; + if (parent) + this.parent = parent; +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EmptyView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EmptyView.js new file mode 100644 index 00000000..a8b51c17 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EmptyView.js @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.View} + */ +WebInspector.EmptyView = function(text) +{ + WebInspector.View.call(this); + this._text = text; +} + +WebInspector.EmptyView.prototype = { + wasShown: function() + { + this.element.className = "empty-view"; + this.element.textContent = this._text; + }, + + set text(text) + { + this._text = text; + if (this.isShowing()) + this.element.textContent = this._text; + }, + + __proto__: WebInspector.View.prototype +} + diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EventListenersSidebarPane.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EventListenersSidebarPane.js new file mode 100644 index 00000000..ba8cb3bc --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/EventListenersSidebarPane.js @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.SidebarPane} + */ +WebInspector.EventListenersSidebarPane = function() +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Event Listeners")); + this.bodyElement.addStyleClass("events-pane"); + + this.sections = []; + + this.settingsSelectElement = document.createElement("select"); + this.settingsSelectElement.className = "select-filter"; + + var option = document.createElement("option"); + option.value = "all"; + option.label = WebInspector.UIString("All Nodes"); + this.settingsSelectElement.appendChild(option); + + option = document.createElement("option"); + option.value = "selected"; + option.label = WebInspector.UIString("Selected Node Only"); + this.settingsSelectElement.appendChild(option); + + var filter = WebInspector.settings.eventListenersFilter.get(); + if (filter === "all") + this.settingsSelectElement[0].selected = true; + else if (filter === "selected") + this.settingsSelectElement[1].selected = true; + this.settingsSelectElement.addEventListener("click", function(event) { event.consume() }, false); + this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false); + + this.titleElement.appendChild(this.settingsSelectElement); + + this._linkifier = new WebInspector.Linkifier(); +} + +WebInspector.EventListenersSidebarPane._objectGroupName = "event-listeners-sidebar-pane"; + +WebInspector.EventListenersSidebarPane.prototype = { + update: function(node) + { + RuntimeAgent.releaseObjectGroup(WebInspector.EventListenersSidebarPane._objectGroupName); + this._linkifier.reset(); + + var body = this.bodyElement; + body.removeChildren(); + this.sections = []; + + var self = this; + function callback(error, eventListeners) { + if (error) + return; + + var selectedNodeOnly = "selected" === WebInspector.settings.eventListenersFilter.get(); + var sectionNames = []; + var sectionMap = {}; + for (var i = 0; i < eventListeners.length; ++i) { + var eventListener = eventListeners[i]; + if (selectedNodeOnly && (node.id !== eventListener.nodeId)) + continue; + eventListener.node = WebInspector.domAgent.nodeForId(eventListener.nodeId); + delete eventListener.nodeId; // no longer needed + if (/^function _inspectorCommandLineAPI_logEvent\(/.test(eventListener.handlerBody.toString())) + continue; // ignore event listeners generated by monitorEvent + var type = eventListener.type; + var section = sectionMap[type]; + if (!section) { + section = new WebInspector.EventListenersSection(type, node.id, self._linkifier); + sectionMap[type] = section; + sectionNames.push(type); + self.sections.push(section); + } + section.addListener(eventListener); + } + + if (sectionNames.length === 0) { + var div = document.createElement("div"); + div.className = "info"; + div.textContent = WebInspector.UIString("No Event Listeners"); + body.appendChild(div); + return; + } + + sectionNames.sort(); + for (var i = 0; i < sectionNames.length; ++i) { + var section = sectionMap[sectionNames[i]]; + body.appendChild(section.element); + } + } + + if (node) + node.eventListeners(WebInspector.EventListenersSidebarPane._objectGroupName, callback); + this._selectedNode = node; + }, + + willHide: function() + { + delete this._selectedNode; + }, + + _changeSetting: function() + { + var selectedOption = this.settingsSelectElement[this.settingsSelectElement.selectedIndex]; + WebInspector.settings.eventListenersFilter.set(selectedOption.value); + this.update(this._selectedNode); + }, + + __proto__: WebInspector.SidebarPane.prototype +} + +/** + * @constructor + * @extends {WebInspector.PropertiesSection} + */ +WebInspector.EventListenersSection = function(title, nodeId, linkifier) +{ + this.eventListeners = []; + this._nodeId = nodeId; + this._linkifier = linkifier; + WebInspector.PropertiesSection.call(this, title); + + // Changed from a Properties List + this.propertiesElement.remove(); + delete this.propertiesElement; + delete this.propertiesTreeOutline; + + this._eventBars = document.createElement("div"); + this._eventBars.className = "event-bars"; + this.element.appendChild(this._eventBars); +} + +WebInspector.EventListenersSection.prototype = { + addListener: function(eventListener) + { + var eventListenerBar = new WebInspector.EventListenerBar(eventListener, this._nodeId, this._linkifier); + this._eventBars.appendChild(eventListenerBar.element); + }, + + __proto__: WebInspector.PropertiesSection.prototype +} + +/** + * @constructor + * @extends {WebInspector.ObjectPropertiesSection} + */ +WebInspector.EventListenerBar = function(eventListener, nodeId, linkifier) +{ + WebInspector.ObjectPropertiesSection.call(this, WebInspector.RemoteObject.fromPrimitiveValue("")); + + this.eventListener = eventListener; + this._nodeId = nodeId; + this._setNodeTitle(); + this._setFunctionSubtitle(linkifier); + this.editable = false; + this.element.className = "event-bar"; /* Changed from "section" */ + this.headerElement.addStyleClass("source-code"); + this.propertiesElement.className = "event-properties properties-tree source-code"; /* Changed from "properties" */ +} + +WebInspector.EventListenerBar.prototype = { + update: function() + { + function updateWithNodeObject(nodeObject) + { + var properties = []; + + if (this.eventListener.type) + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("type", this.eventListener.type)); + if (typeof this.eventListener.useCapture !== "undefined") + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("useCapture", this.eventListener.useCapture)); + if (typeof this.eventListener.isAttribute !== "undefined") + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("isAttribute", this.eventListener.isAttribute)); + if (nodeObject) + properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject)); + if (typeof this.eventListener.handler !== "undefined") { + var remoteObject = WebInspector.RemoteObject.fromPayload(this.eventListener.handler); + properties.push(new WebInspector.RemoteObjectProperty("handler", remoteObject)); + } + if (typeof this.eventListener.handlerBody !== "undefined") + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("listenerBody", this.eventListener.handlerBody)); + if (this.eventListener.sourceName) + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("sourceName", this.eventListener.sourceName)); + if (this.eventListener.location) + properties.push(WebInspector.RemoteObjectProperty.fromPrimitiveValue("lineNumber", this.eventListener.location.lineNumber + 1)); + + this.updateProperties(properties); + } + WebInspector.RemoteObject.resolveNode(this.eventListener.node, WebInspector.EventListenersSidebarPane._objectGroupName, updateWithNodeObject.bind(this)); + }, + + _setNodeTitle: function() + { + var node = this.eventListener.node; + if (!node) + return; + + if (node.nodeType() === Node.DOCUMENT_NODE) { + this.titleElement.textContent = "document"; + return; + } + + if (node.id === this._nodeId) { + this.titleElement.textContent = node.appropriateSelectorFor(); + return; + } + + this.titleElement.removeChildren(); + this.titleElement.appendChild(WebInspector.DOMPresentationUtils.linkifyNodeReference(this.eventListener.node)); + }, + + _setFunctionSubtitle: function(linkifier) + { + // Requires that Function.toString() return at least the function's signature. + if (this.eventListener.location) { + this.subtitleElement.removeChildren(); + var urlElement; + if (this.eventListener.location.scriptId) + urlElement = linkifier.linkifyRawLocation(this.eventListener.location); + if (!urlElement) { + var url = this.eventListener.sourceName; + var lineNumber = this.eventListener.location.lineNumber; + var columnNumber = 0; + urlElement = linkifier.linkifyLocation(url, lineNumber, columnNumber); + } + this.subtitleElement.appendChild(urlElement); + } else { + var match = this.eventListener.handlerBody.match(/function ([^\(]+?)\(/); + if (match) + this.subtitleElement.textContent = match[1]; + else + this.subtitleElement.textContent = WebInspector.UIString("(anonymous function)"); + } + }, + + __proto__: WebInspector.ObjectPropertiesSection.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAPI.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAPI.js new file mode 100644 index 00000000..31d062c6 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAPI.js @@ -0,0 +1,907 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +function defineCommonExtensionSymbols(apiPrivate) +{ + if (!apiPrivate.audits) + apiPrivate.audits = {}; + apiPrivate.audits.Severity = { + Info: "info", + Warning: "warning", + Severe: "severe" + }; + + if (!apiPrivate.console) + apiPrivate.console = {}; + apiPrivate.console.Severity = { + Debug: "debug", + Log: "log", + Warning: "warning", + Error: "error" + }; + + if (!apiPrivate.panels) + apiPrivate.panels = {}; + apiPrivate.panels.SearchAction = { + CancelSearch: "cancelSearch", + PerformSearch: "performSearch", + NextSearchResult: "nextSearchResult", + PreviousSearchResult: "previousSearchResult" + }; + + apiPrivate.Events = { + AuditStarted: "audit-started-", + ButtonClicked: "button-clicked-", + ConsoleMessageAdded: "console-message-added", + ElementsPanelObjectSelected: "panel-objectSelected-elements", + NetworkRequestFinished: "network-request-finished", + OpenResource: "open-resource", + PanelSearch: "panel-search-", + ResourceAdded: "resource-added", + ResourceContentCommitted: "resource-content-committed", + TimelineEventRecorded: "timeline-event-recorded", + ViewShown: "view-shown-", + ViewHidden: "view-hidden-" + }; + + apiPrivate.Commands = { + AddAuditCategory: "addAuditCategory", + AddAuditResult: "addAuditResult", + AddConsoleMessage: "addConsoleMessage", + AddRequestHeaders: "addRequestHeaders", + CreatePanel: "createPanel", + CreateSidebarPane: "createSidebarPane", + CreateStatusBarButton: "createStatusBarButton", + EvaluateOnInspectedPage: "evaluateOnInspectedPage", + ForwardKeyboardEvent: "_forwardKeyboardEvent", + GetConsoleMessages: "getConsoleMessages", + GetHAR: "getHAR", + GetPageResources: "getPageResources", + GetRequestContent: "getRequestContent", + GetResourceContent: "getResourceContent", + Reload: "Reload", + Subscribe: "subscribe", + SetOpenResourceHandler: "setOpenResourceHandler", + SetResourceContent: "setResourceContent", + SetSidebarContent: "setSidebarContent", + SetSidebarHeight: "setSidebarHeight", + SetSidebarPage: "setSidebarPage", + ShowPanel: "showPanel", + StopAuditCategoryRun: "stopAuditCategoryRun", + OpenResource: "openResource", + Reload: "Reload", + Unsubscribe: "unsubscribe", + UpdateAuditProgress: "updateAuditProgress", + UpdateButton: "updateButton", + InspectedURLChanged: "inspectedURLChanged" + }; +} + +function injectedExtensionAPI(injectedScriptId) +{ + +var apiPrivate = {}; + +defineCommonExtensionSymbols(apiPrivate); + +var commands = apiPrivate.Commands; +var events = apiPrivate.Events; +var userAction = false; + +// Here and below, all constructors are private to API implementation. +// For a public type Foo, if internal fields are present, these are on +// a private FooImpl type, an instance of FooImpl is used in a closure +// by Foo consutrctor to re-bind publicly exported members to an instance +// of Foo. + +/** + * @constructor + */ +function EventSinkImpl(type, customDispatch) +{ + this._type = type; + this._listeners = []; + this._customDispatch = customDispatch; +} + +EventSinkImpl.prototype = { + addListener: function(callback) + { + if (typeof callback !== "function") + throw "addListener: callback is not a function"; + if (this._listeners.length === 0) + extensionServer.sendRequest({ command: commands.Subscribe, type: this._type }); + this._listeners.push(callback); + extensionServer.registerHandler("notify-" + this._type, this._dispatch.bind(this)); + }, + + removeListener: function(callback) + { + var listeners = this._listeners; + + for (var i = 0; i < listeners.length; ++i) { + if (listeners[i] === callback) { + listeners.splice(i, 1); + break; + } + } + if (this._listeners.length === 0) + extensionServer.sendRequest({ command: commands.Unsubscribe, type: this._type }); + }, + + _fire: function() + { + var listeners = this._listeners.slice(); + for (var i = 0; i < listeners.length; ++i) + listeners[i].apply(null, arguments); + }, + + _dispatch: function(request) + { + if (this._customDispatch) + this._customDispatch.call(this, request); + else + this._fire.apply(this, request.arguments); + } +} + +/** + * @constructor + */ +function InspectorExtensionAPI() +{ + this.audits = new Audits(); + this.inspectedWindow = new InspectedWindow(); + this.panels = new Panels(); + this.network = new Network(); + defineDeprecatedProperty(this, "webInspector", "resources", "network"); + this.timeline = new Timeline(); + this.console = new ConsoleAPI(); +} + +/** + * @constructor + */ +function ConsoleAPI() +{ + this.onMessageAdded = new EventSink(events.ConsoleMessageAdded); +} + +ConsoleAPI.prototype = { + getMessages: function(callback) + { + extensionServer.sendRequest({ command: commands.GetConsoleMessages }, callback); + }, + + addMessage: function(severity, text, url, line) + { + extensionServer.sendRequest({ command: commands.AddConsoleMessage, severity: severity, text: text, url: url, line: line }); + }, + + get Severity() + { + return apiPrivate.console.Severity; + } +} + +/** + * @constructor + */ +function Network() +{ + function dispatchRequestEvent(message) + { + var request = message.arguments[1]; + request.__proto__ = new Request(message.arguments[0]); + this._fire(request); + } + this.onRequestFinished = new EventSink(events.NetworkRequestFinished, dispatchRequestEvent); + defineDeprecatedProperty(this, "network", "onFinished", "onRequestFinished"); + this.onNavigated = new EventSink(events.InspectedURLChanged); +} + +Network.prototype = { + getHAR: function(callback) + { + function callbackWrapper(result) + { + var entries = (result && result.entries) || []; + for (var i = 0; i < entries.length; ++i) { + entries[i].__proto__ = new Request(entries[i]._requestId); + delete entries[i]._requestId; + } + callback(result); + } + return extensionServer.sendRequest({ command: commands.GetHAR }, callback && callbackWrapper); + }, + + addRequestHeaders: function(headers) + { + return extensionServer.sendRequest({ command: commands.AddRequestHeaders, headers: headers, extensionId: window.location.hostname }); + } +} + +/** + * @constructor + */ +function RequestImpl(id) +{ + this._id = id; +} + +RequestImpl.prototype = { + getContent: function(callback) + { + function callbackWrapper(response) + { + callback(response.content, response.encoding); + } + extensionServer.sendRequest({ command: commands.GetRequestContent, id: this._id }, callback && callbackWrapper); + } +} + +/** + * @constructor + */ +function Panels() +{ + var panels = { + elements: new ElementsPanel() + }; + + function panelGetter(name) + { + return panels[name]; + } + for (var panel in panels) + this.__defineGetter__(panel, panelGetter.bind(null, panel)); +} + +Panels.prototype = { + create: function(title, icon, page, callback) + { + var id = "extension-panel-" + extensionServer.nextObjectId(); + var request = { + command: commands.CreatePanel, + id: id, + title: title, + icon: icon, + page: page + }; + extensionServer.sendRequest(request, callback && callback.bind(this, new ExtensionPanel(id))); + }, + + setOpenResourceHandler: function(callback) + { + var hadHandler = extensionServer.hasHandler(events.OpenResource); + + if (!callback) + extensionServer.unregisterHandler(events.OpenResource); + else { + function callbackWrapper(message) + { + // Allow the panel to show itself when handling the event. + userAction = true; + try { + callback.call(null, new Resource(message.resource), message.lineNumber); + } finally { + userAction = false; + } + } + extensionServer.registerHandler(events.OpenResource, callbackWrapper); + } + // Only send command if we either removed an existing handler or added handler and had none before. + if (hadHandler === !callback) + extensionServer.sendRequest({ command: commands.SetOpenResourceHandler, "handlerPresent": !!callback }); + }, + + openResource: function(url, lineNumber, callback) + { + extensionServer.sendRequest({ command: commands.OpenResource, "url": url, "lineNumber": lineNumber }, callback); + }, + + get SearchAction() + { + return apiPrivate.panels.SearchAction; + } +} + +/** + * @constructor + */ +function ExtensionViewImpl(id) +{ + this._id = id; + + function dispatchShowEvent(message) + { + var frameIndex = message.arguments[0]; + this._fire(window.parent.frames[frameIndex]); + } + this.onShown = new EventSink(events.ViewShown + id, dispatchShowEvent); + this.onHidden = new EventSink(events.ViewHidden + id); +} + +/** + * @constructor + */ +function PanelWithSidebarImpl(id) +{ + this._id = id; +} + +PanelWithSidebarImpl.prototype = { + createSidebarPane: function(title, callback) + { + var id = "extension-sidebar-" + extensionServer.nextObjectId(); + var request = { + command: commands.CreateSidebarPane, + panel: this._id, + id: id, + title: title + }; + function callbackWrapper() + { + callback(new ExtensionSidebarPane(id)); + } + extensionServer.sendRequest(request, callback && callbackWrapper); + }, + + __proto__: ExtensionViewImpl.prototype +} + +/** + * @constructor + * @extends {PanelWithSidebar} + */ +function ElementsPanel() +{ + var id = "elements"; + PanelWithSidebar.call(this, id); + this.onSelectionChanged = new EventSink(events.ElementsPanelObjectSelected); +} + +/** + * @constructor + * @extends {ExtensionViewImpl} + */ +function ExtensionPanelImpl(id) +{ + ExtensionViewImpl.call(this, id); + this.onSearch = new EventSink(events.PanelSearch + id); +} + +ExtensionPanelImpl.prototype = { + createStatusBarButton: function(iconPath, tooltipText, disabled) + { + var id = "button-" + extensionServer.nextObjectId(); + var request = { + command: commands.CreateStatusBarButton, + panel: this._id, + id: id, + icon: iconPath, + tooltip: tooltipText, + disabled: !!disabled + }; + extensionServer.sendRequest(request); + return new Button(id); + }, + + show: function() + { + if (!userAction) + return; + + var request = { + command: commands.ShowPanel, + id: this._id + }; + extensionServer.sendRequest(request); + }, + + __proto__: ExtensionViewImpl.prototype +} + +/** + * @constructor + * @extends {ExtensionViewImpl} + */ +function ExtensionSidebarPaneImpl(id) +{ + ExtensionViewImpl.call(this, id); +} + +ExtensionSidebarPaneImpl.prototype = { + setHeight: function(height) + { + extensionServer.sendRequest({ command: commands.SetSidebarHeight, id: this._id, height: height }); + }, + + setExpression: function(expression, rootTitle, evaluateOptions) + { + var request = { + command: commands.SetSidebarContent, + id: this._id, + expression: expression, + rootTitle: rootTitle, + evaluateOnPage: true, + }; + if (typeof evaluateOptions === "object") + request.evaluateOptions = evaluateOptions; + extensionServer.sendRequest(request, extractCallbackArgument(arguments)); + }, + + setObject: function(jsonObject, rootTitle, callback) + { + extensionServer.sendRequest({ command: commands.SetSidebarContent, id: this._id, expression: jsonObject, rootTitle: rootTitle }, callback); + }, + + setPage: function(page) + { + extensionServer.sendRequest({ command: commands.SetSidebarPage, id: this._id, page: page }); + } +} + +/** + * @constructor + */ +function ButtonImpl(id) +{ + this._id = id; + this.onClicked = new EventSink(events.ButtonClicked + id); +} + +ButtonImpl.prototype = { + update: function(iconPath, tooltipText, disabled) + { + var request = { + command: commands.UpdateButton, + id: this._id, + icon: iconPath, + tooltip: tooltipText, + disabled: !!disabled + }; + extensionServer.sendRequest(request); + } +}; + +/** + * @constructor + */ +function Audits() +{ +} + +Audits.prototype = { + addCategory: function(displayName, resultCount) + { + var id = "extension-audit-category-" + extensionServer.nextObjectId(); + if (typeof resultCount !== "undefined") + console.warn("Passing resultCount to audits.addCategory() is deprecated. Use AuditResult.updateProgress() instead."); + extensionServer.sendRequest({ command: commands.AddAuditCategory, id: id, displayName: displayName, resultCount: resultCount }); + return new AuditCategory(id); + } +} + +/** + * @constructor + */ +function AuditCategoryImpl(id) +{ + function dispatchAuditEvent(request) + { + var auditResult = new AuditResult(request.arguments[0]); + try { + this._fire(auditResult); + } catch (e) { + console.error("Uncaught exception in extension audit event handler: " + e); + auditResult.done(); + } + } + this._id = id; + this.onAuditStarted = new EventSink(events.AuditStarted + id, dispatchAuditEvent); +} + +/** + * @constructor + */ +function AuditResultImpl(id) +{ + this._id = id; + + this.createURL = this._nodeFactory.bind(null, "url"); + this.createSnippet = this._nodeFactory.bind(null, "snippet"); + this.createText = this._nodeFactory.bind(null, "text"); + this.createObject = this._nodeFactory.bind(null, "object"); + this.createNode = this._nodeFactory.bind(null, "node"); +} + +AuditResultImpl.prototype = { + addResult: function(displayName, description, severity, details) + { + // shorthand for specifying details directly in addResult(). + if (details && !(details instanceof AuditResultNode)) + details = new AuditResultNode(details instanceof Array ? details : [details]); + + var request = { + command: commands.AddAuditResult, + resultId: this._id, + displayName: displayName, + description: description, + severity: severity, + details: details + }; + extensionServer.sendRequest(request); + }, + + createResult: function() + { + return new AuditResultNode(Array.prototype.slice.call(arguments)); + }, + + updateProgress: function(worked, totalWork) + { + extensionServer.sendRequest({ command: commands.UpdateAuditProgress, resultId: this._id, progress: worked / totalWork }); + }, + + done: function() + { + extensionServer.sendRequest({ command: commands.StopAuditCategoryRun, resultId: this._id }); + }, + + get Severity() + { + return apiPrivate.audits.Severity; + }, + + createResourceLink: function(url, lineNumber) + { + return { + type: "resourceLink", + arguments: [url, lineNumber && lineNumber - 1] + }; + }, + + _nodeFactory: function(type) + { + return { + type: type, + arguments: Array.prototype.slice.call(arguments, 1) + }; + } +} + +/** + * @constructor + */ +function AuditResultNode(contents) +{ + this.contents = contents; + this.children = []; + this.expanded = false; +} + +AuditResultNode.prototype = { + addChild: function() + { + var node = new AuditResultNode(Array.prototype.slice.call(arguments)); + this.children.push(node); + return node; + } +}; + +/** + * @constructor + */ +function InspectedWindow() +{ + function dispatchResourceEvent(message) + { + this._fire(new Resource(message.arguments[0])); + } + function dispatchResourceContentEvent(message) + { + this._fire(new Resource(message.arguments[0]), message.arguments[1]); + } + this.onResourceAdded = new EventSink(events.ResourceAdded, dispatchResourceEvent); + this.onResourceContentCommitted = new EventSink(events.ResourceContentCommitted, dispatchResourceContentEvent); +} + +InspectedWindow.prototype = { + reload: function(optionsOrUserAgent) + { + var options = null; + if (typeof optionsOrUserAgent === "object") + options = optionsOrUserAgent; + else if (typeof optionsOrUserAgent === "string") { + options = { userAgent: optionsOrUserAgent }; + console.warn("Passing userAgent as string parameter to inspectedWindow.reload() is deprecated. " + + "Use inspectedWindow.reload({ userAgent: value}) instead."); + } + return extensionServer.sendRequest({ command: commands.Reload, options: options }); + }, + + eval: function(expression, evaluateOptions) + { + var callback = extractCallbackArgument(arguments); + function callbackWrapper(result) + { + if (result.isError || result.isException) + callback(undefined, result); + else + callback(result.value); + } + var request = { + command: commands.EvaluateOnInspectedPage, + expression: expression + }; + if (typeof evaluateOptions === "object") + request.evaluateOptions = evaluateOptions; + return extensionServer.sendRequest(request, callback && callbackWrapper); + }, + + getResources: function(callback) + { + function wrapResource(resourceData) + { + return new Resource(resourceData); + } + function callbackWrapper(resources) + { + callback(resources.map(wrapResource)); + } + return extensionServer.sendRequest({ command: commands.GetPageResources }, callback && callbackWrapper); + } +} + +/** + * @constructor + */ +function ResourceImpl(resourceData) +{ + this._url = resourceData.url + this._type = resourceData.type; +} + +ResourceImpl.prototype = { + get url() + { + return this._url; + }, + + get type() + { + return this._type; + }, + + getContent: function(callback) + { + function callbackWrapper(response) + { + callback(response.content, response.encoding); + } + + return extensionServer.sendRequest({ command: commands.GetResourceContent, url: this._url }, callback && callbackWrapper); + }, + + setContent: function(content, commit, callback) + { + return extensionServer.sendRequest({ command: commands.SetResourceContent, url: this._url, content: content, commit: commit }, callback); + } +} + +/** + * @constructor + */ +function TimelineImpl() +{ + this.onEventRecorded = new EventSink(events.TimelineEventRecorded); +} + +function forwardKeyboardEvent(event) +{ + const Esc = "U+001B"; + // We only care about global hotkeys, not about random text + if (!event.ctrlKey && !event.altKey && !event.metaKey && !/^F\d+$/.test(event.keyIdentifier) && event.keyIdentifier !== Esc) + return; + var request = { + command: commands.ForwardKeyboardEvent, + eventType: event.type, + ctrlKey: event.ctrlKey, + altKey: event.altKey, + metaKey: event.metaKey, + keyIdentifier: event.keyIdentifier, + location: event.location + }; + extensionServer.sendRequest(request); +} + +document.addEventListener("keydown", forwardKeyboardEvent, false); +document.addEventListener("keypress", forwardKeyboardEvent, false); + +/** + * @constructor + */ +function ExtensionServerClient() +{ + this._callbacks = {}; + this._handlers = {}; + this._lastRequestId = 0; + this._lastObjectId = 0; + + this.registerHandler("callback", this._onCallback.bind(this)); + + var channel = new MessageChannel(); + this._port = channel.port1; + this._port.addEventListener("message", this._onMessage.bind(this), false); + this._port.start(); + + window.parent.postMessage("registerExtension", [ channel.port2 ], "*"); +} + +ExtensionServerClient.prototype = { + /** + * @param {function()=} callback + */ + sendRequest: function(message, callback) + { + if (typeof callback === "function") + message.requestId = this._registerCallback(callback); + return this._port.postMessage(message); + }, + + hasHandler: function(command) + { + return !!this._handlers[command]; + }, + + registerHandler: function(command, handler) + { + this._handlers[command] = handler; + }, + + unregisterHandler: function(command) + { + delete this._handlers[command]; + }, + + nextObjectId: function() + { + return injectedScriptId + "_" + ++this._lastObjectId; + }, + + _registerCallback: function(callback) + { + var id = ++this._lastRequestId; + this._callbacks[id] = callback; + return id; + }, + + _onCallback: function(request) + { + if (request.requestId in this._callbacks) { + var callback = this._callbacks[request.requestId]; + delete this._callbacks[request.requestId]; + callback(request.result); + } + }, + + _onMessage: function(event) + { + var request = event.data; + var handler = this._handlers[request.command]; + if (handler) + handler.call(this, request); + } +} + +function populateInterfaceClass(interface, implementation) +{ + for (var member in implementation) { + if (member.charAt(0) === "_") + continue; + var descriptor = null; + // Traverse prototype chain until we find the owner. + for (var owner = implementation; owner && !descriptor; owner = owner.__proto__) + descriptor = Object.getOwnPropertyDescriptor(owner, member); + if (!descriptor) + continue; + if (typeof descriptor.value === "function") + interface[member] = descriptor.value.bind(implementation); + else if (typeof descriptor.get === "function") + interface.__defineGetter__(member, descriptor.get.bind(implementation)); + else + Object.defineProperty(interface, member, descriptor); + } +} + +function declareInterfaceClass(implConstructor) +{ + return function() + { + var impl = { __proto__: implConstructor.prototype }; + implConstructor.apply(impl, arguments); + populateInterfaceClass(this, impl); + } +} + +function defineDeprecatedProperty(object, className, oldName, newName) +{ + var warningGiven = false; + function getter() + { + if (!warningGiven) { + console.warn(className + "." + oldName + " is deprecated. Use " + className + "." + newName + " instead"); + warningGiven = true; + } + return object[newName]; + } + object.__defineGetter__(oldName, getter); +} + +function extractCallbackArgument(args) +{ + var lastArgument = args[args.length - 1]; + return typeof lastArgument === "function" ? lastArgument : undefined; +} + +var AuditCategory = declareInterfaceClass(AuditCategoryImpl); +var AuditResult = declareInterfaceClass(AuditResultImpl); +var Button = declareInterfaceClass(ButtonImpl); +var EventSink = declareInterfaceClass(EventSinkImpl); +var ExtensionPanel = declareInterfaceClass(ExtensionPanelImpl); +var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl); +var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl); +var Request = declareInterfaceClass(RequestImpl); +var Resource = declareInterfaceClass(ResourceImpl); +var Timeline = declareInterfaceClass(TimelineImpl); + +// extensionServer is a closure variable defined by the glue below -- make sure we fail if it's not there. +if (!extensionServer) + extensionServer = new ExtensionServerClient(); + +return new InspectorExtensionAPI(); +} + +/** + * @param {ExtensionDescriptor} extensionInfo + * @return {string} + */ +function buildExtensionAPIInjectedScript(extensionInfo) +{ + return "(function(injectedScriptId){ " + + "var extensionServer;" + + defineCommonExtensionSymbols.toString() + ";" + + injectedExtensionAPI.toString() + ";" + + buildPlatformExtensionAPI(extensionInfo) + ";" + + "platformExtensionAPI(injectedExtensionAPI(injectedScriptId));" + + "return {};" + + "})"; +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAuditCategory.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAuditCategory.js new file mode 100644 index 00000000..818349ab --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionAuditCategory.js @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.AuditCategory} + * @param {string} extensionOrigin + * @param {string} id + * @param {string} displayName + * @param {number=} ruleCount + */ +WebInspector.ExtensionAuditCategory = function(extensionOrigin, id, displayName, ruleCount) +{ + this._extensionOrigin = extensionOrigin; + this._id = id; + this._displayName = displayName; + this._ruleCount = ruleCount; +} + +WebInspector.ExtensionAuditCategory.prototype = { + // AuditCategory interface + get id() + { + return this._id; + }, + + get displayName() + { + return this._displayName; + }, + + /** + * @param {Array.} requests + * @param {function(WebInspector.AuditRuleResult)} ruleResultCallback + * @param {function()} categoryDoneCallback + * @param {WebInspector.Progress} progress + */ + run: function(requests, ruleResultCallback, categoryDoneCallback, progress) + { + var results = new WebInspector.ExtensionAuditCategoryResults(this, ruleResultCallback, categoryDoneCallback, progress); + WebInspector.extensionServer.startAuditRun(this, results); + } +} + +/** + * @constructor + * @param {WebInspector.ExtensionAuditCategory} category + * @param {function(WebInspector.AuditRuleResult)} ruleResultCallback + * @param {function()} categoryDoneCallback + * @param {WebInspector.Progress} progress + */ +WebInspector.ExtensionAuditCategoryResults = function(category, ruleResultCallback, categoryDoneCallback, progress) +{ + this._category = category; + this._ruleResultCallback = ruleResultCallback; + this._categoryDoneCallback = categoryDoneCallback; + this._progress = progress; + this._progress.setTotalWork(1); + this._expectedResults = category._ruleCount; + this._actualResults = 0; + + this.id = category.id + "-" + ++WebInspector.ExtensionAuditCategoryResults._lastId; +} + +WebInspector.ExtensionAuditCategoryResults.prototype = { + done: function() + { + WebInspector.extensionServer.stopAuditRun(this); + this._progress.done(); + this._categoryDoneCallback(); + }, + + addResult: function(displayName, description, severity, details) + { + var result = new WebInspector.AuditRuleResult(displayName); + result.addChild(description); + result.severity = severity; + if (details) + this._addNode(result, details); + this._addResult(result); + }, + + _addNode: function(parent, node) + { + var contents = WebInspector.auditFormatters.partiallyApply(WebInspector.ExtensionAuditFormatters, this, node.contents); + var addedNode = parent.addChild(contents, node.expanded); + if (node.children) { + for (var i = 0; i < node.children.length; ++i) + this._addNode(addedNode, node.children[i]); + } + }, + + _addResult: function(result) + { + this._ruleResultCallback(result); + ++this._actualResults; + if (typeof this._expectedResults === "number") { + this._progress.setWorked(this._actualResults / this._expectedResults); + if (this._actualResults === this._expectedResults) + this.done(); + } + }, + + /** + * @param {number} progress + */ + updateProgress: function(progress) + { + this._progress.setWorked(progress); + }, + + /** + * @param {string} expression + * @param {function(WebInspector.RemoteObject)} callback + */ + evaluate: function(expression, evaluateOptions, callback) + { + /** + * @param {?string} error + * @param {?RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + */ + function onEvaluate(error, result, wasThrown) + { + if (wasThrown) + return; + var object = WebInspector.RemoteObject.fromPayload(result); + callback(object); + } + WebInspector.extensionServer.evaluate(expression, false, false, evaluateOptions, this._category._extensionOrigin, onEvaluate); + } +} + +WebInspector.ExtensionAuditFormatters = { + /** + * @this {WebInspector.ExtensionAuditCategoryResults} + * @param {string} expression + * @param {string} title + * @param {Object} evaluateOptions + */ + object: function(expression, title, evaluateOptions) + { + var parentElement = document.createElement("div"); + function onEvaluate(remoteObject) + { + var section = new WebInspector.ObjectPropertiesSection(remoteObject, title); + section.expanded = true; + section.editable = false; + parentElement.appendChild(section.element); + } + this.evaluate(expression, evaluateOptions, onEvaluate); + return parentElement; + }, + + /** + * @this {WebInspector.ExtensionAuditCategoryResults} + * @param {string} expression + * @param {Object} evaluateOptions + */ + node: function(expression, evaluateOptions) + { + var parentElement = document.createElement("div"); + /** + * @param {?number} nodeId + */ + function onNodeAvailable(nodeId) + { + if (!nodeId) + return; + var treeOutline = new WebInspector.ElementsTreeOutline(false, false); + treeOutline.rootDOMNode = WebInspector.domAgent.nodeForId(nodeId); + treeOutline.element.addStyleClass("outline-disclosure"); + treeOutline.setVisible(true); + parentElement.appendChild(treeOutline.element); + } + /** + * @param {WebInspector.RemoteObject} remoteObject + */ + function onEvaluate(remoteObject) + { + remoteObject.pushNodeToFrontend(onNodeAvailable); + } + this.evaluate(expression, evaluateOptions, onEvaluate); + return parentElement; + } +} + +WebInspector.ExtensionAuditCategoryResults._lastId = 0; diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionPanel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionPanel.js new file mode 100644 index 00000000..ce8513bc --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionPanel.js @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.Panel} + * @param {string} id + * @param {string} pageURL + */ +WebInspector.ExtensionPanel = function(id, pageURL) +{ + WebInspector.Panel.call(this, id); + this.setHideOnDetach(); + this._statusBarItems = []; + var extensionView = new WebInspector.ExtensionView(id, pageURL, "extension panel"); + extensionView.show(this.element); + this.setDefaultFocusedElement(extensionView.defaultFocusedElement()); +} + +WebInspector.ExtensionPanel.prototype = { + defaultFocusedElement: function() + { + return WebInspector.View.prototype.defaultFocusedElement.call(this); + }, + + get statusBarItems() + { + return this._statusBarItems; + }, + + /** + * @param {Element} element + */ + addStatusBarItem: function(element) + { + this._statusBarItems.push(element); + }, + + searchCanceled: function(startingNewSearch) + { + WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.CancelSearch); + WebInspector.Panel.prototype.searchCanceled.apply(this, arguments); + }, + + /** + * @param {string} query + * @param {boolean} shouldJump + */ + performSearch: function(query, shouldJump) + { + WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.PerformSearch, query); + }, + + jumpToNextSearchResult: function() + { + WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.NextSearchResult); + WebInspector.Panel.prototype.jumpToNextSearchResult.call(this); + }, + + jumpToPreviousSearchResult: function() + { + WebInspector.extensionServer.notifySearchAction(this.name, WebInspector.extensionAPI.panels.SearchAction.PreviousSearchResult); + WebInspector.Panel.prototype.jumpToPreviousSearchResult.call(this); + }, + + __proto__: WebInspector.Panel.prototype +} + +/** + * @constructor + * @param {string} id + * @param {string} iconURL + * @param {string=} tooltip + * @param {boolean=} disabled + */ +WebInspector.ExtensionButton = function(id, iconURL, tooltip, disabled) +{ + this._id = id; + this.element = document.createElement("button"); + this.element.className = "status-bar-item extension"; + this.element.addEventListener("click", this._onClicked.bind(this), false); + this.update(iconURL, tooltip, disabled); +} + +WebInspector.ExtensionButton.prototype = { + /** + * @param {string} iconURL + * @param {string=} tooltip + * @param {boolean=} disabled + */ + update: function(iconURL, tooltip, disabled) + { + if (typeof iconURL === "string") + this.element.style.backgroundImage = "url(" + iconURL + ")"; + if (typeof tooltip === "string") + this.element.title = tooltip; + if (typeof disabled === "boolean") + this.element.disabled = disabled; + }, + + _onClicked: function() + { + WebInspector.extensionServer.notifyButtonClicked(this._id); + } +} + +/** + * @constructor + * @extends {WebInspector.SidebarPane} + * @param {string} title + * @param {string} id + */ +WebInspector.ExtensionSidebarPane = function(title, id) +{ + WebInspector.SidebarPane.call(this, title); + this.setHideOnDetach(); + this._id = id; +} + +WebInspector.ExtensionSidebarPane.prototype = { + /** + * @param {Object} object + * @param {string} title + * @param {function(?string=)} callback + */ + setObject: function(object, title, callback) + { + this._createObjectPropertiesView(); + this._setObject(WebInspector.RemoteObject.fromLocalObject(object), title, callback); + }, + + /** + * @param {string} expression + * @param {string} title + * @param {function(?string=)} callback + */ + setExpression: function(expression, title, evaluateOptions, securityOrigin, callback) + { + this._createObjectPropertiesView(); + return WebInspector.extensionServer.evaluate(expression, true, false, evaluateOptions, securityOrigin, this._onEvaluate.bind(this, title, callback)); + }, + + /** + * @param {string} url + */ + setPage: function(url) + { + if (this._objectPropertiesView) { + this._objectPropertiesView.detach(); + delete this._objectPropertiesView; + } + if (this._extensionView) + this._extensionView.detach(true); + + this._extensionView = new WebInspector.ExtensionView(this._id, url, "extension fill"); + this._extensionView.show(this.bodyElement); + + if (!this.bodyElement.style.height) + this.setHeight("150px"); + }, + + /** + * @param {string} height + */ + setHeight: function(height) + { + this.bodyElement.style.height = height; + }, + + /** + * @param {string} title + * @param {function(?string=)} callback + * @param {?Protocol.Error} error + * @param {RuntimeAgent.RemoteObject} result + * @param {boolean=} wasThrown + */ + _onEvaluate: function(title, callback, error, result, wasThrown) + { + if (error) + callback(error.toString()); + else + this._setObject(WebInspector.RemoteObject.fromPayload(result), title, callback); + }, + + _createObjectPropertiesView: function() + { + if (this._objectPropertiesView) + return; + if (this._extensionView) { + this._extensionView.detach(true); + delete this._extensionView; + } + this._objectPropertiesView = new WebInspector.ExtensionNotifierView(this._id); + this._objectPropertiesView.show(this.bodyElement); + }, + + /** + * @param {WebInspector.RemoteObject} object + * @param {string} title + * @param {function(?string=)} callback + */ + _setObject: function(object, title, callback) + { + // This may only happen if setPage() was called while we were evaluating the expression. + if (!this._objectPropertiesView) { + callback("operation cancelled"); + return; + } + this._objectPropertiesView.element.removeChildren(); + var section = new WebInspector.ObjectPropertiesSection(object, title); + if (!title) + section.headerElement.addStyleClass("hidden"); + section.expanded = true; + section.editable = false; + this._objectPropertiesView.element.appendChild(section.element); + callback(); + }, + + __proto__: WebInspector.SidebarPane.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionRegistryStub.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionRegistryStub.js new file mode 100644 index 00000000..25808802 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionRegistryStub.js @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +if (!window.InspectorExtensionRegistry) { + +/** + * @constructor + */ +WebInspector.InspectorExtensionRegistryStub = function() +{ +} + +WebInspector.InspectorExtensionRegistryStub.prototype = { + getExtensionsAsync: function() + { + } +} + +var InspectorExtensionRegistry = new WebInspector.InspectorExtensionRegistryStub(); + +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionServer.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionServer.js new file mode 100644 index 00000000..15a668c3 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionServer.js @@ -0,0 +1,910 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + */ +WebInspector.ExtensionServer = function() +{ + this._clientObjects = {}; + this._handlers = {}; + this._subscribers = {}; + this._subscriptionStartHandlers = {}; + this._subscriptionStopHandlers = {}; + this._extraHeaders = {}; + this._requests = {}; + this._lastRequestId = 0; + this._registeredExtensions = {}; + this._status = new WebInspector.ExtensionStatus(); + + var commands = WebInspector.extensionAPI.Commands; + + this._registerHandler(commands.AddAuditCategory, this._onAddAuditCategory.bind(this)); + this._registerHandler(commands.AddAuditResult, this._onAddAuditResult.bind(this)); + this._registerHandler(commands.AddConsoleMessage, this._onAddConsoleMessage.bind(this)); + this._registerHandler(commands.AddRequestHeaders, this._onAddRequestHeaders.bind(this)); + this._registerHandler(commands.CreatePanel, this._onCreatePanel.bind(this)); + this._registerHandler(commands.CreateSidebarPane, this._onCreateSidebarPane.bind(this)); + this._registerHandler(commands.CreateStatusBarButton, this._onCreateStatusBarButton.bind(this)); + this._registerHandler(commands.EvaluateOnInspectedPage, this._onEvaluateOnInspectedPage.bind(this)); + this._registerHandler(commands.ForwardKeyboardEvent, this._onForwardKeyboardEvent.bind(this)); + this._registerHandler(commands.GetHAR, this._onGetHAR.bind(this)); + this._registerHandler(commands.GetConsoleMessages, this._onGetConsoleMessages.bind(this)); + this._registerHandler(commands.GetPageResources, this._onGetPageResources.bind(this)); + this._registerHandler(commands.GetRequestContent, this._onGetRequestContent.bind(this)); + this._registerHandler(commands.GetResourceContent, this._onGetResourceContent.bind(this)); + this._registerHandler(commands.Reload, this._onReload.bind(this)); + this._registerHandler(commands.SetOpenResourceHandler, this._onSetOpenResourceHandler.bind(this)); + this._registerHandler(commands.SetResourceContent, this._onSetResourceContent.bind(this)); + this._registerHandler(commands.SetSidebarHeight, this._onSetSidebarHeight.bind(this)); + this._registerHandler(commands.SetSidebarContent, this._onSetSidebarContent.bind(this)); + this._registerHandler(commands.SetSidebarPage, this._onSetSidebarPage.bind(this)); + this._registerHandler(commands.ShowPanel, this._onShowPanel.bind(this)); + this._registerHandler(commands.StopAuditCategoryRun, this._onStopAuditCategoryRun.bind(this)); + this._registerHandler(commands.Subscribe, this._onSubscribe.bind(this)); + this._registerHandler(commands.OpenResource, this._onOpenResource.bind(this)); + this._registerHandler(commands.Unsubscribe, this._onUnsubscribe.bind(this)); + this._registerHandler(commands.UpdateButton, this._onUpdateButton.bind(this)); + this._registerHandler(commands.UpdateAuditProgress, this._onUpdateAuditProgress.bind(this)); + + window.addEventListener("message", this._onWindowMessage.bind(this), false); +} + +WebInspector.ExtensionServer.prototype = { + hasExtensions: function() + { + return !!Object.keys(this._registeredExtensions).length; + }, + + notifySearchAction: function(panelId, action, searchString) + { + this._postNotification(WebInspector.extensionAPI.Events.PanelSearch + panelId, action, searchString); + }, + + notifyViewShown: function(identifier, frameIndex) + { + this._postNotification(WebInspector.extensionAPI.Events.ViewShown + identifier, frameIndex); + }, + + notifyViewHidden: function(identifier) + { + this._postNotification(WebInspector.extensionAPI.Events.ViewHidden + identifier); + }, + + notifyButtonClicked: function(identifier) + { + this._postNotification(WebInspector.extensionAPI.Events.ButtonClicked + identifier); + }, + + _inspectedURLChanged: function(event) + { + this._requests = {}; + var url = event.data; + this._postNotification(WebInspector.extensionAPI.Events.InspectedURLChanged, url); + }, + + startAuditRun: function(category, auditRun) + { + this._clientObjects[auditRun.id] = auditRun; + this._postNotification("audit-started-" + category.id, auditRun.id); + }, + + stopAuditRun: function(auditRun) + { + delete this._clientObjects[auditRun.id]; + }, + + /** + * @param {string} type + * @return {boolean} + */ + hasSubscribers: function(type) + { + return !!this._subscribers[type]; + }, + + /** + * @param {string} type + * @param {...*} vararg + */ + _postNotification: function(type, vararg) + { + var subscribers = this._subscribers[type]; + if (!subscribers) + return; + var message = { + command: "notify-" + type, + arguments: Array.prototype.slice.call(arguments, 1) + }; + for (var i = 0; i < subscribers.length; ++i) + subscribers[i].postMessage(message); + }, + + _onSubscribe: function(message, port) + { + var subscribers = this._subscribers[message.type]; + if (subscribers) + subscribers.push(port); + else { + this._subscribers[message.type] = [ port ]; + if (this._subscriptionStartHandlers[message.type]) + this._subscriptionStartHandlers[message.type](); + } + }, + + _onUnsubscribe: function(message, port) + { + var subscribers = this._subscribers[message.type]; + if (!subscribers) + return; + subscribers.remove(port); + if (!subscribers.length) { + delete this._subscribers[message.type]; + if (this._subscriptionStopHandlers[message.type]) + this._subscriptionStopHandlers[message.type](); + } + }, + + _onAddRequestHeaders: function(message) + { + var id = message.extensionId; + if (typeof id !== "string") + return this._status.E_BADARGTYPE("extensionId", typeof id, "string"); + var extensionHeaders = this._extraHeaders[id]; + if (!extensionHeaders) { + extensionHeaders = {}; + this._extraHeaders[id] = extensionHeaders; + } + for (var name in message.headers) + extensionHeaders[name] = message.headers[name]; + var allHeaders = /** @type NetworkAgent.Headers */ ({}); + for (var extension in this._extraHeaders) { + var headers = this._extraHeaders[extension]; + for (name in headers) { + if (typeof headers[name] === "string") + allHeaders[name] = headers[name]; + } + } + NetworkAgent.setExtraHTTPHeaders(allHeaders); + }, + + _onCreatePanel: function(message, port) + { + var id = message.id; + // The ids are generated on the client API side and must be unique, so the check below + // shouldn't be hit unless someone is bypassing the API. + if (id in this._clientObjects || id in WebInspector.panels) + return this._status.E_EXISTS(id); + + var page = this._expandResourcePath(port._extensionOrigin, message.page); + var panelDescriptor = new WebInspector.PanelDescriptor(id, message.title, undefined, undefined, new WebInspector.ExtensionPanel(id, page)); + this._clientObjects[id] = panelDescriptor.panel(); + WebInspector.inspectorView.addPanel(panelDescriptor); + return this._status.OK(); + }, + + _onShowPanel: function(message) + { + // Note: WebInspector.showPanel already sanitizes input. + WebInspector.showPanel(message.id); + }, + + _onCreateStatusBarButton: function(message, port) + { + var panel = this._clientObjects[message.panel]; + if (!panel || !(panel instanceof WebInspector.ExtensionPanel)) + return this._status.E_NOTFOUND(message.panel); + var button = new WebInspector.ExtensionButton(message.id, this._expandResourcePath(port._extensionOrigin, message.icon), message.tooltip, message.disabled); + this._clientObjects[message.id] = button; + panel.addStatusBarItem(button.element); + return this._status.OK(); + }, + + _onUpdateButton: function(message, port) + { + var button = this._clientObjects[message.id]; + if (!button || !(button instanceof WebInspector.ExtensionButton)) + return this._status.E_NOTFOUND(message.id); + button.update(this._expandResourcePath(port._extensionOrigin, message.icon), message.tooltip, message.disabled); + return this._status.OK(); + }, + + _onCreateSidebarPane: function(message) + { + var panel = WebInspector.panel(message.panel); + if (!panel) + return this._status.E_NOTFOUND(message.panel); + if (!panel.addExtensionSidebarPane) + return this._status.E_NOTSUPPORTED(); + var id = message.id; + var sidebar = new WebInspector.ExtensionSidebarPane(message.title, message.id); + this._clientObjects[id] = sidebar; + panel.addExtensionSidebarPane(id, sidebar); + + return this._status.OK(); + }, + + _onSetSidebarHeight: function(message) + { + var sidebar = this._clientObjects[message.id]; + if (!sidebar) + return this._status.E_NOTFOUND(message.id); + sidebar.setHeight(message.height); + return this._status.OK(); + }, + + _onSetSidebarContent: function(message, port) + { + var sidebar = this._clientObjects[message.id]; + if (!sidebar) + return this._status.E_NOTFOUND(message.id); + function callback(error) + { + var result = error ? this._status.E_FAILED(error) : this._status.OK(); + this._dispatchCallback(message.requestId, port, result); + } + if (message.evaluateOnPage) + return sidebar.setExpression(message.expression, message.rootTitle, message.evaluateOptions, port._extensionOrigin, callback.bind(this)); + sidebar.setObject(message.expression, message.rootTitle, callback.bind(this)); + }, + + _onSetSidebarPage: function(message, port) + { + var sidebar = this._clientObjects[message.id]; + if (!sidebar) + return this._status.E_NOTFOUND(message.id); + sidebar.setPage(this._expandResourcePath(port._extensionOrigin, message.page)); + }, + + _onOpenResource: function(message) + { + var a = document.createElement("a"); + a.href = message.url; + a.lineNumber = message.lineNumber; + return WebInspector.showAnchorLocation(a) ? this._status.OK() : this._status.E_NOTFOUND(message.url); + }, + + _onSetOpenResourceHandler: function(message, port) + { + var name = this._registeredExtensions[port._extensionOrigin].name || ("Extension " + port._extensionOrigin); + if (message.handlerPresent) + WebInspector.openAnchorLocationRegistry.registerHandler(name, this._handleOpenURL.bind(this, port)); + else + WebInspector.openAnchorLocationRegistry.unregisterHandler(name); + }, + + _handleOpenURL: function(port, details) + { + var url = /** @type {string} */ (details.url); + var contentProvider = WebInspector.workspace.uiSourceCodeForOriginURL(url) || WebInspector.resourceForURL(url); + if (!contentProvider) + return false; + + var lineNumber = details.lineNumber; + if (typeof lineNumber === "number") + lineNumber += 1; + port.postMessage({ + command: "open-resource", + resource: this._makeResource(contentProvider), + lineNumber: lineNumber + }); + return true; + }, + + _onReload: function(message) + { + var options = /** @type ExtensionReloadOptions */ (message.options || {}); + NetworkAgent.setUserAgentOverride(typeof options.userAgent === "string" ? options.userAgent : ""); + var injectedScript; + if (options.injectedScript) + injectedScript = "(function(){" + options.injectedScript + "})()"; + var preprocessingScript = options.preprocessingScript; + PageAgent.reload(!!options.ignoreCache, injectedScript, preprocessingScript); + return this._status.OK(); + }, + + _onEvaluateOnInspectedPage: function(message, port) + { + /** + * @param {?Protocol.Error} error + * @param {RuntimeAgent.RemoteObject} resultPayload + * @param {boolean=} wasThrown + */ + function callback(error, resultPayload, wasThrown) + { + var result; + if (error) + result = this._status.E_PROTOCOLERROR(error.toString()); + else if (wasThrown) + result = { isException: true, value: resultPayload.description }; + else + result = { value: resultPayload.value }; + + this._dispatchCallback(message.requestId, port, result); + } + return this.evaluate(message.expression, true, true, message.evaluateOptions, port._extensionOrigin, callback.bind(this)); + }, + + _onGetConsoleMessages: function() + { + return WebInspector.console.messages.map(this._makeConsoleMessage); + }, + + _onAddConsoleMessage: function(message) + { + function convertSeverity(level) + { + switch (level) { + case WebInspector.extensionAPI.console.Severity.Log: + return WebInspector.ConsoleMessage.MessageLevel.Log; + case WebInspector.extensionAPI.console.Severity.Warning: + return WebInspector.ConsoleMessage.MessageLevel.Warning; + case WebInspector.extensionAPI.console.Severity.Error: + return WebInspector.ConsoleMessage.MessageLevel.Error; + case WebInspector.extensionAPI.console.Severity.Debug: + return WebInspector.ConsoleMessage.MessageLevel.Debug; + } + } + var level = convertSeverity(message.severity); + if (!level) + return this._status.E_BADARG("message.severity", message.severity); + + var consoleMessage = WebInspector.ConsoleMessage.create( + WebInspector.ConsoleMessage.MessageSource.JS, + level, + message.text, + WebInspector.ConsoleMessage.MessageType.Log, + message.url, + message.line); + WebInspector.console.addMessage(consoleMessage); + }, + + _makeConsoleMessage: function(message) + { + function convertLevel(level) + { + if (!level) + return; + switch (level) { + case WebInspector.ConsoleMessage.MessageLevel.Log: + return WebInspector.extensionAPI.console.Severity.Log; + case WebInspector.ConsoleMessage.MessageLevel.Warning: + return WebInspector.extensionAPI.console.Severity.Warning; + case WebInspector.ConsoleMessage.MessageLevel.Error: + return WebInspector.extensionAPI.console.Severity.Error; + case WebInspector.ConsoleMessage.MessageLevel.Debug: + return WebInspector.extensionAPI.console.Severity.Debug; + default: + return WebInspector.extensionAPI.console.Severity.Log; + } + } + var result = { + severity: convertLevel(message.level), + text: message.text, + }; + if (message.url) + result.url = message.url; + if (message.line) + result.line = message.line; + return result; + }, + + _onGetHAR: function() + { + var requests = WebInspector.networkLog.requests; + var harLog = (new WebInspector.HARLog(requests)).build(); + for (var i = 0; i < harLog.entries.length; ++i) + harLog.entries[i]._requestId = this._requestId(requests[i]); + return harLog; + }, + + /** + * @param {WebInspector.ContentProvider} contentProvider + */ + _makeResource: function(contentProvider) + { + return { + url: contentProvider.contentURL(), + type: contentProvider.contentType().name() + }; + }, + + /** + * @return {!Array.} + */ + _onGetPageResources: function() + { + var resources = {}; + + function pushResourceData(contentProvider) + { + if (!resources[contentProvider.contentURL()]) + resources[contentProvider.contentURL()] = this._makeResource(contentProvider); + } + var uiSourceCodes = WebInspector.workspace.uiSourceCodesForProjectType(WebInspector.projectTypes.Network); + uiSourceCodes.forEach(pushResourceData.bind(this)); + WebInspector.resourceTreeModel.forAllResources(pushResourceData.bind(this)); + return Object.values(resources); + }, + + /** + * @param {WebInspector.ContentProvider} contentProvider + */ + _getResourceContent: function(contentProvider, message, port) + { + /** + * @param {?string} content + * @param {boolean} contentEncoded + * @param {string} mimeType + */ + function onContentAvailable(content, contentEncoded, mimeType) + { + var response = { + encoding: contentEncoded ? "base64" : "", + content: content + }; + this._dispatchCallback(message.requestId, port, response); + } + contentProvider.requestContent(onContentAvailable.bind(this)); + }, + + _onGetRequestContent: function(message, port) + { + var request = this._requestById(message.id); + if (!request) + return this._status.E_NOTFOUND(message.id); + this._getResourceContent(request, message, port); + }, + + _onGetResourceContent: function(message, port) + { + var url = /** @type {string} */ (message.url); + var contentProvider = WebInspector.workspace.uiSourceCodeForOriginURL(url) || WebInspector.resourceForURL(url); + if (!contentProvider) + return this._status.E_NOTFOUND(url); + this._getResourceContent(contentProvider, message, port); + }, + + _onSetResourceContent: function(message, port) + { + /** + * @param {?Protocol.Error} error + */ + function callbackWrapper(error) + { + var response = error ? this._status.E_FAILED(error) : this._status.OK(); + this._dispatchCallback(message.requestId, port, response); + } + + var url = /** @type {string} */ (message.url); + var uiSourceCode = WebInspector.workspace.uiSourceCodeForOriginURL(url); + if (!uiSourceCode) { + var resource = WebInspector.resourceTreeModel.resourceForURL(url); + if (!resource) + return this._status.E_NOTFOUND(url); + return this._status.E_NOTSUPPORTED("Resource is not editable") + } + uiSourceCode.setWorkingCopy(message.content); + if (message.commit) + uiSourceCode.commitWorkingCopy(callbackWrapper.bind(this)); + else + callbackWrapper.call(this, null); + }, + + _requestId: function(request) + { + if (!request._extensionRequestId) { + request._extensionRequestId = ++this._lastRequestId; + this._requests[request._extensionRequestId] = request; + } + return request._extensionRequestId; + }, + + _requestById: function(id) + { + return this._requests[id]; + }, + + _onAddAuditCategory: function(message, port) + { + var category = new WebInspector.ExtensionAuditCategory(port._extensionOrigin, message.id, message.displayName, message.resultCount); + if (WebInspector.panel("audits").getCategory(category.id)) + return this._status.E_EXISTS(category.id); + this._clientObjects[message.id] = category; + WebInspector.panel("audits").addCategory(category); + }, + + _onAddAuditResult: function(message) + { + var auditResult = this._clientObjects[message.resultId]; + if (!auditResult) + return this._status.E_NOTFOUND(message.resultId); + try { + auditResult.addResult(message.displayName, message.description, message.severity, message.details); + } catch (e) { + return e; + } + return this._status.OK(); + }, + + _onUpdateAuditProgress: function(message) + { + var auditResult = this._clientObjects[message.resultId]; + if (!auditResult) + return this._status.E_NOTFOUND(message.resultId); + auditResult.updateProgress(Math.min(Math.max(0, message.progress), 1)); + }, + + _onStopAuditCategoryRun: function(message) + { + var auditRun = this._clientObjects[message.resultId]; + if (!auditRun) + return this._status.E_NOTFOUND(message.resultId); + auditRun.done(); + }, + + _onForwardKeyboardEvent: function(message) + { + const Esc = "U+001B"; + + if (!message.ctrlKey && !message.altKey && !message.metaKey && !/^F\d+$/.test(message.keyIdentifier) && message.keyIdentifier !== Esc) + return; + // Fool around closure compiler -- it has its own notion of both KeyboardEvent constructor + // and initKeyboardEvent methods and overriding these in externs.js does not have effect. + var event = new window.KeyboardEvent(message.eventType, { + keyIdentifier: message.keyIdentifier, + location: message.location, + ctrlKey: message.ctrlKey, + altKey: message.altKey, + shiftKey: message.shiftKey, + metaKey: message.metaKey + }); + document.dispatchEvent(event); + }, + + _dispatchCallback: function(requestId, port, result) + { + if (requestId) + port.postMessage({ command: "callback", requestId: requestId, result: result }); + }, + + initExtensions: function() + { + this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ConsoleMessageAdded, + WebInspector.console, WebInspector.ConsoleModel.Events.MessageAdded, this._notifyConsoleMessageAdded); + this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.NetworkRequestFinished, + WebInspector.networkManager, WebInspector.NetworkManager.EventTypes.RequestFinished, this._notifyRequestFinished); + this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ResourceAdded, + WebInspector.workspace, + WebInspector.Workspace.Events.UISourceCodeAdded, + this._notifyResourceAdded); + this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ElementsPanelObjectSelected, + WebInspector.notifications, + WebInspector.ElementsTreeOutline.Events.SelectedNodeChanged, + this._notifyElementsSelectionChanged); + this._registerAutosubscriptionHandler(WebInspector.extensionAPI.Events.ResourceContentCommitted, + WebInspector.workspace, + WebInspector.Workspace.Events.UISourceCodeContentCommitted, + this._notifyUISourceCodeContentCommitted); + + function onTimelineSubscriptionStarted() + { + WebInspector.timelineManager.addEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, + this._notifyTimelineEventRecorded, this); + WebInspector.timelineManager.start(); + } + function onTimelineSubscriptionStopped() + { + WebInspector.timelineManager.stop(); + WebInspector.timelineManager.removeEventListener(WebInspector.TimelineManager.EventTypes.TimelineEventRecorded, + this._notifyTimelineEventRecorded, this); + } + this._registerSubscriptionHandler(WebInspector.extensionAPI.Events.TimelineEventRecorded, + onTimelineSubscriptionStarted.bind(this), onTimelineSubscriptionStopped.bind(this)); + + WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.InspectedURLChanged, + this._inspectedURLChanged, this); + this._initDone = true; + if (this._pendingExtensions) { + this._pendingExtensions.forEach(this._innerAddExtension, this); + delete this._pendingExtensions; + } + InspectorExtensionRegistry.getExtensionsAsync(); + }, + + _notifyConsoleMessageAdded: function(event) + { + this._postNotification(WebInspector.extensionAPI.Events.ConsoleMessageAdded, this._makeConsoleMessage(event.data)); + }, + + _notifyResourceAdded: function(event) + { + var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.data); + this._postNotification(WebInspector.extensionAPI.Events.ResourceAdded, this._makeResource(uiSourceCode)); + }, + + _notifyUISourceCodeContentCommitted: function(event) + { + var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.data.uiSourceCode); + var content = /** @type {string} */ (event.data.content); + this._postNotification(WebInspector.extensionAPI.Events.ResourceContentCommitted, this._makeResource(uiSourceCode), content); + }, + + _notifyRequestFinished: function(event) + { + var request = /** @type {WebInspector.NetworkRequest} */ (event.data); + this._postNotification(WebInspector.extensionAPI.Events.NetworkRequestFinished, this._requestId(request), (new WebInspector.HAREntry(request)).build()); + }, + + _notifyElementsSelectionChanged: function() + { + this._postNotification(WebInspector.extensionAPI.Events.ElementsPanelObjectSelected); + }, + + _notifyTimelineEventRecorded: function(event) + { + this._postNotification(WebInspector.extensionAPI.Events.TimelineEventRecorded, event.data); + }, + + /** + * @param {Array.} extensions + */ + _addExtensions: function(extensions) + { + extensions.forEach(this._addExtension, this); + }, + + /** + * @param {ExtensionDescriptor} extensionInfo + */ + _addExtension: function(extensionInfo) + { + if (this._initDone) { + this._innerAddExtension(extensionInfo); + return; + } + if (this._pendingExtensions) + this._pendingExtensions.push(extensionInfo); + else + this._pendingExtensions = [extensionInfo]; + }, + + /** + * @param {ExtensionDescriptor} extensionInfo + */ + _innerAddExtension: function(extensionInfo) + { + const urlOriginRegExp = new RegExp("([^:]+:\/\/[^/]*)\/"); // Can't use regexp literal here, MinJS chokes on it. + var startPage = extensionInfo.startPage; + var name = extensionInfo.name; + + try { + var originMatch = urlOriginRegExp.exec(startPage); + if (!originMatch) { + console.error("Skipping extension with invalid URL: " + startPage); + return false; + } + var extensionOrigin = originMatch[1]; + if (!this._registeredExtensions[extensionOrigin]) { + // See ExtensionAPI.js and ExtensionCommon.js for details. + InspectorFrontendHost.setInjectedScriptForOrigin(extensionOrigin, buildExtensionAPIInjectedScript(extensionInfo)); + this._registeredExtensions[extensionOrigin] = { name: name }; + } + var iframe = document.createElement("iframe"); + iframe.src = startPage; + iframe.style.display = "none"; + document.body.appendChild(iframe); + } catch (e) { + console.error("Failed to initialize extension " + startPage + ":" + e); + return false; + } + return true; + }, + + _onWindowMessage: function(event) + { + if (event.data === "registerExtension") + this._registerExtension(event.origin, event.ports[0]); + }, + + _registerExtension: function(origin, port) + { + if (!this._registeredExtensions.hasOwnProperty(origin)) { + if (origin !== window.location.origin) // Just ignore inspector frames. + console.error("Ignoring unauthorized client request from " + origin); + return; + } + port._extensionOrigin = origin; + port.addEventListener("message", this._onmessage.bind(this), false); + port.start(); + }, + + _onmessage: function(event) + { + var message = event.data; + var result; + + if (message.command in this._handlers) + result = this._handlers[message.command](message, event.target); + else + result = this._status.E_NOTSUPPORTED(message.command); + + if (result && message.requestId) + this._dispatchCallback(message.requestId, event.target, result); + }, + + _registerHandler: function(command, callback) + { + console.assert(command); + this._handlers[command] = callback; + }, + + _registerSubscriptionHandler: function(eventTopic, onSubscribeFirst, onUnsubscribeLast) + { + this._subscriptionStartHandlers[eventTopic] = onSubscribeFirst; + this._subscriptionStopHandlers[eventTopic] = onUnsubscribeLast; + }, + + _registerAutosubscriptionHandler: function(eventTopic, eventTarget, frontendEventType, handler) + { + this._registerSubscriptionHandler(eventTopic, + eventTarget.addEventListener.bind(eventTarget, frontendEventType, handler, this), + eventTarget.removeEventListener.bind(eventTarget, frontendEventType, handler, this)); + }, + + _expandResourcePath: function(extensionPath, resourcePath) + { + if (!resourcePath) + return; + return extensionPath + this._normalizePath(resourcePath); + }, + + _normalizePath: function(path) + { + var source = path.split("/"); + var result = []; + + for (var i = 0; i < source.length; ++i) { + if (source[i] === ".") + continue; + // Ignore empty path components resulting from //, as well as a leading and traling slashes. + if (source[i] === "") + continue; + if (source[i] === "..") + result.pop(); + else + result.push(source[i]); + } + return "/" + result.join("/"); + }, + + /** + * @param {string} expression + * @param {boolean} exposeCommandLineAPI + * @param {boolean} returnByValue + * @param {Object} options + * @param {string} securityOrigin + * @param {function(?string, ?RuntimeAgent.RemoteObject, boolean=)} callback + */ + evaluate: function(expression, exposeCommandLineAPI, returnByValue, options, securityOrigin, callback) + { + var contextId; + if (typeof options === "object") { + + function resolveURLToFrame(url) + { + var found; + function hasMatchingURL(frame) + { + found = (frame.url === url) ? frame : null; + return found; + } + WebInspector.resourceTreeModel.frames().some(hasMatchingURL); + return found; + } + + var frame = options.frameURL ? resolveURLToFrame(options.frameURL) : WebInspector.resourceTreeModel.mainFrame; + if (!frame) { + if (options.frameURL) + console.warn("evaluate: there is no frame with URL " + options.frameURL); + else + console.warn("evaluate: the main frame is not yet available"); + return this._status.E_NOTFOUND(options.frameURL || ""); + } + + var contextSecurityOrigin; + if (options.useContentScriptContext) + contextSecurityOrigin = securityOrigin; + else if (options.scriptExecutionContext) + contextSecurityOrigin = options.scriptExecutionContext; + + var frameContextList = WebInspector.runtimeModel.contextListByFrame(frame); + var context; + if (contextSecurityOrigin) { + context = frameContextList.contextBySecurityOrigin(contextSecurityOrigin); + if (!context) { + console.warn("The JS context " + contextSecurityOrigin + " was not found in the frame " + frame.url) + return this._status.E_NOTFOUND(contextSecurityOrigin) + } + } else { + context = frameContextList.mainWorldContext(); + if (!context) + return this._status.E_FAILED(frame.url + " has no execution context"); + } + + contextId = context.id; + } + RuntimeAgent.evaluate(expression, "extension", exposeCommandLineAPI, true, contextId, returnByValue, false, callback); + } +} + +/** + * @constructor + */ +WebInspector.ExtensionStatus = function() +{ + function makeStatus(code, description) + { + var details = Array.prototype.slice.call(arguments, 2); + var status = { code: code, description: description, details: details }; + if (code !== "OK") { + status.isError = true; + console.log("Extension server error: " + String.vsprintf(description, details)); + } + return status; + } + + this.OK = makeStatus.bind(null, "OK", "OK"); + this.E_EXISTS = makeStatus.bind(null, "E_EXISTS", "Object already exists: %s"); + this.E_BADARG = makeStatus.bind(null, "E_BADARG", "Invalid argument %s: %s"); + this.E_BADARGTYPE = makeStatus.bind(null, "E_BADARGTYPE", "Invalid type for argument %s: got %s, expected %s"); + this.E_NOTFOUND = makeStatus.bind(null, "E_NOTFOUND", "Object not found: %s"); + this.E_NOTSUPPORTED = makeStatus.bind(null, "E_NOTSUPPORTED", "Object does not support requested operation: %s"); + this.E_PROTOCOLERROR = makeStatus.bind(null, "E_PROTOCOLERROR", "Inspector protocol error: %s"); + this.E_FAILED = makeStatus.bind(null, "E_FAILED", "Operation failed: %s"); +} + +WebInspector.addExtensions = function(extensions) +{ + WebInspector.extensionServer._addExtensions(extensions); +} + +WebInspector.extensionAPI = {}; +defineCommonExtensionSymbols(WebInspector.extensionAPI); + +WebInspector.extensionServer = new WebInspector.ExtensionServer(); + +window.addExtension = function(page, name) +{ + WebInspector.extensionServer._addExtension({ + startPage: page, + name: name, + }); +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionView.js new file mode 100644 index 00000000..cc2a19a2 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/ExtensionView.js @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.View} + * @param {string} id + * @param {string} src + * @param {string} className + */ +WebInspector.ExtensionView = function(id, src, className) +{ + WebInspector.View.call(this); + this.element.className = "fill"; + + this._id = id; + this._iframe = document.createElement("iframe"); + this._iframe.addEventListener("load", this._onLoad.bind(this), false); + this._iframe.src = src; + this._iframe.className = className; + this.setDefaultFocusedElement(this._iframe); + + this.element.appendChild(this._iframe); +} + +WebInspector.ExtensionView.prototype = { + wasShown: function() + { + if (typeof this._frameIndex === "number") + WebInspector.extensionServer.notifyViewShown(this._id, this._frameIndex); + }, + + willHide: function() + { + if (typeof this._frameIndex === "number") + WebInspector.extensionServer.notifyViewHidden(this._id); + }, + + _onLoad: function() + { + var frames = /** @type {Window} */ (window.frames); + this._frameIndex = Array.prototype.indexOf.call(frames, this._iframe.contentWindow); + if (this.isShowing()) + WebInspector.extensionServer.notifyViewShown(this._id, this._frameIndex); + }, + + __proto__: WebInspector.View.prototype +} + +/** + * @constructor + * @extends {WebInspector.View} + * @param {string} id + */ +WebInspector.ExtensionNotifierView = function(id) +{ + WebInspector.View.call(this); + + this._id = id; +} + +WebInspector.ExtensionNotifierView.prototype = { + wasShown: function() + { + WebInspector.extensionServer.notifyViewShown(this._id); + }, + + willHide: function() + { + WebInspector.extensionServer.notifyViewHidden(this._id); + }, + + __proto__: WebInspector.View.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileContentView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileContentView.js new file mode 100644 index 00000000..51660173 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileContentView.js @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.View} + * @param {WebInspector.FileSystemModel.File} file + */ +WebInspector.FileContentView = function(file) +{ + WebInspector.View.call(this); + + this._innerView = /** @type {?WebInspector.View} */ (null); + this._file = file; + this._content = null; +} + +WebInspector.FileContentView.prototype = { + wasShown: function() + { + if (!this._innerView) { + if (this._file.isTextFile) + this._innerView = new WebInspector.EmptyView(""); + else + this._innerView = new WebInspector.EmptyView(WebInspector.UIString("Binary File")); + this.refresh(); + } + + this._innerView.show(this.element); + }, + + /** + * @param {number} errorCode + * @param {FileSystemAgent.Metadata} metadata + */ + _metadataReceived: function(errorCode, metadata) + { + if (errorCode || !metadata) + return; + + if (this._content) { + if (!this._content.updateMetadata(metadata)) + return; + var sourceFrame = /** @type {WebInspector.SourceFrame} */ (this._innerView); + this._content.requestContent(sourceFrame.setContent.bind(sourceFrame)); + } else { + this._innerView.detach(); + this._content = new WebInspector.FileContentView.FileContentProvider(this._file, metadata); + this._innerView = new WebInspector.SourceFrame(this._content); + this._innerView.show(this.element); + } + }, + + refresh: function() + { + if (!this._innerView) + return; + + if (this._file.isTextFile) + this._file.requestMetadata(this._metadataReceived.bind(this)); + }, + + __proto__: WebInspector.View.prototype +} + +/** + * @constructor + * @implements {WebInspector.ContentProvider} + * @param {WebInspector.FileSystemModel.File} file + * @param {FileSystemAgent.Metadata} metadata + */ +WebInspector.FileContentView.FileContentProvider = function(file, metadata) +{ + this._file = file; + this._metadata = metadata; +} + +WebInspector.FileContentView.FileContentProvider.prototype = { + /** + * @return {string} + */ + contentURL: function() + { + return this._file.url; + }, + + /** + * @return {WebInspector.ResourceType} + */ + contentType: function() + { + return this._file.resourceType; + }, + + /** + * @param {function(?string, boolean, string)} callback + */ + requestContent: function(callback) + { + var size = /** @type {number} */ (this._metadata.size); + this._file.requestFileContent(true, 0, size, this._charset || "", this._fileContentReceived.bind(this, callback)); + }, + + /** + * @param {function(?string, boolean, string)} callback + * @param {number} errorCode + * @param {string=} content + * @param {boolean=} base64Encoded + * @param {string=} charset + */ + _fileContentReceived: function(callback, errorCode, content, base64Encoded, charset) + { + if (errorCode || !content) { + callback(null, false, ""); + return; + } + + this._charset = charset; + callback(content, false, this.contentType().canonicalMimeType()); + }, + + /** + * @param {string} query + * @param {boolean} caseSensitive + * @param {boolean} isRegex + * @param {function(Array.)} callback + */ + searchInContent: function(query, caseSensitive, isRegex, callback) + { + setTimeout(callback.bind(null, []), 0); + }, + + /** + * @param {FileSystemAgent.Metadata} metadata + * @return {boolean} + */ + updateMetadata: function(metadata) + { + if (this._metadata.modificationTime >= metadata.modificationTime) + return false; + this._metadata = metadata.modificationTime; + return true; + } +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileManager.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileManager.js new file mode 100644 index 00000000..16b25c01 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileManager.js @@ -0,0 +1,123 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.Object} + */ +WebInspector.FileManager = function() +{ + this._saveCallbacks = {}; +} + +WebInspector.FileManager.EventTypes = { + SavedURL: "SavedURL", + AppendedToURL: "AppendedToURL" +} + +WebInspector.FileManager.prototype = { + /** + * @return {boolean} + */ + canSave: function() + { + return true; + }, + + /** + * @param {string} url + * @param {string} content + * @param {boolean} forceSaveAs + * @param {function()=} callback + */ + save: function(url, content, forceSaveAs, callback) + { + // Remove this url from the saved URLs while it is being saved. + var savedURLs = WebInspector.settings.savedURLs.get(); + delete savedURLs[url]; + WebInspector.settings.savedURLs.set(savedURLs); + InspectorFrontendHost.save(url, content, forceSaveAs); + this._saveCallbacks[url] = callback; + }, + + /** + * @param {string} url + */ + savedURL: function(url) + { + var savedURLs = WebInspector.settings.savedURLs.get(); + savedURLs[url] = true; + WebInspector.settings.savedURLs.set(savedURLs); + this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.SavedURL, url); + var callback = this._saveCallbacks[url]; + delete this._saveCallbacks[url]; + if (callback) + callback(); + }, + + /** + * @param {string} url + * @return {boolean} + */ + isURLSaved: function(url) + { + var savedURLs = WebInspector.settings.savedURLs.get(); + return savedURLs[url]; + }, + + /** + * @param {string} url + * @param {string} content + */ + append: function(url, content) + { + InspectorFrontendHost.append(url, content); + }, + + /** + * @param {string} url + */ + close: function(url) + { + InspectorFrontendHost.close(url); + }, + + /** + * @param {string} url + */ + appendedToURL: function(url) + { + this.dispatchEventToListeners(WebInspector.FileManager.EventTypes.AppendedToURL, url); + }, + + __proto__: WebInspector.Object.prototype +} + +WebInspector.fileManager = new WebInspector.FileManager(); diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilePathScoreFunction.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilePathScoreFunction.js new file mode 100644 index 00000000..03903d23 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilePathScoreFunction.js @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @param {string} query + */ +WebInspector.FilePathScoreFunction = function(query) +{ + this._query = query; + this._queryUpperCase = query.toUpperCase(); + this._score = null; + this._sequence = null; + this._dataUpperCase = ""; + this._fileNameIndex = 0; +} + +/** + * @param {string} query + * @return {RegExp} + */ +WebInspector.FilePathScoreFunction.filterRegex = function(query) +{ + const toEscape = String.regexSpecialCharacters(); + var regexString = ""; + for (var i = 0; i < query.length; ++i) { + var c = query.charAt(i); + if (toEscape.indexOf(c) !== -1) + c = "\\" + c; + if (i) + regexString += "[^" + c + "]*"; + regexString += c; + } + return new RegExp(regexString, "i"); +} + +WebInspector.FilePathScoreFunction.prototype = { + /** + * @param {string} data + * @param {?Array.} matchIndexes + * @return {number} + */ + score: function(data, matchIndexes) + { + if (!data || !this._query) + return 0; + var n = this._query.length; + var m = data.length; + if (!this._score || this._score.length < n * m) { + this._score = new Int32Array(n * m * 2); + this._sequence = new Int32Array(n * m * 2); + } + var score = this._score; + var sequence = this._sequence; + this._dataUpperCase = data.toUpperCase(); + this._fileNameIndex = data.lastIndexOf("/"); + for (var i = 0; i < n; ++i) { + for (var j = 0; j < m; ++j) { + var skipCharScore = j === 0 ? 0 : score[i * m + j - 1]; + var prevCharScore = i === 0 || j === 0 ? 0 : score[(i - 1) * m + j - 1]; + var consecutiveMatch = i === 0 || j === 0 ? 0 : sequence[(i - 1) * m + j - 1]; + var pickCharScore = this._match(this._query, data, i, j, consecutiveMatch); + if (pickCharScore && prevCharScore + pickCharScore > skipCharScore) { + sequence[i * m + j] = consecutiveMatch + 1; + score[i * m + j] = (prevCharScore + pickCharScore); + } else { + sequence[i * m + j] = 0; + score[i * m + j] = skipCharScore; + } + } + } + if (matchIndexes) + this._restoreMatchIndexes(sequence, n, m, matchIndexes); + return score[n * m - 1]; + }, + + /** + * @param {string} data + * @param {number} j + * @return {boolean} + */ + _testWordStart: function(data, j) + { + var prevChar = data.charAt(j - 1); + return j === 0 || prevChar === "_" || prevChar === "-" || prevChar === "/" || + (data[j - 1] !== this._dataUpperCase[j - 1] && data[j] === this._dataUpperCase[j]); + }, + + /** + * @param {Int32Array} sequence + * @param {number} n + * @param {number} m + * @param {Array.} out + */ + _restoreMatchIndexes: function(sequence, n, m, out) + { + var i = n - 1, j = m - 1; + while (i >= 0 && j >= 0) { + switch (sequence[i * m + j]) { + case 0: + --j; + break; + default: + out.push(j); + --i; + --j; + break; + } + } + out.reverse(); + }, + + /** + * @param {string} query + * @param {string} data + * @param {number} i + * @param {number} j + * @return {number} + */ + _singleCharScore: function(query, data, i, j) + { + var isWordStart = this._testWordStart(data, j); + var isFileName = j > this._fileNameIndex; + var isPathTokenStart = j === 0 || data[j - 1] === "/"; + var isCapsMatch = query[i] === data[j] && query[i] == this._queryUpperCase[i]; + var score = 10; + if (isPathTokenStart) + score += 4; + if (isWordStart) + score += 2; + if (isCapsMatch) + score += 6; + if (isFileName) + score += 4; + // promote the case of making the whole match in the filename + if (j === this._fileNameIndex + 1 && i === 0) + score += 5; + if (isFileName && isWordStart) + score += 3; + return score; + }, + + /** + * @param {string} query + * @param {string} data + * @param {number} i + * @param {number} j + * @param {number} sequenceLength + * @return {number} + */ + _sequenceCharScore: function(query, data, i, j, sequenceLength) + { + var isFileName = j > this._fileNameIndex; + var isPathTokenStart = j === 0 || data[j - 1] === "/"; + var score = 10; + if (isFileName) + score += 4; + if (isPathTokenStart) + score += 5; + score += sequenceLength * 4; + return score; + }, + + /** + * @param {string} query + * @param {string} data + * @param {number} i + * @param {number} j + * @param {number} consecutiveMatch + * @return {number} + */ + _match: function(query, data, i, j, consecutiveMatch) + { + if (this._queryUpperCase[i] !== this._dataUpperCase[j]) + return 0; + + if (!consecutiveMatch) + return this._singleCharScore(query, data, i, j); + else + return this._sequenceCharScore(query, data, i, j - consecutiveMatch, consecutiveMatch); + }, +} + diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemMapping.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemMapping.js new file mode 100644 index 00000000..8366a406 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemMapping.js @@ -0,0 +1,450 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.Object} + */ +WebInspector.FileSystemMapping = function() +{ + WebInspector.Object.call(this); + this._fileSystemMappingSetting = WebInspector.settings.createSetting("fileSystemMapping", {}); + this._excludedFoldersSetting = WebInspector.settings.createSetting("workspaceExcludedFolders", {}); + var defaultCommonExcludedFolders = [ + "/\\.git/", + "/\\.sass-cache/", + "/\\.hg/", + "/\\.idea/", + "/\\.svn/", + "/\\.cache/", + "/\\.project/" + ]; + var defaultWinExcludedFolders = [ + "/Thumbs.db$", + "/ehthumbs.db$", + "/Desktop.ini$", + "/\\$RECYCLE.BIN/" + ]; + var defaultMacExcludedFolders = [ + "/\\.DS_Store$", + "/\\.Trashes$", + "/\\.Spotlight-V100$", + "/\\.AppleDouble$", + "/\\.LSOverride$", + "/Icon$", + "/\\._.*$" + ]; + var defaultLinuxExcludedFolders = [ + "/.*~$" + ]; + var defaultExcludedFolders = defaultCommonExcludedFolders; + if (WebInspector.isWin()) + defaultExcludedFolders = defaultExcludedFolders.concat(defaultWinExcludedFolders); + else if (WebInspector.isMac()) + defaultExcludedFolders = defaultExcludedFolders.concat(defaultMacExcludedFolders); + else + defaultExcludedFolders = defaultExcludedFolders.concat(defaultLinuxExcludedFolders); + var defaultExcludedFoldersPattern = defaultExcludedFolders.join("|"); + WebInspector.settings.workspaceFolderExcludePattern = WebInspector.settings.createSetting("workspaceFolderExcludePattern", defaultExcludedFoldersPattern); + /** @type {!Object.>} */ + this._fileSystemMappings = {}; + /** @type {!Object.>} */ + this._excludedFolders = {}; + this._loadFromSettings(); +} + +WebInspector.FileSystemMapping.Events = { + FileMappingAdded: "FileMappingAdded", + FileMappingRemoved: "FileMappingRemoved", + ExcludedFolderAdded: "ExcludedFolderAdded", + ExcludedFolderRemoved: "ExcludedFolderRemoved" +} + + +WebInspector.FileSystemMapping.prototype = { + _loadFromSettings: function() + { + var savedMapping = this._fileSystemMappingSetting.get(); + this._fileSystemMappings = {}; + for (var fileSystemPath in savedMapping) { + var savedFileSystemMappings = savedMapping[fileSystemPath]; + + this._fileSystemMappings[fileSystemPath] = []; + var fileSystemMappings = this._fileSystemMappings[fileSystemPath]; + + for (var i = 0; i < savedFileSystemMappings.length; ++i) { + var savedEntry = savedFileSystemMappings[i]; + var entry = new WebInspector.FileSystemMapping.Entry(savedEntry.fileSystemPath, savedEntry.urlPrefix, savedEntry.pathPrefix); + fileSystemMappings.push(entry); + } + } + + var savedExcludedFolders = this._excludedFoldersSetting.get(); + this._excludedFolders = {}; + for (var fileSystemPath in savedExcludedFolders) { + var savedExcludedFoldersForPath = savedExcludedFolders[fileSystemPath]; + + this._excludedFolders[fileSystemPath] = []; + var excludedFolders = this._excludedFolders[fileSystemPath]; + + for (var i = 0; i < savedExcludedFoldersForPath.length; ++i) { + var savedEntry = savedExcludedFoldersForPath[i]; + var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(savedEntry.fileSystemPath, savedEntry.path); + excludedFolders.push(entry); + } + } + + var workspaceFolderExcludePattern = WebInspector.settings.workspaceFolderExcludePattern.get() + try { + var flags = WebInspector.isWin() ? "i" : ""; + this._workspaceFolderExcludeRegex = workspaceFolderExcludePattern ? new RegExp(workspaceFolderExcludePattern, flags) : null; + } catch (e) { + } + + this._rebuildIndexes(); + }, + + _saveToSettings: function() + { + var savedMapping = this._fileSystemMappings; + this._fileSystemMappingSetting.set(savedMapping); + + var savedExcludedFolders = this._excludedFolders; + this._excludedFoldersSetting.set(savedExcludedFolders); + + this._rebuildIndexes(); + }, + + _rebuildIndexes: function() + { + // We are building an index here to search for the longest url prefix match faster. + this._mappingForURLPrefix = {}; + this._urlPrefixes = []; + for (var fileSystemPath in this._fileSystemMappings) { + var fileSystemMapping = this._fileSystemMappings[fileSystemPath]; + for (var i = 0; i < fileSystemMapping.length; ++i) { + var entry = fileSystemMapping[i]; + this._mappingForURLPrefix[entry.urlPrefix] = entry; + this._urlPrefixes.push(entry.urlPrefix); + } + } + this._urlPrefixes.sort(); + }, + + /** + * @param {string} fileSystemPath + */ + addFileSystem: function(fileSystemPath) + { + if (this._fileSystemMappings[fileSystemPath]) + return; + + this._fileSystemMappings[fileSystemPath] = []; + this._saveToSettings(); + }, + + /** + * @param {string} fileSystemPath + */ + removeFileSystem: function(fileSystemPath) + { + if (!this._fileSystemMappings[fileSystemPath]) + return; + delete this._fileSystemMappings[fileSystemPath]; + delete this._excludedFolders[fileSystemPath]; + this._saveToSettings(); + }, + + /** + * @param {string} fileSystemPath + * @param {string} urlPrefix + * @param {string} pathPrefix + */ + addFileMapping: function(fileSystemPath, urlPrefix, pathPrefix) + { + var entry = new WebInspector.FileSystemMapping.Entry(fileSystemPath, urlPrefix, pathPrefix); + this._fileSystemMappings[fileSystemPath].push(entry); + this._saveToSettings(); + this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingAdded, entry); + }, + + /** + * @param {string} fileSystemPath + * @param {string} urlPrefix + * @param {string} pathPrefix + */ + removeFileMapping: function(fileSystemPath, urlPrefix, pathPrefix) + { + var entry = this._mappingEntryForPathPrefix(fileSystemPath, pathPrefix); + if (!entry) + return; + this._fileSystemMappings[fileSystemPath].remove(entry); + this._saveToSettings(); + this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.FileMappingRemoved, entry); + }, + + /** + * @param {string} fileSystemPath + * @param {string} excludedFolderPath + */ + addExcludedFolder: function(fileSystemPath, excludedFolderPath) + { + if (!this._excludedFolders[fileSystemPath]) + this._excludedFolders[fileSystemPath] = []; + var entry = new WebInspector.FileSystemMapping.ExcludedFolderEntry(fileSystemPath, excludedFolderPath); + this._excludedFolders[fileSystemPath].push(entry); + this._saveToSettings(); + this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderAdded, entry); + }, + + /** + * @param {string} fileSystemPath + * @param {string} path + */ + removeExcludedFolder: function(fileSystemPath, path) + { + var entry = this._excludedFolderEntryForPath(fileSystemPath, path); + if (!entry) + return; + this._excludedFolders[fileSystemPath].remove(entry); + this._saveToSettings(); + this.dispatchEventToListeners(WebInspector.FileSystemMapping.Events.ExcludedFolderRemoved, entry); + }, + + /** + * @return {Array.} + */ + fileSystemPaths: function() + { + return Object.keys(this._fileSystemMappings); + }, + + /** + * @param {string} url + * @return {WebInspector.FileSystemMapping.Entry} + */ + _mappingEntryForURL: function(url) + { + for (var i = this._urlPrefixes.length - 1; i >= 0; --i) { + var urlPrefix = this._urlPrefixes[i]; + if (url.startsWith(urlPrefix)) + return this._mappingForURLPrefix[urlPrefix]; + } + return null; + }, + + /** + * @param {string} fileSystemPath + * @param {string} path + * @return {?WebInspector.FileSystemMapping.ExcludedFolderEntry} + */ + _excludedFolderEntryForPath: function(fileSystemPath, path) + { + var entries = this._excludedFolders[fileSystemPath]; + if (!entries) + return null; + + for (var i = 0; i < entries.length; ++i) { + if (entries[i].path === path) + return entries[i]; + } + return null; + }, + + /** + * @param {string} fileSystemPath + * @param {string} filePath + * @return {?WebInspector.FileSystemMapping.Entry} + */ + _mappingEntryForPath: function(fileSystemPath, filePath) + { + var entries = this._fileSystemMappings[fileSystemPath]; + if (!entries) + return null; + + var entry = null; + for (var i = 0; i < entries.length; ++i) { + var pathPrefix = entries[i].pathPrefix; + // We are looking for the longest pathPrefix match. + if (entry && entry.pathPrefix.length > pathPrefix.length) + continue; + if (filePath.startsWith(pathPrefix.substr(1))) + entry = entries[i]; + } + return entry; + }, + + /** + * @param {string} fileSystemPath + * @param {string} pathPrefix + * @return {WebInspector.FileSystemMapping.Entry} + */ + _mappingEntryForPathPrefix: function(fileSystemPath, pathPrefix) + { + var entries = this._fileSystemMappings[fileSystemPath]; + for (var i = 0; i < entries.length; ++i) { + if (pathPrefix === entries[i].pathPrefix) + return entries[i]; + } + return null; + }, + + /** + * @param {string} fileSystemPath + * @param {string} folderPath + * @return {boolean} + */ + isFileExcluded: function(fileSystemPath, folderPath) + { + var excludedFolders = this._excludedFolders[fileSystemPath] || []; + for (var i = 0; i < excludedFolders.length; ++i) { + var entry = excludedFolders[i]; + if (entry.path === folderPath) + return true; + } + return this._workspaceFolderExcludeRegex && this._workspaceFolderExcludeRegex.test(folderPath); + }, + + /** + * @param {string} fileSystemPath + * @return {Array.} + */ + excludedFolders: function(fileSystemPath) + { + var excludedFolders = this._excludedFolders[fileSystemPath]; + return excludedFolders ? excludedFolders.slice() : []; + }, + + /** + * @param {string} fileSystemPath + * @return {Array.} + */ + mappingEntries: function(fileSystemPath) + { + return this._fileSystemMappings[fileSystemPath].slice(); + }, + + /** + * @param {string} url + * @return {boolean} + */ + hasMappingForURL: function(url) + { + return !!this._mappingEntryForURL(url); + }, + + /** + * @param {string} url + * @return {?{fileSystemPath: string, filePath: string}} + */ + fileForURL: function(url) + { + var entry = this._mappingEntryForURL(url); + if (!entry) + return null; + var file = {}; + file.fileSystemPath = entry.fileSystemPath; + file.filePath = entry.pathPrefix.substr(1) + url.substr(entry.urlPrefix.length); + return file; + }, + + /** + * @param {string} fileSystemPath + * @param {string} filePath + * @return {string} + */ + urlForPath: function(fileSystemPath, filePath) + { + var entry = this._mappingEntryForPath(fileSystemPath, filePath); + if (!entry) + return ""; + return entry.urlPrefix + filePath.substring(entry.pathPrefix.length - 1); + }, + + /** + * @param {string} url + */ + removeMappingForURL: function(url) + { + var entry = this._mappingEntryForURL(url); + if (!entry) + return; + this._fileSystemMappings[entry.fileSystemPath].remove(entry); + this._saveToSettings(); + }, + + /** + * @param {string} url + * @param {string} fileSystemPath + * @param {string} filePath + */ + addMappingForResource: function(url, fileSystemPath, filePath) + { + var commonPathSuffixLength = 0; + var normalizedFilePath = "/" + filePath; + for (var i = 0; i < normalizedFilePath.length; ++i) { + var filePathCharacter = normalizedFilePath[normalizedFilePath.length - 1 - i]; + var urlCharacter = url[url.length - 1 - i]; + if (filePathCharacter !== urlCharacter) + break; + if (filePathCharacter === "/") + commonPathSuffixLength = i; + } + var pathPrefix = normalizedFilePath.substr(0, normalizedFilePath.length - commonPathSuffixLength); + var urlPrefix = url.substr(0, url.length - commonPathSuffixLength); + this.addFileMapping(fileSystemPath, urlPrefix, pathPrefix); + }, + + __proto__: WebInspector.Object.prototype +} + +/** + * @constructor + * @param {string} fileSystemPath + * @param {string} urlPrefix + * @param {string} pathPrefix + */ +WebInspector.FileSystemMapping.Entry = function(fileSystemPath, urlPrefix, pathPrefix) +{ + this.fileSystemPath = fileSystemPath; + this.urlPrefix = urlPrefix; + this.pathPrefix = pathPrefix; +} + +/** + * @constructor + * @param {string} fileSystemPath + * @param {string} path + */ +WebInspector.FileSystemMapping.ExcludedFolderEntry = function(fileSystemPath, path) +{ + this.fileSystemPath = fileSystemPath; + this.path = path; +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemModel.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemModel.js new file mode 100644 index 00000000..14c1372c --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemModel.js @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.Object} + */ +WebInspector.FileSystemModel = function() +{ + WebInspector.Object.call(this); + + this._fileSystemsForOrigin = {}; + + WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginAdded, this._securityOriginAdded, this); + WebInspector.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.SecurityOriginRemoved, this._securityOriginRemoved, this); + + FileSystemAgent.enable(); + + this._reset(); +} + +WebInspector.FileSystemModel.prototype = { + _reset: function() + { + for (var securityOrigin in this._fileSystemsForOrigin) + this._removeOrigin(securityOrigin); + var securityOrigins = WebInspector.resourceTreeModel.securityOrigins(); + for (var i = 0; i < securityOrigins.length; ++i) + this._addOrigin(securityOrigins[i]); + }, + + /** + * @param {WebInspector.Event} event + */ + _securityOriginAdded: function(event) + { + var securityOrigin = /** @type {string} */ (event.data); + this._addOrigin(securityOrigin); + }, + + /** + * @param {WebInspector.Event} event + */ + _securityOriginRemoved: function(event) + { + var securityOrigin = /** @type {string} */ (event.data); + this._removeOrigin(securityOrigin); + }, + + /** + * @param {string} securityOrigin + */ + _addOrigin: function(securityOrigin) + { + this._fileSystemsForOrigin[securityOrigin] = {}; + + var types = ["persistent", "temporary"]; + for (var i = 0; i < types.length; ++i) + this._requestFileSystemRoot(securityOrigin, types[i], this._fileSystemRootReceived.bind(this, securityOrigin, types[i], this._fileSystemsForOrigin[securityOrigin])); + }, + + /** + * @param {string} securityOrigin + */ + _removeOrigin: function(securityOrigin) + { + for (var type in this._fileSystemsForOrigin[securityOrigin]) { + var fileSystem = this._fileSystemsForOrigin[securityOrigin][type]; + delete this._fileSystemsForOrigin[securityOrigin][type]; + this._fileSystemRemoved(fileSystem); + } + delete this._fileSystemsForOrigin[securityOrigin]; + }, + + /** + * @param {string} origin + * @param {string} type + * @param {function(number, FileSystemAgent.Entry=)} callback + */ + _requestFileSystemRoot: function(origin, type, callback) + { + /** + * @param {?Protocol.Error} error + * @param {number} errorCode + * @param {FileSystemAgent.Entry=} backendRootEntry + */ + function innerCallback(error, errorCode, backendRootEntry) + { + if (error) { + callback(FileError.SECURITY_ERR); + return; + } + + callback(errorCode, backendRootEntry); + } + + FileSystemAgent.requestFileSystemRoot(origin, type, innerCallback.bind(this)); + }, + + /** + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + */ + _fileSystemAdded: function(fileSystem) + { + this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemAdded, fileSystem); + }, + + /** + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + */ + _fileSystemRemoved: function(fileSystem) + { + this.dispatchEventToListeners(WebInspector.FileSystemModel.EventTypes.FileSystemRemoved, fileSystem); + }, + + refreshFileSystemList: function() + { + this._reset(); + }, + + /** + * @param {string} origin + * @param {string} type + * @param {Object.} store + * @param {number} errorCode + * @param {FileSystemAgent.Entry=} backendRootEntry + */ + _fileSystemRootReceived: function(origin, type, store, errorCode, backendRootEntry) + { + if (!errorCode && backendRootEntry && this._fileSystemsForOrigin[origin] === store) { + var fileSystem = new WebInspector.FileSystemModel.FileSystem(this, origin, type, backendRootEntry); + store[type] = fileSystem; + this._fileSystemAdded(fileSystem); + } + }, + + /** + * @param {WebInspector.FileSystemModel.Directory} directory + * @param {function(number, Array.=)} callback + */ + requestDirectoryContent: function(directory, callback) + { + this._requestDirectoryContent(directory.url, this._directoryContentReceived.bind(this, directory, callback)); + }, + + /** + * @param {string} url + * @param {function(number, Array.=)} callback + */ + _requestDirectoryContent: function(url, callback) + { + /** + * @param {?Protocol.Error} error + * @param {number} errorCode + * @param {Array.=} backendEntries + */ + function innerCallback(error, errorCode, backendEntries) + { + if (error) { + callback(FileError.SECURITY_ERR); + return; + } + + if (errorCode !== 0) { + callback(errorCode, null); + return; + } + + callback(errorCode, backendEntries); + } + + FileSystemAgent.requestDirectoryContent(url, innerCallback.bind(this)); + }, + + /** + * @param {WebInspector.FileSystemModel.Directory} parentDirectory + * @param {function(number, Array.=)} callback + * @param {number} errorCode + * @param {Array.=} backendEntries + */ + _directoryContentReceived: function(parentDirectory, callback, errorCode, backendEntries) + { + var entries = []; + for (var i = 0; i < backendEntries.length; ++i) { + if (backendEntries[i].isDirectory) + entries.push(new WebInspector.FileSystemModel.Directory(this, parentDirectory.fileSystem, backendEntries[i])); + else + entries.push(new WebInspector.FileSystemModel.File(this, parentDirectory.fileSystem, backendEntries[i])); + } + + callback(errorCode, entries); + }, + + /** + * @param {WebInspector.FileSystemModel.Entry} entry + * @param {function(number, FileSystemAgent.Metadata=)} callback + */ + requestMetadata: function(entry, callback) + { + /** + * @param {?Protocol.Error} error + * @param {number} errorCode + * @param {FileSystemAgent.Metadata=} metadata + */ + function innerCallback(error, errorCode, metadata) + { + if (error) { + callback(FileError.SECURITY_ERR); + return; + } + + callback(errorCode, metadata); + } + + FileSystemAgent.requestMetadata(entry.url, innerCallback.bind(this)); + }, + + /** + * @param {WebInspector.FileSystemModel.File} file + * @param {boolean} readAsText + * @param {number=} start + * @param {number=} end + * @param {string=} charset + * @param {function(number, string=, string=)=} callback + */ + requestFileContent: function(file, readAsText, start, end, charset, callback) + { + this._requestFileContent(file.url, readAsText, start, end, charset, callback); + }, + + /** + * @param {string} url + * @param {boolean} readAsText + * @param {number=} start + * @param {number=} end + * @param {string=} charset + * @param {function(number, string=, string=)=} callback + */ + _requestFileContent: function(url, readAsText, start, end, charset, callback) + { + /** + * @param {?Protocol.Error} error + * @param {number} errorCode + * @param {string=} content + * @param {string=} charset + */ + function innerCallback(error, errorCode, content, charset) + { + if (error) { + if (callback) + callback(FileError.SECURITY_ERR); + return; + } + + if (callback) + callback(errorCode, content, charset); + } + + FileSystemAgent.requestFileContent(url, readAsText, start, end, charset, innerCallback.bind(this)); + }, + /** + * @param {WebInspector.FileSystemModel.Entry} entry + * @param {function(number)=} callback + */ + deleteEntry: function(entry, callback) + { + var fileSystemModel = this; + if (entry === entry.fileSystem.root) + this._deleteEntry(entry.url, hookFileSystemDeletion); + else + this._deleteEntry(entry.url, callback); + + function hookFileSystemDeletion(errorCode) + { + callback(errorCode); + if (!errorCode) + fileSystemModel._removeFileSystem(entry.fileSystem); + } + }, + + /** + * @param {string} url + * @param {function(number)=} callback + */ + _deleteEntry: function(url, callback) + { + /** + * @param {?Protocol.Error} error + * @param {number} errorCode + */ + function innerCallback(error, errorCode) + { + if (error) { + if (callback) + callback(FileError.SECURITY_ERR); + return; + } + + if (callback) + callback(errorCode); + } + + FileSystemAgent.deleteEntry(url, innerCallback.bind(this)); + }, + + /** + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + */ + _removeFileSystem: function(fileSystem) + { + var origin = fileSystem.origin; + var type = fileSystem.type; + if (this._fileSystemsForOrigin[origin] && this._fileSystemsForOrigin[origin][type]) { + delete this._fileSystemsForOrigin[origin][type]; + this._fileSystemRemoved(fileSystem); + + if (Object.isEmpty(this._fileSystemsForOrigin[origin])) + delete this._fileSystemsForOrigin[origin]; + } + }, + + __proto__: WebInspector.Object.prototype +} + + +WebInspector.FileSystemModel.EventTypes = { + FileSystemAdded: "FileSystemAdded", + FileSystemRemoved: "FileSystemRemoved" +} + +/** + * @constructor + * @param {WebInspector.FileSystemModel} fileSystemModel + * @param {string} origin + * @param {string} type + * @param {FileSystemAgent.Entry} backendRootEntry + */ +WebInspector.FileSystemModel.FileSystem = function(fileSystemModel, origin, type, backendRootEntry) +{ + this.origin = origin; + this.type = type; + + this.root = new WebInspector.FileSystemModel.Directory(fileSystemModel, this, backendRootEntry); +} + +WebInspector.FileSystemModel.FileSystem.prototype = { + /** + * @type {string} + */ + get name() + { + return "filesystem:" + this.origin + "/" + this.type; + } +} + +/** + * @constructor + * @param {WebInspector.FileSystemModel} fileSystemModel + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + * @param {FileSystemAgent.Entry} backendEntry + */ +WebInspector.FileSystemModel.Entry = function(fileSystemModel, fileSystem, backendEntry) +{ + this._fileSystemModel = fileSystemModel; + this._fileSystem = fileSystem; + + this._url = backendEntry.url; + this._name = backendEntry.name; + this._isDirectory = backendEntry.isDirectory; +} + +/** + * @param {WebInspector.FileSystemModel.Entry} x + * @param {WebInspector.FileSystemModel.Entry} y + * @return {number} + */ +WebInspector.FileSystemModel.Entry.compare = function(x, y) +{ + if (x.isDirectory != y.isDirectory) + return y.isDirectory ? 1 : -1; + return x.name.compareTo(y.name); +} + +WebInspector.FileSystemModel.Entry.prototype = { + /** + * @type {WebInspector.FileSystemModel} + */ + get fileSystemModel() + { + return this._fileSystemModel; + }, + + /** + * @type {WebInspector.FileSystemModel.FileSystem} + */ + get fileSystem() + { + return this._fileSystem; + }, + + /** + * @type {string} + */ + get url() + { + return this._url; + }, + + /** + * @type {string} + */ + get name() + { + return this._name; + }, + + /** + * @type {boolean} + */ + get isDirectory() + { + return this._isDirectory; + }, + + /** + * @param {function(number, FileSystemAgent.Metadata)} callback + */ + requestMetadata: function(callback) + { + this.fileSystemModel.requestMetadata(this, callback); + }, + + /** + * @param {function(number)} callback + */ + deleteEntry: function(callback) + { + this.fileSystemModel.deleteEntry(this, callback); + } +} + +/** + * @constructor + * @extends {WebInspector.FileSystemModel.Entry} + * @param {WebInspector.FileSystemModel} fileSystemModel + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + * @param {FileSystemAgent.Entry} backendEntry + */ +WebInspector.FileSystemModel.Directory = function(fileSystemModel, fileSystem, backendEntry) +{ + WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry); +} + +WebInspector.FileSystemModel.Directory.prototype = { + /** + * @param {function(number, Array.)} callback + */ + requestDirectoryContent: function(callback) + { + this.fileSystemModel.requestDirectoryContent(this, callback); + }, + + __proto__: WebInspector.FileSystemModel.Entry.prototype +} + +/** + * @constructor + * @extends {WebInspector.FileSystemModel.Entry} + * @param {WebInspector.FileSystemModel} fileSystemModel + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + * @param {FileSystemAgent.Entry} backendEntry + */ +WebInspector.FileSystemModel.File = function(fileSystemModel, fileSystem, backendEntry) +{ + WebInspector.FileSystemModel.Entry.call(this, fileSystemModel, fileSystem, backendEntry); + + this._mimeType = backendEntry.mimeType; + this._resourceType = WebInspector.resourceTypes[backendEntry.resourceType]; + this._isTextFile = backendEntry.isTextFile; +} + +WebInspector.FileSystemModel.File.prototype = { + /** + * @type {string} + */ + get mimeType() + { + return this._mimeType; + }, + + /** + * @type {WebInspector.ResourceType} + */ + get resourceType() + { + return this._resourceType; + }, + + /** + * @type {boolean} + */ + get isTextFile() + { + return this._isTextFile; + }, + + /** + * @param {boolean} readAsText + * @param {number=} start + * @param {number=} end + * @param {string=} charset + * @param {function(number, string=)=} callback + */ + requestFileContent: function(readAsText, start, end, charset, callback) + { + this.fileSystemModel.requestFileContent(this, readAsText, start, end, charset, callback); + }, + + __proto__: WebInspector.FileSystemModel.Entry.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemProjectDelegate.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemProjectDelegate.js new file mode 100644 index 00000000..ec6d8656 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemProjectDelegate.js @@ -0,0 +1,533 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @implements {WebInspector.ProjectDelegate} + * @extends {WebInspector.Object} + * @param {WebInspector.IsolatedFileSystem} isolatedFileSystem + * @param {WebInspector.Workspace} workspace + */ +WebInspector.FileSystemProjectDelegate = function(isolatedFileSystem, workspace) +{ + this._fileSystem = isolatedFileSystem; + this._normalizedFileSystemPath = this._fileSystem.path(); + if (WebInspector.isWin()) + this._normalizedFileSystemPath = this._normalizedFileSystemPath.replace(/\\/g, "/"); + this._fileSystemURL = "file://" + this._normalizedFileSystemPath + "/"; + this._workspace = workspace; + /** @type {Object.)>} */ + this._searchCallbacks = {}; + /** @type {Object.} */ + this._indexingCallbacks = {}; + /** @type {Object.} */ + this._indexingProgresses = {}; +} + +WebInspector.FileSystemProjectDelegate._scriptExtensions = ["js", "java", "coffee", "ts", "dart"].keySet(); +WebInspector.FileSystemProjectDelegate._styleSheetExtensions = ["css", "scss", "sass", "less"].keySet(); +WebInspector.FileSystemProjectDelegate._documentExtensions = ["htm", "html", "asp", "aspx", "phtml", "jsp"].keySet(); + +WebInspector.FileSystemProjectDelegate.projectId = function(fileSystemPath) +{ + return "filesystem:" + fileSystemPath; +} + +WebInspector.FileSystemProjectDelegate._lastRequestId = 0; + +WebInspector.FileSystemProjectDelegate.prototype = { + /** + * @return {string} + */ + id: function() + { + return WebInspector.FileSystemProjectDelegate.projectId(this._fileSystem.path()); + }, + + /** + * @return {string} + */ + type: function() + { + return WebInspector.projectTypes.FileSystem; + }, + + /** + * @return {string} + */ + fileSystemPath: function() + { + return this._fileSystem.path(); + }, + + /** + * @return {string} + */ + displayName: function() + { + return this._normalizedFileSystemPath.substr(this._normalizedFileSystemPath.lastIndexOf("/") + 1); + }, + + /** + * @param {string} path + * @return {string} + */ + _filePathForPath: function(path) + { + return "/" + path; + }, + + /** + * @param {string} path + * @param {function(?string,boolean,string)} callback + */ + requestFileContent: function(path, callback) + { + var filePath = this._filePathForPath(path); + this._fileSystem.requestFileContent(filePath, innerCallback.bind(this)); + + /** + * @param {?string} content + */ + function innerCallback(content) + { + var extension = this._extensionForPath(path); + var mimeType = WebInspector.ResourceType.mimeTypesForExtensions[extension]; + callback(content, false, mimeType); + } + }, + + /** + * @param {string} path + * @param {function(?Date, ?number)} callback + */ + requestMetadata: function(path, callback) + { + var filePath = this._filePathForPath(path); + this._fileSystem.requestMetadata(filePath, callback); + }, + + /** + * @return {boolean} + */ + canSetFileContent: function() + { + return true; + }, + + /** + * @param {string} path + * @param {string} newContent + * @param {function(?string)} callback + */ + setFileContent: function(path, newContent, callback) + { + var filePath = this._filePathForPath(path); + this._fileSystem.setFileContent(filePath, newContent, callback.bind(this, "")); + }, + + /** + * @return {boolean} + */ + canRename: function() + { + return true; + }, + + /** + * @param {string} path + * @param {string} newName + * @param {function(boolean, string=)} callback + */ + rename: function(path, newName, callback) + { + var filePath = this._filePathForPath(path); + this._fileSystem.renameFile(filePath, newName, callback); + }, + + /** + * @param {string} path + * @param {string} query + * @param {boolean} caseSensitive + * @param {boolean} isRegex + * @param {function(Array.)} callback + */ + searchInFileContent: function(path, query, caseSensitive, isRegex, callback) + { + var filePath = this._filePathForPath(path); + this._fileSystem.requestFileContent(filePath, contentCallback.bind(this)); + + /** + * @param {?string} content + */ + function contentCallback(content) + { + var result = []; + if (content !== null) + result = WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex); + callback(result); + } + }, + + /** + * @param {string} query + * @param {boolean} caseSensitive + * @param {boolean} isRegex + * @param {WebInspector.Progress} progress + * @param {function(StringMap)} callback + */ + searchInContent: function(query, caseSensitive, isRegex, progress, callback) + { + var requestId = ++WebInspector.FileSystemProjectDelegate._lastRequestId; + this._searchCallbacks[requestId] = innerCallback.bind(this); + InspectorFrontendHost.searchInPath(requestId, this._fileSystem.path(), isRegex ? "" : query); + + function innerCallback(files) + { + function trimAndNormalizeFileSystemPath(fullPath) + { + var trimmedPath = fullPath.substr(this._fileSystem.path().length + 1); + if (WebInspector.isWin()) + trimmedPath = trimmedPath.replace(/\\/g, "/"); + return trimmedPath; + } + + files = files.map(trimAndNormalizeFileSystemPath.bind(this)); + var result = new StringMap(); + progress.setTotalWork(files.length); + if (files.length === 0) { + progress.done(); + callback(result); + return; + } + + var fileIndex = 0; + var maxFileContentRequests = 20; + var callbacksLeft = 0; + + function searchInNextFiles() + { + for (; callbacksLeft < maxFileContentRequests; ++callbacksLeft) { + if (fileIndex >= files.length) + break; + var path = files[fileIndex++]; + var filePath = this._filePathForPath(path); + this._fileSystem.requestFileContent(filePath, contentCallback.bind(this, path)); + } + } + + searchInNextFiles.call(this); + + /** + * @param {string} path + * @param {?string} content + */ + function contentCallback(path, content) + { + var matches = []; + if (content !== null) + matches = WebInspector.ContentProvider.performSearchInContent(content, query, caseSensitive, isRegex); + + result.put(path, matches); + progress.worked(1); + + --callbacksLeft; + if (fileIndex < files.length) { + searchInNextFiles.call(this); + } else { + if (callbacksLeft) + return; + progress.done(); + callback(result); + } + } + } + }, + + /** + * @param {number} requestId + * @param {Array.} files + */ + searchCompleted: function(requestId, files) + { + if (!this._searchCallbacks[requestId]) + return; + var callback = this._searchCallbacks[requestId]; + delete this._searchCallbacks[requestId]; + callback(files); + }, + + /** + * @param {WebInspector.Progress} progress + * @param {function()} callback + */ + indexContent: function(progress, callback) + { + var requestId = ++WebInspector.FileSystemProjectDelegate._lastRequestId; + this._indexingCallbacks[requestId] = callback; + this._indexingProgresses[requestId] = progress; + progress.setTotalWork(1); + progress.addEventListener(WebInspector.Progress.Events.Canceled, this._indexingCanceled.bind(this, requestId)); + InspectorFrontendHost.indexPath(requestId, this._fileSystem.path()); + }, + + /** + * @param {number} requestId + */ + _indexingCanceled: function(requestId) + { + if (!this._indexingProgresses[requestId]) + return; + InspectorFrontendHost.stopIndexing(requestId); + delete this._indexingProgresses[requestId]; + delete this._indexingCallbacks[requestId]; + }, + + /** + * @param {number} requestId + * @param {number} totalWork + */ + indexingTotalWorkCalculated: function(requestId, totalWork) + { + if (!this._indexingProgresses[requestId]) + return; + var progress = this._indexingProgresses[requestId]; + progress.setTotalWork(totalWork); + }, + + /** + * @param {number} requestId + * @param {number} worked + */ + indexingWorked: function(requestId, worked) + { + if (!this._indexingProgresses[requestId]) + return; + var progress = this._indexingProgresses[requestId]; + progress.worked(worked); + }, + + /** + * @param {number} requestId + */ + indexingDone: function(requestId) + { + if (!this._indexingProgresses[requestId]) + return; + var progress = this._indexingProgresses[requestId]; + var callback = this._indexingCallbacks[requestId]; + delete this._indexingProgresses[requestId]; + delete this._indexingCallbacks[requestId]; + progress.done(); + callback.call(); + }, + + /** + * @param {string} path + * @return {string} + */ + _extensionForPath: function(path) + { + var extensionIndex = path.lastIndexOf("."); + if (extensionIndex === -1) + return ""; + return path.substring(extensionIndex + 1).toLowerCase(); + }, + + /** + * @param {string} extension + * @return {WebInspector.ResourceType} + */ + _contentTypeForExtension: function(extension) + { + if (WebInspector.FileSystemProjectDelegate._scriptExtensions[extension]) + return WebInspector.resourceTypes.Script; + if (WebInspector.FileSystemProjectDelegate._styleSheetExtensions[extension]) + return WebInspector.resourceTypes.Stylesheet; + if (WebInspector.FileSystemProjectDelegate._documentExtensions[extension]) + return WebInspector.resourceTypes.Document; + return WebInspector.resourceTypes.Other; + }, + + populate: function() + { + this._fileSystem.requestFilesRecursive("", this._addFile.bind(this)); + }, + + /** + * @param {string} path + */ + refresh: function(path) + { + this._fileSystem.requestFilesRecursive(path, this._addFile.bind(this)); + }, + + /** + * @param {string} path + */ + excludeFolder: function(path) + { + WebInspector.isolatedFileSystemManager.mapping().addExcludedFolder(this._fileSystem.path(), path); + }, + + /** + * @param {string} path + * @param {?string} name + * @param {function(?string)} callback + */ + createFile: function(path, name, callback) + { + this._fileSystem.createFile(path, name, innerCallback.bind(this)); + + function innerCallback(filePath) + { + this._addFile(filePath); + callback(filePath); + } + }, + + /** + * @param {string} path + */ + deleteFile: function(path) + { + this._fileSystem.deleteFile(path); + this._removeFile(path); + }, + + remove: function() + { + WebInspector.isolatedFileSystemManager.removeFileSystem(this._fileSystem.path()); + }, + + /** + * @param {string} filePath + */ + _addFile: function(filePath) + { + if (!filePath) + console.assert(false); + + var slash = filePath.lastIndexOf("/"); + var parentPath = filePath.substring(0, slash); + var name = filePath.substring(slash + 1); + + var url = this._workspace.urlForPath(this._fileSystem.path(), filePath); + var extension = this._extensionForPath(name); + var contentType = this._contentTypeForExtension(extension); + + var fileDescriptor = new WebInspector.FileDescriptor(parentPath, name, this._fileSystemURL + filePath, url, contentType, true); + this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileAdded, fileDescriptor); + }, + + /** + * @param {string} path + */ + _removeFile: function(path) + { + this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.FileRemoved, path); + }, + + reset: function() + { + this.dispatchEventToListeners(WebInspector.ProjectDelegate.Events.Reset, null); + }, + + __proto__: WebInspector.Object.prototype +} + +/** + * @type {?WebInspector.FileSystemProjectDelegate} + */ +WebInspector.fileSystemProjectDelegate = null; + +/** + * @constructor + * @param {WebInspector.IsolatedFileSystemManager} isolatedFileSystemManager + * @param {WebInspector.Workspace} workspace + */ +WebInspector.FileSystemWorkspaceProvider = function(isolatedFileSystemManager, workspace) +{ + this._isolatedFileSystemManager = isolatedFileSystemManager; + this._workspace = workspace; + this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemAdded, this._fileSystemAdded, this); + this._isolatedFileSystemManager.addEventListener(WebInspector.IsolatedFileSystemManager.Events.FileSystemRemoved, this._fileSystemRemoved, this); + this._projectDelegates = {}; +} + +WebInspector.FileSystemWorkspaceProvider.prototype = { + /** + * @param {WebInspector.Event} event + */ + _fileSystemAdded: function(event) + { + var fileSystem = /** @type {WebInspector.IsolatedFileSystem} */ (event.data); + var projectId = WebInspector.FileSystemProjectDelegate.projectId(fileSystem.path()); + var projectDelegate = new WebInspector.FileSystemProjectDelegate(fileSystem, this._workspace) + this._projectDelegates[projectDelegate.id()] = projectDelegate; + console.assert(!this._workspace.project(projectDelegate.id())); + this._workspace.addProject(projectDelegate); + projectDelegate.populate(); + }, + + /** + * @param {WebInspector.Event} event + */ + _fileSystemRemoved: function(event) + { + var fileSystem = /** @type {WebInspector.IsolatedFileSystem} */ (event.data); + var projectId = WebInspector.FileSystemProjectDelegate.projectId(fileSystem.path()); + this._workspace.removeProject(projectId); + delete this._projectDelegates[projectId]; + }, + + /** + * @param {WebInspector.UISourceCode} uiSourceCode + */ + fileSystemPath: function(uiSourceCode) + { + var projectDelegate = this._projectDelegates[uiSourceCode.project().id()]; + return projectDelegate.fileSystemPath(); + }, + + /** + * @param {WebInspector.FileSystemProjectDelegate} fileSystemPath + */ + delegate: function(fileSystemPath) + { + var projectId = WebInspector.FileSystemProjectDelegate.projectId(fileSystemPath); + return this._projectDelegates[projectId]; + } +} + +/** + * @type {?WebInspector.FileSystemWorkspaceProvider} + */ +WebInspector.fileSystemWorkspaceProvider = null; diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemView.js new file mode 100644 index 00000000..7f6a1505 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileSystemView.js @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.SidebarView} + * @param {WebInspector.FileSystemModel.FileSystem} fileSystem + */ +WebInspector.FileSystemView = function(fileSystem) +{ + WebInspector.SidebarView.call(this, WebInspector.SidebarView.SidebarPosition.Start, "FileSystemViewSidebarWidth"); + this.element.addStyleClass("file-system-view"); + this.element.addStyleClass("storage-view"); + + var directoryTreeElement = this.element.createChild("ol", "filesystem-directory-tree"); + this._directoryTree = new TreeOutline(directoryTreeElement); + this.sidebarElement.appendChild(directoryTreeElement); + this.sidebarElement.addStyleClass("outline-disclosure"); + this.sidebarElement.addStyleClass("sidebar"); + + var rootItem = new WebInspector.FileSystemView.EntryTreeElement(this, fileSystem.root); + rootItem.expanded = true; + this._directoryTree.appendChild(rootItem); + this._visibleView = null; + + this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); + this._refreshButton.visible = true; + this._refreshButton.addEventListener("click", this._refresh, this); + + this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); + this._deleteButton.visible = true; + this._deleteButton.addEventListener("click", this._confirmDelete, this); +} + +WebInspector.FileSystemView.prototype = { + /** + * @type {Array.} + */ + get statusBarItems() + { + return [this._refreshButton.element, this._deleteButton.element]; + }, + + /** + * @type {WebInspector.View} + */ + get visibleView() + { + return this._visibleView; + }, + + /** + * @param {WebInspector.View} view + */ + showView: function(view) + { + if (this._visibleView === view) + return; + if (this._visibleView) + this._visibleView.detach(); + this._visibleView = view; + view.show(this.mainElement); + }, + + _refresh: function() + { + this._directoryTree.children[0].refresh(); + }, + + _confirmDelete: function() + { + if (confirm(WebInspector.UIString("Are you sure you want to delete the selected entry?"))) + this._delete(); + }, + + _delete: function() + { + this._directoryTree.selectedTreeElement.deleteEntry(); + }, + + __proto__: WebInspector.SidebarView.prototype +} + +/** + * @constructor + * @extends {TreeElement} + * @param {WebInspector.FileSystemView} fileSystemView + * @param {WebInspector.FileSystemModel.Entry} entry + */ +WebInspector.FileSystemView.EntryTreeElement = function(fileSystemView, entry) +{ + TreeElement.call(this, entry.name, null, entry.isDirectory); + + this._entry = entry; + this._fileSystemView = fileSystemView; +} + +WebInspector.FileSystemView.EntryTreeElement.prototype = { + onattach: function() + { + var selection = this.listItemElement.createChild("div", "selection"); + this.listItemElement.insertBefore(selection, this.listItemElement.firstChild); + }, + + onselect: function() + { + if (!this._view) { + if (this._entry.isDirectory) + this._view = new WebInspector.DirectoryContentView(); + else { + var file = /** @type {WebInspector.FileSystemModel.File} */ (this._entry); + this._view = new WebInspector.FileContentView(file); + } + } + this._fileSystemView.showView(this._view); + this.refresh(); + }, + + onpopulate: function() + { + this.refresh(); + }, + + /** + * @param {number} errorCode + * @param {Array.=} entries + */ + _directoryContentReceived: function(errorCode, entries) + { + if (errorCode === FileError.NOT_FOUND_ERR) { + if (this.parent !== this.treeOutline) + this.parent.refresh(); + return; + } + + if (errorCode !== 0 || !entries) { + console.error("Failed to read directory: " + errorCode); + return; + } + + entries.sort(WebInspector.FileSystemModel.Entry.compare); + if (this._view) + this._view.showEntries(entries); + + var oldChildren = this.children.slice(0); + + var newEntryIndex = 0; + var oldChildIndex = 0; + var currentTreeItem = 0; + while (newEntryIndex < entries.length && oldChildIndex < oldChildren.length) { + var newEntry = entries[newEntryIndex]; + var oldChild = oldChildren[oldChildIndex]; + var order = newEntry.name.compareTo(oldChild._entry.name); + + if (order === 0) { + if (oldChild._entry.isDirectory) + oldChild.shouldRefreshChildren = true; + else + oldChild.refresh(); + + ++newEntryIndex; + ++oldChildIndex; + ++currentTreeItem; + continue; + } + if (order < 0) { + this.insertChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, newEntry), currentTreeItem); + ++newEntryIndex; + ++currentTreeItem; + continue; + } + + this.removeChildAtIndex(currentTreeItem); + ++oldChildIndex; + } + for (; newEntryIndex < entries.length; ++newEntryIndex) + this.appendChild(new WebInspector.FileSystemView.EntryTreeElement(this._fileSystemView, entries[newEntryIndex])); + + for (; oldChildIndex < oldChildren.length; ++oldChildIndex) + this.removeChild(oldChildren[oldChildIndex]); + }, + + refresh: function() + { + if (!this._entry.isDirectory) { + if (this._view && this._view === this._fileSystemView.visibleView) { + var fileContentView = /** @type {WebInspector.FileContentView} */ (this._view); + fileContentView.refresh(); + } + } else + this._entry.requestDirectoryContent(this._directoryContentReceived.bind(this)); + }, + + deleteEntry: function() + { + this._entry.deleteEntry(this._deletionCompleted.bind(this)); + }, + + _deletionCompleted: function() + { + if (this._entry != this._entry.fileSystem.root) + this.parent.refresh(); + }, + + __proto__: TreeElement.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileUtils.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileUtils.js new file mode 100644 index 00000000..359711d5 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FileUtils.js @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @interface + */ +WebInspector.OutputStreamDelegate = function() +{ +} + +WebInspector.OutputStreamDelegate.prototype = { + onTransferStarted: function() { }, + + onTransferFinished: function() { }, + + /** + * @param {WebInspector.ChunkedReader} reader + */ + onChunkTransferred: function(reader) { }, + + /** + * @param {WebInspector.ChunkedReader} reader + */ + onError: function(reader, event) { }, +} + +/** + * @interface + */ +WebInspector.OutputStream = function() +{ +} + +WebInspector.OutputStream.prototype = { + /** + * @param {string} data + * @param {function(WebInspector.OutputStream)=} callback + */ + write: function(data, callback) { }, + + close: function() { } +} + +/** + * @interface + */ +WebInspector.ChunkedReader = function() +{ +} + +WebInspector.ChunkedReader.prototype = { + /** + * @return {number} + */ + fileSize: function() { }, + + /** + * @return {number} + */ + loadedSize: function() { }, + + /** + * @return {string} + */ + fileName: function() { }, + + cancel: function() { } +} + +/** + * @constructor + * @implements {WebInspector.ChunkedReader} + * @param {!File} file + * @param {number} chunkSize + * @param {!WebInspector.OutputStreamDelegate} delegate + */ +WebInspector.ChunkedFileReader = function(file, chunkSize, delegate) +{ + this._file = file; + this._fileSize = file.size; + this._loadedSize = 0; + this._chunkSize = chunkSize; + this._delegate = delegate; + this._isCanceled = false; +} + +WebInspector.ChunkedFileReader.prototype = { + /** + * @param {!WebInspector.OutputStream} output + */ + start: function(output) + { + this._output = output; + + this._reader = new FileReader(); + this._reader.onload = this._onChunkLoaded.bind(this); + this._reader.onerror = this._delegate.onError.bind(this._delegate, this); + this._delegate.onTransferStarted(); + this._loadChunk(); + }, + + cancel: function() + { + this._isCanceled = true; + }, + + /** + * @return {number} + */ + loadedSize: function() + { + return this._loadedSize; + }, + + /** + * @return {number} + */ + fileSize: function() + { + return this._fileSize; + }, + + /** + * @return {string} + */ + fileName: function() + { + return this._file.name; + }, + + /** + * @param {Event} event + */ + _onChunkLoaded: function(event) + { + if (this._isCanceled) + return; + + if (event.target.readyState !== FileReader.DONE) + return; + + var data = event.target.result; + this._loadedSize += data.length; + + this._output.write(data); + if (this._isCanceled) + return; + this._delegate.onChunkTransferred(this); + + if (this._loadedSize === this._fileSize) { + this._file = null; + this._reader = null; + this._output.close(); + this._delegate.onTransferFinished(); + return; + } + + this._loadChunk(); + }, + + _loadChunk: function() + { + var chunkStart = this._loadedSize; + var chunkEnd = Math.min(this._fileSize, chunkStart + this._chunkSize) + var nextPart = this._file.slice(chunkStart, chunkEnd); + this._reader.readAsText(nextPart); + } +} + +/** + * @constructor + * @implements {WebInspector.ChunkedReader} + * @param {string} url + * @param {!WebInspector.OutputStreamDelegate} delegate + */ +WebInspector.ChunkedXHRReader = function(url, delegate) +{ + this._url = url; + this._delegate = delegate; + this._fileSize = 0; + this._loadedSize = 0; + this._isCanceled = false; +} + +WebInspector.ChunkedXHRReader.prototype = { + /** + * @param {!WebInspector.OutputStream} output + */ + start: function(output) + { + this._output = output; + + this._xhr = new XMLHttpRequest(); + this._xhr.open("GET", this._url, true); + this._xhr.onload = this._onLoad.bind(this); + this._xhr.onprogress = this._onProgress.bind(this); + this._xhr.onerror = this._delegate.onError.bind(this._delegate, this); + this._xhr.send(null); + + this._delegate.onTransferStarted(); + }, + + cancel: function() + { + this._isCanceled = true; + this._xhr.abort(); + }, + + /** + * @return {number} + */ + loadedSize: function() + { + return this._loadedSize; + }, + + /** + * @return {number} + */ + fileSize: function() + { + return this._fileSize; + }, + + /** + * @return {string} + */ + fileName: function() + { + return this._url; + }, + + /** + * @param {Event} event + */ + _onProgress: function(event) + { + if (this._isCanceled) + return; + + if (event.lengthComputable) + this._fileSize = event.total; + + var data = this._xhr.responseText.substring(this._loadedSize); + if (!data.length) + return; + + this._loadedSize += data.length; + this._output.write(data); + if (this._isCanceled) + return; + this._delegate.onChunkTransferred(this); + }, + + /** + * @param {Event} event + */ + _onLoad: function(event) + { + this._onProgress(event); + + if (this._isCanceled) + return; + + this._output.close(); + this._delegate.onTransferFinished(); + } +} + +/** + * @param {function(!File)} callback + * @return {Node} + */ +WebInspector.createFileSelectorElement = function(callback) { + var fileSelectorElement = document.createElement("input"); + fileSelectorElement.type = "file"; + fileSelectorElement.style.display = "none"; + fileSelectorElement.setAttribute("tabindex", -1); + fileSelectorElement.onchange = onChange; + function onChange(event) + { + callback(fileSelectorElement.files[0]); + }; + return fileSelectorElement; +} + +/** + * @param {string} source + * @param {number=} startIndex + * @param {number=} lastIndex + */ +WebInspector.findBalancedCurlyBrackets = function(source, startIndex, lastIndex) { + lastIndex = lastIndex || source.length; + startIndex = startIndex || 0; + var counter = 0; + var inString = false; + + for (var index = startIndex; index < lastIndex; ++index) { + var character = source[index]; + if (inString) { + if (character === "\\") + ++index; + else if (character === "\"") + inString = false; + } else { + if (character === "\"") + inString = true; + else if (character === "{") + ++counter; + else if (character === "}") { + if (--counter === 0) + return index + 1; + } + } + } + return -1; +} + +/** + * @constructor + * @implements {WebInspector.OutputStream} + */ +WebInspector.FileOutputStream = function() +{ +} + +WebInspector.FileOutputStream.prototype = { + /** + * @param {string} fileName + * @param {function(WebInspector.FileOutputStream, string=)} callback + */ + open: function(fileName, callback) + { + this._closed = false; + this._writeCallbacks = []; + this._fileName = fileName; + function callbackWrapper() + { + WebInspector.fileManager.removeEventListener(WebInspector.FileManager.EventTypes.SavedURL, callbackWrapper, this); + WebInspector.fileManager.addEventListener(WebInspector.FileManager.EventTypes.AppendedToURL, this._onAppendDone, this); + callback(this); + } + WebInspector.fileManager.addEventListener(WebInspector.FileManager.EventTypes.SavedURL, callbackWrapper, this); + WebInspector.fileManager.save(this._fileName, "", true); + }, + + /** + * @param {string} data + * @param {function(WebInspector.OutputStream)=} callback + */ + write: function(data, callback) + { + this._writeCallbacks.push(callback); + WebInspector.fileManager.append(this._fileName, data); + }, + + close: function() + { + this._closed = true; + if (this._writeCallbacks.length) + return; + WebInspector.fileManager.removeEventListener(WebInspector.FileManager.EventTypes.AppendedToURL, this._onAppendDone, this); + WebInspector.fileManager.close(this._fileName); + }, + + /** + * @param {Event} event + */ + _onAppendDone: function(event) + { + if (event.data !== this._fileName) + return; + var callback = this._writeCallbacks.shift(); + if (callback) + callback(this); + if (!this._writeCallbacks.length) { + if (this._closed) { + WebInspector.fileManager.removeEventListener(WebInspector.FileManager.EventTypes.AppendedToURL, this._onAppendDone, this); + WebInspector.fileManager.close(this._fileName); + } + } + } +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilteredItemSelectionDialog.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilteredItemSelectionDialog.js new file mode 100644 index 00000000..c7b4e30e --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FilteredItemSelectionDialog.js @@ -0,0 +1,868 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.DialogDelegate} + * @implements {WebInspector.ViewportControl.Provider} + * @param {WebInspector.SelectionDialogContentProvider} delegate + */ +WebInspector.FilteredItemSelectionDialog = function(delegate) +{ + WebInspector.DialogDelegate.call(this); + + var xhr = new XMLHttpRequest(); + xhr.open("GET", "filteredItemSelectionDialog.css", false); + xhr.send(null); + + this.element = document.createElement("div"); + this.element.className = "filtered-item-list-dialog"; + this.element.addEventListener("keydown", this._onKeyDown.bind(this), false); + var styleElement = this.element.createChild("style"); + styleElement.type = "text/css"; + styleElement.textContent = xhr.responseText; + + this._promptElement = this.element.createChild("input", "monospace"); + this._promptElement.addEventListener("input", this._onInput.bind(this), false); + this._promptElement.type = "text"; + this._promptElement.setAttribute("spellcheck", "false"); + + this._filteredItems = []; + this._viewportControl = new WebInspector.ViewportControl(this); + this._itemElementsContainer = this._viewportControl.element; + this._itemElementsContainer.addStyleClass("container"); + this._itemElementsContainer.addStyleClass("monospace"); + this._itemElementsContainer.addEventListener("click", this._onClick.bind(this), false); + this.element.appendChild(this._itemElementsContainer); + + this._delegate = delegate; + this._delegate.setRefreshCallback(this._itemsLoaded.bind(this)); + this._itemsLoaded(); + + this._shouldShowMatchingItems = true; +} + +WebInspector.FilteredItemSelectionDialog.prototype = { + /** + * @param {Element} element + * @param {Element} relativeToElement + */ + position: function(element, relativeToElement) + { + const minWidth = 500; + const minHeight = 204; + var width = Math.max(relativeToElement.offsetWidth * 2 / 3, minWidth); + var height = Math.max(relativeToElement.offsetHeight * 2 / 3, minHeight); + + this.element.style.width = width + "px"; + + const shadowPadding = 20; // shadow + padding + element.positionAt( + relativeToElement.totalOffsetLeft() + Math.max((relativeToElement.offsetWidth - width - 2 * shadowPadding) / 2, shadowPadding), + relativeToElement.totalOffsetTop() + Math.max((relativeToElement.offsetHeight - height - 2 * shadowPadding) / 2, shadowPadding)); + this._dialogHeight = height; + + this._updateShowMatchingItems(); + }, + + focus: function() + { + WebInspector.setCurrentFocusElement(this._promptElement); + if (this._filteredItems.length && this._viewportControl.lastVisibleIndex() === -1) + this._viewportControl.refresh(); + }, + + willHide: function() + { + if (this._isHiding) + return; + this._isHiding = true; + this._delegate.dispose(); + if (this._filterTimer) + clearTimeout(this._filterTimer); + }, + + renderAsTwoRows: function() + { + this._renderAsTwoRows = true; + }, + + onEnter: function() + { + if (!this._delegate.itemCount()) + return; + this._delegate.selectItem(this._filteredItems[this._selectedIndexInFiltered], this._promptElement.value.trim()); + }, + + _itemsLoaded: function() + { + + if (this._loadTimeout) + return; + this._loadTimeout = setTimeout(this._updateAfterItemsLoaded.bind(this), 0); + }, + + _updateAfterItemsLoaded: function() + { + delete this._loadTimeout; + this._filterItems(); + }, + + /** + * @param {number} index + * @return {Element} + */ + _createItemElement: function(index) + { + var itemElement = document.createElement("div"); + itemElement.className = "filtered-item-list-dialog-item " + (this._renderAsTwoRows ? "two-rows" : "one-row"); + itemElement._titleElement = itemElement.createChild("span"); + itemElement._titleSuffixElement = itemElement.createChild("span"); + itemElement._subtitleElement = itemElement.createChild("div", "filtered-item-list-dialog-subtitle"); + itemElement._subtitleElement.textContent = "\u200B"; + itemElement._index = index; + this._delegate.renderItem(index, this._promptElement.value.trim(), itemElement._titleElement, itemElement._subtitleElement); + return itemElement; + }, + + /** + * @param {string} query + */ + setQuery: function(query) + { + this._promptElement.value = query; + this._scheduleFilter(); + }, + + _filterItems: function() + { + delete this._filterTimer; + if (this._scoringTimer) { + clearTimeout(this._scoringTimer); + delete this._scoringTimer; + } + + var query = this._delegate.rewriteQuery(this._promptElement.value.trim()); + this._query = query; + var queryLength = query.length; + var filterRegex = query ? WebInspector.FilePathScoreFunction.filterRegex(query) : null; + + var oldSelectedAbsoluteIndex = this._selectedIndexInFiltered ? this._filteredItems[this._selectedIndexInFiltered] : null; + var filteredItems = []; + this._selectedIndexInFiltered = 0; + + var bestScores = []; + var bestItems = []; + var bestItemsToCollect = 100; + var minBestScore = 0; + var overflowItems = []; + + scoreItems.call(this, 0); + + /** + * @param {number} a + * @param {number} b + * @return {number} + */ + function compareIntegers(a, b) + { + return b - a; + } + + function scoreItems(fromIndex) + { + var maxWorkItems = 1000; + var workDone = 0; + for (var i = fromIndex; i < this._delegate.itemCount() && workDone < maxWorkItems; ++i) { + // Filter out non-matching items quickly. + if (filterRegex && !filterRegex.test(this._delegate.itemKeyAt(i))) + continue; + + // Score item. + var score = this._delegate.itemScoreAt(i, query); + if (query) + workDone++; + + // Find its index in the scores array (earlier elements have bigger scores). + if (score > minBestScore || bestScores.length < bestItemsToCollect) { + var index = insertionIndexForObjectInListSortedByFunction(score, bestScores, compareIntegers, true); + bestScores.splice(index, 0, score); + bestItems.splice(index, 0, i); + if (bestScores.length > bestItemsToCollect) { + // Best list is too large -> drop last elements. + overflowItems.push(bestItems.peekLast()); + bestScores.length = bestItemsToCollect; + bestItems.length = bestItemsToCollect; + } + minBestScore = bestScores.peekLast(); + } else + filteredItems.push(i); + } + + // Process everything in chunks. + if (i < this._delegate.itemCount()) { + this._scoringTimer = setTimeout(scoreItems.bind(this, i), 0); + return; + } + delete this._scoringTimer; + + this._filteredItems = bestItems.concat(overflowItems).concat(filteredItems); + for (var i = 0; i < this._filteredItems.length; ++i) { + if (this._filteredItems[i] === oldSelectedAbsoluteIndex) { + this._selectedIndexInFiltered = i; + break; + } + } + this._viewportControl.refresh(); + if (!query) + this._selectedIndexInFiltered = 0; + this._updateSelection(this._selectedIndexInFiltered, false); + } + }, + + _onInput: function(event) + { + this._shouldShowMatchingItems = this._delegate.shouldShowMatchingItems(this._promptElement.value); + this._updateShowMatchingItems(); + this._scheduleFilter(); + }, + + _updateShowMatchingItems: function() + { + this._itemElementsContainer.enableStyleClass("hidden", !this._shouldShowMatchingItems); + this.element.style.height = this._shouldShowMatchingItems ? this._dialogHeight + "px" : "auto"; + }, + + _onKeyDown: function(event) + { + var newSelectedIndex = this._selectedIndexInFiltered; + + switch (event.keyCode) { + case WebInspector.KeyboardShortcut.Keys.Down.code: + if (++newSelectedIndex >= this._filteredItems.length) + newSelectedIndex = this._filteredItems.length - 1; + this._updateSelection(newSelectedIndex, true); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.Up.code: + if (--newSelectedIndex < 0) + newSelectedIndex = 0; + this._updateSelection(newSelectedIndex, false); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.PageDown.code: + newSelectedIndex = Math.min(newSelectedIndex + this._viewportControl.rowsPerViewport(), this._filteredItems.length - 1); + this._updateSelection(newSelectedIndex, true); + event.consume(true); + break; + case WebInspector.KeyboardShortcut.Keys.PageUp.code: + newSelectedIndex = Math.max(newSelectedIndex - this._viewportControl.rowsPerViewport(), 0); + this._updateSelection(newSelectedIndex, false); + event.consume(true); + break; + default: + } + }, + + _scheduleFilter: function() + { + if (this._filterTimer) + return; + this._filterTimer = setTimeout(this._filterItems.bind(this), 0); + }, + + /** + * @param {number} index + * @param {boolean} makeLast + */ + _updateSelection: function(index, makeLast) + { + var element = this._viewportControl.renderedElementAt(this._selectedIndexInFiltered); + if (element) + element.removeStyleClass("selected"); + this._viewportControl.scrollItemIntoView(index, makeLast); + this._selectedIndexInFiltered = index; + element = this._viewportControl.renderedElementAt(index); + if (element) + element.addStyleClass("selected"); + }, + + _onClick: function(event) + { + var itemElement = event.target.enclosingNodeOrSelfWithClass("filtered-item-list-dialog-item"); + if (!itemElement) + return; + this._delegate.selectItem(itemElement._index, this._promptElement.value.trim()); + WebInspector.Dialog.hide(); + }, + + /** + * @return {number} + */ + itemCount: function() + { + return this._filteredItems.length; + }, + + /** + * @param {number} index + * @return {Element} + */ + itemElement: function(index) + { + var delegateIndex = this._filteredItems[index]; + var element = this._createItemElement(delegateIndex); + if (index === this._selectedIndexInFiltered) + element.addStyleClass("selected"); + return element; + }, + + __proto__: WebInspector.DialogDelegate.prototype +} + +/** + * @constructor + */ +WebInspector.SelectionDialogContentProvider = function() +{ +} + +WebInspector.SelectionDialogContentProvider.prototype = { + /** + * @param {function():void} refreshCallback + */ + setRefreshCallback: function(refreshCallback) + { + this._refreshCallback = refreshCallback; + }, + + /** + * @param {string} query + * @return {boolean} + */ + shouldShowMatchingItems: function(query) + { + return true; + }, + + /** + * @return {number} + */ + itemCount: function() + { + return 0; + }, + + /** + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + return ""; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + return 1; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @param {Element} titleElement + * @param {Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + }, + + /** + * @param {Element} element + * @param {string} query + * @return {boolean} + */ + highlightRanges: function(element, query) + { + if (!query) + return false; + + /** + * @param {string} text + * @param {string} query + * @return {?Array.<{offset:number, length:number}>} + */ + function rangesForMatch(text, query) + { + var sm = new difflib.SequenceMatcher(query, text); + var opcodes = sm.get_opcodes(); + var ranges = []; + + for (var i = 0; i < opcodes.length; ++i) { + var opcode = opcodes[i]; + if (opcode[0] === "equal") + ranges.push({offset: opcode[3], length: opcode[4] - opcode[3]}); + else if (opcode[0] !== "insert") + return null; + } + return ranges; + } + + var text = element.textContent; + var ranges = rangesForMatch(text, query); + if (!ranges) + ranges = rangesForMatch(text.toUpperCase(), query.toUpperCase()); + if (ranges) { + WebInspector.highlightRangesWithStyleClass(element, ranges, "highlight"); + return true; + } + return false; + }, + + /** + * @param {number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + }, + + refresh: function() + { + this._refreshCallback(); + }, + + /** + * @param {string} query + * @return {string} + */ + rewriteQuery: function(query) + { + return query; + }, + + dispose: function() + { + } +} + +/** + * @constructor + * @extends {WebInspector.SelectionDialogContentProvider} + * @param {WebInspector.View} view + * @param {WebInspector.ContentProvider} contentProvider + */ +WebInspector.JavaScriptOutlineDialog = function(view, contentProvider) +{ + WebInspector.SelectionDialogContentProvider.call(this); + + this._functionItems = []; + this._view = view; + contentProvider.requestContent(this._contentAvailable.bind(this)); +} + +/** + * @param {WebInspector.View} view + * @param {WebInspector.ContentProvider} contentProvider + */ +WebInspector.JavaScriptOutlineDialog.show = function(view, contentProvider) +{ + if (WebInspector.Dialog.currentInstance()) + return null; + var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.JavaScriptOutlineDialog(view, contentProvider)); + WebInspector.Dialog.show(view.element, filteredItemSelectionDialog); +} + +WebInspector.JavaScriptOutlineDialog.prototype = { + /** + * @param {?string} content + * @param {boolean} contentEncoded + * @param {string} mimeType + */ + _contentAvailable: function(content, contentEncoded, mimeType) + { + this._outlineWorker = new Worker("ScriptFormatterWorker.js"); + this._outlineWorker.onmessage = this._didBuildOutlineChunk.bind(this); + const method = "outline"; + this._outlineWorker.postMessage({ method: method, params: { content: content } }); + }, + + _didBuildOutlineChunk: function(event) + { + var data = event.data; + var chunk = data["chunk"]; + for (var i = 0; i < chunk.length; ++i) + this._functionItems.push(chunk[i]); + + if (data.total === data.index) + this.dispose(); + + this.refresh(); + }, + + /** + * @return {number} + */ + itemCount: function() + { + return this._functionItems.length; + }, + + /** + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + return this._functionItems[itemIndex].name; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + var item = this._functionItems[itemIndex]; + return -item.line; + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @param {Element} titleElement + * @param {Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + var item = this._functionItems[itemIndex]; + titleElement.textContent = item.name + (item.arguments ? item.arguments : ""); + this.highlightRanges(titleElement, query); + subtitleElement.textContent = ":" + (item.line + 1); + }, + + /** + * @param {number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + var lineNumber = this._functionItems[itemIndex].line; + if (!isNaN(lineNumber) && lineNumber >= 0) + this._view.highlightPosition(lineNumber, this._functionItems[itemIndex].column); + this._view.focus(); + }, + + dispose: function() + { + if (this._outlineWorker) { + this._outlineWorker.terminate(); + delete this._outlineWorker; + } + }, + + __proto__: WebInspector.SelectionDialogContentProvider.prototype +} + +/** + * @constructor + * @extends {WebInspector.SelectionDialogContentProvider} + * @param {Map.=} defaultScores + */ +WebInspector.SelectUISourceCodeDialog = function(defaultScores) +{ + WebInspector.SelectionDialogContentProvider.call(this); + + /** @type {!Array.} */ + this._uiSourceCodes = []; + var projects = WebInspector.workspace.projects().filter(this.filterProject.bind(this)); + for (var i = 0; i < projects.length; ++i) + this._uiSourceCodes = this._uiSourceCodes.concat(projects[i].uiSourceCodes()); + this._defaultScores = defaultScores; + this._scorer = new WebInspector.FilePathScoreFunction(""); + WebInspector.workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); +} + +WebInspector.SelectUISourceCodeDialog.prototype = { + /** + * @param {WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber) + { + // Overridden by subclasses + }, + + /** + * @param {WebInspector.Project} project + */ + filterProject: function(project) + { + return true; + // Overridden by subclasses + }, + + /** + * @return {number} + */ + itemCount: function() + { + return this._uiSourceCodes.length; + }, + + /** + * @param {number} itemIndex + * @return {string} + */ + itemKeyAt: function(itemIndex) + { + return this._uiSourceCodes[itemIndex].fullDisplayName(); + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @return {number} + */ + itemScoreAt: function(itemIndex, query) + { + var uiSourceCode = this._uiSourceCodes[itemIndex]; + var score = this._defaultScores ? (this._defaultScores.get(uiSourceCode) || 0) : 0; + if (!query || query.length < 2) + return score; + + if (this._query !== query) { + this._query = query; + this._scorer = new WebInspector.FilePathScoreFunction(query); + } + + var path = uiSourceCode.fullDisplayName(); + return score + 10 * this._scorer.score(path, null); + }, + + /** + * @param {number} itemIndex + * @param {string} query + * @param {Element} titleElement + * @param {Element} subtitleElement + */ + renderItem: function(itemIndex, query, titleElement, subtitleElement) + { + query = this.rewriteQuery(query); + var uiSourceCode = this._uiSourceCodes[itemIndex]; + titleElement.textContent = uiSourceCode.displayName() + (this._queryLineNumber ? this._queryLineNumber : ""); + subtitleElement.textContent = uiSourceCode.fullDisplayName().trimEnd(100); + + var indexes = []; + var score = new WebInspector.FilePathScoreFunction(query).score(subtitleElement.textContent, indexes); + var fileNameIndex = subtitleElement.textContent.lastIndexOf("/"); + var ranges = []; + for (var i = 0; i < indexes.length; ++i) + ranges.push({offset: indexes[i], length: 1}); + if (indexes[0] > fileNameIndex) { + for (var i = 0; i < ranges.length; ++i) + ranges[i].offset -= fileNameIndex + 1; + return WebInspector.highlightRangesWithStyleClass(titleElement, ranges, "highlight"); + } else { + return WebInspector.highlightRangesWithStyleClass(subtitleElement, ranges, "highlight"); + } + }, + + /** + * @param {number} itemIndex + * @param {string} promptValue + */ + selectItem: function(itemIndex, promptValue) + { + if (/^:\d+$/.test(promptValue.trimRight())) { + var lineNumber = parseInt(promptValue.trimRight().substring(1), 10) - 1; + if (!isNaN(lineNumber) && lineNumber >= 0) + this.uiSourceCodeSelected(null, lineNumber); + return; + } + var lineNumberMatch = promptValue.match(/[^:]+\:([\d]*)$/); + var lineNumber = lineNumberMatch ? Math.max(parseInt(lineNumberMatch[1], 10) - 1, 0) : undefined; + this.uiSourceCodeSelected(this._uiSourceCodes[itemIndex], lineNumber); + }, + + /** + * @param {string} query + * @return {string} + */ + rewriteQuery: function(query) + { + if (!query) + return query; + query = query.trim(); + var lineNumberMatch = query.match(/([^:]+)(\:[\d]*)$/); + this._queryLineNumber = lineNumberMatch ? lineNumberMatch[2] : ""; + return lineNumberMatch ? lineNumberMatch[1] : query; + }, + + /** + * @param {WebInspector.Event} event + */ + _uiSourceCodeAdded: function(event) + { + var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (event.data); + if (!this.filterProject(uiSourceCode.project())) + return; + this._uiSourceCodes.push(uiSourceCode) + this.refresh(); + }, + + dispose: function() + { + WebInspector.workspace.removeEventListener(WebInspector.Workspace.Events.UISourceCodeAdded, this._uiSourceCodeAdded, this); + }, + + __proto__: WebInspector.SelectionDialogContentProvider.prototype +} + +/** + * @constructor + * @extends {WebInspector.SelectUISourceCodeDialog} + * @param {WebInspector.ScriptsPanel} panel + * @param {Map.=} defaultScores + */ +WebInspector.OpenResourceDialog = function(panel, defaultScores) +{ + WebInspector.SelectUISourceCodeDialog.call(this, defaultScores); + this._panel = panel; +} + +WebInspector.OpenResourceDialog.prototype = { + + /** + * @param {?WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber) + { + if (!uiSourceCode) + uiSourceCode = this._panel.currentUISourceCode(); + if (!uiSourceCode) + return; + this._panel.showUISourceCode(uiSourceCode, lineNumber); + }, + + /** + * @param {string} query + * @return {boolean} + */ + shouldShowMatchingItems: function(query) + { + return !query.startsWith(":"); + }, + + /** + * @param {WebInspector.Project} project + */ + filterProject: function(project) + { + return !project.isServiceProject(); + }, + + __proto__: WebInspector.SelectUISourceCodeDialog.prototype +} + +/** + * @param {WebInspector.ScriptsPanel} panel + * @param {Element} relativeToElement + * @param {string=} name + * @param {Map.=} defaultScores + */ +WebInspector.OpenResourceDialog.show = function(panel, relativeToElement, name, defaultScores) +{ + if (WebInspector.Dialog.currentInstance()) + return; + + var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.OpenResourceDialog(panel, defaultScores)); + filteredItemSelectionDialog.renderAsTwoRows(); + if (name) + filteredItemSelectionDialog.setQuery(name); + WebInspector.Dialog.show(relativeToElement, filteredItemSelectionDialog); +} + +/** + * @constructor + * @extends {WebInspector.SelectUISourceCodeDialog} + * @param {string} type + * @param {function(WebInspector.UISourceCode)} callback + */ +WebInspector.SelectUISourceCodeForProjectTypeDialog = function(type, callback) +{ + this._type = type; + WebInspector.SelectUISourceCodeDialog.call(this); + this._callback = callback; +} + +WebInspector.SelectUISourceCodeForProjectTypeDialog.prototype = { + /** + * @param {WebInspector.UISourceCode} uiSourceCode + * @param {number=} lineNumber + */ + uiSourceCodeSelected: function(uiSourceCode, lineNumber) + { + this._callback(uiSourceCode); + }, + + /** + * @param {WebInspector.Project} project + */ + filterProject: function(project) + { + return project.type() === this._type; + }, + + __proto__: WebInspector.SelectUISourceCodeDialog.prototype +} + +/** + * @param {string} type + * @param {function(WebInspector.UISourceCode)} callback + * @param {Element} relativeToElement + */ +WebInspector.SelectUISourceCodeForProjectTypeDialog.show = function(name, type, callback, relativeToElement) +{ + if (WebInspector.Dialog.currentInstance()) + return; + + var filteredItemSelectionDialog = new WebInspector.FilteredItemSelectionDialog(new WebInspector.SelectUISourceCodeForProjectTypeDialog(type, callback)); + filteredItemSelectionDialog.setQuery(name); + filteredItemSelectionDialog.renderAsTwoRows(); + WebInspector.Dialog.show(relativeToElement, filteredItemSelectionDialog); +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FlameChart.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FlameChart.js new file mode 100644 index 00000000..f6146031 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FlameChart.js @@ -0,0 +1,815 @@ +/* + * Copyright (C) 2013 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.View} + * @param {WebInspector.CPUProfileView} cpuProfileView + */ +WebInspector.FlameChart = function(cpuProfileView) +{ + WebInspector.View.call(this); + this.registerRequiredCSS("flameChart.css"); + this.element.className = "fill"; + this.element.id = "cpu-flame-chart"; + + this._overviewContainer = this.element.createChild("div", "overview-container"); + this._overviewGrid = new WebInspector.OverviewGrid("flame-chart"); + this._overviewCanvas = this._overviewContainer.createChild("canvas", "flame-chart-overview-canvas"); + this._overviewContainer.appendChild(this._overviewGrid.element); + this._overviewCalculator = new WebInspector.FlameChart.OverviewCalculator(); + this._overviewGrid.addEventListener(WebInspector.OverviewGrid.Events.WindowChanged, this._onWindowChanged, this); + + this._chartContainer = this.element.createChild("div", "chart-container"); + this._timelineGrid = new WebInspector.TimelineGrid(); + this._chartContainer.appendChild(this._timelineGrid.element); + this._calculator = new WebInspector.FlameChart.Calculator(); + + this._canvas = this._chartContainer.createChild("canvas"); + this._canvas.addEventListener("mousemove", this._onMouseMove.bind(this)); + WebInspector.installDragHandle(this._canvas, this._startCanvasDragging.bind(this), this._canvasDragging.bind(this), this._endCanvasDragging.bind(this), "col-resize"); + + this._cpuProfileView = cpuProfileView; + this._windowLeft = 0.0; + this._windowRight = 1.0; + this._barHeight = 15; + this._minWidth = 2; + this._paddingLeft = 15; + this._canvas.addEventListener("mousewheel", this._onMouseWheel.bind(this), false); + this._canvas.addEventListener("click", this._onClick.bind(this), false); + this._linkifier = new WebInspector.Linkifier(); + this._highlightedEntryIndex = -1; + + if (!WebInspector.FlameChart._colorGenerator) + WebInspector.FlameChart._colorGenerator = new WebInspector.FlameChart.ColorGenerator(); +} + +/** + * @constructor + * @implements {WebInspector.TimelineGrid.Calculator} + */ +WebInspector.FlameChart.Calculator = function() +{ +} + +WebInspector.FlameChart.Calculator.prototype = { + /** + * @param {WebInspector.FlameChart} flameChart + */ + _updateBoundaries: function(flameChart) + { + this._minimumBoundaries = flameChart._windowLeft * flameChart._timelineData.totalTime; + this._maximumBoundaries = flameChart._windowRight * flameChart._timelineData.totalTime; + this.paddingLeft = flameChart._paddingLeft; + this._width = flameChart._canvas.width - this.paddingLeft; + this._timeToPixel = this._width / this.boundarySpan(); + }, + + /** + * @param {number} time + */ + computePosition: function(time) + { + return (time - this._minimumBoundaries) * this._timeToPixel + this.paddingLeft; + }, + + formatTime: function(value) + { + return WebInspector.UIString("%s\u2009ms", Number.withThousandsSeparator(Math.round(value + this._minimumBoundaries))); + }, + + maximumBoundary: function() + { + return this._maximumBoundaries; + }, + + minimumBoundary: function() + { + return this._minimumBoundaries; + }, + + zeroTime: function() + { + return 0; + }, + + boundarySpan: function() + { + return this._maximumBoundaries - this._minimumBoundaries; + } +} + +/** + * @constructor + * @implements {WebInspector.TimelineGrid.Calculator} + */ +WebInspector.FlameChart.OverviewCalculator = function() +{ +} + +WebInspector.FlameChart.OverviewCalculator.prototype = { + /** + * @param {WebInspector.FlameChart} flameChart + */ + _updateBoundaries: function(flameChart) + { + this._minimumBoundaries = 0; + this._maximumBoundaries = flameChart._timelineData.totalTime; + this._xScaleFactor = flameChart._canvas.width / flameChart._timelineData.totalTime; + }, + + /** + * @param {number} time + */ + computePosition: function(time) + { + return (time - this._minimumBoundaries) * this._xScaleFactor; + }, + + formatTime: function(value) + { + return Number.secondsToString((value + this._minimumBoundaries) / 1000); + }, + + maximumBoundary: function() + { + return this._maximumBoundaries; + }, + + minimumBoundary: function() + { + return this._minimumBoundaries; + }, + + zeroTime: function() + { + return this._minimumBoundaries; + }, + + boundarySpan: function() + { + return this._maximumBoundaries - this._minimumBoundaries; + } +} + +WebInspector.FlameChart.Events = { + SelectedNode: "SelectedNode" +} + +/** + * @constructor + */ +WebInspector.FlameChart.ColorGenerator = function() +{ + this._colorPairs = {}; + this._currentColorIndex = 0; + this._colorPairs["(idle)::0"] = this._createPair(0, 50); + this._colorPairs["(program)::0"] = this._createPair(5, 50); + this._colorPairs["(garbage collector)::0"] = this._createPair(10, 50); +} + +WebInspector.FlameChart.ColorGenerator.prototype = { + /** + * @param {!string} id + */ + _colorPairForID: function(id) + { + var colorPairs = this._colorPairs; + var colorPair = colorPairs[id]; + if (!colorPair) + colorPairs[id] = colorPair = this._createPair(++this._currentColorIndex); + return colorPair; + }, + + /** + * @param {!number} index + * @param {number=} sat + */ + _createPair: function(index, sat) + { + var hue = (index * 7 + 12 * (index % 2)) % 360; + if (typeof sat !== "number") + sat = 100; + return {highlighted: "hsla(" + hue + ", " + sat + "%, 33%, 0.7)", normal: "hsla(" + hue + ", " + sat + "%, 66%, 0.7)"} + } +} + +/** + * @constructor + * @param {!Object} colorPair + * @param {!number} depth + * @param {!number} duration + * @param {!number} startTime + * @param {Object} node + */ +WebInspector.FlameChart.Entry = function(colorPair, depth, duration, startTime, node) +{ + this.colorPair = colorPair; + this.depth = depth; + this.duration = duration; + this.startTime = startTime; + this.node = node; + this.selfTime = 0; +} + +WebInspector.FlameChart.prototype = { + /** + * @param {!number} timeLeft + * @param {!number} timeRight + */ + selectRange: function(timeLeft, timeRight) + { + this._overviewGrid.setWindow(timeLeft / this._totalTime, timeRight / this._totalTime); + }, + + _onWindowChanged: function(event) + { + this._scheduleUpdate(); + }, + + _startCanvasDragging: function(event) + { + if (!this._timelineData) + return false; + this._isDragging = true; + this._wasDragged = false; + this._dragStartPoint = event.pageX; + this._dragStartWindowLeft = this._windowLeft; + this._dragStartWindowRight = this._windowRight; + + return true; + }, + + _canvasDragging: function(event) + { + var pixelShift = this._dragStartPoint - event.pageX; + var windowShift = pixelShift / this._totalPixels; + + var windowLeft = Math.max(0, this._dragStartWindowLeft + windowShift); + if (windowLeft === this._windowLeft) + return; + windowShift = windowLeft - this._dragStartWindowLeft; + + var windowRight = Math.min(1, this._dragStartWindowRight + windowShift); + if (windowRight === this._windowRight) + return; + windowShift = windowRight - this._dragStartWindowRight; + this._overviewGrid.setWindow(this._dragStartWindowLeft + windowShift, this._dragStartWindowRight + windowShift); + this._wasDragged = true; + }, + + _endCanvasDragging: function() + { + this._isDragging = false; + }, + + _calculateTimelineData: function() + { + if (this._cpuProfileView.samples) + return this._calculateTimelineDataForSamples(); + + if (this._timelineData) + return this._timelineData; + + if (!this._cpuProfileView.profileHead) + return null; + + var index = 0; + var entries = []; + + function appendReversedArray(toArray, fromArray) + { + for (var i = fromArray.length - 1; i >= 0; --i) + toArray.push(fromArray[i]); + } + + var stack = []; + appendReversedArray(stack, this._cpuProfileView.profileHead.children); + + var levelOffsets = /** @type {Array.} */ ([0]); + var levelExitIndexes = /** @type {Array.} */ ([0]); + var colorGenerator = WebInspector.FlameChart._colorGenerator; + + while (stack.length) { + var level = levelOffsets.length - 1; + var node = stack.pop(); + var offset = levelOffsets[level]; + + var colorPair = colorGenerator._colorPairForID(node.functionName + ":" + node.url + ":" + node.lineNumber); + + entries.push(new WebInspector.FlameChart.Entry(colorPair, level, node.totalTime, offset, node)); + + ++index; + + levelOffsets[level] += node.totalTime; + if (node.children.length) { + levelExitIndexes.push(stack.length); + levelOffsets.push(offset + node.selfTime / 2); + appendReversedArray(stack, node.children); + } + + while (stack.length === levelExitIndexes[levelExitIndexes.length - 1]) { + levelOffsets.pop(); + levelExitIndexes.pop(); + } + } + + this._timelineData = { + entries: entries, + totalTime: this._cpuProfileView.profileHead.totalTime, + } + + return this._timelineData; + }, + + _calculateTimelineDataForSamples: function() + { + if (this._timelineData) + return this._timelineData; + + if (!this._cpuProfileView.profileHead) + return null; + + var samples = this._cpuProfileView.samples; + var idToNode = this._cpuProfileView._idToNode; + var gcNode = this._cpuProfileView._gcNode; + var samplesCount = samples.length; + + var index = 0; + var entries = /** @type {Array.} */ ([]); + + var openIntervals = []; + var stackTrace = []; + var colorGenerator = WebInspector.FlameChart._colorGenerator; + for (var sampleIndex = 0; sampleIndex < samplesCount; sampleIndex++) { + var node = idToNode[samples[sampleIndex]]; + stackTrace.length = 0; + while (node) { + stackTrace.push(node); + node = node.parent; + } + stackTrace.pop(); // Remove (root) node + + var depth = 0; + node = stackTrace.pop(); + var intervalIndex; + + // GC samples have no stack, so we just put GC node on top of the last recoreded sample. + if (node === gcNode) { + while (depth < openIntervals.length) { + intervalIndex = openIntervals[depth].index; + entries[intervalIndex].duration += 1; + ++depth; + } + // If previous stack is also GC then just continue. + if (openIntervals.length > 0 && openIntervals.peekLast().node === node) { + entries[intervalIndex].selfTime += 1; + continue; + } + } + + while (node && depth < openIntervals.length && node === openIntervals[depth].node) { + intervalIndex = openIntervals[depth].index; + entries[intervalIndex].duration += 1; + node = stackTrace.pop(); + ++depth; + } + if (depth < openIntervals.length) + openIntervals.length = depth; + if (!node) { + entries[intervalIndex].selfTime += 1; + continue; + } + + while (node) { + var colorPair = colorGenerator._colorPairForID(node.functionName + ":" + node.url + ":" + node.lineNumber); + + entries.push(new WebInspector.FlameChart.Entry(colorPair, depth, 1, sampleIndex, node)); + openIntervals.push({node: node, index: index}); + ++index; + + node = stackTrace.pop(); + ++depth; + } + entries[entries.length - 1].selfTime += 1; + } + + this._timelineData = { + entries: entries, + totalTime: samplesCount, + }; + + return this._timelineData; + }, + + _onMouseMove: function(event) + { + if (this._isDragging) + return; + + var entryIndex = this._coordinatesToEntryIndex(event.offsetX, event.offsetY); + + if (this._highlightedEntryIndex === entryIndex) + return; + + if (entryIndex === -1 || this._timelineData.entries[entryIndex].node.scriptId === "0") + this._canvas.style.cursor = "default"; + else + this._canvas.style.cursor = "pointer"; + + this._highlightedEntryIndex = entryIndex; + this._scheduleUpdate(); + }, + + _millisecondsToString: function(ms) + { + if (ms === 0) + return "0"; + if (ms < 1000) + return WebInspector.UIString("%.1f\u2009ms", ms); + return Number.secondsToString(ms / 1000, true); + }, + + _prepareHighlightedEntryInfo: function() + { + if (this._isDragging) + return null; + var entry = this._timelineData.entries[this._highlightedEntryIndex]; + if (!entry) + return null; + var node = entry.node; + if (!node) + return null; + + var entryInfo = []; + function pushEntryInfoRow(title, text) + { + var row = {}; + row.title = title; + row.text = text; + entryInfo.push(row); + } + + pushEntryInfoRow(WebInspector.UIString("Name"), node.functionName); + if (this._cpuProfileView.samples) { + var rate = this._cpuProfileView.samplesPerMs; + var selfTime = this._millisecondsToString(entry.selfTime / rate); + var totalTime = this._millisecondsToString(entry.duration / rate); + pushEntryInfoRow(WebInspector.UIString("Self time"), selfTime); + pushEntryInfoRow(WebInspector.UIString("Total time"), totalTime); + } + if (node.url) + pushEntryInfoRow(WebInspector.UIString("URL"), node.url + ":" + node.lineNumber); + pushEntryInfoRow(WebInspector.UIString("Aggregated self time"), Number.secondsToString(node.selfTime / 1000, true)); + pushEntryInfoRow(WebInspector.UIString("Aggregated total time"), Number.secondsToString(node.totalTime / 1000, true)); + return entryInfo; + }, + + _onClick: function(e) + { + // onClick comes after dragStart and dragEnd events. + // So if there was drag (mouse move) in the middle of that events + // we skip the click. Otherwise we jump to the sources. + if (this._wasDragged) + return; + if (this._highlightedEntryIndex === -1) + return; + var node = this._timelineData.entries[this._highlightedEntryIndex].node; + this.dispatchEventToListeners(WebInspector.FlameChart.Events.SelectedNode, node); + }, + + _onMouseWheel: function(e) + { + if (e.wheelDeltaY) { + const zoomFactor = 1.1; + const mouseWheelZoomSpeed = 1 / 120; + + var zoom = Math.pow(zoomFactor, -e.wheelDeltaY * mouseWheelZoomSpeed); + var overviewReference = (this._pixelWindowLeft + e.offsetX - this._paddingLeft) / this._totalPixels; + this._overviewGrid.zoom(zoom, overviewReference); + } else { + var shift = Number.constrain(-1 * this._windowWidth / 4 * e.wheelDeltaX / 120, -this._windowLeft, 1 - this._windowRight); + this._overviewGrid.setWindow(this._windowLeft + shift, this._windowRight + shift); + } + }, + + /** + * @param {!number} x + * @param {!number} y + */ + _coordinatesToEntryIndex: function(x, y) + { + var timelineData = this._timelineData; + if (!timelineData) + return -1; + var timelineEntries = timelineData.entries; + var cursorTime = (x + this._pixelWindowLeft - this._paddingLeft) * this._pixelToTime; + var cursorLevel = Math.floor((this._canvas.height / window.devicePixelRatio - y) / this._barHeight); + + for (var i = 0; i < timelineEntries.length; ++i) { + if (cursorTime < timelineEntries[i].startTime) + return -1; + if (cursorTime < (timelineEntries[i].startTime + timelineEntries[i].duration) + && cursorLevel === timelineEntries[i].depth) + return i; + } + return -1; + }, + + onResize: function() + { + this._updateOverviewCanvas = true; + this._scheduleUpdate(); + }, + + _drawOverviewCanvas: function(width, height) + { + if (!this._timelineData) + return; + + var timelineEntries = this._timelineData.entries; + + var drawData = new Uint8Array(width); + var scaleFactor = width / this._totalTime; + var maxStackDepth = 5; // minimum stack depth for the case when we see no activity. + + for (var entryIndex = 0; entryIndex < timelineEntries.length; ++entryIndex) { + var entry = timelineEntries[entryIndex]; + var start = Math.floor(entry.startTime * scaleFactor); + var finish = Math.floor((entry.startTime + entry.duration) * scaleFactor); + for (var x = start; x < finish; ++x) { + drawData[x] = Math.max(drawData[x], entry.depth + 1); + maxStackDepth = Math.max(maxStackDepth, entry.depth + 1); + } + } + + var ratio = window.devicePixelRatio; + var canvasWidth = width * ratio; + var canvasHeight = height * ratio; + this._overviewCanvas.width = canvasWidth; + this._overviewCanvas.height = canvasHeight; + this._overviewCanvas.style.width = width + "px"; + this._overviewCanvas.style.height = height + "px"; + + var context = this._overviewCanvas.getContext("2d"); + + var yScaleFactor = canvasHeight / (maxStackDepth * 1.1); + context.lineWidth = 1; + context.translate(0.5, 0.5); + context.strokeStyle = "rgba(20,0,0,0.4)"; + context.fillStyle = "rgba(214,225,254,0.8)"; + context.moveTo(-1, canvasHeight - 1); + if (drawData) + context.lineTo(-1, Math.round(height - drawData[0] * yScaleFactor - 1)); + var value; + for (var x = 0; x < width; ++x) { + value = Math.round(canvasHeight - drawData[x] * yScaleFactor - 1); + context.lineTo(x * ratio, value); + } + context.lineTo(canvasWidth + 1, value); + context.lineTo(canvasWidth + 1, canvasHeight - 1); + context.fill(); + context.stroke(); + context.closePath(); + }, + + /** + * @param {WebInspector.FlameChart.Entry} entry + * @param {AnchorBox} anchorBox + */ + _entryToAnchorBox: function(entry, anchorBox) + { + anchorBox.x = Math.floor(entry.startTime * this._timeToPixel) - this._pixelWindowLeft + this._paddingLeft; + anchorBox.y = this._canvas.height / window.devicePixelRatio - (entry.depth + 1) * this._barHeight; + anchorBox.width = Math.max(Math.ceil(entry.duration * this._timeToPixel), this._minWidth); + anchorBox.height = this._barHeight; + if (anchorBox.x < 0) { + anchorBox.width += anchorBox.x; + anchorBox.x = 0; + } + anchorBox.width = Number.constrain(anchorBox.width, 0, this._canvas.width - anchorBox.x); + }, + + /** + * @param {!number} height + * @param {!number} width + */ + draw: function(width, height) + { + var timelineData = this._calculateTimelineData(); + if (!timelineData) + return; + var timelineEntries = timelineData.entries; + + var ratio = window.devicePixelRatio; + var canvasWidth = width * ratio; + var canvasHeight = height * ratio; + this._canvas.width = canvasWidth; + this._canvas.height = canvasHeight; + this._canvas.style.width = width + "px"; + this._canvas.style.height = height + "px"; + + var barHeight = this._barHeight; + + var context = this._canvas.getContext("2d"); + context.scale(ratio, ratio); + var visibleTimeLeft = this._timeWindowLeft - this._paddingLeftTime; + var timeWindowRight = this._timeWindowRight; + + function forEachEntry(flameChart, callback) + { + var anchorBox = new AnchorBox(); + for (var i = 0; i < timelineEntries.length; ++i) { + var entry = timelineEntries[i]; + var startTime = entry.startTime; + if (startTime > timeWindowRight) + break; + if ((startTime + entry.duration) < visibleTimeLeft) + continue; + flameChart._entryToAnchorBox(entry, anchorBox); + + callback(flameChart, context, entry, anchorBox, flameChart._highlightedEntryIndex === i); + } + } + + function drawBar(flameChart, context, entry, anchorBox, highlighted) + { + context.beginPath(); + context.rect(anchorBox.x, anchorBox.y, anchorBox.width - 1, anchorBox.height - 1); + var colorPair = entry.colorPair; + context.fillStyle = highlighted ? colorPair.highlighted : colorPair.normal; + context.fill(); + } + + forEachEntry(this, drawBar); + + context.font = (barHeight - 4) + "px " + window.getComputedStyle(this.element, null).getPropertyValue("font-family"); + context.textBaseline = "alphabetic"; + context.fillStyle = "#333"; + this._dotsWidth = context.measureText("\u2026").width; + var textPaddingLeft = 2; + + function drawText(flameChart, context, entry, anchorBox, highlighted) + { + var xText = Math.max(0, anchorBox.x); + var widthText = anchorBox.width - textPaddingLeft + anchorBox.x - xText; + var title = flameChart._prepareText(context, entry.node.functionName, widthText); + if (title) + context.fillText(title, xText + textPaddingLeft, anchorBox.y + barHeight - 4); + } + + forEachEntry(this, drawText); + + var entryInfo = this._prepareHighlightedEntryInfo(); + if (entryInfo) + this._printEntryInfo(context, entryInfo, 0, 25, width); + }, + + _printEntryInfo: function(context, entryInfo, x, y, width) + { + const lineHeight = 18; + const paddingLeft = 10; + const paddingTop = 5; + var maxTitleWidth = 0; + var basicFont = "100% " + window.getComputedStyle(this.element, null).getPropertyValue("font-family"); + context.font = "bold " + basicFont; + context.textBaseline = "top"; + for (var i = 0; i < entryInfo.length; ++i) + maxTitleWidth = Math.max(maxTitleWidth, context.measureText(entryInfo[i].title).width); + + var maxTextWidth = 0; + for (var i = 0; i < entryInfo.length; ++i) + maxTextWidth = Math.max(maxTextWidth, context.measureText(entryInfo[i].text).width); + maxTextWidth = Math.min(maxTextWidth, width - 2 * paddingLeft - maxTitleWidth); + + context.beginPath(); + context.rect(x, y, maxTitleWidth + maxTextWidth + 5, lineHeight * entryInfo.length + 5); + context.strokeStyle = "rgba(0,0,0,0)"; + context.fillStyle = "rgba(254,254,254,0.8)"; + context.fill(); + context.stroke(); + + context.fillStyle = "#333"; + for (var i = 0; i < entryInfo.length; ++i) + context.fillText(entryInfo[i].title, x + paddingLeft, y + lineHeight * i); + + context.font = basicFont; + for (var i = 0; i < entryInfo.length; ++i) { + var text = this._prepareText(context, entryInfo[i].text, maxTextWidth); + context.fillText(text, x + paddingLeft + maxTitleWidth + paddingLeft, y + lineHeight * i); + } + }, + + _prepareText: function(context, title, maxSize) + { + if (maxSize < this._dotsWidth) + return null; + var titleWidth = context.measureText(title).width; + if (maxSize > titleWidth) + return title; + maxSize -= this._dotsWidth; + var dotRegExp=/[\.\$]/g; + var match = dotRegExp.exec(title); + if (!match) { + var visiblePartSize = maxSize / titleWidth; + var newTextLength = Math.floor(title.length * visiblePartSize) + 1; + var minTextLength = 4; + if (newTextLength < minTextLength) + return null; + var substring; + do { + --newTextLength; + substring = title.substring(0, newTextLength); + } while (context.measureText(substring).width > maxSize); + return title.substring(0, newTextLength) + "\u2026"; + } + while (match) { + var substring = title.substring(match.index + 1); + var width = context.measureText(substring).width; + if (maxSize > width) + return "\u2026" + substring; + match = dotRegExp.exec(title); + } + var i = 0; + do { + ++i; + } while (context.measureText(title.substring(0, i)).width < maxSize); + return title.substring(0, i - 1) + "\u2026"; + }, + + _scheduleUpdate: function() + { + if (this._updateTimerId) + return; + this._updateTimerId = setTimeout(this.update.bind(this), 10); + }, + + _updateBoundaries: function() + { + this._windowLeft = this._overviewGrid.windowLeft(); + this._windowRight = this._overviewGrid.windowRight(); + this._windowWidth = this._windowRight - this._windowLeft; + + this._totalTime = this._timelineData.totalTime; + this._timeWindowLeft = this._windowLeft * this._totalTime; + this._timeWindowRight = this._windowRight * this._totalTime; + + this._pixelWindowWidth = this._chartContainer.clientWidth; + this._totalPixels = Math.floor(this._pixelWindowWidth / this._windowWidth); + this._pixelWindowLeft = Math.floor(this._totalPixels * this._windowLeft); + this._pixelWindowRight = Math.floor(this._totalPixels * this._windowRight); + + this._timeToPixel = this._totalPixels / this._totalTime; + this._pixelToTime = this._totalTime / this._totalPixels; + this._paddingLeftTime = this._paddingLeft / this._timeToPixel; + }, + + update: function() + { + this._updateTimerId = 0; + if (!this._timelineData) + this._calculateTimelineData(); + if (!this._timelineData) + return; + this._updateBoundaries(); + this.draw(this._chartContainer.clientWidth, this._chartContainer.clientHeight); + this._calculator._updateBoundaries(this); + this._overviewCalculator._updateBoundaries(this); + this._timelineGrid.element.style.width = this.element.clientWidth; + this._timelineGrid.updateDividers(this._calculator); + this._overviewGrid.updateDividers(this._overviewCalculator); + if (this._updateOverviewCanvas) { + this._drawOverviewCanvas(this._overviewContainer.clientWidth, this._overviewContainer.clientHeight - 20); + this._updateOverviewCanvas = false; + } + }, + + __proto__: WebInspector.View.prototype +}; diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FontView.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FontView.js new file mode 100644 index 00000000..64dbd5b6 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/FontView.js @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @extends {WebInspector.ResourceView} + * @constructor + */ +WebInspector.FontView = function(resource) +{ + WebInspector.ResourceView.call(this, resource); + + this.element.addStyleClass("font"); +} + +WebInspector.FontView._fontPreviewLines = [ "ABCDEFGHIJKLM", "NOPQRSTUVWXYZ", "abcdefghijklm", "nopqrstuvwxyz", "1234567890" ]; + +WebInspector.FontView._fontId = 0; + +WebInspector.FontView._measureFontSize = 50; + +WebInspector.FontView.prototype = { + hasContent: function() + { + return true; + }, + + _createContentIfNeeded: function() + { + if (this.fontPreviewElement) + return; + + var uniqueFontName = "WebInspectorFontPreview" + (++WebInspector.FontView._fontId); + + this.fontStyleElement = document.createElement("style"); + this.fontStyleElement.textContent = "@font-face { font-family: \"" + uniqueFontName + "\"; src: url(" + this.resource.url + "); }"; + document.head.appendChild(this.fontStyleElement); + + var fontPreview = document.createElement("div"); + for (var i = 0; i < WebInspector.FontView._fontPreviewLines.length; ++i) { + if (i > 0) + fontPreview.appendChild(document.createElement("br")); + fontPreview.appendChild(document.createTextNode(WebInspector.FontView._fontPreviewLines[i])); + } + this.fontPreviewElement = fontPreview.cloneNode(true); + this.fontPreviewElement.style.setProperty("font-family", uniqueFontName); + this.fontPreviewElement.style.setProperty("visibility", "hidden"); + + this._dummyElement = fontPreview; + this._dummyElement.style.visibility = "hidden"; + this._dummyElement.style.zIndex = "-1"; + this._dummyElement.style.display = "inline"; + this._dummyElement.style.position = "absolute"; + this._dummyElement.style.setProperty("font-family", uniqueFontName); + this._dummyElement.style.setProperty("font-size", WebInspector.FontView._measureFontSize + "px"); + + this.element.appendChild(this.fontPreviewElement); + }, + + wasShown: function() + { + this._createContentIfNeeded(); + + this.updateFontPreviewSize(); + }, + + onResize: function() + { + if (this._inResize) + return; + + this._inResize = true; + try { + this.updateFontPreviewSize(); + } finally { + delete this._inResize; + } + }, + + _measureElement: function() + { + this.element.appendChild(this._dummyElement); + var result = { width: this._dummyElement.offsetWidth, height: this._dummyElement.offsetHeight }; + this.element.removeChild(this._dummyElement); + + return result; + }, + + updateFontPreviewSize: function() + { + if (!this.fontPreviewElement || !this.isShowing()) + return; + + this.fontPreviewElement.style.removeProperty("visibility"); + var dimension = this._measureElement(); + + const height = dimension.height; + const width = dimension.width; + + // Subtract some padding. This should match the paddings in the CSS plus room for the scrollbar. + const containerWidth = this.element.offsetWidth - 50; + const containerHeight = this.element.offsetHeight - 30; + + if (!height || !width || !containerWidth || !containerHeight) { + this.fontPreviewElement.style.removeProperty("font-size"); + return; + } + + var widthRatio = containerWidth / width; + var heightRatio = containerHeight / height; + var finalFontSize = Math.floor(WebInspector.FontView._measureFontSize * Math.min(widthRatio, heightRatio)) - 2; + + this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null); + }, + + __proto__: WebInspector.ResourceView.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/GoToLineDialog.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/GoToLineDialog.js new file mode 100644 index 00000000..f25fe4c6 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/GoToLineDialog.js @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.DialogDelegate} + */ +WebInspector.GoToLineDialog = function(view) +{ + WebInspector.DialogDelegate.call(this); + + this.element = document.createElement("div"); + this.element.className = "go-to-line-dialog"; + + this.element.createChild("label").textContent = WebInspector.UIString("Go to line: "); + + this._input = this.element.createChild("input"); + this._input.setAttribute("type", "text"); + this._input.setAttribute("size", 6); + + this._goButton = this.element.createChild("button"); + this._goButton.textContent = WebInspector.UIString("Go"); + this._goButton.addEventListener("click", this._onGoClick.bind(this), false); + + this._view = view; +} + +/** + * @param {WebInspector.Panel} panel + * @param {function():?WebInspector.View} viewGetter + */ +WebInspector.GoToLineDialog.install = function(panel, viewGetter) +{ + var goToLineShortcut = WebInspector.GoToLineDialog.createShortcut(); + panel.registerShortcuts([goToLineShortcut], WebInspector.GoToLineDialog._show.bind(null, viewGetter)); +} + +/** + * @param {function():?WebInspector.View} viewGetter + * @param {Event=} event + * @return {boolean} + */ +WebInspector.GoToLineDialog._show = function(viewGetter, event) +{ + var sourceView = viewGetter(); + if (!sourceView || !sourceView.canHighlightPosition()) + return false; + WebInspector.Dialog.show(sourceView.element, new WebInspector.GoToLineDialog(sourceView)); + return true; +} + +/** + * @return {!WebInspector.KeyboardShortcut.Descriptor} + */ +WebInspector.GoToLineDialog.createShortcut = function() +{ + var isMac = WebInspector.isMac(); + var shortcut; + return WebInspector.KeyboardShortcut.makeDescriptor("g", WebInspector.KeyboardShortcut.Modifiers.Ctrl); +} + +WebInspector.GoToLineDialog.prototype = { + focus: function() + { + WebInspector.setCurrentFocusElement(this._input); + this._input.select(); + }, + + _onGoClick: function() + { + this._applyLineNumber(); + WebInspector.Dialog.hide(); + }, + + _applyLineNumber: function() + { + var value = this._input.value; + var lineNumber = parseInt(value, 10) - 1; + if (!isNaN(lineNumber) && lineNumber >= 0) + this._view.highlightPosition(lineNumber); + }, + + onEnter: function() + { + this._applyLineNumber(); + }, + + __proto__: WebInspector.DialogDelegate.prototype +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HAREntry.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HAREntry.js new file mode 100644 index 00000000..51f996e5 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HAREntry.js @@ -0,0 +1,430 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// See http://www.softwareishard.com/blog/har-12-spec/ +// for HAR specification. + +// FIXME: Some fields are not yet supported due to back-end limitations. +// See https://bugs.webkit.org/show_bug.cgi?id=58127 for details. + +/** + * @constructor + * @param {WebInspector.NetworkRequest} request + */ +WebInspector.HAREntry = function(request) +{ + this._request = request; +} + +WebInspector.HAREntry.prototype = { + /** + * @return {Object} + */ + build: function() + { + var entry = { + startedDateTime: new Date(this._request.startTime * 1000), + time: WebInspector.HAREntry._toMilliseconds(this._request.duration), + request: this._buildRequest(), + response: this._buildResponse(), + cache: { }, // Not supported yet. + timings: this._buildTimings() + }; + if (this._request.connectionId) + entry.connection = String(this._request.connectionId); + var page = WebInspector.networkLog.pageLoadForRequest(this._request); + if (page) + entry.pageref = "page_" + page.id; + return entry; + }, + + /** + * @return {Object} + */ + _buildRequest: function() + { + var res = { + method: this._request.requestMethod, + url: this._buildRequestURL(this._request.url), + httpVersion: this._request.requestHttpVersion, + headers: this._request.requestHeaders, + queryString: this._buildParameters(this._request.queryParameters || []), + cookies: this._buildCookies(this._request.requestCookies || []), + headersSize: this._request.requestHeadersSize, + bodySize: this.requestBodySize + }; + if (this._request.requestFormData) + res.postData = this._buildPostData(); + + return res; + }, + + /** + * @return {Object} + */ + _buildResponse: function() + { + return { + status: this._request.statusCode, + statusText: this._request.statusText, + httpVersion: this._request.responseHttpVersion, + headers: this._request.responseHeaders, + cookies: this._buildCookies(this._request.responseCookies || []), + content: this._buildContent(), + redirectURL: this._request.responseHeaderValue("Location") || "", + headersSize: this._request.responseHeadersSize, + bodySize: this.responseBodySize + }; + }, + + /** + * @return {Object} + */ + _buildContent: function() + { + var content = { + size: this._request.resourceSize, + mimeType: this._request.mimeType, + // text: this._request.content // TODO: pull out into a boolean flag, as content can be huge (and needs to be requested with an async call) + }; + var compression = this.responseCompression; + if (typeof compression === "number") + content.compression = compression; + return content; + }, + + /** + * @return {Object} + */ + _buildTimings: function() + { + var waitForConnection = this._interval("connectStart", "connectEnd"); + var blocked = 0; + var connect = -1; + + if (this._request.connectionReused) + blocked = waitForConnection; + else + connect = waitForConnection; + + return { + blocked: blocked, + dns: this._interval("dnsStart", "dnsEnd"), + connect: connect, + send: this._interval("sendStart", "sendEnd"), + wait: this._interval("sendEnd", "receiveHeadersEnd"), + receive: WebInspector.HAREntry._toMilliseconds(this._request.receiveDuration), + ssl: this._interval("sslStart", "sslEnd") + }; + }, + + /** + * @return {Object} + */ + _buildPostData: function() + { + var res = { + mimeType: this._request.requestHeaderValue("Content-Type"), + text: this._request.requestFormData + }; + if (this._request.formParameters) + res.params = this._buildParameters(this._request.formParameters); + return res; + }, + + /** + * @param {Array.} parameters + * @return {Array.} + */ + _buildParameters: function(parameters) + { + return parameters.slice(); + }, + + /** + * @param {string} url + * @return {string} + */ + _buildRequestURL: function(url) + { + return url.split("#", 2)[0]; + }, + + /** + * @param {Array.} cookies + * @return {Array.} + */ + _buildCookies: function(cookies) + { + return cookies.map(this._buildCookie.bind(this)); + }, + + /** + * @param {WebInspector.Cookie} cookie + * @return {Object} + */ + _buildCookie: function(cookie) + { + return { + name: cookie.name(), + value: cookie.value(), + path: cookie.path(), + domain: cookie.domain(), + expires: cookie.expiresDate(new Date(this._request.startTime * 1000)), + httpOnly: cookie.httpOnly(), + secure: cookie.secure() + }; + }, + + /** + * @param {string} start + * @param {string} end + * @return {number} + */ + _interval: function(start, end) + { + var timing = this._request.timing; + if (!timing) + return -1; + var startTime = timing[start]; + return typeof startTime !== "number" || startTime === -1 ? -1 : Math.round(timing[end] - startTime); + }, + + /** + * @return {number} + */ + get requestBodySize() + { + return !this._request.requestFormData ? 0 : this._request.requestFormData.length; + }, + + /** + * @return {number} + */ + get responseBodySize() + { + if (this._request.cached || this._request.statusCode === 304) + return 0; + return this._request.transferSize - this._request.responseHeadersSize; + }, + + /** + * @return {number|undefined} + */ + get responseCompression() + { + if (this._request.cached || this._request.statusCode === 304 || this._request.statusCode === 206) + return; + return this._request.resourceSize - this.responseBodySize; + } +} + +/** + * @param {number} time + * @return {number} + */ +WebInspector.HAREntry._toMilliseconds = function(time) +{ + return time === -1 ? -1 : Math.round(time * 1000); +} + +/** + * @constructor + * @param {Array.} requests + */ +WebInspector.HARLog = function(requests) +{ + this._requests = requests; +} + +WebInspector.HARLog.prototype = { + /** + * @return {Object} + */ + build: function() + { + return { + version: "1.2", + creator: this._creator(), + pages: this._buildPages(), + entries: this._requests.map(this._convertResource.bind(this)) + } + }, + + _creator: function() + { + var webKitVersion = /AppleWebKit\/([^ ]+)/.exec(window.navigator.userAgent); + + return { + name: "WebInspector", + version: webKitVersion ? webKitVersion[1] : "n/a" + }; + }, + + /** + * @return {Array} + */ + _buildPages: function() + { + var seenIdentifiers = {}; + var pages = []; + for (var i = 0; i < this._requests.length; ++i) { + var page = WebInspector.networkLog.pageLoadForRequest(this._requests[i]); + if (!page || seenIdentifiers[page.id]) + continue; + seenIdentifiers[page.id] = true; + pages.push(this._convertPage(page)); + } + return pages; + }, + + /** + * @param {WebInspector.PageLoad} page + * @return {Object} + */ + _convertPage: function(page) + { + return { + startedDateTime: new Date(page.startTime * 1000), + id: "page_" + page.id, + title: page.url, // We don't have actual page title here. URL is probably better than nothing. + pageTimings: { + onContentLoad: this._pageEventTime(page, page.contentLoadTime), + onLoad: this._pageEventTime(page, page.loadTime) + } + } + }, + + /** + * @param {WebInspector.NetworkRequest} request + * @return {Object} + */ + _convertResource: function(request) + { + return (new WebInspector.HAREntry(request)).build(); + }, + + /** + * @param {WebInspector.PageLoad} page + * @param {number} time + * @return {number} + */ + _pageEventTime: function(page, time) + { + var startTime = page.startTime; + if (time === -1 || startTime === -1) + return -1; + return WebInspector.HAREntry._toMilliseconds(time - startTime); + } +} + +/** + * @constructor + */ +WebInspector.HARWriter = function() +{ +} + +WebInspector.HARWriter.prototype = { + /** + * @param {WebInspector.OutputStream} stream + * @param {Array.} requests + * @param {WebInspector.Progress} progress + */ + write: function(stream, requests, progress) + { + this._stream = stream; + this._harLog = (new WebInspector.HARLog(requests)).build(); + this._pendingRequests = 1; // Guard against completing resource transfer before all requests are made. + var entries = this._harLog.entries; + for (var i = 0; i < entries.length; ++i) { + var content = requests[i].content; + if (typeof content === "undefined" && requests[i].finished) { + ++this._pendingRequests; + requests[i].requestContent(this._onContentAvailable.bind(this, entries[i])); + } else if (content !== null) + entries[i].response.content.text = content; + } + var compositeProgress = new WebInspector.CompositeProgress(progress); + this._writeProgress = compositeProgress.createSubProgress(); + if (--this._pendingRequests) { + this._requestsProgress = compositeProgress.createSubProgress(); + this._requestsProgress.setTitle(WebInspector.UIString("Collecting content…")); + this._requestsProgress.setTotalWork(this._pendingRequests); + } else + this._beginWrite(); + }, + + /** + * @param {Object} entry + * @param {string|null} content + * @param {boolean} contentEncoded + * @param {string=} mimeType + */ + _onContentAvailable: function(entry, content, contentEncoded, mimeType) + { + if (content !== null) + entry.response.content.text = content; + if (this._requestsProgress) + this._requestsProgress.worked(); + if (!--this._pendingRequests) { + this._requestsProgress.done(); + this._beginWrite(); + } + }, + + _beginWrite: function() + { + const jsonIndent = 2; + this._text = JSON.stringify({log: this._harLog}, null, jsonIndent); + this._writeProgress.setTitle(WebInspector.UIString("Writing file…")); + this._writeProgress.setTotalWork(this._text.length); + this._bytesWritten = 0; + this._writeNextChunk(this._stream); + }, + + /** + * @param {WebInspector.OutputStream} stream + * @param {string=} error + */ + _writeNextChunk: function(stream, error) + { + if (this._bytesWritten >= this._text.length || error) { + stream.close(); + this._writeProgress.done(); + return; + } + const chunkSize = 100000; + var text = this._text.substring(this._bytesWritten, this._bytesWritten + chunkSize); + this._bytesWritten += text.length; + stream.write(text, this._writeNextChunk.bind(this)); + this._writeProgress.setWorked(this._bytesWritten); + } +} diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HandlerRegistry.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HandlerRegistry.js new file mode 100644 index 00000000..239a0bb1 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HandlerRegistry.js @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.Object} + * @implements {WebInspector.ContextMenu.Provider} + */ +WebInspector.HandlerRegistry = function(setting) +{ + WebInspector.Object.call(this); + this._handlers = {}; + this._setting = setting; + this._activeHandler = this._setting.get(); + WebInspector.ContextMenu.registerProvider(this); +} + +WebInspector.HandlerRegistry.prototype = { + get handlerNames() + { + return Object.getOwnPropertyNames(this._handlers); + }, + + get activeHandler() + { + return this._activeHandler; + }, + + set activeHandler(value) + { + this._activeHandler = value; + this._setting.set(value); + }, + + /** + * @param {Object} data + */ + dispatch: function(data) + { + return this.dispatchToHandler(this._activeHandler, data); + }, + + /** + * @param {string} name + * @param {Object} data + */ + dispatchToHandler: function(name, data) + { + var handler = this._handlers[name]; + var result = handler && handler(data); + return !!result; + }, + + registerHandler: function(name, handler) + { + this._handlers[name] = handler; + this.dispatchEventToListeners(WebInspector.HandlerRegistry.EventTypes.HandlersUpdated); + }, + + unregisterHandler: function(name) + { + delete this._handlers[name]; + this.dispatchEventToListeners(WebInspector.HandlerRegistry.EventTypes.HandlersUpdated); + }, + + /** + * @param {WebInspector.ContextMenu} contextMenu + * @param {Object} target + */ + appendApplicableItems: function(event, contextMenu, target) + { + this._appendContentProviderItems(contextMenu, target); + this._appendHrefItems(contextMenu, target); + }, + + /** + * @param {WebInspector.ContextMenu} contextMenu + * @param {Object} target + */ + _appendContentProviderItems: function(contextMenu, target) + { + if (!(target instanceof WebInspector.UISourceCode || target instanceof WebInspector.Resource || target instanceof WebInspector.NetworkRequest)) + return; + var contentProvider = /** @type {WebInspector.ContentProvider} */ (target); + if (!contentProvider.contentURL()) + return; + + contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, contentProvider.contentURL(), false)); + // Skip 0th handler, as it's 'Use default panel' one. + for (var i = 1; i < this.handlerNames.length; ++i) { + var handler = this.handlerNames[i]; + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open using %s" : "Open Using %s", handler), + this.dispatchToHandler.bind(this, handler, { url: contentProvider.contentURL() })); + } + contextMenu.appendItem(WebInspector.copyLinkAddressLabel(), InspectorFrontendHost.copyText.bind(InspectorFrontendHost, contentProvider.contentURL())); + + if (!contentProvider.contentURL()) + return; + + var contentType = contentProvider.contentType(); + if (contentType !== WebInspector.resourceTypes.Document && + contentType !== WebInspector.resourceTypes.Stylesheet && + contentType !== WebInspector.resourceTypes.Script) + return; + + /** + * @param {boolean} forceSaveAs + * @param {?string} content + */ + function doSave(forceSaveAs, content) + { + var url = contentProvider.contentURL(); + WebInspector.fileManager.save(url, content, forceSaveAs); + WebInspector.fileManager.close(url); + } + + /** + * @param {boolean} forceSaveAs + */ + function save(forceSaveAs) + { + if (contentProvider instanceof WebInspector.UISourceCode) { + var uiSourceCode = /** @type {WebInspector.UISourceCode} */ (contentProvider); + uiSourceCode.saveToFileSystem(forceSaveAs); + return; + } + contentProvider.requestContent(doSave.bind(this, forceSaveAs)); + } + + contextMenu.appendSeparator(); + contextMenu.appendItem(WebInspector.UIString("Save"), save.bind(this, false)); + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Save as..." : "Save As..."), save.bind(this, true)); + }, + + /** + * @param {WebInspector.ContextMenu} contextMenu + * @param {Object} target + */ + _appendHrefItems: function(contextMenu, target) + { + if (!(target instanceof Node)) + return; + var targetNode = /** @type {Node} */ (target); + + var anchorElement = targetNode.enclosingNodeOrSelfWithClass("webkit-html-resource-link") || targetNode.enclosingNodeOrSelfWithClass("webkit-html-external-link"); + if (!anchorElement) + return; + + var resourceURL = anchorElement.href; + if (!resourceURL) + return; + + // Add resource-related actions. + contextMenu.appendItem(WebInspector.openLinkExternallyLabel(), WebInspector.openResource.bind(WebInspector, resourceURL, false)); + if (WebInspector.resourceForURL(resourceURL)) + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Open link in Resources panel" : "Open Link in Resources Panel"), WebInspector.openResource.bind(null, resourceURL, true)); + contextMenu.appendItem(WebInspector.copyLinkAddressLabel(), InspectorFrontendHost.copyText.bind(InspectorFrontendHost, resourceURL)); + }, + + __proto__: WebInspector.Object.prototype +} + + +WebInspector.HandlerRegistry.EventTypes = { + HandlersUpdated: "HandlersUpdated" +} + +/** + * @constructor + */ +WebInspector.HandlerSelector = function(handlerRegistry) +{ + this._handlerRegistry = handlerRegistry; + this.element = document.createElement("select"); + this.element.addEventListener("change", this._onChange.bind(this), false); + this._update(); + this._handlerRegistry.addEventListener(WebInspector.HandlerRegistry.EventTypes.HandlersUpdated, this._update.bind(this)); +} + +WebInspector.HandlerSelector.prototype = +{ + _update: function() + { + this.element.removeChildren(); + var names = this._handlerRegistry.handlerNames; + var activeHandler = this._handlerRegistry.activeHandler; + + for (var i = 0; i < names.length; ++i) { + var option = document.createElement("option"); + option.textContent = names[i]; + option.selected = activeHandler === names[i]; + this.element.appendChild(option); + } + this.element.disabled = names.length <= 1; + }, + + _onChange: function(event) + { + var value = event.target.value; + this._handlerRegistry.activeHandler = value; + } +} + + +/** + * @type {WebInspector.HandlerRegistry} + */ +WebInspector.openAnchorLocationRegistry = null; diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshot.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshot.js new file mode 100644 index 00000000..987cfe3e --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshot.js @@ -0,0 +1,1824 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + */ +WebInspector.HeapSnapshotArraySlice = function(array, start, end) +{ + this._array = array; + this._start = start; + this.length = end - start; +} + +WebInspector.HeapSnapshotArraySlice.prototype = { + item: function(index) + { + return this._array[this._start + index]; + }, + + slice: function(start, end) + { + if (typeof end === "undefined") + end = this.length; + return this._array.subarray(this._start + start, this._start + end); + } +} + +/** + * @constructor + * @param {number=} edgeIndex + */ +WebInspector.HeapSnapshotEdge = function(snapshot, edges, edgeIndex) +{ + this._snapshot = snapshot; + this._edges = edges; + this.edgeIndex = edgeIndex || 0; +} + +WebInspector.HeapSnapshotEdge.prototype = { + clone: function() + { + return new WebInspector.HeapSnapshotEdge(this._snapshot, this._edges, this.edgeIndex); + }, + + hasStringName: function() + { + throw new Error("Not implemented"); + }, + + name: function() + { + throw new Error("Not implemented"); + }, + + node: function() + { + return this._snapshot.createNode(this.nodeIndex()); + }, + + nodeIndex: function() + { + return this._edges.item(this.edgeIndex + this._snapshot._edgeToNodeOffset); + }, + + rawEdges: function() + { + return this._edges; + }, + + toString: function() + { + return "HeapSnapshotEdge: " + this.name(); + }, + + type: function() + { + return this._snapshot._edgeTypes[this._type()]; + }, + + serialize: function() + { + var node = this.node(); + return { + name: this.name(), + node: node.serialize(), + nodeIndex: this.nodeIndex(), + type: this.type(), + distance: node.distance() + }; + }, + + _type: function() + { + return this._edges.item(this.edgeIndex + this._snapshot._edgeTypeOffset); + } +}; + +/** + * @constructor + */ +WebInspector.HeapSnapshotEdgeIterator = function(edge) +{ + this.edge = edge; +} + +WebInspector.HeapSnapshotEdgeIterator.prototype = { + rewind: function() + { + this.edge.edgeIndex = 0; + }, + + hasNext: function() + { + return this.edge.edgeIndex < this.edge._edges.length; + }, + + index: function() + { + return this.edge.edgeIndex; + }, + + setIndex: function(newIndex) + { + this.edge.edgeIndex = newIndex; + }, + + item: function() + { + return this.edge; + }, + + next: function() + { + this.edge.edgeIndex += this.edge._snapshot._edgeFieldsCount; + } +}; + +/** + * @constructor + */ +WebInspector.HeapSnapshotRetainerEdge = function(snapshot, retainedNodeIndex, retainerIndex) +{ + this._snapshot = snapshot; + this._retainedNodeIndex = retainedNodeIndex; + + var retainedNodeOrdinal = retainedNodeIndex / snapshot._nodeFieldCount; + this._firstRetainer = snapshot._firstRetainerIndex[retainedNodeOrdinal]; + this._retainersCount = snapshot._firstRetainerIndex[retainedNodeOrdinal + 1] - this._firstRetainer; + + this.setRetainerIndex(retainerIndex); +} + +WebInspector.HeapSnapshotRetainerEdge.prototype = { + clone: function() + { + return new WebInspector.HeapSnapshotRetainerEdge(this._snapshot, this._retainedNodeIndex, this.retainerIndex()); + }, + + hasStringName: function() + { + return this._edge().hasStringName(); + }, + + name: function() + { + return this._edge().name(); + }, + + node: function() + { + return this._node(); + }, + + nodeIndex: function() + { + return this._nodeIndex; + }, + + retainerIndex: function() + { + return this._retainerIndex; + }, + + setRetainerIndex: function(newIndex) + { + if (newIndex !== this._retainerIndex) { + this._retainerIndex = newIndex; + this.edgeIndex = newIndex; + } + }, + + set edgeIndex(edgeIndex) + { + var retainerIndex = this._firstRetainer + edgeIndex; + this._globalEdgeIndex = this._snapshot._retainingEdges[retainerIndex]; + this._nodeIndex = this._snapshot._retainingNodes[retainerIndex]; + delete this._edgeInstance; + delete this._nodeInstance; + }, + + _node: function() + { + if (!this._nodeInstance) + this._nodeInstance = this._snapshot.createNode(this._nodeIndex); + return this._nodeInstance; + }, + + _edge: function() + { + if (!this._edgeInstance) { + var edgeIndex = this._globalEdgeIndex - this._node()._edgeIndexesStart(); + this._edgeInstance = this._snapshot.createEdge(this._node().rawEdges(), edgeIndex); + } + return this._edgeInstance; + }, + + toString: function() + { + return this._edge().toString(); + }, + + serialize: function() + { + var node = this.node(); + return { + name: this.name(), + node: node.serialize(), + nodeIndex: this.nodeIndex(), + type: this.type(), + distance: node.distance() + }; + }, + + type: function() + { + return this._edge().type(); + } +} + +/** + * @constructor + */ +WebInspector.HeapSnapshotRetainerEdgeIterator = function(retainer) +{ + this.retainer = retainer; +} + +WebInspector.HeapSnapshotRetainerEdgeIterator.prototype = { + rewind: function() + { + this.retainer.setRetainerIndex(0); + }, + + hasNext: function() + { + return this.retainer.retainerIndex() < this.retainer._retainersCount; + }, + + index: function() + { + return this.retainer.retainerIndex(); + }, + + setIndex: function(newIndex) + { + this.retainer.setRetainerIndex(newIndex); + }, + + item: function() + { + return this.retainer; + }, + + next: function() + { + this.retainer.setRetainerIndex(this.retainer.retainerIndex() + 1); + } +}; + +/** + * @constructor + * @param {number=} nodeIndex + */ +WebInspector.HeapSnapshotNode = function(snapshot, nodeIndex) +{ + this._snapshot = snapshot; + this._firstNodeIndex = nodeIndex; + this.nodeIndex = nodeIndex; +} + +WebInspector.HeapSnapshotNode.prototype = { + distance: function() + { + return this._snapshot._nodeDistances[this.nodeIndex / this._snapshot._nodeFieldCount]; + }, + + className: function() + { + throw new Error("Not implemented"); + }, + + classIndex: function() + { + throw new Error("Not implemented"); + }, + + dominatorIndex: function() + { + var nodeFieldCount = this._snapshot._nodeFieldCount; + return this._snapshot._dominatorsTree[this.nodeIndex / this._snapshot._nodeFieldCount] * nodeFieldCount; + }, + + edges: function() + { + return new WebInspector.HeapSnapshotEdgeIterator(this._snapshot.createEdge(this.rawEdges(), 0)); + }, + + edgesCount: function() + { + return (this._edgeIndexesEnd() - this._edgeIndexesStart()) / this._snapshot._edgeFieldsCount; + }, + + id: function() + { + throw new Error("Not implemented"); + }, + + isRoot: function() + { + return this.nodeIndex === this._snapshot._rootNodeIndex; + }, + + name: function() + { + return this._snapshot._strings[this._name()]; + }, + + rawEdges: function() + { + return new WebInspector.HeapSnapshotArraySlice(this._snapshot._containmentEdges, this._edgeIndexesStart(), this._edgeIndexesEnd()); + }, + + retainedSize: function() + { + var snapshot = this._snapshot; + return snapshot._nodes[this.nodeIndex + snapshot._nodeRetainedSizeOffset]; + }, + + retainers: function() + { + return new WebInspector.HeapSnapshotRetainerEdgeIterator(this._snapshot.createRetainingEdge(this.nodeIndex, 0)); + }, + + selfSize: function() + { + var snapshot = this._snapshot; + return snapshot._nodes[this.nodeIndex + snapshot._nodeSelfSizeOffset]; + }, + + type: function() + { + return this._snapshot._nodeTypes[this._type()]; + }, + + serialize: function() + { + return { + id: this.id(), + name: this.name(), + distance: this.distance(), + nodeIndex: this.nodeIndex, + retainedSize: this.retainedSize(), + selfSize: this.selfSize(), + type: this.type(), + }; + }, + + _name: function() + { + var snapshot = this._snapshot; + return snapshot._nodes[this.nodeIndex + snapshot._nodeNameOffset]; + }, + + _edgeIndexesStart: function() + { + return this._snapshot._firstEdgeIndexes[this._ordinal()]; + }, + + _edgeIndexesEnd: function() + { + return this._snapshot._firstEdgeIndexes[this._ordinal() + 1]; + }, + + _ordinal: function() + { + return this.nodeIndex / this._snapshot._nodeFieldCount; + }, + + _nextNodeIndex: function() + { + return this.nodeIndex + this._snapshot._nodeFieldCount; + }, + + _type: function() + { + var snapshot = this._snapshot; + return snapshot._nodes[this.nodeIndex + snapshot._nodeTypeOffset]; + } +}; + +/** + * @constructor + */ +WebInspector.HeapSnapshotNodeIterator = function(node) +{ + this.node = node; + this._nodesLength = node._snapshot._nodes.length; +} + +WebInspector.HeapSnapshotNodeIterator.prototype = { + rewind: function() + { + this.node.nodeIndex = this.node._firstNodeIndex; + }, + + hasNext: function() + { + return this.node.nodeIndex < this._nodesLength; + }, + + index: function() + { + return this.node.nodeIndex; + }, + + setIndex: function(newIndex) + { + this.node.nodeIndex = newIndex; + }, + + item: function() + { + return this.node; + }, + + next: function() + { + this.node.nodeIndex = this.node._nextNodeIndex(); + } +} + + +/** + * @param{WebInspector.HeapSnapshotWorkerDispatcher=} dispatcher + * @constructor + */ +WebInspector.HeapSnapshotProgress = function(dispatcher) +{ + this._dispatcher = dispatcher; +} + +WebInspector.HeapSnapshotProgress.Event = { + Update: "ProgressUpdate" +}; + +WebInspector.HeapSnapshotProgress.prototype = { + /** + * @param{string} status + */ + updateStatus: function(status) + { + this._sendUpdateEvent(WebInspector.UIString(status)); + }, + + /** + * @param{string} title + * @param{number} value + * @param{number} total + */ + updateProgress: function(title, value, total) + { + var percentValue = ((total ? (value / total) : 0) * 100).toFixed(0); + this._sendUpdateEvent(WebInspector.UIString(title, percentValue)); + }, + + /** + * @param{string} text + */ + _sendUpdateEvent: function(text) + { + // May be undefined in tests. + if (this._dispatcher) + this._dispatcher.sendEvent(WebInspector.HeapSnapshotProgress.Event.Update, text); + } +} + + +/** + * @param{WebInspector.HeapSnapshotProgress} progress + * @constructor + */ +WebInspector.HeapSnapshot = function(profile, progress) +{ + this.uid = profile.snapshot.uid; + this._nodes = profile.nodes; + this._containmentEdges = profile.edges; + /** @type{HeapSnapshotMetainfo} */ + this._metaNode = profile.snapshot.meta; + this._strings = profile.strings; + this._progress = progress; + + this._noDistance = -5; + this._rootNodeIndex = 0; + if (profile.snapshot.root_index) + this._rootNodeIndex = profile.snapshot.root_index; + + this._snapshotDiffs = {}; + this._aggregatesForDiff = null; + + this._init(); +} + +/** + * @constructor + */ +function HeapSnapshotMetainfo() +{ + // New format. + this.node_fields = []; + this.node_types = []; + this.edge_fields = []; + this.edge_types = []; + this.type_strings = {}; + + // Old format. + this.fields = []; + this.types = []; +} + +/** + * @constructor + */ +function HeapSnapshotHeader() +{ + // New format. + this.title = ""; + this.uid = 0; + this.meta = new HeapSnapshotMetainfo(); + this.node_count = 0; + this.edge_count = 0; +} + +WebInspector.HeapSnapshot.prototype = { + _init: function() + { + var meta = this._metaNode; + + this._nodeTypeOffset = meta.node_fields.indexOf("type"); + this._nodeNameOffset = meta.node_fields.indexOf("name"); + this._nodeIdOffset = meta.node_fields.indexOf("id"); + this._nodeSelfSizeOffset = meta.node_fields.indexOf("self_size"); + this._nodeEdgeCountOffset = meta.node_fields.indexOf("edge_count"); + this._nodeFieldCount = meta.node_fields.length; + + this._nodeTypes = meta.node_types[this._nodeTypeOffset]; + this._nodeHiddenType = this._nodeTypes.indexOf("hidden"); + this._nodeObjectType = this._nodeTypes.indexOf("object"); + this._nodeNativeType = this._nodeTypes.indexOf("native"); + this._nodeCodeType = this._nodeTypes.indexOf("code"); + this._nodeSyntheticType = this._nodeTypes.indexOf("synthetic"); + + this._edgeFieldsCount = meta.edge_fields.length; + this._edgeTypeOffset = meta.edge_fields.indexOf("type"); + this._edgeNameOffset = meta.edge_fields.indexOf("name_or_index"); + this._edgeToNodeOffset = meta.edge_fields.indexOf("to_node"); + + this._edgeTypes = meta.edge_types[this._edgeTypeOffset]; + this._edgeTypes.push("invisible"); + this._edgeElementType = this._edgeTypes.indexOf("element"); + this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); + this._edgeInternalType = this._edgeTypes.indexOf("internal"); + this._edgeShortcutType = this._edgeTypes.indexOf("shortcut"); + this._edgeWeakType = this._edgeTypes.indexOf("weak"); + this._edgeInvisibleType = this._edgeTypes.indexOf("invisible"); + + this.nodeCount = this._nodes.length / this._nodeFieldCount; + this._edgeCount = this._containmentEdges.length / this._edgeFieldsCount; + + this._progress.updateStatus("Building edge indexes\u2026"); + this._buildEdgeIndexes(); + this._progress.updateStatus("Marking invisible edges\u2026"); + this._markInvisibleEdges(); + this._progress.updateStatus("Building retainers\u2026"); + this._buildRetainers(); + this._progress.updateStatus("Calculating node flags\u2026"); + this._calculateFlags(); + this._progress.updateStatus("Calculating distances\u2026"); + this._calculateDistances(); + this._progress.updateStatus("Building postorder index\u2026"); + var result = this._buildPostOrderIndex(); + // Actually it is array that maps node ordinal number to dominator node ordinal number. + this._progress.updateStatus("Building dominator tree\u2026"); + this._dominatorsTree = this._buildDominatorTree(result.postOrderIndex2NodeOrdinal, result.nodeOrdinal2PostOrderIndex); + this._progress.updateStatus("Calculating retained sizes\u2026"); + this._calculateRetainedSizes(result.postOrderIndex2NodeOrdinal); + this._progress.updateStatus("Buiding dominated nodes\u2026"); + this._buildDominatedNodes(); + this._progress.updateStatus("Finished processing."); + }, + + _buildEdgeIndexes: function() + { + var nodes = this._nodes; + var nodeCount = this.nodeCount; + var firstEdgeIndexes = this._firstEdgeIndexes = new Uint32Array(nodeCount + 1); + var nodeFieldCount = this._nodeFieldCount; + var edgeFieldsCount = this._edgeFieldsCount; + var nodeEdgeCountOffset = this._nodeEdgeCountOffset; + firstEdgeIndexes[nodeCount] = this._containmentEdges.length; + for (var nodeOrdinal = 0, edgeIndex = 0; nodeOrdinal < nodeCount; ++nodeOrdinal) { + firstEdgeIndexes[nodeOrdinal] = edgeIndex; + edgeIndex += nodes[nodeOrdinal * nodeFieldCount + nodeEdgeCountOffset] * edgeFieldsCount; + } + }, + + _buildRetainers: function() + { + var retainingNodes = this._retainingNodes = new Uint32Array(this._edgeCount); + var retainingEdges = this._retainingEdges = new Uint32Array(this._edgeCount); + // Index of the first retainer in the _retainingNodes and _retainingEdges + // arrays. Addressed by retained node index. + var firstRetainerIndex = this._firstRetainerIndex = new Uint32Array(this.nodeCount + 1); + + var containmentEdges = this._containmentEdges; + var edgeFieldsCount = this._edgeFieldsCount; + var nodeFieldCount = this._nodeFieldCount; + var edgeToNodeOffset = this._edgeToNodeOffset; + var nodes = this._nodes; + var firstEdgeIndexes = this._firstEdgeIndexes; + var nodeCount = this.nodeCount; + + for (var toNodeFieldIndex = edgeToNodeOffset, l = containmentEdges.length; toNodeFieldIndex < l; toNodeFieldIndex += edgeFieldsCount) { + var toNodeIndex = containmentEdges[toNodeFieldIndex]; + if (toNodeIndex % nodeFieldCount) + throw new Error("Invalid toNodeIndex " + toNodeIndex); + ++firstRetainerIndex[toNodeIndex / nodeFieldCount]; + } + for (var i = 0, firstUnusedRetainerSlot = 0; i < nodeCount; i++) { + var retainersCount = firstRetainerIndex[i]; + firstRetainerIndex[i] = firstUnusedRetainerSlot; + retainingNodes[firstUnusedRetainerSlot] = retainersCount; + firstUnusedRetainerSlot += retainersCount; + } + firstRetainerIndex[nodeCount] = retainingNodes.length; + + var nextNodeFirstEdgeIndex = firstEdgeIndexes[0]; + for (var srcNodeOrdinal = 0; srcNodeOrdinal < nodeCount; ++srcNodeOrdinal) { + var firstEdgeIndex = nextNodeFirstEdgeIndex; + nextNodeFirstEdgeIndex = firstEdgeIndexes[srcNodeOrdinal + 1]; + var srcNodeIndex = srcNodeOrdinal * nodeFieldCount; + for (var edgeIndex = firstEdgeIndex; edgeIndex < nextNodeFirstEdgeIndex; edgeIndex += edgeFieldsCount) { + var toNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset]; + if (toNodeIndex % nodeFieldCount) + throw new Error("Invalid toNodeIndex " + toNodeIndex); + var firstRetainerSlotIndex = firstRetainerIndex[toNodeIndex / nodeFieldCount]; + var nextUnusedRetainerSlotIndex = firstRetainerSlotIndex + (--retainingNodes[firstRetainerSlotIndex]); + retainingNodes[nextUnusedRetainerSlotIndex] = srcNodeIndex; + retainingEdges[nextUnusedRetainerSlotIndex] = edgeIndex; + } + } + }, + + /** + * @param {number=} nodeIndex + */ + createNode: function(nodeIndex) + { + throw new Error("Not implemented"); + }, + + createEdge: function(edges, edgeIndex) + { + throw new Error("Not implemented"); + }, + + createRetainingEdge: function(retainedNodeIndex, retainerIndex) + { + throw new Error("Not implemented"); + }, + + dispose: function() + { + delete this._nodes; + delete this._strings; + delete this._retainingEdges; + delete this._retainingNodes; + delete this._firstRetainerIndex; + if (this._aggregates) { + delete this._aggregates; + delete this._aggregatesSortedFlags; + } + delete this._dominatedNodes; + delete this._firstDominatedNodeIndex; + delete this._nodeDistances; + delete this._dominatorsTree; + }, + + _allNodes: function() + { + return new WebInspector.HeapSnapshotNodeIterator(this.rootNode()); + }, + + rootNode: function() + { + return this.createNode(this._rootNodeIndex); + }, + + get rootNodeIndex() + { + return this._rootNodeIndex; + }, + + get totalSize() + { + return this.rootNode().retainedSize(); + }, + + _getDominatedIndex: function(nodeIndex) + { + if (nodeIndex % this._nodeFieldCount) + throw new Error("Invalid nodeIndex: " + nodeIndex); + return this._firstDominatedNodeIndex[nodeIndex / this._nodeFieldCount]; + }, + + _dominatedNodesOfNode: function(node) + { + var dominatedIndexFrom = this._getDominatedIndex(node.nodeIndex); + var dominatedIndexTo = this._getDominatedIndex(node._nextNodeIndex()); + return new WebInspector.HeapSnapshotArraySlice(this._dominatedNodes, dominatedIndexFrom, dominatedIndexTo); + }, + + /** + * @param {boolean} sortedIndexes + * @param {string} key + * @param {string=} filterString + */ + aggregates: function(sortedIndexes, key, filterString) + { + if (!this._aggregates) { + this._aggregates = {}; + this._aggregatesSortedFlags = {}; + } + + var aggregatesByClassName = this._aggregates[key]; + if (aggregatesByClassName) { + if (sortedIndexes && !this._aggregatesSortedFlags[key]) { + this._sortAggregateIndexes(aggregatesByClassName); + this._aggregatesSortedFlags[key] = sortedIndexes; + } + return aggregatesByClassName; + } + + var filter; + if (filterString) + filter = this._parseFilter(filterString); + + var aggregates = this._buildAggregates(filter); + this._calculateClassesRetainedSize(aggregates.aggregatesByClassIndex, filter); + aggregatesByClassName = aggregates.aggregatesByClassName; + + if (sortedIndexes) + this._sortAggregateIndexes(aggregatesByClassName); + + this._aggregatesSortedFlags[key] = sortedIndexes; + this._aggregates[key] = aggregatesByClassName; + + return aggregatesByClassName; + }, + + aggregatesForDiff: function() + { + if (this._aggregatesForDiff) + return this._aggregatesForDiff; + + var aggregatesByClassName = this.aggregates(true, "allObjects"); + this._aggregatesForDiff = {}; + + var node = this.createNode(); + for (var className in aggregatesByClassName) { + var aggregate = aggregatesByClassName[className]; + var indexes = aggregate.idxs; + var ids = new Array(indexes.length); + var selfSizes = new Array(indexes.length); + for (var i = 0; i < indexes.length; i++) { + node.nodeIndex = indexes[i]; + ids[i] = node.id(); + selfSizes[i] = node.selfSize(); + } + + this._aggregatesForDiff[className] = { + indexes: indexes, + ids: ids, + selfSizes: selfSizes + }; + } + return this._aggregatesForDiff; + }, + + /** + * @param {!WebInspector.HeapSnapshotNode} node + * @return {!boolean} + */ + _isUserRoot: function(node) + { + return true; + }, + + /** + * @param {function(!WebInspector.HeapSnapshotNode)} action + * @param {boolean=} userRootsOnly + */ + forEachRoot: function(action, userRootsOnly) + { + for (var iter = this.rootNode().edges(); iter.hasNext(); iter.next()) { + var node = iter.edge.node(); + if (!userRootsOnly || this._isUserRoot(node)) + action(node); + } + }, + + _calculateDistances: function() + { + var nodeFieldCount = this._nodeFieldCount; + var nodeCount = this.nodeCount; + var distances = new Int32Array(nodeCount); + var noDistance = this._noDistance; + for (var i = 0; i < nodeCount; ++i) + distances[i] = noDistance; + + var nodesToVisit = new Uint32Array(this.nodeCount); + var nodesToVisitLength = 0; + + /** + * @param {!WebInspector.HeapSnapshotNode} node + */ + function enqueueNode(node) + { + var ordinal = node._ordinal(); + if (distances[ordinal] !== noDistance) + return; + distances[ordinal] = 0; + nodesToVisit[nodesToVisitLength++] = node.nodeIndex; + } + + this.forEachRoot(enqueueNode, true); + this._bfs(nodesToVisit, nodesToVisitLength, distances); + + // bfs for the rest of objects + nodesToVisitLength = 0; + this.forEachRoot(enqueueNode); + this._bfs(nodesToVisit, nodesToVisitLength, distances); + + this._nodeDistances = distances; + }, + + /** + * @param {!Uint32Array} nodesToVisit + * @param {!number} nodesToVisitLength + * @param {!Int32Array} distances + */ + _bfs: function(nodesToVisit, nodesToVisitLength, distances) + { + // Preload fields into local variables for better performance. + var edgeFieldsCount = this._edgeFieldsCount; + var nodeFieldCount = this._nodeFieldCount; + var containmentEdges = this._containmentEdges; + var firstEdgeIndexes = this._firstEdgeIndexes; + var edgeToNodeOffset = this._edgeToNodeOffset; + var edgeTypeOffset = this._edgeTypeOffset; + var nodes = this._nodes; + var nodeCount = this.nodeCount; + var containmentEdgesLength = containmentEdges.length; + var edgeWeakType = this._edgeWeakType; + var noDistance = this._noDistance; + + var index = 0; + while (index < nodesToVisitLength) { + var nodeIndex = nodesToVisit[index++]; // shift generates too much garbage. + var nodeOrdinal = nodeIndex / nodeFieldCount; + var distance = distances[nodeOrdinal] + 1; + var firstEdgeIndex = firstEdgeIndexes[nodeOrdinal]; + var edgesEnd = firstEdgeIndexes[nodeOrdinal + 1]; + for (var edgeIndex = firstEdgeIndex; edgeIndex < edgesEnd; edgeIndex += edgeFieldsCount) { + var edgeType = containmentEdges[edgeIndex + edgeTypeOffset]; + if (edgeType == edgeWeakType) + continue; + var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset]; + var childNodeOrdinal = childNodeIndex / nodeFieldCount; + if (distances[childNodeOrdinal] !== noDistance) + continue; + distances[childNodeOrdinal] = distance; + nodesToVisit[nodesToVisitLength++] = childNodeIndex; + } + } + if (nodesToVisitLength > nodeCount) + throw new Error("BFS failed. Nodes to visit (" + nodesToVisitLength + ") is more than nodes count (" + nodeCount + ")"); + }, + + _buildAggregates: function(filter) + { + var aggregates = {}; + var aggregatesByClassName = {}; + var classIndexes = []; + var nodes = this._nodes; + var mapAndFlag = this.userObjectsMapAndFlag(); + var flags = mapAndFlag ? mapAndFlag.map : null; + var flag = mapAndFlag ? mapAndFlag.flag : 0; + var nodesLength = nodes.length; + var nodeNativeType = this._nodeNativeType; + var nodeFieldCount = this._nodeFieldCount; + var selfSizeOffset = this._nodeSelfSizeOffset; + var nodeTypeOffset = this._nodeTypeOffset; + var node = this.rootNode(); + var nodeDistances = this._nodeDistances; + + for (var nodeIndex = 0; nodeIndex < nodesLength; nodeIndex += nodeFieldCount) { + var nodeOrdinal = nodeIndex / nodeFieldCount; + if (flags && !(flags[nodeOrdinal] & flag)) + continue; + node.nodeIndex = nodeIndex; + if (filter && !filter(node)) + continue; + var selfSize = nodes[nodeIndex + selfSizeOffset]; + if (!selfSize && nodes[nodeIndex + nodeTypeOffset] !== nodeNativeType) + continue; + var classIndex = node.classIndex(); + if (!(classIndex in aggregates)) { + var nodeType = node.type(); + var nameMatters = nodeType === "object" || nodeType === "native"; + var value = { + count: 1, + distance: nodeDistances[nodeOrdinal], + self: selfSize, + maxRet: 0, + type: nodeType, + name: nameMatters ? node.name() : null, + idxs: [nodeIndex] + }; + aggregates[classIndex] = value; + classIndexes.push(classIndex); + aggregatesByClassName[node.className()] = value; + } else { + var clss = aggregates[classIndex]; + clss.distance = Math.min(clss.distance, nodeDistances[nodeOrdinal]); + ++clss.count; + clss.self += selfSize; + clss.idxs.push(nodeIndex); + } + } + + // Shave off provisionally allocated space. + for (var i = 0, l = classIndexes.length; i < l; ++i) { + var classIndex = classIndexes[i]; + aggregates[classIndex].idxs = aggregates[classIndex].idxs.slice(); + } + return {aggregatesByClassName: aggregatesByClassName, aggregatesByClassIndex: aggregates}; + }, + + _calculateClassesRetainedSize: function(aggregates, filter) + { + var rootNodeIndex = this._rootNodeIndex; + var node = this.createNode(rootNodeIndex); + var list = [rootNodeIndex]; + var sizes = [-1]; + var classes = []; + var seenClassNameIndexes = {}; + var nodeFieldCount = this._nodeFieldCount; + var nodeTypeOffset = this._nodeTypeOffset; + var nodeNativeType = this._nodeNativeType; + var dominatedNodes = this._dominatedNodes; + var nodes = this._nodes; + var mapAndFlag = this.userObjectsMapAndFlag(); + var flags = mapAndFlag ? mapAndFlag.map : null; + var flag = mapAndFlag ? mapAndFlag.flag : 0; + var firstDominatedNodeIndex = this._firstDominatedNodeIndex; + + while (list.length) { + var nodeIndex = list.pop(); + node.nodeIndex = nodeIndex; + var classIndex = node.classIndex(); + var seen = !!seenClassNameIndexes[classIndex]; + var nodeOrdinal = nodeIndex / nodeFieldCount; + var dominatedIndexFrom = firstDominatedNodeIndex[nodeOrdinal]; + var dominatedIndexTo = firstDominatedNodeIndex[nodeOrdinal + 1]; + + if (!seen && + (!flags || (flags[nodeOrdinal] & flag)) && + (!filter || filter(node)) && + (node.selfSize() || nodes[nodeIndex + nodeTypeOffset] === nodeNativeType) + ) { + aggregates[classIndex].maxRet += node.retainedSize(); + if (dominatedIndexFrom !== dominatedIndexTo) { + seenClassNameIndexes[classIndex] = true; + sizes.push(list.length); + classes.push(classIndex); + } + } + for (var i = dominatedIndexFrom; i < dominatedIndexTo; i++) + list.push(dominatedNodes[i]); + + var l = list.length; + while (sizes[sizes.length - 1] === l) { + sizes.pop(); + classIndex = classes.pop(); + seenClassNameIndexes[classIndex] = false; + } + } + }, + + _sortAggregateIndexes: function(aggregates) + { + var nodeA = this.createNode(); + var nodeB = this.createNode(); + for (var clss in aggregates) + aggregates[clss].idxs.sort( + function(idxA, idxB) { + nodeA.nodeIndex = idxA; + nodeB.nodeIndex = idxB; + return nodeA.id() < nodeB.id() ? -1 : 1; + }); + }, + + _buildPostOrderIndex: function() + { + var nodeFieldCount = this._nodeFieldCount; + var nodes = this._nodes; + var nodeCount = this.nodeCount; + var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount; + + var edgeFieldsCount = this._edgeFieldsCount; + var edgeTypeOffset = this._edgeTypeOffset; + var edgeToNodeOffset = this._edgeToNodeOffset; + var edgeShortcutType = this._edgeShortcutType; + var firstEdgeIndexes = this._firstEdgeIndexes; + var containmentEdges = this._containmentEdges; + var containmentEdgesLength = this._containmentEdges.length; + + var mapAndFlag = this.userObjectsMapAndFlag(); + var flags = mapAndFlag ? mapAndFlag.map : null; + var flag = mapAndFlag ? mapAndFlag.flag : 0; + + var nodesToVisit = new Uint32Array(nodeCount); + var postOrderIndex2NodeOrdinal = new Uint32Array(nodeCount); + var nodeOrdinal2PostOrderIndex = new Uint32Array(nodeCount); + var painted = new Uint8Array(nodeCount); + var nodesToVisitLength = 0; + var postOrderIndex = 0; + var grey = 1; + var black = 2; + + nodesToVisit[nodesToVisitLength++] = rootNodeOrdinal; + painted[rootNodeOrdinal] = grey; + + while (nodesToVisitLength) { + var nodeOrdinal = nodesToVisit[nodesToVisitLength - 1]; + + if (painted[nodeOrdinal] === grey) { + painted[nodeOrdinal] = black; + var nodeFlag = !flags || (flags[nodeOrdinal] & flag); + var beginEdgeIndex = firstEdgeIndexes[nodeOrdinal]; + var endEdgeIndex = firstEdgeIndexes[nodeOrdinal + 1]; + for (var edgeIndex = beginEdgeIndex; edgeIndex < endEdgeIndex; edgeIndex += edgeFieldsCount) { + if (nodeOrdinal !== rootNodeOrdinal && containmentEdges[edgeIndex + edgeTypeOffset] === edgeShortcutType) + continue; + var childNodeIndex = containmentEdges[edgeIndex + edgeToNodeOffset]; + var childNodeOrdinal = childNodeIndex / nodeFieldCount; + var childNodeFlag = !flags || (flags[childNodeOrdinal] & flag); + // We are skipping the edges from non-page-owned nodes to page-owned nodes. + // Otherwise the dominators for the objects that also were retained by debugger would be affected. + if (nodeOrdinal !== rootNodeOrdinal && childNodeFlag && !nodeFlag) + continue; + if (!painted[childNodeOrdinal]) { + painted[childNodeOrdinal] = grey; + nodesToVisit[nodesToVisitLength++] = childNodeOrdinal; + } + } + } else { + nodeOrdinal2PostOrderIndex[nodeOrdinal] = postOrderIndex; + postOrderIndex2NodeOrdinal[postOrderIndex++] = nodeOrdinal; + --nodesToVisitLength; + } + } + + if (postOrderIndex !== nodeCount) { + console.log("Error: Corrupted snapshot. " + (nodeCount - postOrderIndex) + " nodes are unreachable from the root:"); + var dumpNode = this.rootNode(); + for (var i = 0; i < nodeCount; ++i) { + if (painted[i] !== black) { + // Fix it by giving the node a postorder index anyway. + nodeOrdinal2PostOrderIndex[i] = postOrderIndex; + postOrderIndex2NodeOrdinal[postOrderIndex++] = i; + dumpNode.nodeIndex = i * nodeFieldCount; + console.log(JSON.stringify(dumpNode.serialize())); + for (var retainers = dumpNode.retainers(); retainers.hasNext(); retainers = retainers.item().node().retainers()) + console.log(" edgeName: " + retainers.item().name() + " nodeClassName: " + retainers.item().node().className()); + } + } + } + + return {postOrderIndex2NodeOrdinal: postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex: nodeOrdinal2PostOrderIndex}; + }, + + // The algorithm is based on the article: + // K. Cooper, T. Harvey and K. Kennedy "A Simple, Fast Dominance Algorithm" + // Softw. Pract. Exper. 4 (2001), pp. 1-10. + /** + * @param {Array.} postOrderIndex2NodeOrdinal + * @param {Array.} nodeOrdinal2PostOrderIndex + */ + _buildDominatorTree: function(postOrderIndex2NodeOrdinal, nodeOrdinal2PostOrderIndex) + { + var nodeFieldCount = this._nodeFieldCount; + var nodes = this._nodes; + var firstRetainerIndex = this._firstRetainerIndex; + var retainingNodes = this._retainingNodes; + var retainingEdges = this._retainingEdges; + var edgeFieldsCount = this._edgeFieldsCount; + var edgeTypeOffset = this._edgeTypeOffset; + var edgeToNodeOffset = this._edgeToNodeOffset; + var edgeShortcutType = this._edgeShortcutType; + var firstEdgeIndexes = this._firstEdgeIndexes; + var containmentEdges = this._containmentEdges; + var containmentEdgesLength = this._containmentEdges.length; + var rootNodeIndex = this._rootNodeIndex; + + var mapAndFlag = this.userObjectsMapAndFlag(); + var flags = mapAndFlag ? mapAndFlag.map : null; + var flag = mapAndFlag ? mapAndFlag.flag : 0; + + var nodesCount = postOrderIndex2NodeOrdinal.length; + var rootPostOrderedIndex = nodesCount - 1; + var noEntry = nodesCount; + var dominators = new Uint32Array(nodesCount); + for (var i = 0; i < rootPostOrderedIndex; ++i) + dominators[i] = noEntry; + dominators[rootPostOrderedIndex] = rootPostOrderedIndex; + + // The affected array is used to mark entries which dominators + // have to be racalculated because of changes in their retainers. + var affected = new Uint8Array(nodesCount); + var nodeOrdinal; + + { // Mark the root direct children as affected. + nodeOrdinal = this._rootNodeIndex / nodeFieldCount; + var beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset; + var endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1]; + for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex; + toNodeFieldIndex < endEdgeToNodeFieldIndex; + toNodeFieldIndex += edgeFieldsCount) { + var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount; + affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1; + } + } + + var changed = true; + while (changed) { + changed = false; + for (var postOrderIndex = rootPostOrderedIndex - 1; postOrderIndex >= 0; --postOrderIndex) { + if (affected[postOrderIndex] === 0) + continue; + affected[postOrderIndex] = 0; + // If dominator of the entry has already been set to root, + // then it can't propagate any further. + if (dominators[postOrderIndex] === rootPostOrderedIndex) + continue; + nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex]; + var nodeFlag = !flags || (flags[nodeOrdinal] & flag); + var newDominatorIndex = noEntry; + var beginRetainerIndex = firstRetainerIndex[nodeOrdinal]; + var endRetainerIndex = firstRetainerIndex[nodeOrdinal + 1]; + for (var retainerIndex = beginRetainerIndex; retainerIndex < endRetainerIndex; ++retainerIndex) { + var retainerEdgeIndex = retainingEdges[retainerIndex]; + var retainerEdgeType = containmentEdges[retainerEdgeIndex + edgeTypeOffset]; + var retainerNodeIndex = retainingNodes[retainerIndex]; + if (retainerNodeIndex !== rootNodeIndex && retainerEdgeType === edgeShortcutType) + continue; + var retainerNodeOrdinal = retainerNodeIndex / nodeFieldCount; + var retainerNodeFlag = !flags || (flags[retainerNodeOrdinal] & flag); + // We are skipping the edges from non-page-owned nodes to page-owned nodes. + // Otherwise the dominators for the objects that also were retained by debugger would be affected. + if (retainerNodeIndex !== rootNodeIndex && nodeFlag && !retainerNodeFlag) + continue; + var retanerPostOrderIndex = nodeOrdinal2PostOrderIndex[retainerNodeOrdinal]; + if (dominators[retanerPostOrderIndex] !== noEntry) { + if (newDominatorIndex === noEntry) + newDominatorIndex = retanerPostOrderIndex; + else { + while (retanerPostOrderIndex !== newDominatorIndex) { + while (retanerPostOrderIndex < newDominatorIndex) + retanerPostOrderIndex = dominators[retanerPostOrderIndex]; + while (newDominatorIndex < retanerPostOrderIndex) + newDominatorIndex = dominators[newDominatorIndex]; + } + } + // If idom has already reached the root, it doesn't make sense + // to check other retainers. + if (newDominatorIndex === rootPostOrderedIndex) + break; + } + } + if (newDominatorIndex !== noEntry && dominators[postOrderIndex] !== newDominatorIndex) { + dominators[postOrderIndex] = newDominatorIndex; + changed = true; + nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex]; + beginEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal] + edgeToNodeOffset; + endEdgeToNodeFieldIndex = firstEdgeIndexes[nodeOrdinal + 1]; + for (var toNodeFieldIndex = beginEdgeToNodeFieldIndex; + toNodeFieldIndex < endEdgeToNodeFieldIndex; + toNodeFieldIndex += edgeFieldsCount) { + var childNodeOrdinal = containmentEdges[toNodeFieldIndex] / nodeFieldCount; + affected[nodeOrdinal2PostOrderIndex[childNodeOrdinal]] = 1; + } + } + } + } + + var dominatorsTree = new Uint32Array(nodesCount); + for (var postOrderIndex = 0, l = dominators.length; postOrderIndex < l; ++postOrderIndex) { + nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex]; + dominatorsTree[nodeOrdinal] = postOrderIndex2NodeOrdinal[dominators[postOrderIndex]]; + } + return dominatorsTree; + }, + + _calculateRetainedSizes: function(postOrderIndex2NodeOrdinal) + { + var nodeCount = this.nodeCount; + var nodes = this._nodes; + var nodeSelfSizeOffset = this._nodeSelfSizeOffset; + var nodeFieldCount = this._nodeFieldCount; + var dominatorsTree = this._dominatorsTree; + // Reuse now unused edge_count field to store retained size. + var nodeRetainedSizeOffset = this._nodeRetainedSizeOffset = this._nodeEdgeCountOffset; + delete this._nodeEdgeCountOffset; + + for (var nodeIndex = 0, l = nodes.length; nodeIndex < l; nodeIndex += nodeFieldCount) + nodes[nodeIndex + nodeRetainedSizeOffset] = nodes[nodeIndex + nodeSelfSizeOffset]; + + // Propagate retained sizes for each node excluding root. + for (var postOrderIndex = 0; postOrderIndex < nodeCount - 1; ++postOrderIndex) { + var nodeOrdinal = postOrderIndex2NodeOrdinal[postOrderIndex]; + var nodeIndex = nodeOrdinal * nodeFieldCount; + var dominatorIndex = dominatorsTree[nodeOrdinal] * nodeFieldCount; + nodes[dominatorIndex + nodeRetainedSizeOffset] += nodes[nodeIndex + nodeRetainedSizeOffset]; + } + }, + + _buildDominatedNodes: function() + { + // Builds up two arrays: + // - "dominatedNodes" is a continuous array, where each node owns an + // interval (can be empty) with corresponding dominated nodes. + // - "indexArray" is an array of indexes in the "dominatedNodes" + // with the same positions as in the _nodeIndex. + var indexArray = this._firstDominatedNodeIndex = new Uint32Array(this.nodeCount + 1); + // All nodes except the root have dominators. + var dominatedNodes = this._dominatedNodes = new Uint32Array(this.nodeCount - 1); + + // Count the number of dominated nodes for each node. Skip the root (node at + // index 0) as it is the only node that dominates itself. + var nodeFieldCount = this._nodeFieldCount; + var dominatorsTree = this._dominatorsTree; + + var fromNodeOrdinal = 0; + var toNodeOrdinal = this.nodeCount; + var rootNodeOrdinal = this._rootNodeIndex / nodeFieldCount; + if (rootNodeOrdinal === fromNodeOrdinal) + fromNodeOrdinal = 1; + else if (rootNodeOrdinal === toNodeOrdinal - 1) + toNodeOrdinal = toNodeOrdinal - 1; + else + throw new Error("Root node is expected to be either first or last"); + for (var nodeOrdinal = fromNodeOrdinal; nodeOrdinal < toNodeOrdinal; ++nodeOrdinal) + ++indexArray[dominatorsTree[nodeOrdinal]]; + // Put in the first slot of each dominatedNodes slice the count of entries + // that will be filled. + var firstDominatedNodeIndex = 0; + for (var i = 0, l = this.nodeCount; i < l; ++i) { + var dominatedCount = dominatedNodes[firstDominatedNodeIndex] = indexArray[i]; + indexArray[i] = firstDominatedNodeIndex; + firstDominatedNodeIndex += dominatedCount; + } + indexArray[this.nodeCount] = dominatedNodes.length; + // Fill up the dominatedNodes array with indexes of dominated nodes. Skip the root (node at + // index 0) as it is the only node that dominates itself. + for (var nodeOrdinal = fromNodeOrdinal; nodeOrdinal < toNodeOrdinal; ++nodeOrdinal) { + var dominatorOrdinal = dominatorsTree[nodeOrdinal]; + var dominatedRefIndex = indexArray[dominatorOrdinal]; + dominatedRefIndex += (--dominatedNodes[dominatedRefIndex]); + dominatedNodes[dominatedRefIndex] = nodeOrdinal * nodeFieldCount; + } + }, + + _markInvisibleEdges: function() + { + throw new Error("Not implemented"); + }, + + _calculateFlags: function() + { + throw new Error("Not implemented"); + }, + + userObjectsMapAndFlag: function() + { + throw new Error("Not implemented"); + }, + + calculateSnapshotDiff: function(baseSnapshotId, baseSnapshotAggregates) + { + var snapshotDiff = this._snapshotDiffs[baseSnapshotId]; + if (snapshotDiff) + return snapshotDiff; + snapshotDiff = {}; + + var aggregates = this.aggregates(true, "allObjects"); + for (var className in baseSnapshotAggregates) { + var baseAggregate = baseSnapshotAggregates[className]; + var diff = this._calculateDiffForClass(baseAggregate, aggregates[className]); + if (diff) + snapshotDiff[className] = diff; + } + var emptyBaseAggregate = { ids: [], indexes: [], selfSizes: [] }; + for (var className in aggregates) { + if (className in baseSnapshotAggregates) + continue; + snapshotDiff[className] = this._calculateDiffForClass(emptyBaseAggregate, aggregates[className]); + } + + this._snapshotDiffs[baseSnapshotId] = snapshotDiff; + return snapshotDiff; + }, + + _calculateDiffForClass: function(baseAggregate, aggregate) + { + var baseIds = baseAggregate.ids; + var baseIndexes = baseAggregate.indexes; + var baseSelfSizes = baseAggregate.selfSizes; + + var indexes = aggregate ? aggregate.idxs : []; + + var i = 0, l = baseIds.length; + var j = 0, m = indexes.length; + var diff = { addedCount: 0, + removedCount: 0, + addedSize: 0, + removedSize: 0, + deletedIndexes: [], + addedIndexes: [] }; + + var nodeB = this.createNode(indexes[j]); + while (i < l && j < m) { + var nodeAId = baseIds[i]; + if (nodeAId < nodeB.id()) { + diff.deletedIndexes.push(baseIndexes[i]); + diff.removedCount++; + diff.removedSize += baseSelfSizes[i]; + ++i; + } else if (nodeAId > nodeB.id()) { // Native nodes(e.g. dom groups) may have ids less than max JS object id in the base snapshot + diff.addedIndexes.push(indexes[j]); + diff.addedCount++; + diff.addedSize += nodeB.selfSize(); + nodeB.nodeIndex = indexes[++j]; + } else { // nodeAId === nodeB.id() + ++i; + nodeB.nodeIndex = indexes[++j]; + } + } + while (i < l) { + diff.deletedIndexes.push(baseIndexes[i]); + diff.removedCount++; + diff.removedSize += baseSelfSizes[i]; + ++i; + } + while (j < m) { + diff.addedIndexes.push(indexes[j]); + diff.addedCount++; + diff.addedSize += nodeB.selfSize(); + nodeB.nodeIndex = indexes[++j]; + } + diff.countDelta = diff.addedCount - diff.removedCount; + diff.sizeDelta = diff.addedSize - diff.removedSize; + if (!diff.addedCount && !diff.removedCount) + return null; + return diff; + }, + + _nodeForSnapshotObjectId: function(snapshotObjectId) + { + for (var it = this._allNodes(); it.hasNext(); it.next()) { + if (it.node.id() === snapshotObjectId) + return it.node; + } + return null; + }, + + nodeClassName: function(snapshotObjectId) + { + var node = this._nodeForSnapshotObjectId(snapshotObjectId); + if (node) + return node.className(); + return null; + }, + + dominatorIdsForNode: function(snapshotObjectId) + { + var node = this._nodeForSnapshotObjectId(snapshotObjectId); + if (!node) + return null; + var result = []; + while (!node.isRoot()) { + result.push(node.id()); + node.nodeIndex = node.dominatorIndex(); + } + return result; + }, + + _parseFilter: function(filter) + { + if (!filter) + return null; + var parsedFilter = eval("(function(){return " + filter + "})()"); + return parsedFilter.bind(this); + }, + + createEdgesProvider: function(nodeIndex, showHiddenData) + { + var node = this.createNode(nodeIndex); + var filter = this.containmentEdgesFilter(showHiddenData); + return new WebInspector.HeapSnapshotEdgesProvider(this, filter, node.edges()); + }, + + createEdgesProviderForTest: function(nodeIndex, filter) + { + var node = this.createNode(nodeIndex); + return new WebInspector.HeapSnapshotEdgesProvider(this, filter, node.edges()); + }, + + retainingEdgesFilter: function(showHiddenData) + { + return null; + }, + + containmentEdgesFilter: function(showHiddenData) + { + return null; + }, + + createRetainingEdgesProvider: function(nodeIndex, showHiddenData) + { + var node = this.createNode(nodeIndex); + var filter = this.retainingEdgesFilter(showHiddenData); + return new WebInspector.HeapSnapshotEdgesProvider(this, filter, node.retainers()); + }, + + createAddedNodesProvider: function(baseSnapshotId, className) + { + var snapshotDiff = this._snapshotDiffs[baseSnapshotId]; + var diffForClass = snapshotDiff[className]; + return new WebInspector.HeapSnapshotNodesProvider(this, null, diffForClass.addedIndexes); + }, + + createDeletedNodesProvider: function(nodeIndexes) + { + return new WebInspector.HeapSnapshotNodesProvider(this, null, nodeIndexes); + }, + + classNodesFilter: function() + { + return null; + }, + + createNodesProviderForClass: function(className, aggregatesKey) + { + return new WebInspector.HeapSnapshotNodesProvider(this, this.classNodesFilter(), this.aggregates(false, aggregatesKey)[className].idxs); + }, + + createNodesProviderForDominator: function(nodeIndex) + { + var node = this.createNode(nodeIndex); + return new WebInspector.HeapSnapshotNodesProvider(this, null, this._dominatedNodesOfNode(node)); + }, + + updateStaticData: function() + { + return {nodeCount: this.nodeCount, rootNodeIndex: this._rootNodeIndex, totalSize: this.totalSize, uid: this.uid}; + } +}; + +/** + * @constructor + * @param {Array.=} unfilteredIterationOrder + */ +WebInspector.HeapSnapshotFilteredOrderedIterator = function(iterator, filter, unfilteredIterationOrder) +{ + this._filter = filter; + this._iterator = iterator; + this._unfilteredIterationOrder = unfilteredIterationOrder; + this._iterationOrder = null; + this._position = 0; + this._currentComparator = null; + this._sortedPrefixLength = 0; +} + +WebInspector.HeapSnapshotFilteredOrderedIterator.prototype = { + _createIterationOrder: function() + { + if (this._iterationOrder) + return; + if (this._unfilteredIterationOrder && !this._filter) { + this._iterationOrder = this._unfilteredIterationOrder.slice(0); + this._unfilteredIterationOrder = null; + return; + } + this._iterationOrder = []; + var iterator = this._iterator; + if (!this._unfilteredIterationOrder && !this._filter) { + for (iterator.rewind(); iterator.hasNext(); iterator.next()) + this._iterationOrder.push(iterator.index()); + } else if (!this._unfilteredIterationOrder) { + for (iterator.rewind(); iterator.hasNext(); iterator.next()) { + if (this._filter(iterator.item())) + this._iterationOrder.push(iterator.index()); + } + } else { + var order = this._unfilteredIterationOrder.constructor === Array ? + this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0); + for (var i = 0, l = order.length; i < l; ++i) { + iterator.setIndex(order[i]); + if (this._filter(iterator.item())) + this._iterationOrder.push(iterator.index()); + } + this._unfilteredIterationOrder = null; + } + }, + + rewind: function() + { + this._position = 0; + }, + + hasNext: function() + { + return this._position < this._iterationOrder.length; + }, + + isEmpty: function() + { + if (this._iterationOrder) + return !this._iterationOrder.length; + if (this._unfilteredIterationOrder && !this._filter) + return !this._unfilteredIterationOrder.length; + var iterator = this._iterator; + if (!this._unfilteredIterationOrder && !this._filter) { + iterator.rewind(); + return !iterator.hasNext(); + } else if (!this._unfilteredIterationOrder) { + for (iterator.rewind(); iterator.hasNext(); iterator.next()) + if (this._filter(iterator.item())) + return false; + } else { + var order = this._unfilteredIterationOrder.constructor === Array ? + this._unfilteredIterationOrder : this._unfilteredIterationOrder.slice(0); + for (var i = 0, l = order.length; i < l; ++i) { + iterator.setIndex(order[i]); + if (this._filter(iterator.item())) + return false; + } + } + return true; + }, + + item: function() + { + this._iterator.setIndex(this._iterationOrder[this._position]); + return this._iterator.item(); + }, + + get length() + { + this._createIterationOrder(); + return this._iterationOrder.length; + }, + + next: function() + { + ++this._position; + }, + + /** + * @param {number} begin + * @param {number} end + */ + serializeItemsRange: function(begin, end) + { + this._createIterationOrder(); + if (begin > end) + throw new Error("Start position > end position: " + begin + " > " + end); + if (end >= this._iterationOrder.length) + end = this._iterationOrder.length; + if (this._sortedPrefixLength < end) { + this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, end - this._sortedPrefixLength); + this._sortedPrefixLength = end; + } + + this._position = begin; + var startPosition = this._position; + var count = end - begin; + var result = new Array(count); + for (var i = 0 ; i < count && this.hasNext(); ++i, this.next()) + result[i] = this.item().serialize(); + result.length = i; + result.totalLength = this._iterationOrder.length; + + result.startPosition = startPosition; + result.endPosition = this._position; + return result; + }, + + sortAll: function() + { + this._createIterationOrder(); + if (this._sortedPrefixLength === this._iterationOrder.length) + return; + this.sort(this._currentComparator, this._sortedPrefixLength, this._iterationOrder.length - 1, this._iterationOrder.length); + this._sortedPrefixLength = this._iterationOrder.length; + }, + + sortAndRewind: function(comparator) + { + this._currentComparator = comparator; + this._sortedPrefixLength = 0; + this.rewind(); + } +} + +WebInspector.HeapSnapshotFilteredOrderedIterator.prototype.createComparator = function(fieldNames) +{ + return {fieldName1: fieldNames[0], ascending1: fieldNames[1], fieldName2: fieldNames[2], ascending2: fieldNames[3]}; +} + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotFilteredOrderedIterator} + */ +WebInspector.HeapSnapshotEdgesProvider = function(snapshot, filter, edgesIter) +{ + this.snapshot = snapshot; + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, edgesIter, filter); +} + +WebInspector.HeapSnapshotEdgesProvider.prototype = { + sort: function(comparator, leftBound, rightBound, count) + { + var fieldName1 = comparator.fieldName1; + var fieldName2 = comparator.fieldName2; + var ascending1 = comparator.ascending1; + var ascending2 = comparator.ascending2; + + var edgeA = this._iterator.item().clone(); + var edgeB = edgeA.clone(); + var nodeA = this.snapshot.createNode(); + var nodeB = this.snapshot.createNode(); + + function compareEdgeFieldName(ascending, indexA, indexB) + { + edgeA.edgeIndex = indexA; + edgeB.edgeIndex = indexB; + if (edgeB.name() === "__proto__") return -1; + if (edgeA.name() === "__proto__") return 1; + var result = + edgeA.hasStringName() === edgeB.hasStringName() ? + (edgeA.name() < edgeB.name() ? -1 : (edgeA.name() > edgeB.name() ? 1 : 0)) : + (edgeA.hasStringName() ? -1 : 1); + return ascending ? result : -result; + } + + function compareNodeField(fieldName, ascending, indexA, indexB) + { + edgeA.edgeIndex = indexA; + nodeA.nodeIndex = edgeA.nodeIndex(); + var valueA = nodeA[fieldName](); + + edgeB.edgeIndex = indexB; + nodeB.nodeIndex = edgeB.nodeIndex(); + var valueB = nodeB[fieldName](); + + var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); + return ascending ? result : -result; + } + + function compareEdgeAndNode(indexA, indexB) { + var result = compareEdgeFieldName(ascending1, indexA, indexB); + if (result === 0) + result = compareNodeField(fieldName2, ascending2, indexA, indexB); + return result; + } + + function compareNodeAndEdge(indexA, indexB) { + var result = compareNodeField(fieldName1, ascending1, indexA, indexB); + if (result === 0) + result = compareEdgeFieldName(ascending2, indexA, indexB); + return result; + } + + function compareNodeAndNode(indexA, indexB) { + var result = compareNodeField(fieldName1, ascending1, indexA, indexB); + if (result === 0) + result = compareNodeField(fieldName2, ascending2, indexA, indexB); + return result; + } + + if (fieldName1 === "!edgeName") + this._iterationOrder.sortRange(compareEdgeAndNode, leftBound, rightBound, count); + else if (fieldName2 === "!edgeName") + this._iterationOrder.sortRange(compareNodeAndEdge, leftBound, rightBound, count); + else + this._iterationOrder.sortRange(compareNodeAndNode, leftBound, rightBound, count); + }, + + __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype +} + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotFilteredOrderedIterator} + * @param {Array.=} nodeIndexes + */ +WebInspector.HeapSnapshotNodesProvider = function(snapshot, filter, nodeIndexes) +{ + this.snapshot = snapshot; + WebInspector.HeapSnapshotFilteredOrderedIterator.call(this, snapshot._allNodes(), filter, nodeIndexes); +} + +WebInspector.HeapSnapshotNodesProvider.prototype = { + nodePosition: function(snapshotObjectId) + { + this._createIterationOrder(); + if (this.isEmpty()) + return -1; + this.sortAll(); + + var node = this.snapshot.createNode(); + for (var i = 0; i < this._iterationOrder.length; i++) { + node.nodeIndex = this._iterationOrder[i]; + if (node.id() === snapshotObjectId) + return i; + } + return -1; + }, + + sort: function(comparator, leftBound, rightBound, count) + { + var fieldName1 = comparator.fieldName1; + var fieldName2 = comparator.fieldName2; + var ascending1 = comparator.ascending1; + var ascending2 = comparator.ascending2; + + var nodeA = this.snapshot.createNode(); + var nodeB = this.snapshot.createNode(); + + function sortByNodeField(fieldName, ascending) + { + var valueOrFunctionA = nodeA[fieldName]; + var valueA = typeof valueOrFunctionA !== "function" ? valueOrFunctionA : valueOrFunctionA.call(nodeA); + var valueOrFunctionB = nodeB[fieldName]; + var valueB = typeof valueOrFunctionB !== "function" ? valueOrFunctionB : valueOrFunctionB.call(nodeB); + var result = valueA < valueB ? -1 : (valueA > valueB ? 1 : 0); + return ascending ? result : -result; + } + + function sortByComparator(indexA, indexB) { + nodeA.nodeIndex = indexA; + nodeB.nodeIndex = indexB; + var result = sortByNodeField(fieldName1, ascending1); + if (result === 0) + result = sortByNodeField(fieldName2, ascending2); + return result; + } + + this._iterationOrder.sortRange(sortByComparator, leftBound, rightBound, count); + }, + + __proto__: WebInspector.HeapSnapshotFilteredOrderedIterator.prototype +} + diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotDataGrids.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotDataGrids.js new file mode 100644 index 00000000..513f1053 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotDataGrids.js @@ -0,0 +1,863 @@ +/* + * Copyright (C) 2012 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.DataGrid} + */ +WebInspector.HeapSnapshotSortableDataGrid = function(columns) +{ + WebInspector.DataGrid.call(this, columns); + + /** + * @type {number} + */ + this._recursiveSortingDepth = 0; + /** + * @type {WebInspector.HeapSnapshotGridNode} + */ + this._highlightedNode = null; + /** + * @type {boolean} + */ + this._populatedAndSorted = false; + this.addEventListener("sorting complete", this._sortingComplete, this); + this.addEventListener(WebInspector.DataGrid.Events.SortingChanged, this.sortingChanged, this); +} + +WebInspector.HeapSnapshotSortableDataGrid.Events = { + ContentShown: "ContentShown" +} + +WebInspector.HeapSnapshotSortableDataGrid.prototype = { + /** + * @return {number} + */ + defaultPopulateCount: function() + { + return 100; + }, + + dispose: function() + { + var children = this.topLevelNodes(); + for (var i = 0, l = children.length; i < l; ++i) + children[i].dispose(); + }, + + /** + * @override + */ + wasShown: function() + { + if (this._populatedAndSorted) + this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this); + }, + + _sortingComplete: function() + { + this.removeEventListener("sorting complete", this._sortingComplete, this); + this._populatedAndSorted = true; + this.dispatchEventToListeners(WebInspector.HeapSnapshotSortableDataGrid.Events.ContentShown, this); + }, + + /** + * @override + */ + willHide: function() + { + this._clearCurrentHighlight(); + }, + + /** + * @param {WebInspector.ProfilesPanel} profilesPanel + * @param {WebInspector.ContextMenu} contextMenu + * @param {Event} event + */ + populateContextMenu: function(profilesPanel, contextMenu, event) + { + var td = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!td) + return; + var node = td.heapSnapshotNode; + function revealInDominatorsView() + { + profilesPanel.showObject(node.snapshotNodeId, "Dominators"); + } + function revealInSummaryView() + { + profilesPanel.showObject(node.snapshotNodeId, "Summary"); + } + if(node && node.showRetainingEdges) { + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInSummaryView.bind(this)); + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInDominatorsView.bind(this)); + } + else if (node instanceof WebInspector.HeapSnapshotInstanceNode || node instanceof WebInspector.HeapSnapshotObjectNode) { + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Dominators view" : "Reveal in Dominators View"), revealInDominatorsView.bind(this)); + } else if (node instanceof WebInspector.HeapSnapshotDominatorObjectNode) { + contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Reveal in Summary view" : "Reveal in Summary View"), revealInSummaryView.bind(this)); + } + }, + + resetSortingCache: function() + { + delete this._lastSortColumnIdentifier; + delete this._lastSortAscending; + }, + + topLevelNodes: function() + { + return this.rootNode().children; + }, + + /** + * @param {HeapProfilerAgent.HeapSnapshotObjectId} heapSnapshotObjectId + */ + highlightObjectByHeapSnapshotId: function(heapSnapshotObjectId) + { + }, + + /** + * @param {WebInspector.HeapSnapshotGridNode} node + */ + highlightNode: function(node) + { + var prevNode = this._highlightedNode; + this._clearCurrentHighlight(); + this._highlightedNode = node; + this._highlightedNode.element.addStyleClass("highlighted-row"); + // If highlighted node hasn't changed reinsert it to make the highlight animation restart. + if (node === prevNode) { + var element = node.element; + var parent = element.parentElement; + var nextSibling = element.nextSibling; + parent.removeChild(element); + parent.insertBefore(element, nextSibling); + } + }, + + nodeWasDetached: function(node) + { + if (this._highlightedNode === node) + this._clearCurrentHighlight(); + }, + + _clearCurrentHighlight: function() + { + if (!this._highlightedNode) + return + this._highlightedNode.element.removeStyleClass("highlighted-row"); + this._highlightedNode = null; + }, + + changeNameFilter: function(filter) + { + filter = filter.toLowerCase(); + var children = this.topLevelNodes(); + for (var i = 0, l = children.length; i < l; ++i) { + var node = children[i]; + if (node.depth === 0) + node.revealed = node._name.toLowerCase().indexOf(filter) !== -1; + } + this.updateVisibleNodes(); + }, + + sortingChanged: function() + { + var sortAscending = this.isSortOrderAscending(); + var sortColumnIdentifier = this.sortColumnIdentifier(); + if (this._lastSortColumnIdentifier === sortColumnIdentifier && this._lastSortAscending === sortAscending) + return; + this._lastSortColumnIdentifier = sortColumnIdentifier; + this._lastSortAscending = sortAscending; + var sortFields = this._sortFields(sortColumnIdentifier, sortAscending); + + function SortByTwoFields(nodeA, nodeB) + { + var field1 = nodeA[sortFields[0]]; + var field2 = nodeB[sortFields[0]]; + var result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0); + if (!sortFields[1]) + result = -result; + if (result !== 0) + return result; + field1 = nodeA[sortFields[2]]; + field2 = nodeB[sortFields[2]]; + result = field1 < field2 ? -1 : (field1 > field2 ? 1 : 0); + if (!sortFields[3]) + result = -result; + return result; + } + this._performSorting(SortByTwoFields); + }, + + _performSorting: function(sortFunction) + { + this.recursiveSortingEnter(); + var children = this._topLevelNodes; + this.rootNode().removeChildren(); + children.sort(sortFunction); + for (var i = 0, l = children.length; i < l; ++i) { + var child = children[i]; + this.appendChildAfterSorting(child); + if (child.expanded) + child.sort(); + } + this.updateVisibleNodes(); + this.recursiveSortingLeave(); + }, + + appendChildAfterSorting: function(child) + { + var revealed = child.revealed; + this.rootNode().appendChild(child); + child.revealed = revealed; + }, + + updateVisibleNodes: function() + { + }, + + recursiveSortingEnter: function() + { + ++this._recursiveSortingDepth; + }, + + recursiveSortingLeave: function() + { + if (!this._recursiveSortingDepth) + return; + if (!--this._recursiveSortingDepth) + this.dispatchEventToListeners("sorting complete"); + }, + + __proto__: WebInspector.DataGrid.prototype +} + + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotSortableDataGrid} + */ +WebInspector.HeapSnapshotViewportDataGrid = function(columns) +{ + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); + this.scrollContainer.addEventListener("scroll", this._onScroll.bind(this), true); + this._topLevelNodes = []; + this._topPadding = new WebInspector.HeapSnapshotPaddingNode(); + this._bottomPadding = new WebInspector.HeapSnapshotPaddingNode(); + /** + * @type {WebInspector.HeapSnapshotGridNode} + */ + this._nodeToHighlightAfterScroll = null; +} + +WebInspector.HeapSnapshotViewportDataGrid.prototype = { + topLevelNodes: function() + { + return this._topLevelNodes; + }, + + appendChildAfterSorting: function(child) + { + // Do nothing here, it will be added in updateVisibleNodes. + }, + + updateVisibleNodes: function() + { + var scrollTop = this.scrollContainer.scrollTop; + + var viewPortHeight = this.scrollContainer.offsetHeight; + + this._removePaddingRows(); + + var children = this._topLevelNodes; + + var i = 0; + var topPadding = 0; + while (i < children.length) { + if (children[i].revealed) { + var newTop = topPadding + children[i].nodeHeight(); + if (newTop > scrollTop) + break; + topPadding = newTop; + } + ++i; + } + + var selectedNode = this.selectedNode; + + this.rootNode().removeChildren(); + // The height of the view port + invisible top part. + var heightToFill = viewPortHeight + (scrollTop - topPadding); + var filledHeight = 0; + while (i < children.length && filledHeight < heightToFill) { + if (children[i].revealed) { + this.rootNode().appendChild(children[i]); + filledHeight += children[i].nodeHeight(); + } + ++i; + } + + var bottomPadding = 0; + while (i < children.length) { + bottomPadding += children[i].nodeHeight(); + ++i; + } + + this._addPaddingRows(topPadding, bottomPadding); + + if (selectedNode) { + if (selectedNode.parent) { + selectedNode.select(true); + } else { + // Keep selection even if the node is not in the current viewport. + this.selectedNode = selectedNode; + } + } + }, + + appendTopLevelNode: function(node) + { + this._topLevelNodes.push(node); + }, + + removeTopLevelNodes: function() + { + this.rootNode().removeChildren(); + this._topLevelNodes = []; + }, + + /** + * @override + * @param {WebInspector.HeapSnapshotGridNode} node + */ + highlightNode: function(node) + { + if (this._isScrolledIntoView(node.element)) + WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, node); + else { + node.element.scrollIntoViewIfNeeded(true); + this._nodeToHighlightAfterScroll = node; + } + }, + + _isScrolledIntoView: function(element) + { + var viewportTop = this.scrollContainer.scrollTop; + var viewportBottom = viewportTop + this.scrollContainer.clientHeight; + var elemTop = element.offsetTop + var elemBottom = elemTop + element.offsetHeight; + return elemBottom <= viewportBottom && elemTop >= viewportTop; + }, + + _addPaddingRows: function(top, bottom) + { + if (this._topPadding.element.parentNode !== this.dataTableBody) + this.dataTableBody.insertBefore(this._topPadding.element, this.dataTableBody.firstChild); + if (this._bottomPadding.element.parentNode !== this.dataTableBody) + this.dataTableBody.insertBefore(this._bottomPadding.element, this.dataTableBody.lastChild); + this._topPadding.setHeight(top); + this._bottomPadding.setHeight(bottom); + }, + + _removePaddingRows: function() + { + this._bottomPadding.removeFromTable(); + this._topPadding.removeFromTable(); + }, + + onResize: function() + { + WebInspector.HeapSnapshotSortableDataGrid.prototype.onResize.call(this); + this.updateVisibleNodes(); + }, + + _onScroll: function(event) + { + this.updateVisibleNodes(); + + if (this._nodeToHighlightAfterScroll) { + WebInspector.HeapSnapshotSortableDataGrid.prototype.highlightNode.call(this, this._nodeToHighlightAfterScroll); + this._nodeToHighlightAfterScroll = null; + } + }, + + __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype +} + +/** + * @constructor + */ +WebInspector.HeapSnapshotPaddingNode = function() +{ + this.element = document.createElement("tr"); + this.element.addStyleClass("revealed"); +} + +WebInspector.HeapSnapshotPaddingNode.prototype = { + setHeight: function(height) + { + this.element.style.height = height + "px"; + }, + removeFromTable: function() + { + var parent = this.element.parentNode; + if (parent) + parent.removeChild(this.element); + } +} + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotSortableDataGrid} + * @param {Array.=} columns + */ +WebInspector.HeapSnapshotContainmentDataGrid = function(columns) +{ + columns = columns || [ + {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true}, + {id: "distance", title: WebInspector.UIString("Distance"), width: "80px", sortable: true}, + {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, + {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true, sort: WebInspector.DataGrid.Order.Descending} + ]; + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotContainmentDataGrid.prototype = { + setDataSource: function(snapshot, nodeIndex) + { + this.snapshot = snapshot; + var node = new WebInspector.HeapSnapshotNode(snapshot, nodeIndex || snapshot.rootNodeIndex); + var fakeEdge = { node: node }; + this.setRootNode(new WebInspector.HeapSnapshotObjectNode(this, false, fakeEdge, null)); + this.rootNode().sort(); + }, + + sortingChanged: function() + { + this.rootNode().sort(); + }, + + __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype +} + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotContainmentDataGrid} + */ +WebInspector.HeapSnapshotRetainmentDataGrid = function() +{ + this.showRetainingEdges = true; + var columns = [ + {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true}, + {id: "distance", title: WebInspector.UIString("Distance"), width: "80px", sortable: true, sort: WebInspector.DataGrid.Order.Ascending}, + {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, + {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sortable: true} + ]; + WebInspector.HeapSnapshotContainmentDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotRetainmentDataGrid.Events = { + ExpandRetainersComplete: "ExpandRetainersComplete" +} + +WebInspector.HeapSnapshotRetainmentDataGrid.prototype = { + _sortFields: function(sortColumn, sortAscending) + { + return { + object: ["_name", sortAscending, "_count", false], + count: ["_count", sortAscending, "_name", true], + shallowSize: ["_shallowSize", sortAscending, "_name", true], + retainedSize: ["_retainedSize", sortAscending, "_name", true], + distance: ["_distance", sortAscending, "_name", true] + }[sortColumn]; + }, + + reset: function() + { + this.rootNode().removeChildren(); + this.resetSortingCache(); + }, + + /** + * @param {!WebInspector.HeapSnapshotProxy} snapshot + * @param {number} nodeIndex + */ + setDataSource: function(snapshot, nodeIndex) + { + WebInspector.HeapSnapshotContainmentDataGrid.prototype.setDataSource.call(this, snapshot, nodeIndex); + + var dataGrid = this; + var maxExpandLevels = 20; + /** + * @this {!WebInspector.HeapSnapshotObjectNode} + */ + function populateComplete() + { + this.removeEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this); + this.expand(); + if (--maxExpandLevels > 0 && this.children.length > 0) { + var retainer = this.children[0]; + if (retainer._distance > 1) { + retainer.addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, retainer); + retainer.populate(); + return; + } + } + dataGrid.dispatchEventToListeners(WebInspector.HeapSnapshotRetainmentDataGrid.Events.ExpandRetainersComplete); + } + this.rootNode().addEventListener(WebInspector.HeapSnapshotGridNode.Events.PopulateComplete, populateComplete, this.rootNode()); + }, + + __proto__: WebInspector.HeapSnapshotContainmentDataGrid.prototype +} + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotViewportDataGrid} + */ +WebInspector.HeapSnapshotConstructorsDataGrid = function() +{ + var columns = [ + {id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true}, + {id: "distance", title: WebInspector.UIString("Distance"), width: "90px", sortable: true}, + {id: "count", title: WebInspector.UIString("Objects Count"), width: "90px", sortable: true}, + {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, + {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true} + ]; + WebInspector.HeapSnapshotViewportDataGrid.call(this, columns); + this._profileIndex = -1; + this._topLevelNodes = []; + + this._objectIdToSelect = null; +} + +/** + * @constructor + * @param {number=} minNodeId + * @param {number=} maxNodeId + */ +WebInspector.HeapSnapshotConstructorsDataGrid.Request = function(minNodeId, maxNodeId) +{ + if (typeof minNodeId === "number") { + this.key = minNodeId + ".." + maxNodeId; + this.filter = "function(node) { var id = node.id(); return id > " + minNodeId + " && id <= " + maxNodeId + "; }"; + } else { + this.key = "allObjects"; + this.filter = null; + } +} + +WebInspector.HeapSnapshotConstructorsDataGrid.prototype = { + _sortFields: function(sortColumn, sortAscending) + { + return { + object: ["_name", sortAscending, "_count", false], + distance: ["_distance", sortAscending, "_retainedSize", true], + count: ["_count", sortAscending, "_name", true], + shallowSize: ["_shallowSize", sortAscending, "_name", true], + retainedSize: ["_retainedSize", sortAscending, "_name", true] + }[sortColumn]; + }, + + /** + * @override + * @param {HeapProfilerAgent.HeapSnapshotObjectId} id + */ + highlightObjectByHeapSnapshotId: function(id) + { + if (!this.snapshot) { + this._objectIdToSelect = id; + return; + } + + function didGetClassName(className) + { + var constructorNodes = this.topLevelNodes(); + for (var i = 0; i < constructorNodes.length; i++) { + var parent = constructorNodes[i]; + if (parent._name === className) { + parent.revealNodeBySnapshotObjectId(parseInt(id, 10)); + return; + } + } + } + this.snapshot.nodeClassName(parseInt(id, 10), didGetClassName.bind(this)); + }, + + setDataSource: function(snapshot) + { + this.snapshot = snapshot; + if (this._profileIndex === -1) + this._populateChildren(); + + if (this._objectIdToSelect) { + this.highlightObjectByHeapSnapshotId(this._objectIdToSelect); + this._objectIdToSelect = null; + } + }, + + /** + * @param {number} minNodeId + * @param {number} maxNodeId + */ + setSelectionRange: function(minNodeId, maxNodeId) + { + this._populateChildren(new WebInspector.HeapSnapshotConstructorsDataGrid.Request(minNodeId, maxNodeId)); + }, + + _aggregatesReceived: function(key, aggregates) + { + this._requestInProgress = null; + if (this._nextRequest) { + this.snapshot.aggregates(false, this._nextRequest.key, this._nextRequest.filter, this._aggregatesReceived.bind(this, this._nextRequest.key)); + this._requestInProgress = this._nextRequest; + this._nextRequest = null; + } + this.dispose(); + this.removeTopLevelNodes(); + this.resetSortingCache(); + for (var constructor in aggregates) + this.appendTopLevelNode(new WebInspector.HeapSnapshotConstructorNode(this, constructor, aggregates[constructor], key)); + this.sortingChanged(); + this._lastKey = key; + }, + + /** + * @param {WebInspector.HeapSnapshotConstructorsDataGrid.Request=} request + */ + _populateChildren: function(request) + { + request = request || new WebInspector.HeapSnapshotConstructorsDataGrid.Request(); + + if (this._requestInProgress) { + this._nextRequest = this._requestInProgress.key === request.key ? null : request; + return; + } + if (this._lastKey === request.key) + return; + this._requestInProgress = request; + this.snapshot.aggregates(false, request.key, request.filter, this._aggregatesReceived.bind(this, request.key)); + }, + + filterSelectIndexChanged: function(profiles, profileIndex) + { + this._profileIndex = profileIndex; + + var request = null; + if (profileIndex !== -1) { + var minNodeId = profileIndex > 0 ? profiles[profileIndex - 1].maxJSObjectId : 0; + var maxNodeId = profiles[profileIndex].maxJSObjectId; + request = new WebInspector.HeapSnapshotConstructorsDataGrid.Request(minNodeId, maxNodeId) + } + + this._populateChildren(request); + }, + + __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype +} + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotViewportDataGrid} + */ +WebInspector.HeapSnapshotDiffDataGrid = function() +{ + var columns = [ + {id: "object", title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true}, + {id: "addedCount", title: WebInspector.UIString("# New"), width: "72px", sortable: true}, + {id: "removedCount", title: WebInspector.UIString("# Deleted"), width: "72px", sortable: true}, + {id: "countDelta", title: "# Delta", width: "64px", sortable: true}, + {id: "addedSize", title: WebInspector.UIString("Alloc. Size"), width: "72px", sortable: true, sort: WebInspector.DataGrid.Order.Descending}, + {id: "removedSize", title: WebInspector.UIString("Freed Size"), width: "72px", sortable: true}, + {id: "sizeDelta", title: "Size Delta", width: "72px", sortable: true} + ]; + WebInspector.HeapSnapshotViewportDataGrid.call(this, columns); +} + +WebInspector.HeapSnapshotDiffDataGrid.prototype = { + /** + * @override + * @return {number} + */ + defaultPopulateCount: function() + { + return 50; + }, + + _sortFields: function(sortColumn, sortAscending) + { + return { + object: ["_name", sortAscending, "_count", false], + addedCount: ["_addedCount", sortAscending, "_name", true], + removedCount: ["_removedCount", sortAscending, "_name", true], + countDelta: ["_countDelta", sortAscending, "_name", true], + addedSize: ["_addedSize", sortAscending, "_name", true], + removedSize: ["_removedSize", sortAscending, "_name", true], + sizeDelta: ["_sizeDelta", sortAscending, "_name", true] + }[sortColumn]; + }, + + setDataSource: function(snapshot) + { + this.snapshot = snapshot; + }, + + /** + * @param {WebInspector.HeapSnapshotProxy} baseSnapshot + */ + setBaseDataSource: function(baseSnapshot) + { + this.baseSnapshot = baseSnapshot; + this.dispose(); + this.removeTopLevelNodes(); + this.resetSortingCache(); + if (this.baseSnapshot === this.snapshot) { + this.dispatchEventToListeners("sorting complete"); + return; + } + this._populateChildren(); + }, + + _populateChildren: function() + { + function aggregatesForDiffReceived(aggregatesForDiff) + { + this.snapshot.calculateSnapshotDiff(this.baseSnapshot.uid, aggregatesForDiff, didCalculateSnapshotDiff.bind(this)); + function didCalculateSnapshotDiff(diffByClassName) + { + for (var className in diffByClassName) { + var diff = diffByClassName[className]; + this.appendTopLevelNode(new WebInspector.HeapSnapshotDiffNode(this, className, diff)); + } + this.sortingChanged(); + } + } + // Two snapshots live in different workers isolated from each other. That is why + // we first need to collect information about the nodes in the first snapshot and + // then pass it to the second snapshot to calclulate the diff. + this.baseSnapshot.aggregatesForDiff(aggregatesForDiffReceived.bind(this)); + }, + + __proto__: WebInspector.HeapSnapshotViewportDataGrid.prototype +} + + +/** + * @constructor + * @extends {WebInspector.HeapSnapshotSortableDataGrid} + */ +WebInspector.HeapSnapshotDominatorsDataGrid = function() +{ + var columns = [ + {id: "object", title: WebInspector.UIString("Object"), disclosure: true, sortable: true}, + {id: "shallowSize", title: WebInspector.UIString("Shallow Size"), width: "120px", sortable: true}, + {id: "retainedSize", title: WebInspector.UIString("Retained Size"), width: "120px", sort: WebInspector.DataGrid.Order.Descending, sortable: true} + ]; + WebInspector.HeapSnapshotSortableDataGrid.call(this, columns); + this._objectIdToSelect = null; +} + +WebInspector.HeapSnapshotDominatorsDataGrid.prototype = { + /** + * @override + * @return {number} + */ + defaultPopulateCount: function() + { + return 25; + }, + + setDataSource: function(snapshot) + { + this.snapshot = snapshot; + + var fakeNode = { nodeIndex: this.snapshot.rootNodeIndex }; + this.setRootNode(new WebInspector.HeapSnapshotDominatorObjectNode(this, fakeNode)); + this.rootNode().sort(); + + if (this._objectIdToSelect) { + this.highlightObjectByHeapSnapshotId(this._objectIdToSelect); + this._objectIdToSelect = null; + } + }, + + sortingChanged: function() + { + this.rootNode().sort(); + }, + + /** + * @override + * @param {HeapProfilerAgent.HeapSnapshotObjectId} id + */ + highlightObjectByHeapSnapshotId: function(id) + { + if (!this.snapshot) { + this._objectIdToSelect = id; + return; + } + + function didGetDominators(dominatorIds) + { + if (!dominatorIds) { + WebInspector.log(WebInspector.UIString("Cannot find corresponding heap snapshot node")); + return; + } + var dominatorNode = this.rootNode(); + expandNextDominator.call(this, dominatorIds, dominatorNode); + } + + function expandNextDominator(dominatorIds, dominatorNode) + { + if (!dominatorNode) { + console.error("Cannot find dominator node"); + return; + } + if (!dominatorIds.length) { + this.highlightNode(dominatorNode); + dominatorNode.element.scrollIntoViewIfNeeded(true); + return; + } + var snapshotObjectId = dominatorIds.pop(); + dominatorNode.retrieveChildBySnapshotObjectId(snapshotObjectId, expandNextDominator.bind(this, dominatorIds)); + } + + this.snapshot.dominatorIdsForNode(parseInt(id, 10), didGetDominators.bind(this)); + }, + + __proto__: WebInspector.HeapSnapshotSortableDataGrid.prototype +} + diff --git a/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotGridNodes.js b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotGridNodes.js new file mode 100644 index 00000000..8683d043 --- /dev/null +++ b/src/iisnode/node-inspector-0.7.3/node_modules/node-inspector/front-end/HeapSnapshotGridNodes.js @@ -0,0 +1,1119 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @constructor + * @extends {WebInspector.DataGridNode} + * @param {WebInspector.HeapSnapshotSortableDataGrid} tree + * @param {boolean} hasChildren + */ +WebInspector.HeapSnapshotGridNode = function(tree, hasChildren) +{ + WebInspector.DataGridNode.call(this, null, hasChildren); + this._dataGrid = tree; + this._instanceCount = 0; + + this._savedChildren = null; + /** + * List of position ranges for all visible nodes: [startPos1, endPos1),...,[startPosN, endPosN) + * Position is an item position in the provider. + */ + this._retrievedChildrenRanges = []; +} + +WebInspector.HeapSnapshotGridNode.Events = { + PopulateComplete: "PopulateComplete" +} + +WebInspector.HeapSnapshotGridNode.prototype = { + /** + * @return {WebInspector.HeapSnapshotProviderProxy} + */ + createProvider: function() + { + throw new Error("Needs implemented."); + }, + + /** + * @return {WebInspector.HeapSnapshotProviderProxy} + */ + _provider: function() + { + if (!this._providerObject) + this._providerObject = this.createProvider(); + return this._providerObject; + }, + + createCell: function(columnIdentifier) + { + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); + if (this._searchMatched) + cell.addStyleClass("highlight"); + return cell; + }, + + collapse: function() + { + WebInspector.DataGridNode.prototype.collapse.call(this); + this._dataGrid.updateVisibleNodes(); + }, + + dispose: function() + { + if (this._provider()) + this._provider().dispose(); + for (var node = this.children[0]; node; node = node.traverseNextNode(true, this, true)) + if (node.dispose) + node.dispose(); + }, + + _reachableFromWindow: false, + + queryObjectContent: function(callback) + { + }, + + /** + * @override + */ + wasDetached: function() + { + this._dataGrid.nodeWasDetached(this); + }, + + _toPercentString: function(num) + { + return num.toFixed(0) + "\u2009%"; // \u2009 is a thin space. + }, + + /** + * @param {number} nodePosition + */ + childForPosition: function(nodePosition) + { + var indexOfFirsChildInRange = 0; + for (var i = 0; i < this._retrievedChildrenRanges.length; i++) { + var range = this._retrievedChildrenRanges[i]; + if (range.from <= nodePosition && nodePosition < range.to) { + var childIndex = indexOfFirsChildInRange + nodePosition - range.from; + return this.children[childIndex]; + } + indexOfFirsChildInRange += range.to - range.from + 1; + } + return null; + }, + + _createValueCell: function(columnIdentifier) + { + var cell = document.createElement("td"); + cell.className = columnIdentifier + "-column"; + if (this.dataGrid.snapshot.totalSize !== 0) { + var div = document.createElement("div"); + var valueSpan = document.createElement("span"); + valueSpan.textContent = this.data[columnIdentifier]; + div.appendChild(valueSpan); + var percentColumn = columnIdentifier + "-percent"; + if (percentColumn in this.data) { + var percentSpan = document.createElement("span"); + percentSpan.className = "percent-column"; + percentSpan.textContent = this.data[percentColumn]; + div.appendChild(percentSpan); + div.addStyleClass("heap-snapshot-multiple-values"); + } + cell.appendChild(div); + } + return cell; + }, + + populate: function(event) + { + if (this._populated) + return; + this._populated = true; + + function sorted() + { + this._populateChildren(); + } + this._provider().sortAndRewind(this.comparator(), sorted.bind(this)); + }, + + expandWithoutPopulate: function(callback) + { + // Make sure default populate won't take action. + this._populated = true; + this.expand(); + this._provider().sortAndRewind(this.comparator(), callback); + }, + + /** + * @param {?number} fromPosition + * @param {?number} toPosition + */ + _populateChildren: function(fromPosition, toPosition, afterPopulate) + { + fromPosition = fromPosition || 0; + toPosition = toPosition || fromPosition + this._dataGrid.defaultPopulateCount(); + var firstNotSerializedPosition = fromPosition; + function serializeNextChunk() + { + if (firstNotSerializedPosition >= toPosition) + return; + var end = Math.min(firstNotSerializedPosition + this._dataGrid.defaultPopulateCount(), toPosition); + this._provider().serializeItemsRange(firstNotSerializedPosition, end, childrenRetrieved.bind(this)); + firstNotSerializedPosition = end; + } + function insertRetrievedChild(item, insertionIndex) + { + if (this._savedChildren) { + var hash = this._childHashForEntity(item); + if (hash in this._savedChildren) { + this.insertChild(this._savedChildren[hash], insertionIndex); + return; + } + } + this.insertChild(this._createChildNode(item), insertionIndex); + } + function insertShowMoreButton(from, to, insertionIndex) + { + var button = new WebInspector.ShowMoreDataGridNode(this._populateChildren.bind(this), from, to, this._dataGrid.defaultPopulateCount()); + this.insertChild(button, insertionIndex); + } + function childrenRetrieved(items) + { + var itemIndex = 0; + var itemPosition = items.startPosition; + var insertionIndex = 0; + + if (!this._retrievedChildrenRanges.length) { + if (items.startPosition > 0) { + this._retrievedChildrenRanges.push({from: 0, to: 0}); + insertShowMoreButton.call(this, 0, items.startPosition, insertionIndex++); + } + this._retrievedChildrenRanges.push({from: items.startPosition, to: items.endPosition}); + for (var i = 0, l = items.length; i < l; ++i) + insertRetrievedChild.call(this, items[i], insertionIndex++); + if (items.endPosition < items.totalLength) + insertShowMoreButton.call(this, items.endPosition, items.totalLength, insertionIndex++); + } else { + var rangeIndex = 0; + var found = false; + var range; + while (rangeIndex < this._retrievedChildrenRanges.length) { + range = this._retrievedChildrenRanges[rangeIndex]; + if (range.to >= itemPosition) { + found = true; + break; + } + insertionIndex += range.to - range.from; + // Skip the button if there is one. + if (range.to < items.totalLength) + insertionIndex += 1; + ++rangeIndex; + } + + if (!found || items.startPosition < range.from) { + // Update previous button. + this.children[insertionIndex - 1].setEndPosition(items.startPosition); + insertShowMoreButton.call(this, items.startPosition, found ? range.from : items.totalLength, insertionIndex); + range = {from: items.startPosition, to: items.startPosition}; + if (!found) + rangeIndex = this._retrievedChildrenRanges.length; + this._retrievedChildrenRanges.splice(rangeIndex, 0, range); + } else { + insertionIndex += itemPosition - range.from; + } + // At this point insertionIndex is always an index before button or between nodes. + // Also it is always true here that range.from <= itemPosition <= range.to + + // Stretch the range right bound to include all new items. + while (range.to < items.endPosition) { + // Skip already added nodes. + var skipCount = range.to - itemPosition; + insertionIndex += skipCount; + itemIndex += skipCount; + itemPosition = range.to; + + // We're at the position before button: ...x