From 9b66c14f9fdc08fc3ddbb9c057cc09e1b4efa900 Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Thu, 29 Nov 2018 18:30:33 -0800
Subject: [PATCH 1/7] TEST FOR MAC CRASH ON COMPLETION OF TESTS

---
 libraries/audio-client/src/AudioClient.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 92f7a27853..2b3f56350c 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -675,6 +675,7 @@ void AudioClient::start() {
 }
 
 void AudioClient::stop() {
+    return;
     qCDebug(audioclient) << "AudioClient::stop(), requesting switchInputToAudioDevice() to shut down";
     switchInputToAudioDevice(QAudioDeviceInfo(), true);
 

From f5a19efa8c9cc167f45ad359aef510762962889c Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Wed, 5 Dec 2018 11:36:55 -0800
Subject: [PATCH 2/7] Saves text results in zip file.

---
 tools/nitpick/src/Test.cpp | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp
index b1254a3c04..b2cb77143b 100644
--- a/tools/nitpick/src/Test.cpp
+++ b/tools/nitpick/src/Test.cpp
@@ -146,6 +146,11 @@ int Test::checkTextResults() {
 
     // Add results to Test Results folder
     foreach(QString currentFilename, testsFailed) {
+        appendTestResultsToFile(currentFilename, true);
+    }
+
+    foreach(QString currentFilename, testsPassed) {
+        appendTestResultsToFile(currentFilename, false);
     }
 
     return testsFailed.length();
@@ -215,17 +220,28 @@ void Test::appendTestResultsToFile(TestResult testResult, QPixmap comparisonImag
 }
 
 void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed) {
+    // The test name includes everything until the penultimate period
+    QString testNameTemp = testResultFilename.left(testResultFilename.lastIndexOf('.'));
+    QString testName = testResultFilename.left(testNameTemp.lastIndexOf('.'));
     QString resultFolderPath;
     if (hasFailed) {
-        resultFolderPath = _testResultsFolderPath + "/Failure_";
+        resultFolderPath = _testResultsFolderPath + "/Failure_" + testName;
         ++_failureIndex;
     } else {
-        resultFolderPath = _testResultsFolderPath + "/Success_";
+        resultFolderPath = _testResultsFolderPath + "/Success_" + testName;
         ++_successIndex;
     }
 
-    if (!QFile::copy(testResultFilename, resultFolderPath)) {
-////        QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile);
+    if (!QDir().mkdir(resultFolderPath)) {
+        QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
+            "Failed to create folder " + resultFolderPath);
+        exit(-1);
+    }
+
+    QString source = _snapshotDirectory + "/" + testResultFilename;
+    QString destination = resultFolderPath + "/" + testResultFilename;
+    if (!QFile::copy(source, destination)) {
+        QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + source + " to " + destination);
         exit(-1);
     }
 }
@@ -246,7 +262,7 @@ void Test::startTestsEvaluation(const bool isRunningFromCommandLine,
         if (!parent.isNull() && parent.right(1) != "/") {
             parent += "/";
         }
-        _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", parent,
+        _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the snapshots", parent,
             QFileDialog::ShowDirsOnly);
 
         // If user canceled then restore previous selection and return
@@ -384,7 +400,7 @@ void Test::createTests() {
         parent += "/";
     }
 
-    _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", parent,
+    _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the snapshots", parent,
                                                           QFileDialog::ShowDirsOnly);
 
     // If user canceled then restore previous selection and return

From e3402328c899fe9602db6333b1ed0730bd05b159 Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Wed, 5 Dec 2018 12:10:28 -0800
Subject: [PATCH 3/7] Use same name for all text results in zipped folder.

---
 tools/nitpick/src/Test.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/tools/nitpick/src/Test.cpp b/tools/nitpick/src/Test.cpp
index b2cb77143b..896b015611 100644
--- a/tools/nitpick/src/Test.cpp
+++ b/tools/nitpick/src/Test.cpp
@@ -225,10 +225,10 @@ void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed)
     QString testName = testResultFilename.left(testNameTemp.lastIndexOf('.'));
     QString resultFolderPath;
     if (hasFailed) {
-        resultFolderPath = _testResultsFolderPath + "/Failure_" + testName;
+        resultFolderPath = _testResultsFolderPath + "/Failure_" + QString::number(_failureIndex) + "--" + testName;
         ++_failureIndex;
     } else {
-        resultFolderPath = _testResultsFolderPath + "/Success_" + testName;
+        resultFolderPath = _testResultsFolderPath + "/Success_" + QString::number(_successIndex) + "--" + testName;
         ++_successIndex;
     }
 
@@ -239,7 +239,7 @@ void::Test::appendTestResultsToFile(QString testResultFilename, bool hasFailed)
     }
 
     QString source = _snapshotDirectory + "/" + testResultFilename;
-    QString destination = resultFolderPath + "/" + testResultFilename;
+    QString destination = resultFolderPath + "/Result.txt";
     if (!QFile::copy(source, destination)) {
         QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + source + " to " + destination);
         exit(-1);

From 079a623b30ec83454bcc6f0c19dc972e0093c098 Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Wed, 5 Dec 2018 17:25:03 -0800
Subject: [PATCH 4/7] Added text results to HTML.

---
 tools/nitpick/src/AWSInterface.cpp | 158 +++++++++++++++++++++++------
 tools/nitpick/src/AWSInterface.h   |   4 +-
 2 files changed, 131 insertions(+), 31 deletions(-)

diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp
index 2e9ba7ad6d..034feae7f9 100644
--- a/tools/nitpick/src/AWSInterface.cpp
+++ b/tools/nitpick/src/AWSInterface.cpp
@@ -10,6 +10,8 @@
 #include "AWSInterface.h"
 
 #include <QDirIterator>
+#include <QJsonDocument>
+#include <QJsonObject>
 #include <QMessageBox>
 #include <QProcess>
 
@@ -168,7 +170,7 @@ void AWSInterface::writeTable(QTextStream& stream) {
             continue;
         }
 
-        // Only process failure folders
+        // Only process result folders
         if (!nextDirectory.contains("--tests.")) {
             continue;
         }
@@ -209,9 +211,9 @@ void AWSInterface::writeTable(QTextStream& stream) {
 
     // Mac does not read folders in lexicographic order, so this step is divided into 2
     // Each test consists of the test name and its index.
-    QDirIterator it2(_htmlFailuresFolder);
     QStringList folderNames;
 
+    QDirIterator it2(_htmlFailuresFolder);
     while (it2.hasNext()) {
         QString nextDirectory = it2.next();
 
@@ -242,8 +244,7 @@ void AWSInterface::writeTable(QTextStream& stream) {
             previousTestName = testName;
 
             stream << "\t\t<h2>" << testName << "</h2>\n";
-
-            openTable(stream);
+            openTable(stream, folderName, true);
         }
 
         createEntry(testNumber, folderName, stream, true);
@@ -253,6 +254,9 @@ void AWSInterface::writeTable(QTextStream& stream) {
     stream << "\t" << "\t" << "<font color=\"blue\">\n";
     stream << "\t" << "\t" << "<h1>The following tests passed:</h1>";
 
+    // Now do the same for passes
+    folderNames.clear();
+
     QDirIterator it3(_htmlSuccessesFolder);
     while (it3.hasNext()) {
         QString nextDirectory = it3.next();
@@ -263,10 +267,17 @@ void AWSInterface::writeTable(QTextStream& stream) {
         }
 
         QStringList pathComponents = nextDirectory.split('/');
-        QString filename = pathComponents[pathComponents.length() - 1];
-        int splitIndex = filename.lastIndexOf(".");
-        QString testName = filename.left(splitIndex).replace(".", " / ");
-        QString testNumber = filename.right(filename.length() - (splitIndex + 1));
+        QString folderName = pathComponents[pathComponents.length() - 1];
+
+        folderNames << folderName;
+    }
+
+    folderNames.sort();
+    for (const auto& folderName : folderNames) {
+        int splitIndex = folderName.lastIndexOf(".");
+        QString testName = folderName.left(splitIndex).replace('.', " / ");
+
+        int testNumber = folderName.right(folderName.length() - (splitIndex + 1)).toInt();
 
         // The failures are ordered lexicographically, so we know that we can rely on the testName changing to create a new table
         if (testName != previousTestName) {
@@ -277,39 +288,67 @@ void AWSInterface::writeTable(QTextStream& stream) {
             previousTestName = testName;
 
             stream << "\t\t<h2>" << testName << "</h2>\n";
-
-            openTable(stream);
+            openTable(stream, folderName, false);
         }
 
-        createEntry(testNumber.toInt(), filename, stream, false);
+        createEntry(testNumber, folderName, stream, false);
     }
 
     closeTable(stream);
 }
 
-void AWSInterface::openTable(QTextStream& stream) {
-    stream << "\t\t<table>\n";
-    stream << "\t\t\t<tr>\n";
-    stream << "\t\t\t\t<th><h1>Test</h1></th>\n";
-    stream << "\t\t\t\t<th><h1>Actual Image</h1></th>\n";
-    stream << "\t\t\t\t<th><h1>Expected Image</h1></th>\n";
-    stream << "\t\t\t\t<th><h1>Difference Image</h1></th>\n";
-    stream << "\t\t\t</tr>\n";
+void AWSInterface::openTable(QTextStream& stream, const QString& testResult, const bool isFailure) {
+    QStringList resultNameComponents = testResult.split('/');
+    QString resultName = resultNameComponents[resultNameComponents.length() - 1];
+
+    bool textResultsFileFound;
+    if (isFailure) {
+        textResultsFileFound = QFile::exists(_htmlFailuresFolder + "/" + resultName + "/Result.txt");
+    } else {
+        textResultsFileFound = QFile::exists(_htmlSuccessesFolder + "/" + resultName + "/Result.txt");
+    }
+
+    if (textResultsFileFound) {
+        if (isFailure) {
+            stream << "\t\t<table>\n";
+            stream << "\t\t\t<tr>\n";
+            stream << "\t\t\t\t<th><h1>Element</h1></th>\n";
+            stream << "\t\t\t\t<th><h1>Actual Value</h1></th>\n";
+            stream << "\t\t\t\t<th><h1>Expected Value</h1></th>\n";
+            stream << "\t\t\t</tr>\n";
+        } else {
+            stream << "\t\t<h3>No errors found</h3>\n\n";
+            stream << "\t\t<h3>===============</h3>\n\n";
+        }
+    } else {
+        stream << "\t\t<table>\n";
+        stream << "\t\t\t<tr>\n";
+        stream << "\t\t\t\t<th><h1>Test</h1></th>\n";
+        stream << "\t\t\t\t<th><h1>Actual Image</h1></th>\n";
+        stream << "\t\t\t\t<th><h1>Expected Image</h1></th>\n";
+        stream << "\t\t\t\t<th><h1>Difference Image</h1></th>\n";
+        stream << "\t\t\t</tr>\n";
+    }
 }
 
 void AWSInterface::closeTable(QTextStream& stream) {
     stream << "\t\t</table>\n";
 }
 
-void AWSInterface::createEntry(int index, const QString& testResult, QTextStream& stream, const bool isFailure) {
-    stream << "\t\t\t<tr>\n";
-    stream << "\t\t\t\t<td><h1>" << QString::number(index) << "</h1></td>\n";
-
+void AWSInterface::createEntry(const int index, const QString& testResult, QTextStream& stream, const bool isFailure) {
     // For a test named `D:/t/fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf/Failure_1--tests.engine.interaction.pick.collision.many.00000`
     // we need `Failure_1--tests.engine.interaction.pick.collision.many.00000`
     QStringList resultNameComponents = testResult.split('/');
     QString resultName = resultNameComponents[resultNameComponents.length() - 1];
 
+    QString textResultFilename;
+    if (isFailure) {
+        textResultFilename = _htmlFailuresFolder + "/" + resultName + "/Result.txt";
+    } else {
+        textResultFilename = _htmlSuccessesFolder + "/" + resultName + "/Result.txt";
+    }
+    bool textResultsFileFound{ QFile::exists(textResultFilename) };
+
     QString folder;
     bool differenceFileFound;
     if (isFailure) {
@@ -320,17 +359,78 @@ void AWSInterface::createEntry(int index, const QString& testResult, QTextStream
         differenceFileFound = QFile::exists(_htmlSuccessesFolder + "/" + resultName + "/Difference Image.png");
     }
 
+    if (textResultsFileFound) {
+        // Parse the JSON file
+        QFile file;
+        file.setFileName(textResultFilename);
+        if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+            QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__),
+                "Failed to open file " + textResultFilename);
+        }
 
-    stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Actual Image.png\" width = \"576\" height = \"324\" ></td>\n";
-    stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Expected Image.png\" width = \"576\" height = \"324\" ></td>\n";
+        QString value = file.readAll();
+        file.close();
 
-    if (differenceFileFound) {
-        stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Difference Image.png\" width = \"576\" height = \"324\" ></td>\n";
+        // The Result.txt file is an object containing elements such as the following:
+        //    "angularDamping": {
+        //        "actual": 0.3938899040222168,
+        //        "expected" : 0.3938899,
+        //        "result" : "pass"
+        //    },
+        //
+        // Failures are thos element that have "fail for the result
+
+        QJsonDocument document = QJsonDocument::fromJson(value.toUtf8());
+        QJsonObject json = document.object();
+        foreach(const QString& key, json.keys()) {
+            QJsonValue value = json.value(key);
+            QJsonObject object = value.toObject();
+
+            QJsonValue actualValue = object.value("actual");
+            QString actualValueString;
+            if (actualValue.isString()) {
+                actualValueString = actualValue.toString();
+            } else if (actualValue.isBool()) {
+                actualValueString = actualValue.toBool() ? "true" : "false";
+            } else if (actualValue.isDouble()) {
+                actualValueString = QString::number(actualValue.toDouble());
+            }
+
+            QJsonValue expectedValue = object.value("expected");
+            QString expectedValueString;
+            if (expectedValue.isString()) {
+                expectedValueString = expectedValue.toString();
+            } else if (expectedValue.isBool()) {
+                expectedValueString = expectedValue.toBool() ? "true" : "false";
+            } else if (expectedValue.isDouble()) {
+                expectedValueString = QString::number(expectedValue.toDouble());
+            }
+            QString result = object.value("result").toString();
+           
+            if (result == "fail") {
+                stream << "\t\t\t<tr>\n";
+                stream << "\t\t\t\t<td><font size=\"6\">" + key + "</td>\n";
+                stream << "\t\t\t\t<td><font size=\"6\">" + actualValueString + "</td>\n";
+                stream << "\t\t\t\t<td><font size=\"6\">" + expectedValueString + "</td>\n";
+                stream << "\t\t\t</tr>\n";
+            }
+        }
     } else {
-        stream << "\t\t\t\t<td><h2>No Image Found</h2>\n";
+        stream << "\t\t\t<tr>\n";
+        stream << "\t\t\t\t<td><h1>" << QString::number(index) << "</h1></td>\n";
+
+        stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Actual Image.png\" width = \"576\" height = \"324\" ></td>\n";
+        stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Expected Image.png\" width = \"576\" height = \"324\" ></td>\n";
+
+        if (differenceFileFound) {
+            stream << "\t\t\t\t<td><img src=\"./" << folder << "/" << resultName << "/Difference Image.png\" width = \"576\" height = \"324\" ></td>\n";
+        } else {
+            stream << "\t\t\t\t<td><h2>No Image Found</h2>\n";
+        }
+
+        stream << "\t\t\t</tr>\n";
     }
 
-    stream << "\t\t\t</tr>\n";
 }
 
 void AWSInterface::updateAWS() {
diff --git a/tools/nitpick/src/AWSInterface.h b/tools/nitpick/src/AWSInterface.h
index c5be5f35bb..43d2240c19 100644
--- a/tools/nitpick/src/AWSInterface.h
+++ b/tools/nitpick/src/AWSInterface.h
@@ -40,10 +40,10 @@ public:
 
     void writeTitle(QTextStream& stream);
     void writeTable(QTextStream& stream);
-    void openTable(QTextStream& stream);
+    void openTable(QTextStream& stream, const QString& testResult, const bool isFailure);
     void closeTable(QTextStream& stream);
 
-    void createEntry(int index, const QString& testResult, QTextStream& stream, const bool isFailure);
+    void createEntry(const int index, const QString& testResult, QTextStream& stream, const bool isFailure);
 
     void updateAWS();
 

From 8938afd35015378b4fa77d2086f4070d68d0048e Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Thu, 6 Dec 2018 08:42:38 -0800
Subject: [PATCH 5/7] Updated for v1.2

---
 tools/nitpick/README.md | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/tools/nitpick/README.md b/tools/nitpick/README.md
index 7d75d660d7..23105a0e02 100644
--- a/tools/nitpick/README.md
+++ b/tools/nitpick/README.md
@@ -5,7 +5,7 @@ Nitpick is a stand alone application that provides a mechanism for regression te
 * The snapshots are compared to a 'canonical' set of images that have been produced beforehand.
 * The result, if any test failed, is a zipped folder describing the failure.
 
-Nitpick has 5 functions, separated into 4 tabs:
+Nitpick has 5 functions, separated into separate tabs:
 1. Creating tests, MD files and recursive scripts
 1. Windows task bar utility (Windows only)
 1. Running tests
@@ -22,9 +22,9 @@ Nitpick is built as part of the High Fidelity build.
 1.  Select all, right-click and select 7-Zip->Add to archive...
 1.  Set Archive format to 7z
 1.  Check "Create SFX archive
-1.  Enter installer name (i.e. `nitpick-installer-v1.1.exe`)
+1.  Enter installer name (i.e. `nitpick-installer-v1.2.exe`)
 1.  Click "OK"
-1.  Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe: aws s3 cp nitpick-installer-v1.1.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.exe
+1.  Copy created installer to https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.2.exe: aws s3 cp nitpick-installer-v1.2.exe s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.2.exe
 #### Mac
 These steps assume the hifi repository has been cloned to `~/hifi`.
 1.  (first time) Install brew
@@ -37,12 +37,12 @@ These steps assume the hifi repository has been cloned to `~/hifi`.
 1.  Change the loader instruction to find the dynamic library locally
     In a terminal: `install_name_tool -change ~/hifi/build/ext/Xcode/quazip/project/lib/libquazip5.1.dylib libquazip5.1.dylib nitpick`
 1.  Delete any existing disk images. In a terminal: `rm *.dmg`
-1.  Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.1 nitpick-installer-v1.1.dmg .`  
+1.  Create installer (note final period).In a terminal: `create-dmg --volname nitpick-installer-v1.2 nitpick-installer-v1.2.dmg .`  
     Make sure to wait for completion.
-1.  Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.1.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.1.dmg`
+1.  Copy created installer to AWS: `~/Library/Python/3.7/bin/aws s3 cp nitpick-installer-v1.2.dmg s3://hifi-qa/nitpick/Mac/nitpick-installer-v1.2.dmg`
 ### Installation
 #### Windows
-1.  (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe)
+1.  (First time) download and install vc_redist.x64.exe (available at https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.2.exe)
 1.  (First time) download and install Python 3 from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/python-3.7.0-amd64.exe (also located at https://www.python.org/downloads/)
     1. After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable.
 1.  (First time) download and install AWS CLI from https://hifi-qa.s3.amazonaws.com/nitpick/Windows/AWSCLI64PY3.msi (also available at https://aws.amazon.com/cli/
@@ -52,7 +52,7 @@ These steps assume the hifi repository has been cloned to `~/hifi`.
     1.  Leave region name and ouput format as default [None]
     1.  Install the latest release of Boto3 via pip:  `pip install boto3`
 
-1. Download the installer by browsing to [here](<https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.1.exe>)
+1. Download the installer by browsing to [here](<https://hifi-qa.s3.amazonaws.com/nitpick/Windows/nitpick-installer-v1.2.exe>)
 1. Double click on the installer and install to a convenient location  
 ![](./setup_7z.PNG)
 
@@ -76,14 +76,14 @@ In a terminal: `python3 get-pip.py --user`
     1.  Enter the secret key
     1.  Leave region name and ouput format as default [None]
     1.  Install the latest release of Boto3 via pip:  pip3 install boto3
-1.  Download the installer by browsing to [here](<https://hifi-qa.s3.amazonaws.com/nitpick/Mac/nitpick-installer-v1.1.dmg>).
+1.  Download the installer by browsing to [here](<https://hifi-qa.s3.amazonaws.com/nitpick/Mac/nitpick-installer-v1.2.dmg>).
 1.  Double-click on the downloaded image to mount it
 1. Create a folder for the nitpick files (e.g. ~/nitpick)
    If this folder exists then delete all it's contents.
 1. Copy the downloaded files to the folder  
    In a terminal:  
      `cd ~/nitpick`  
-     `cp -r /Volumes/nitpick-installer-v1.1/* .`
+     `cp -r /Volumes/nitpick-installer-v1.2/* .`
 
 1. __To run nitpick, cd to the folder that you copied to and run `./nitpick`__  
 # Usage

From a665e728e6af8978c2b3c49c054f13fbd04cf8d8 Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Thu, 6 Dec 2018 09:52:21 -0800
Subject: [PATCH 6/7] Improved contents of the HTML results.

---
 tools/nitpick/src/AWSInterface.cpp | 121 ++++++++++++++++-------------
 tools/nitpick/src/AWSInterface.h   |   4 +-
 2 files changed, 68 insertions(+), 57 deletions(-)

diff --git a/tools/nitpick/src/AWSInterface.cpp b/tools/nitpick/src/AWSInterface.cpp
index 034feae7f9..0b93ce44e5 100644
--- a/tools/nitpick/src/AWSInterface.cpp
+++ b/tools/nitpick/src/AWSInterface.cpp
@@ -103,62 +103,8 @@ void AWSInterface::writeHead(QTextStream& stream) {
 
 void AWSInterface::writeBody(QTextStream& stream) {
     stream << "\t" << "<body>\n";
-    writeTitle(stream);
-    writeTable(stream);
-    stream << "\t" << "</body>\n";
-}
 
-void AWSInterface::finishHTMLpage(QTextStream& stream) {
-    stream << "</html>\n";
-}
-
-void AWSInterface::writeTitle(QTextStream& stream) {
-    // Separate relevant components from the results name
-    // The expected format is as follows: `D:/tt/snapshots/TestResults--2018-10-04_11-09-41(PR14128)[DESKTOP-PMKNLSQ].zip`
-    QStringList tokens = _testResults.split('/');
-
-    // date_buildorPR_hostName will be 2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ]
-    QString date_buildorPR_hostName = tokens[tokens.length() - 1].split("--")[1].split(".")[0];
-
-    QString buildorPR = date_buildorPR_hostName.split('(')[1].split(')')[0];
-    QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0];
-
-    QStringList dateList = date_buildorPR_hostName.split('(')[0].split('_')[0].split('-');
-    QString year = dateList[0];
-    QString month = dateList[1];
-    QString day = dateList[2];
-
-    QStringList timeList = date_buildorPR_hostName.split('(')[0].split('_')[1].split('-');
-    QString hour = timeList[0];
-    QString minute = timeList[1];
-    QString second = timeList[2];
-
-    const QString months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-    stream << "\t" << "\t" << "<font color=\"red\">\n";
-    stream << "\t" << "\t" << "<h1>Failures for ";
-    stream << months[month.toInt() - 1] << " " << day << ", " << year << ", ";
-    stream << hour << ":" << minute << ":" << second << ", ";
-
-    if (buildorPR.left(2) == "PR") {
-        stream << "PR " << buildorPR.right(buildorPR.length() - 2) << ", ";
-    } else {
-        stream << "build " << buildorPR << ", ";
-    }
-
-    stream << "run on " << hostName << "</h1>\n";
-}
-
-void AWSInterface::writeTable(QTextStream& stream) {
-    QString previousTestName{ "" };
-
-    // Loop over all entries in directory.  This is done in stages, as the names are not in the order of the tests
-    //      The first stage reads the directory names into a list 
-    //      The second stage renames the tests by removing everything up to "--tests."
-    //      The third stage renames the directories
-    //      The fourth and lasts stage creates the HTML entries
-    //
-    // Note that failures are processed first, then successes
+    // The results are read here as they are used both in the title (for the summary) and for table
     QStringList originalNamesFailures;
     QStringList originalNamesSuccesses;
     QDirIterator it1(_workingDirectory);
@@ -185,6 +131,71 @@ void AWSInterface::writeTable(QTextStream& stream) {
         }
     }
 
+    writeTitle(stream, originalNamesFailures, originalNamesSuccesses);
+    writeTable(stream, originalNamesFailures, originalNamesSuccesses);
+    stream << "\t" << "</body>\n";
+}
+
+void AWSInterface::finishHTMLpage(QTextStream& stream) {
+    stream << "</html>\n";
+}
+
+void AWSInterface::writeTitle(QTextStream& stream, const QStringList& originalNamesFailures, const QStringList& originalNamesSuccesses) {
+    // Separate relevant components from the results name
+    // The expected format is as follows: `D:/tt/snapshots/TestResults--2018-10-04_11-09-41(PR14128)[DESKTOP-PMKNLSQ].zip`
+    QStringList tokens = _testResults.split('/');
+
+    // date_buildorPR_hostName will be 2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ]
+    QString date_buildorPR_hostName = tokens[tokens.length() - 1].split("--")[1].split(".")[0];
+
+    QString buildorPR = date_buildorPR_hostName.split('(')[1].split(')')[0];
+    QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0];
+
+    QStringList dateList = date_buildorPR_hostName.split('(')[0].split('_')[0].split('-');
+    QString year = dateList[0];
+    QString month = dateList[1];
+    QString day = dateList[2];
+
+    QStringList timeList = date_buildorPR_hostName.split('(')[0].split('_')[1].split('-');
+    QString hour = timeList[0];
+    QString minute = timeList[1];
+    QString second = timeList[2];
+
+    const QString months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+    stream << "\t" << "\t" << "<font color=\"Green\">\n";
+    stream << "\t" << "\t" << "<h1>Results for ";
+    stream << months[month.toInt() - 1] << " " << day << ", " << year << ", ";
+    stream << hour << ":" << minute << ":" << second << ", ";
+
+    if (buildorPR.left(2) == "PR") {
+        stream << "PR " << buildorPR.right(buildorPR.length() - 2) << ", ";
+    } else {
+        stream << "build " << buildorPR << ", ";
+    }
+
+    stream << "run on " << hostName << "</h1>\n";
+
+    int numberOfFailures = originalNamesFailures.length();
+    int numberOfSuccesses = originalNamesSuccesses.length();
+
+    stream << "<h2>" << QString::number(numberOfFailures) << " failed, out of a total of " << QString::number(numberOfSuccesses) << " tests</h2>\n";
+
+    stream << "\t" << "\t" << "<font color=\"red\">\n";
+    stream << "\t" << "\t" << "<h1>The following tests failed:</h1>";
+}
+
+void AWSInterface::writeTable(QTextStream& stream, const QStringList& originalNamesFailures, const QStringList& originalNamesSuccesses) {
+    QString previousTestName{ "" };
+
+    // Loop over all entries in directory.  This is done in stages, as the names are not in the order of the tests
+    //      The first stage reads the directory names into a list 
+    //      The second stage renames the tests by removing everything up to "--tests."
+    //      The third stage renames the directories
+    //      The fourth and lasts stage creates the HTML entries
+    //
+    // Note that failures are processed first, then successes
+
     QStringList newNamesFailures;
     for (int i = 0; i < originalNamesFailures.length(); ++i) {
         newNamesFailures.append(originalNamesFailures[i].split("--tests.")[1]);
diff --git a/tools/nitpick/src/AWSInterface.h b/tools/nitpick/src/AWSInterface.h
index 43d2240c19..fda250b115 100644
--- a/tools/nitpick/src/AWSInterface.h
+++ b/tools/nitpick/src/AWSInterface.h
@@ -38,8 +38,8 @@ public:
     void writeBody(QTextStream& stream);
     void finishHTMLpage(QTextStream& stream);
 
-    void writeTitle(QTextStream& stream);
-    void writeTable(QTextStream& stream);
+    void writeTitle(QTextStream& stream, const QStringList& originalNamesFailures, const QStringList& originalNamesSuccesses);
+    void writeTable(QTextStream& stream, const QStringList& originalNamesFailures, const QStringList& originalNamesSuccesses);
     void openTable(QTextStream& stream, const QString& testResult, const bool isFailure);
     void closeTable(QTextStream& stream);
 

From 4a50baddc2b25da7f5a5d53c95be0e5a7926449b Mon Sep 17 00:00:00 2001
From: NissimHadar <nissim.hadar@gmail.com>
Date: Thu, 6 Dec 2018 09:55:48 -0800
Subject: [PATCH 7/7] Reverted debug code.

---
 libraries/audio-client/src/AudioClient.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/libraries/audio-client/src/AudioClient.cpp b/libraries/audio-client/src/AudioClient.cpp
index 9d0a2ea79b..9bad7e2f45 100644
--- a/libraries/audio-client/src/AudioClient.cpp
+++ b/libraries/audio-client/src/AudioClient.cpp
@@ -674,7 +674,6 @@ void AudioClient::start() {
 }
 
 void AudioClient::stop() {
-    return;
     qCDebug(audioclient) << "AudioClient::stop(), requesting switchInputToAudioDevice() to shut down";
     switchInputToAudioDevice(QAudioDeviceInfo(), true);